import { getTemplateFilters, importTemplateIntoApplicationViaOnboardingFlow, } from "actions/templateActions"; import type { Template } from "api/TemplatesApi"; import type { AppState } from "@appsmith/reducers"; import { TemplatesContent } from "pages/Templates"; import React, { useEffect, useState } from "react"; import { useDispatch, useSelector } from "react-redux"; import { allTemplatesFiltersSelector, getForkableWorkspaces, getTemplatesSelector, isImportingTemplateToAppSelector, } from "selectors/templatesSelectors"; import styled from "styled-components"; import { getAllTemplates } from "actions/templateActions"; import { Link, Text } from "design-system"; import { CREATE_NEW_APPS_STEP_SUBTITLE, CREATE_NEW_APPS_STEP_TITLE, GO_BACK, START_FROM_SCRATCH_SUBTITLE, START_FROM_SCRATCH_TITLE, START_FROM_TEMPLATE_SUBTITLE, START_FROM_TEMPLATE_TITLE, createMessage, } from "@appsmith/constants/messages"; import Filters from "pages/Templates/Filters"; import { isEmpty } from "lodash"; import StartScratch from "assets/images/start-from-scratch.svg"; import StartTemplate from "assets/images/start-from-template.svg"; import AnalyticsUtil from "utils/AnalyticsUtil"; import { TemplateView } from "pages/Templates/TemplateView"; import { firstTimeUserOnboardingInit, resetCurrentApplicationIdForCreateNewApp, } from "actions/onboardingActions"; import { getApplicationByIdFromWorkspaces } from "@appsmith/selectors/applicationSelectors"; import urlBuilder from "@appsmith/entities/URLRedirect/URLAssembly"; const SectionWrapper = styled.div` display: flex; flex-direction: column; padding: 0 var(--ads-v2-spaces-7) var(--ads-v2-spaces-7); ${(props) => ` height: calc(100vh - ${props.theme.homePage.header}px); margin-top: ${props.theme.homePage.header}px; `} `; const BackWrapper = styled.div<{ hidden?: boolean }>` position: sticky; ${(props) => ` top: ${props.theme.homePage.header}px; `} background: var(--ads-v2-color-bg); padding: var(--ads-v2-spaces-3); z-index: 1; margin-left: -4px; ${(props) => `${props.hidden && "visibility: hidden; opacity: 0;"}`} `; const FiltersWrapper = styled.div` width: ${(props) => props.theme.homePage.sidebar}px; height: 100%; display: flex; flex-direction: column; border-right: 1px solid var(--ads-v2-color-border); flex-shrink: 0; .filter-wrapper { height: 100%; } `; const TemplateWrapper = styled.div` display: flex; flex-grow: 1; overflow: hidden; `; const TemplateContentWrapper = styled.div` flex-grow: 1; overflow: auto; `; const OptionWrapper = styled.div` display: flex; align-items: center; flex-direction: column; justify-content: center; flex-grow: 1; `; const CardsWrapper = styled.div` display: flex; gap: 16px; margin-top: 48px; `; const CardContainer = styled.div` display: flex; flex-direction: column; padding: 48px; border: 1px solid var(--ads-v2-color-border); width: 324px; align-items: center; text-align: center; cursor: pointer; border-radius: 4px; img { height: 160px; margin-bottom: 48px; } position: relative; `; interface CardProps { onClick?: () => void; src: string; subTitle: string; testid: string; title: string; } const Card = ({ onClick, src, subTitle, testid, title }: CardProps) => { return ( {title} {title} {subTitle} ); }; const CreateNewAppsOption = ({ currentApplicationIdForCreateNewApp, onClickBack, }: { currentApplicationIdForCreateNewApp: string; onClickBack: () => void; }) => { const [useTemplate, setUseTemplate] = useState(false); const [selectedTemplate, setSelectedTemplate] = useState(""); const templatesCount = useSelector( (state: AppState) => state.ui.templates.templates.length, ); const filters = useSelector(allTemplatesFiltersSelector); const workspaceList = useSelector(getForkableWorkspaces); const isImportingTemplate = useSelector(isImportingTemplateToAppSelector); const allTemplates = useSelector(getTemplatesSelector); const application = useSelector((state) => getApplicationByIdFromWorkspaces( state, currentApplicationIdForCreateNewApp, ), ); const dispatch = useDispatch(); const onClickStartFromTemplate = () => { AnalyticsUtil.logEvent("CREATE_APP_FROM_TEMPLATE"); if (isEmpty(filters.functions)) { dispatch(getTemplateFilters()); } if (!templatesCount) { dispatch(getAllTemplates()); } setUseTemplate(true); }; const onClickStartFromScratch = () => { if (application) { AnalyticsUtil.logEvent("CREATE_APP_FROM_SCRATCH"); dispatch( firstTimeUserOnboardingInit( application.id, application.defaultPageId as string, ), ); } }; const goBackFromTemplate = () => { setUseTemplate(false); }; const getTemplateById = (id: string) => { const template = allTemplates.find((template) => template.id === id); return template; }; const onTemplateClick = (id: string) => { const template = getTemplateById(id); if (template) { AnalyticsUtil.logEvent("CLICK_ON_TEMPLATE_CARD_WHEN_ONBOARDING", { id, title: template.title, }); // When template is clicked to view the template details if (!isImportingTemplate) setSelectedTemplate(id); } }; const resetCreateNewAppFlow = () => { dispatch(resetCurrentApplicationIdForCreateNewApp()); }; const onClickUseTemplate = (id: string) => { const template = getTemplateById(id); if (template) { AnalyticsUtil.logEvent("USE_TEMPLATE_FROM_DETAILS_PAGE_WHEN_ONBOARDING", { title: template.title, }); // When Use template is clicked on template view detail screen if (!isImportingTemplate && application) { dispatch( importTemplateIntoApplicationViaOnboardingFlow( id, template.title as string, template.pages.map((p) => p.name), application.id, application.workspaceId, ), ); } } }; const onForkTemplateClick = (template: Template) => { const title = template.title; AnalyticsUtil.logEvent("FORK_TEMPLATE_WHEN_ONBOARDING", { title }); // When fork template is clicked to add a new app using the template if (!isImportingTemplate && application) { dispatch( importTemplateIntoApplicationViaOnboardingFlow( template.id, template.title, template.pages.map((p) => p.name), application.id, application.workspaceId, ), ); } }; const onClickBackButton = () => { if (isImportingTemplate) return; if (useTemplate) { if (selectedTemplate) { // Going back from template details view screen const template = getTemplateById(selectedTemplate); if (template) { AnalyticsUtil.logEvent( "ONBOARDING_FLOW_CLICK_BACK_BUTTON_TEMPLATE_DETAILS_PAGE", { title: template.title }, ); } setSelectedTemplate(""); } else { // Going back from start from template screen AnalyticsUtil.logEvent( "ONBOARDING_FLOW_CLICK_BACK_BUTTON_START_FROM_TEMPLATE_PAGE", ); goBackFromTemplate(); } } else { // Going back from create new app flow AnalyticsUtil.logEvent( "ONBOARDING_FLOW_CLICK_BACK_BUTTON_CREATE_NEW_APP_PAGE", ); onClickBack(); } }; const selectionOptions: CardProps[] = [ { onClick: onClickStartFromScratch, src: StartScratch, subTitle: createMessage(START_FROM_SCRATCH_SUBTITLE), testid: "t--start-from-scratch", title: createMessage(START_FROM_SCRATCH_TITLE), }, { onClick: onClickStartFromTemplate, src: StartTemplate, subTitle: createMessage(START_FROM_TEMPLATE_SUBTITLE), testid: "t--start-from-template", title: createMessage(START_FROM_TEMPLATE_TITLE), }, ]; useEffect(() => { AnalyticsUtil.logEvent("ONBOARDING_CREATE_APP_FLOW", { totalOptions: selectionOptions.length, }); if (application) urlBuilder.updateURLParams( { applicationSlug: application.slug, applicationVersion: application.applicationVersion, applicationId: application.id, }, application.pages.map((page) => ({ pageSlug: page.slug, customSlug: page.customSlug, pageId: page.id, })), ); return () => { resetCreateNewAppFlow(); }; }, []); return ( {useTemplate ? ( selectedTemplate ? ( ) : ( ) ) : ( {createMessage(CREATE_NEW_APPS_STEP_TITLE)} {createMessage(CREATE_NEW_APPS_STEP_SUBTITLE)} {selectionOptions.map((option: CardProps) => ( ))} )} ); }; export default CreateNewAppsOption;