diff --git a/src/OnboardingSPA/chapters/siteGen/core.js b/src/OnboardingSPA/chapters/siteGen/core.js new file mode 100644 index 000000000..5352d8c96 --- /dev/null +++ b/src/OnboardingSPA/chapters/siteGen/core.js @@ -0,0 +1,19 @@ +import { __ } from '@wordpress/i18n'; + +import { CHAPTER_SITEGEN_CORE } from '../../../constants'; +import { Chapter } from '../../data/models/Chapter'; +import { stepSiteGenSiteDetails } from '../../steps/SiteGen/SiteDetails/step'; +import { stepSiteGenSiteLogo } from '../../steps/SiteGen/SiteLogo/step'; +import { stepSiteGenSocialMedia } from '../../steps/SiteGen/SocialMedia/step'; + +const steps = [ + stepSiteGenSiteDetails, + stepSiteGenSocialMedia, + stepSiteGenSiteLogo, +]; + +export const siteGenCore = new Chapter( { + id: CHAPTER_SITEGEN_CORE, + name: __( 'Sitegen Core', 'wp-module-onboarding' ), + steps, +} ); diff --git a/src/OnboardingSPA/chapters/siteGen/design.js b/src/OnboardingSPA/chapters/siteGen/design.js new file mode 100644 index 000000000..92873fd92 --- /dev/null +++ b/src/OnboardingSPA/chapters/siteGen/design.js @@ -0,0 +1,14 @@ +import { __ } from '@wordpress/i18n'; + +import { CHAPTER_SITEGEN_DESIGN } from '../../../constants'; +import { Chapter } from '../../data/models/Chapter'; +import { stepSiteGenEditor } from '../../steps/SiteGen/Editor/step'; +import { stepSiteGenPreview } from '../../steps/SiteGen/Preview/step'; + +const steps = [ stepSiteGenPreview, stepSiteGenEditor ]; + +export const siteGenDesign = new Chapter( { + id: CHAPTER_SITEGEN_DESIGN, + name: __( 'Sitegen Design', 'wp-module-onboarding' ), + steps, +} ); diff --git a/src/OnboardingSPA/chapters/siteGen/features.js b/src/OnboardingSPA/chapters/siteGen/features.js new file mode 100644 index 000000000..118f82766 --- /dev/null +++ b/src/OnboardingSPA/chapters/siteGen/features.js @@ -0,0 +1,14 @@ +import { __ } from '@wordpress/i18n'; + +import { CHAPTER_SITEGEN_FEATURES } from '../../../constants'; +import { Chapter } from '../../data/models/Chapter'; +import { stepSiteGenBuilding } from '../../steps/SiteGen/Building/step'; +import { stepSiteGenExperience } from '../../steps/SiteGen/Experience/step'; + +const steps = [ stepSiteGenExperience, stepSiteGenBuilding ]; + +export const siteGenFeatures = new Chapter( { + id: CHAPTER_SITEGEN_FEATURES, + name: __( 'Sitegen Features', 'wp-module-onboarding' ), + steps, +} ); diff --git a/src/OnboardingSPA/chapters/sitegen.js b/src/OnboardingSPA/chapters/sitegen.js deleted file mode 100644 index faaf53ad6..000000000 --- a/src/OnboardingSPA/chapters/sitegen.js +++ /dev/null @@ -1,28 +0,0 @@ -import { CHAPTER_SITEGEN } from '../../constants'; -import { Chapter } from '../data/models/Chapter'; -import { __ } from '@wordpress/i18n'; -import { stepSiteGenWelcome } from '../steps/SiteGen/Welcome/step'; -import { stepSiteGenSiteDetails } from '../steps/SiteGen/SiteDetails/step'; -import { stepSiteGenSiteLogo } from '../steps/SiteGen/SiteLogo/step'; -import { stepSiteGenSocialMedia } from '../steps/SiteGen/SocialMedia/step'; -import { stepSiteGenExperience } from '../steps/SiteGen/Experience/step'; -import { stepSiteGenBuilding } from '../steps/SiteGen/Building/step'; -import { stepSiteGenPreview } from '../steps/SiteGen/Preview/step'; -import { stepSiteGenEditor } from '../steps/SiteGen/Editor/step'; - -const steps = [ - stepSiteGenWelcome, - stepSiteGenSiteDetails, - stepSiteGenSocialMedia, - stepSiteGenSiteLogo, - stepSiteGenExperience, - stepSiteGenBuilding, - stepSiteGenPreview, - stepSiteGenEditor, -]; - -export const sitegen = new Chapter( { - id: CHAPTER_SITEGEN, - name: __( 'Site Generation', 'wp-module-onboarding' ), - steps, -} ); diff --git a/src/OnboardingSPA/components/LivePreview/SiteGenPreviewSelectableCard/index.js b/src/OnboardingSPA/components/LivePreview/SiteGenPreviewSelectableCard/index.js index ea686bdb7..003149088 100644 --- a/src/OnboardingSPA/components/LivePreview/SiteGenPreviewSelectableCard/index.js +++ b/src/OnboardingSPA/components/LivePreview/SiteGenPreviewSelectableCard/index.js @@ -16,6 +16,7 @@ const SiteGenPreviewSelectableCard = ( { overlay = false, skeletonLoadingTime = 2500, slug, + position, title, isFavorite, palette, @@ -28,19 +29,19 @@ const SiteGenPreviewSelectableCard = ( { const onPreview = () => { if ( typeof handlePreview === 'function' ) { - return handlePreview( slug ); + return handlePreview( slug, position ); } }; const onRegenerate = () => { if ( typeof handleRegenerate === 'function' ) { - return handleRegenerate( slug, palette, isFavorite ); + return handleRegenerate( slug, palette, isFavorite, position ); } }; const onFavorite = () => { if ( typeof handleFavorite === 'function' ) { - return handleFavorite( slug ); + return handleFavorite( slug, position ); } }; diff --git a/src/OnboardingSPA/components/NewfoldInterfaceSkeleton/SiteGen/index.js b/src/OnboardingSPA/components/NewfoldInterfaceSkeleton/SiteGen/index.js index d7c2917c5..69ea1625f 100644 --- a/src/OnboardingSPA/components/NewfoldInterfaceSkeleton/SiteGen/index.js +++ b/src/OnboardingSPA/components/NewfoldInterfaceSkeleton/SiteGen/index.js @@ -26,6 +26,15 @@ import { SKIP_FLOW_ERROR_CODE_DATABASE, SKIP_FLOW_ERROR_CODE_20, } from '../../../../constants'; +import { + OnboardingEvent, + trackOnboardingEvent, +} from '../../../utils/analytics/hiive'; +import { + ACTION_ONBOARDING_CHAPTER_COMPLETE, + ACTION_ONBOARDING_CHAPTER_STARTED, +} from '../../../utils/analytics/hiive/constants'; +import { SITEGEN_FLOW } from '../../../data/flows/constants'; // Wrapping the NewfoldInterfaceSkeleton with the HOC to make theme available const ThemedNewfoldInterfaceSkeleton = themeToggleHOC( @@ -35,29 +44,15 @@ const ThemedNewfoldInterfaceSkeleton = themeToggleHOC( ); const SiteGen = () => { - const { newfoldBrand } = useSelect( ( select ) => { - return { - newfoldBrand: select( nfdOnboardingStore ).getNewfoldBrand(), - }; - }, [] ); - - // Update Title and Tagline on the site. - const { editEntityRecord } = useDispatch( coreStore ); - const { getEditedEntityRecord } = useSelect( ( select ) => { - return select( coreStore ); - }, [] ); - - useEffect( () => { - document.body.classList.add( `nfd-brand-${ newfoldBrand }` ); - }, [ newfoldBrand ] ); - const location = useLocation(); - const { currentData, initialize, pluginInstallHash, siteGenErrorStatus, interactionDisabled, + newfoldBrand, + currentStep, + lastChapter, } = useSelect( ( select ) => { return { currentData: @@ -69,11 +64,28 @@ const SiteGen = () => { select( nfdOnboardingStore ).getSiteGenErrorStatus(), interactionDisabled: select( nfdOnboardingStore ).getInteractionDisabled(), + newfoldBrand: select( nfdOnboardingStore ).getNewfoldBrand(), + currentStep: select( nfdOnboardingStore ).getCurrentStep(), + lastChapter: select( nfdOnboardingStore ).getCurrentChapter(), }; } ); - const { setCurrentOnboardingData, updateSiteGenErrorStatus } = - useDispatch( nfdOnboardingStore ); + const { + setCurrentOnboardingData, + updateSiteGenErrorStatus, + setActiveChapter, + } = useDispatch( nfdOnboardingStore ); + + // Update Title and Tagline on the site. + const { editEntityRecord } = useDispatch( coreStore ); + const { getEditedEntityRecord } = useSelect( ( select ) => { + return select( coreStore ); + }, [] ); + + useEffect( () => { + document.body.classList.add( `nfd-brand-${ newfoldBrand }` ); + }, [ newfoldBrand ] ); + const location = useLocation(); const prevSiteGenErrorStatus = useRef(); @@ -147,6 +159,14 @@ const SiteGen = () => { ) { return; } + + if ( ! window.nfdOnboarding?.siteGenTimerInterval ) { + window.nfdOnboarding.siteGenTime = 0; + window.nfdOnboarding.siteGenTimerInterval = setInterval( () => { + window.nfdOnboarding.siteGenTime += 1; + }, 1000 ); + } + let identifiers = await getSiteGenIdentifiers(); identifiers = identifiers.body; @@ -187,6 +207,55 @@ const SiteGen = () => { }; }; + const trackChapters = () => { + const currentChapter = currentStep?.chapter; + + if ( lastChapter !== currentChapter ) { + if ( lastChapter ) { + if ( currentData.data.chapters[ lastChapter ] ) { + currentData.data.chapters[ lastChapter ].completed = true; + } + trackOnboardingEvent( + new OnboardingEvent( + ACTION_ONBOARDING_CHAPTER_COMPLETE, + lastChapter, + { + source: SITEGEN_FLOW, + } + ) + ); + } + + if ( currentChapter ) { + if ( currentData.data.chapters[ currentChapter ] ) { + currentData.data.chapters[ + currentChapter + ].completed = false; + } + trackOnboardingEvent( + new OnboardingEvent( + ACTION_ONBOARDING_CHAPTER_STARTED, + currentChapter, + { + source: SITEGEN_FLOW, + } + ) + ); + } + + setActiveChapter( currentChapter ); + } + + if ( currentChapter && currentData.data.chapters[ currentChapter ] ) { + currentData.data.chapters[ currentChapter ].lastStep = + currentStep?.path ?? ''; + } + }; + + useEffect( () => { + trackChapters(); + }, [ currentStep ] ); + useEffect( () => { if ( initialize ) { initializePlugins( pluginInstallHash ); diff --git a/src/OnboardingSPA/components/Sidebar/components/Customize/DesignColorsPanel/ColorPaletteIcon/index.js b/src/OnboardingSPA/components/Sidebar/components/Customize/DesignColorsPanel/ColorPaletteIcon/index.js index c48dc5175..ac3ea39da 100644 --- a/src/OnboardingSPA/components/Sidebar/components/Customize/DesignColorsPanel/ColorPaletteIcon/index.js +++ b/src/OnboardingSPA/components/Sidebar/components/Customize/DesignColorsPanel/ColorPaletteIcon/index.js @@ -1,3 +1,9 @@ +import { SITEGEN_FLOW } from '../../../../../../data/flows/constants'; +import { + OnboardingEvent, + trackOnboardingEvent, +} from '../../../../../../utils/analytics/hiive'; +import { ACTION_COLORS_SELECTED } from '../../../../../../utils/analytics/hiive/constants'; import './stylesheet.scss'; const ColorPaletteIcon = ( { @@ -16,6 +22,13 @@ const ColorPaletteIcon = ( { const handleClick = () => { setSelectedPalette( idx ); setSelectedColor( colors[ idx ] ); + const { isDefault, ...colorsForEvent } = colors[ idx ]; + trackOnboardingEvent( + new OnboardingEvent( ACTION_COLORS_SELECTED, 'generated', { + colors: colorsForEvent, + source: SITEGEN_FLOW, + } ) + ); if ( setShowCustomColors ) { setShowCustomColors( false ); } diff --git a/src/OnboardingSPA/components/Sidebar/components/Customize/DesignColorsPanel/index.js b/src/OnboardingSPA/components/Sidebar/components/Customize/DesignColorsPanel/index.js index f4d57b6e7..a9f2d7872 100644 --- a/src/OnboardingSPA/components/Sidebar/components/Customize/DesignColorsPanel/index.js +++ b/src/OnboardingSPA/components/Sidebar/components/Customize/DesignColorsPanel/index.js @@ -11,6 +11,12 @@ import { store as nfdOnboardingStore } from '../../../../../store'; import { __ } from '@wordpress/i18n'; // eslint-disable-next-line import/no-extraneous-dependencies import { cloneDeep } from 'lodash'; +import { + OnboardingEvent, + trackOnboardingEvent, +} from '../../../../../utils/analytics/hiive'; +import { ACTION_COLORS_SELECTED } from '../../../../../utils/analytics/hiive/constants'; +import { SITEGEN_FLOW } from '../../../../../data/flows/constants'; const DesignColorsPanel = forwardRef( ( @@ -150,6 +156,13 @@ const DesignColorsPanel = forwardRef( setIsEditingCustomColors( false ); setSelectedPalette( 'custom' ); setCustomColors( selectedColor ); + const { isDefault, ...colorsForEvent } = selectedColor; + trackOnboardingEvent( + new OnboardingEvent( ACTION_COLORS_SELECTED, 'custom', { + colors: colorsForEvent, + source: SITEGEN_FLOW, + } ) + ); }; const handleEditCustomColors = () => { diff --git a/src/OnboardingSPA/components/Sidebar/components/Customize/DesignFontsPanel/index.js b/src/OnboardingSPA/components/Sidebar/components/Customize/DesignFontsPanel/index.js index 5c9f21429..0aebb3367 100644 --- a/src/OnboardingSPA/components/Sidebar/components/Customize/DesignFontsPanel/index.js +++ b/src/OnboardingSPA/components/Sidebar/components/Customize/DesignFontsPanel/index.js @@ -6,6 +6,12 @@ import { PanelBody, PanelRow, Button } from '@wordpress/components'; import './stylesheet.scss'; import { store as nfdOnboardingStore } from '../../../../../store'; import { __ } from '@wordpress/i18n'; +import { + OnboardingEvent, + trackOnboardingEvent, +} from '../../../../../utils/analytics/hiive'; +import { ACTION_FONTS_SELECTED } from '../../../../../utils/analytics/hiive/constants'; +import { SITEGEN_FLOW } from '../../../../../data/flows/constants'; const FontGroup = ( { baseClassName, @@ -336,6 +342,16 @@ const DesignFontsPanel = forwardRef( setShowCustomFonts( false ); } setSelectedGroup( groupId ); + const eventFonts = { + headings: fontGroups[ groupId ].headings, + body: fontGroups[ groupId ].body, + }; + trackOnboardingEvent( + new OnboardingEvent( ACTION_FONTS_SELECTED, 'generated', { + fonts: eventFonts, + source: SITEGEN_FLOW, + } ) + ); }; const handleSelectYourOwnFonts = () => { @@ -360,6 +376,12 @@ const DesignFontsPanel = forwardRef( const handleApplyCustomFonts = () => { setSelectedGroup( null ); setSelectedCustomFont( customFont ); + trackOnboardingEvent( + new OnboardingEvent( ACTION_FONTS_SELECTED, 'custom', { + fonts: customFont, + source: SITEGEN_FLOW, + } ) + ); setIsEditingCustomFont( false ); setSelectedGroup( 'custom' ); }; diff --git a/src/OnboardingSPA/components/Sidebar/components/SitegenEditorPatterns/Sidebar.js b/src/OnboardingSPA/components/Sidebar/components/SitegenEditorPatterns/Sidebar.js index 9c96c9c08..237b793b8 100644 --- a/src/OnboardingSPA/components/Sidebar/components/SitegenEditorPatterns/Sidebar.js +++ b/src/OnboardingSPA/components/Sidebar/components/SitegenEditorPatterns/Sidebar.js @@ -21,6 +21,16 @@ import TabPanelHover from '../../../TabPanelHover'; import { cloneDeep } from 'lodash'; import { getGlobalStyles } from '../../../../utils/api/themes'; import { LivePreview } from '../../../LivePreview'; +import { + OnboardingEvent, + trackOnboardingEvent, +} from '../../../../utils/analytics/hiive'; +import { + ACTION_SITEGEN_HOMEPAGE_FAVORITED, + ACTION_SITEGEN_HOMEPAGE_SELECTED, + ACTION_SITEGEN_SIDEBAR_OPENED, +} from '../../../../utils/analytics/hiive/constants'; +import { SITEGEN_FLOW } from '../../../../data/flows/constants'; const SitegenEditorPatternsSidebar = () => { const [ homepages, setHomepages ] = useState(); @@ -45,17 +55,32 @@ const SitegenEditorPatternsSidebar = () => { setIsSidebarOpened( false ); }; - const handlePreview = ( slug ) => { + const handleTabSwitch = ( tab ) => { + trackOnboardingEvent( + new OnboardingEvent( ACTION_SITEGEN_SIDEBAR_OPENED, tab.name, { + source: SITEGEN_FLOW, + } ) + ); + setActiveTab( tab ); + }; + + const handlePreview = ( slug, position ) => { if ( ! ( slug in homepages ) ) { return false; } - currentData.sitegen.homepages.active = homepages[ slug ]; + currentData.sitegen.homepages.active = homepages[ slug ]; setActiveHomepage( homepages[ slug ] ); setCurrentOnboardingData( currentData ); + trackOnboardingEvent( + new OnboardingEvent( ACTION_SITEGEN_HOMEPAGE_SELECTED, slug, { + position: position + 1, + source: SITEGEN_FLOW, + } ) + ); }; - const handleFavorite = ( slug ) => { + const handleFavorite = ( slug, position ) => { if ( ! ( slug in homepages ) ) { return; } @@ -69,6 +94,15 @@ const SitegenEditorPatternsSidebar = () => { setHomepages( homepagesCopy ); setCurrentOnboardingData( currentData ); + + trackOnboardingEvent( + new OnboardingEvent( ACTION_SITEGEN_HOMEPAGE_FAVORITED, slug, { + favorite: isFavorite, + position: position + 1, + placement: 'editor_sidebar', + source: SITEGEN_FLOW, + } ) + ); }; const loadData = async () => { @@ -95,7 +129,7 @@ const SitegenEditorPatternsSidebar = () => { useEffect( () => { setActiveTab( { - name: __( 'All Versions', 'wp-module-onboarding' ), + name: 'all_versions', title: (

{ __( 'All Versions', 'wp-module-onboarding' ) }

@@ -105,7 +139,7 @@ const SitegenEditorPatternsSidebar = () => { homepages && activeHomepage && globalStyles && - Object.keys( homepages ).map( ( homepage ) => { + Object.keys( homepages ).map( ( homepage, idx ) => { const data = homepages[ homepage ]; const newPreviewSettings = cloneDeep( globalStyles[ 0 ] ); newPreviewSettings.settings.color.palette = @@ -123,10 +157,14 @@ const SitegenEditorPatternsSidebar = () => { >
handlePreview( data.slug ) } + onClick={ () => + handlePreview( data.slug, idx ) + } role="button" tabIndex={ 0 } - onKeyDown={ () => handlePreview( data.slug ) } + onKeyDown={ () => + handlePreview( data.slug, idx ) + } > { role="button" tabIndex={ 0 } onClick={ () => - handleFavorite( data.slug ) + handleFavorite( data.slug, idx ) } onKeyDown={ () => - handleFavorite( data.slug ) + handleFavorite( data.slug, idx ) } >

@@ -183,10 +221,7 @@ const SitegenEditorPatternsSidebar = () => { } tabs={ [ { - name: __( - 'All Versions', - 'wp-module-onboarding' - ), + name: 'all_versions', title: (

@@ -203,7 +238,7 @@ const SitegenEditorPatternsSidebar = () => { activeHomepage && globalStyles && Object.keys( homepages ).map( - ( homepage ) => { + ( homepage, idx ) => { const data = homepages[ homepage ]; const newPreviewSettings = @@ -231,12 +266,14 @@ const SitegenEditorPatternsSidebar = () => { tabIndex={ 0 } onKeyDown={ () => handlePreview( - data.slug + data.slug, + idx ) } onClick={ () => handlePreview( - data.slug + data.slug, + idx ) } > @@ -272,12 +309,14 @@ const SitegenEditorPatternsSidebar = () => { } onKeyDown={ () => handleFavorite( - data.slug + data.slug, + idx ) } onClick={ () => handleFavorite( - data.slug + data.slug, + idx ) } >

@@ -293,7 +332,7 @@ const SitegenEditorPatternsSidebar = () => { ), }, { - name: 'Favorites', + name: 'favorites', title: (
@@ -311,7 +350,7 @@ const SitegenEditorPatternsSidebar = () => { activeHomepage && globalStyles && Object.keys( homepages ).map( - ( homepage ) => { + ( homepage, idx ) => { const data = homepages[ homepage ]; if ( ! data.isFavorite ) { @@ -342,12 +381,14 @@ const SitegenEditorPatternsSidebar = () => { tabIndex={ 0 } onKeyDown={ () => handlePreview( - data.slug + data.slug, + idx ) } onClick={ () => handlePreview( - data.slug + data.slug, + idx ) } > @@ -380,7 +421,7 @@ const SitegenEditorPatternsSidebar = () => { ), }, ] } - callback={ setActiveTab } + callback={ handleTabSwitch } triggerEvent="click" >
diff --git a/src/OnboardingSPA/components/StartOptions/index.js b/src/OnboardingSPA/components/StartOptions/index.js index 6dbb43305..80b1c3716 100644 --- a/src/OnboardingSPA/components/StartOptions/index.js +++ b/src/OnboardingSPA/components/StartOptions/index.js @@ -5,6 +5,11 @@ import { validateFlow } from '../../data/flows/utils'; import { useNavigate } from 'react-router-dom'; import { memo } from '@wordpress/element'; import { store as nfdOnboardingStore } from '../../store'; +import { + OnboardingEvent, + trackOnboardingEvent, +} from '../../utils/analytics/hiive'; +import { ACTION_SITEGEN_FORK_OPTION_SELECTED } from '../../utils/analytics/hiive/constants'; const StartOptions = ( { questionnaire, oldFlow, options } ) => { const navigate = useNavigate(); @@ -50,13 +55,29 @@ const StartOptions = ( { questionnaire, oldFlow, options } ) => { navigate( data.steps[ 1 ].path ); }; const selectFlow = ( flow ) => { + let flowForEvent = false; switch ( flow ) { case 'sitebuild': - return switchFlow( oldFlow ); + flowForEvent = 'DIY'; + switchFlow( oldFlow ); + break; case 'sitegen': - return switchFlow( SITEGEN_FLOW ); + flowForEvent = 'AI'; + switchFlow( SITEGEN_FLOW ); + break; case 'hirepro': - return window.open( hireProUrl, '_blank' ); + flowForEvent = 'PRO'; + window.open( hireProUrl, '_blank' ); + break; + } + + if ( flowForEvent ) { + trackOnboardingEvent( + new OnboardingEvent( + ACTION_SITEGEN_FORK_OPTION_SELECTED, + flowForEvent + ) + ); } }; return ( diff --git a/src/OnboardingSPA/components/TextInput/TextInputSiteGen/index.js b/src/OnboardingSPA/components/TextInput/TextInputSiteGen/index.js index 4675e6a9d..122876aa8 100644 --- a/src/OnboardingSPA/components/TextInput/TextInputSiteGen/index.js +++ b/src/OnboardingSPA/components/TextInput/TextInputSiteGen/index.js @@ -10,6 +10,7 @@ const TextInputSiteGen = ( { customerInput, setIsValidInput, setCustomerInput, + setCustomerInputStrength, customChildren = false, } ) => { const textareaRef = useRef( null ); @@ -22,6 +23,7 @@ const TextInputSiteGen = ( { textareaRef.current.style.height = scrollHeight + 'px'; const analysisResult = calculateAnalysisScore( customerInput?.trim() ); setAnalysisScore( analysisResult ); + setCustomerInputStrength( analysisResult ); setIsValidInput( analysisResult >= 2 ); }, [ customerInput ] ); diff --git a/src/OnboardingSPA/data/flows/sitegen.js b/src/OnboardingSPA/data/flows/sitegen.js index c0a078b3e..525ddc303 100644 --- a/src/OnboardingSPA/data/flows/sitegen.js +++ b/src/OnboardingSPA/data/flows/sitegen.js @@ -1,15 +1,18 @@ -import { sitegen } from '../../chapters/sitegen'; +import { siteGenDesign } from '../../chapters/siteGen/design'; +import { siteGenFeatures } from '../../chapters/siteGen/features'; +import { siteGenCore } from '../../chapters/siteGen/core'; import { errorPage } from '../../pages/ErrorPage/page'; import { indexPage } from '../../pages/IndexPage/page'; +import { stepSiteGenWelcome } from '../../steps/SiteGen/Welcome/step'; import { stepTheFork } from '../../steps/TheFork/step'; export const pages = [ indexPage, errorPage ]; -export const initialChapters = [ sitegen ]; +export const initialChapters = [ siteGenCore, siteGenFeatures, siteGenDesign ]; export const getSteps = ( chapters = initialChapters ) => { let steps = []; - steps.push( stepTheFork ); + steps.push( stepTheFork, stepSiteGenWelcome ); chapters.forEach( ( chapter ) => { steps = steps.concat( [ ...chapter.steps, @@ -21,7 +24,7 @@ export const getSteps = ( chapters = initialChapters ) => { export const getRoutes = ( chapters = initialChapters ) => { let routes = [ ...pages ]; - routes.push( stepTheFork ); + routes.push( stepTheFork, stepSiteGenWelcome ); chapters.forEach( ( chapter ) => { routes = routes.concat( [ ...chapter.steps, diff --git a/src/OnboardingSPA/steps/SiteGen/Editor/Header/index.js b/src/OnboardingSPA/steps/SiteGen/Editor/Header/index.js index 996c77bcb..2fbfd5129 100644 --- a/src/OnboardingSPA/steps/SiteGen/Editor/Header/index.js +++ b/src/OnboardingSPA/steps/SiteGen/Editor/Header/index.js @@ -23,6 +23,19 @@ import StepEditorHeaderCenter from './center'; import { getGlobalStyles } from '../../../../utils/api/themes'; import { LivePreview } from '../../../../components/LivePreview'; import { blockRenderScreenshot } from '../../../../utils/api/blockRender'; +import { + OnboardingEvent, + sendOnboardingEvent, + trackOnboardingEvent, +} from '../../../../utils/analytics/hiive'; +import { + ACTION_ONBOARDING_COMPLETE, + ACTION_SITEGEN_HOMEPAGE_FAVORITED, + ACTION_SITEGEN_HOMEPAGE_REGENERATED, + ACTION_SITEGEN_HOMEPAGE_RENAMED, + ACTION_SITEGEN_SIDEBAR_OPENED, +} from '../../../../utils/analytics/hiive/constants'; +import { SITEGEN_FLOW } from '../../../../data/flows/constants'; const StepSiteGenEditorHeader = () => { const [ homepage, setHomepage ] = useState(); @@ -63,6 +76,17 @@ const StepSiteGenEditorHeader = () => { currentData.sitegen.homepages.data[ homepage.slug ] = homepage; currentData.sitegen.homepages.active = homepage; setCurrentOnboardingData( currentData ); + trackOnboardingEvent( + new OnboardingEvent( + ACTION_SITEGEN_HOMEPAGE_FAVORITED, + homepage.slug, + { + favorite: isFavorite, + placement: 'editor_toolbar', + source: SITEGEN_FLOW, + } + ) + ); }; const handleRegenerate = async () => { @@ -109,11 +133,33 @@ const StepSiteGenEditorHeader = () => { currentData.sitegen.homepages.active = regeneratedHomepage; setCurrentOnboardingData( currentData ); setIsRegenerating( false ); + trackOnboardingEvent( + new OnboardingEvent( ACTION_SITEGEN_HOMEPAGE_REGENERATED, slug, { + source: SITEGEN_FLOW, + placement: 'editor_toolbar', + } ) + ); }; const handleViewAll = () => { + if ( + isSidebarOpened && + sideBarView === SIDEBAR_SITEGEN_EDITOR_PATTERNS + ) { + return; + } + setSidebarActiveView( SIDEBAR_SITEGEN_EDITOR_PATTERNS ); setIsSidebarOpened( true ); + trackOnboardingEvent( + new OnboardingEvent( + ACTION_SITEGEN_SIDEBAR_OPENED, + 'all_versions', + { + source: SITEGEN_FLOW, + } + ) + ); }; const handleCustomize = async () => { @@ -121,6 +167,16 @@ const StepSiteGenEditorHeader = () => { sideBarView === 'Customize' ? ! isSidebarOpened : isSidebarOpened; setSidebarActiveView( 'Customize' ); setIsSidebarOpened( isSidebarOpenedNew ); + + if ( isSidebarOpenedNew === true ) { + trackOnboardingEvent( + new OnboardingEvent( + ACTION_SITEGEN_SIDEBAR_OPENED, + 'customize' + ) + ); + } + const globalStylesResponse = await getGlobalStyles(); setGlobalStyles( globalStylesResponse.body ); }; @@ -130,6 +186,16 @@ const StepSiteGenEditorHeader = () => { currentData.sitegen.homepages.data[ homepage.slug ] = homepage; currentData.sitegen.homepages.active = homepage; setCurrentOnboardingData( currentData ); + trackOnboardingEvent( + new OnboardingEvent( + ACTION_SITEGEN_HOMEPAGE_RENAMED, + homepage.slug, + { + name: title, + source: SITEGEN_FLOW, + } + ) + ); }; const buildPreviewsForScreenshot = ( homepages, activeHomepage ) => { @@ -218,6 +284,11 @@ const StepSiteGenEditorHeader = () => { } await setFlow( currentData ); await completeFlow(); + sendOnboardingEvent( + new OnboardingEvent( ACTION_ONBOARDING_COMPLETE, { + source: SITEGEN_FLOW, + } ) + ); window.location.replace( pluginDashboardPage ); }; @@ -320,9 +391,9 @@ const StepSiteGenEditorHeader = () => { > { isLargeViewport ? __( - 'Save & Continue', - 'wp-module-onboarding' - ) + 'Save & Continue', + 'wp-module-onboarding' + ) : __( 'Next', 'wp-module-onboarding' ) }
{ isSaving ? ( diff --git a/src/OnboardingSPA/steps/SiteGen/Experience/index.js b/src/OnboardingSPA/steps/SiteGen/Experience/index.js index 2f26d02ce..dc268d267 100644 --- a/src/OnboardingSPA/steps/SiteGen/Experience/index.js +++ b/src/OnboardingSPA/steps/SiteGen/Experience/index.js @@ -8,6 +8,12 @@ import CommonLayout from '../../../components/Layouts/Common'; import CardWithOptions from '../../../components/CardWithOptions'; import SiteGenLoader from '../../../components/Loaders/SiteGenLoader'; import SitegenAiStateHandler from '../../../components/StateHandlers/SitegenAi'; +import { + OnboardingEvent, + trackOnboardingEvent, +} from '../../../utils/analytics/hiive'; +import { ACTION_EXPERIENCE_LEVEL_SET } from '../../../utils/analytics/hiive/constants'; +import { SITEGEN_FLOW } from '../../../data/flows/constants'; const SiteGenExperience = () => { const content = getContents(); @@ -51,6 +57,30 @@ const SiteGenExperience = () => { setSelection( idx ); currentData.sitegen.experience.level = idx; setCurrentOnboardingData( currentData ); + let experienceForEvent = false; + switch ( idx ) { + case 1: + experienceForEvent = 'novice'; + break; + case 2: + experienceForEvent = 'intermediate'; + break; + case 3: + experienceForEvent = 'expert'; + break; + } + + if ( experienceForEvent ) { + trackOnboardingEvent( + new OnboardingEvent( + ACTION_EXPERIENCE_LEVEL_SET, + experienceForEvent, + { + source: SITEGEN_FLOW, + } + ) + ); + } }; return ( diff --git a/src/OnboardingSPA/steps/SiteGen/Preview/index.js b/src/OnboardingSPA/steps/SiteGen/Preview/index.js index 65a3b3d92..0b058df29 100644 --- a/src/OnboardingSPA/steps/SiteGen/Preview/index.js +++ b/src/OnboardingSPA/steps/SiteGen/Preview/index.js @@ -15,6 +15,17 @@ import { getHomepages, regenerateHomepage } from '../../../utils/api/siteGen'; import { getGlobalStyles } from '../../../utils/api/themes'; import SitegenAiStateHandler from '../../../components/StateHandlers/SitegenAi'; import Animate from '../../../components/Animate'; +import { + OnboardingEvent, + trackOnboardingEvent, +} from '../../../utils/analytics/hiive'; +import { + ACTION_SITEGEN_HOMEPAGE_FAVORITED, + ACTION_SITEGEN_HOMEPAGE_REGENERATED, + ACTION_SITEGEN_HOMEPAGE_SELECTED, + ACTION_SITEGEN_SITE_GENERATION_TIME, +} from '../../../utils/analytics/hiive/constants'; +import { SITEGEN_FLOW } from '../../../data/flows/constants'; const SiteGenPreview = () => { const navigate = useNavigate(); @@ -75,6 +86,7 @@ const SiteGenPreview = () => { if ( ! isEmpty( currentData.sitegen.homepages.data ) ) { setHomepages( currentData.sitegen.homepages.data ); setIsPreviewLoading( false ); + trackSiteGenerationTime(); return; } if ( currentData.sitegen.siteDetails?.prompt === '' ) { @@ -96,6 +108,22 @@ const SiteGenPreview = () => { setHomepages( response.body ); setCurrentOnboardingData( currentData ); setIsPreviewLoading( false ); + trackSiteGenerationTime(); + }; + + const trackSiteGenerationTime = () => { + if ( window.nfdOnboarding.siteGenTimerInterval ) { + clearInterval( window.nfdOnboarding.siteGenTimerInterval ); + trackOnboardingEvent( + new OnboardingEvent( + ACTION_SITEGEN_SITE_GENERATION_TIME, + window.nfdOnboarding.siteGenTime, + { + source: SITEGEN_FLOW, + } + ) + ); + } }; const loadGlobalStyles = async () => { @@ -112,13 +140,19 @@ const SiteGenPreview = () => { loadGlobalStyles(); }, [] ); - const handlePreview = ( slug ) => { + const handlePreview = ( slug, position ) => { if ( ! ( slug in homepages ) ) { return false; } currentData.sitegen.homepages.active = homepages[ slug ]; currentData.sitegen.skipCache = false; setCurrentOnboardingData( currentData ); + trackOnboardingEvent( + new OnboardingEvent( ACTION_SITEGEN_HOMEPAGE_SELECTED, slug, { + position, + source: SITEGEN_FLOW, + } ) + ); navigate( nextStep.path ); }; @@ -139,7 +173,7 @@ const SiteGenPreview = () => { } }; - const handleFavorite = ( slug ) => { + const handleFavorite = ( slug, position ) => { if ( ! ( slug in homepages ) ) { return; } @@ -148,9 +182,18 @@ const SiteGenPreview = () => { currentData.sitegen.homepages.data = homepages; setHomepages( homepages ); setCurrentOnboardingData( currentData ); + + trackOnboardingEvent( + new OnboardingEvent( ACTION_SITEGEN_HOMEPAGE_FAVORITED, slug, { + favorite: isFavorite, + placement: 'preview_grid', + position, + source: SITEGEN_FLOW, + } ) + ); }; - const handleRegenerate = async ( slug, palette, isFavorite ) => { + const handleRegenerate = async ( slug, palette, isFavorite, position ) => { scrollSelectionIntoView(); setIsRegenerating( true ); if ( ! ( slug in homepages ) ) { @@ -181,6 +224,13 @@ const SiteGenPreview = () => { setHomepages( homepages ); setCurrentOnboardingData( currentData ); setIsRegenerating( false ); + trackOnboardingEvent( + new OnboardingEvent( ACTION_SITEGEN_HOMEPAGE_REGENERATED, slug, { + position, + source: SITEGEN_FLOW, + placement: 'preview_grid', + } ) + ); }; const buildPreviews = () => { @@ -222,6 +272,7 @@ const SiteGenPreview = () => { blockGrammar={ blockGrammar } previewSettings={ newPreviewSettings } slug={ slug } + position={ idx + 1 } title={ data.title } isFavorite={ data.isFavorite } palette={ data.color } diff --git a/src/OnboardingSPA/steps/SiteGen/SiteDetails/index.js b/src/OnboardingSPA/steps/SiteGen/SiteDetails/index.js index 3de09121d..de6343386 100644 --- a/src/OnboardingSPA/steps/SiteGen/SiteDetails/index.js +++ b/src/OnboardingSPA/steps/SiteGen/SiteDetails/index.js @@ -11,11 +11,18 @@ import CommonLayout from '../../../components/Layouts/Common'; import TextInputSiteGen from '../../../components/TextInput/TextInputSiteGen'; import NextButtonSiteGen from '../../../components/Button/NextButtonSiteGen'; import SitegenAiStateHandler from '../../../components/StateHandlers/SitegenAi'; +import { + OnboardingEvent, + trackOnboardingEvent, +} from '../../../utils/analytics/hiive'; +import { ACTION_SITEGEN_SITE_DETAILS_PROMPT_SET } from '../../../utils/analytics/hiive/constants'; +import { SITEGEN_FLOW } from '../../../data/flows/constants'; const SiteGenSiteDetails = () => { const content = getContents(); const isLargeViewport = useViewportMatch( 'small' ); const [ customerInput, setCustomerInput ] = useState(); + const [ customerInputStrength, setCustomerInputStrength ] = useState( 0 ); const [ isValidInput, setIsValidInput ] = useState( false ); const { currentData } = useSelect( ( select ) => { return { @@ -50,6 +57,31 @@ const SiteGenSiteDetails = () => { setIsFooterNavAllowed( false ); }, [] ); + const trackPromptSetEvent = () => { + let customerInputStrengthForEvent = false; + switch ( customerInputStrength ) { + case 2: + customerInputStrengthForEvent = 'MEDIUM'; + break; + case 3: + customerInputStrengthForEvent = 'HIGH'; + break; + } + + if ( customerInputStrengthForEvent ) { + trackOnboardingEvent( + new OnboardingEvent( + ACTION_SITEGEN_SITE_DETAILS_PROMPT_SET, + customerInput, + { + strength: customerInputStrengthForEvent, + source: SITEGEN_FLOW, + } + ) + ); + } + }; + useEffect( () => { if ( customerInput !== undefined && @@ -80,6 +112,9 @@ const SiteGenSiteDetails = () => { customerInput={ customerInput } setIsValidInput={ setIsValidInput } setCustomerInput={ setCustomerInput } + setCustomerInputStrength={ + setCustomerInputStrength + } customChildren={ true } > { isLargeViewport && ( @@ -88,6 +123,9 @@ const SiteGenSiteDetails = () => { className={ 'nfd-sg-site-details--next-btn' } + callback={ () => { + trackPromptSetEvent(); + } } text={ content.buttonText } disabled={ ! isValidInput } /> diff --git a/src/OnboardingSPA/steps/SiteGen/SiteLogo/index.js b/src/OnboardingSPA/steps/SiteGen/SiteLogo/index.js index c090532dd..8a72a5524 100644 --- a/src/OnboardingSPA/steps/SiteGen/SiteLogo/index.js +++ b/src/OnboardingSPA/steps/SiteGen/SiteLogo/index.js @@ -12,6 +12,15 @@ import CommonLayout from '../../../components/Layouts/Common'; import NextButtonSiteGen from '../../../components/Button/NextButtonSiteGen'; import ImageUploaderWithText from '../../../components/ImageUploader/components/ImageUploaderWithText'; import SitegenAiStateHandler from '../../../components/StateHandlers/SitegenAi'; +import { + OnboardingEvent, + trackOnboardingEvent, +} from '../../../utils/analytics/hiive'; +import { + ACTION_LOGO_ADDED, + ACTION_SITEGEN_LOGO_SKIPPED, +} from '../../../utils/analytics/hiive/constants'; +import { SITEGEN_FLOW } from '../../../data/flows/constants'; const SiteGenSiteLogo = () => { const [ siteLogo, setSiteLogo ] = useState(); @@ -52,6 +61,11 @@ const SiteGenSiteLogo = () => { setCurrentOnboardingData( currentDataCopy ); setSiteLogo( undefined ); setIsFooterNavAllowed( false ); + trackOnboardingEvent( + new OnboardingEvent( ACTION_SITEGEN_LOGO_SKIPPED, { + source: SITEGEN_FLOW, + } ) + ); }; useEffect( () => { @@ -104,6 +118,18 @@ const SiteGenSiteLogo = () => { /> { isLargeViewport && ( { + if ( siteLogo ) { + trackOnboardingEvent( + new OnboardingEvent( + ACTION_LOGO_ADDED + ), + { + source: SITEGEN_FLOW, + } + ); + } + } } text={ content.buttons.next } disabled={ siteLogo === undefined || siteLogo?.id === 0 diff --git a/src/OnboardingSPA/steps/SiteGen/SocialMedia/index.js b/src/OnboardingSPA/steps/SiteGen/SocialMedia/index.js index 7032e013a..57b8a547d 100644 --- a/src/OnboardingSPA/steps/SiteGen/SocialMedia/index.js +++ b/src/OnboardingSPA/steps/SiteGen/SocialMedia/index.js @@ -12,6 +12,15 @@ import NextButtonSiteGen from '../../../components/Button/NextButtonSiteGen'; import { FacebookConnectButton } from '@newfold-labs/wp-module-facebook'; import { useNavigate } from 'react-router-dom'; import SitegenAiStateHandler from '../../../components/StateHandlers/SitegenAi'; +import { + OnboardingEvent, + trackOnboardingEvent, +} from '../../../utils/analytics/hiive'; +import { + ACTION_SITEGEN_SOCIAL_CONNECTED, + ACTION_SITEGEN_SOCIAL_CONNECT_SKIPPED, +} from '../../../utils/analytics/hiive/constants'; +import { SITEGEN_FLOW } from '../../../data/flows/constants'; const SiteGenSiteSocialMedia = () => { const isLargeViewport = useViewportMatch( 'small' ); @@ -44,6 +53,12 @@ const SiteGenSiteSocialMedia = () => { } ); const handleConnect = () => { + trackOnboardingEvent( + new OnboardingEvent( ACTION_SITEGEN_SOCIAL_CONNECTED, 'facebook', { + source: SITEGEN_FLOW, + } ) + ); + setConnected( true ); }; @@ -51,6 +66,14 @@ const SiteGenSiteSocialMedia = () => { updateSiteGenErrorStatus( true ); }; + const trackSkipEvent = () => { + trackOnboardingEvent( + new OnboardingEvent( ACTION_SITEGEN_SOCIAL_CONNECT_SKIPPED, { + source: SITEGEN_FLOW, + } ) + ); + }; + useEffect( () => { setIsFooterNavAllowed( connected ); if ( interacted && connected ) { @@ -85,6 +108,7 @@ const SiteGenSiteSocialMedia = () => {
diff --git a/src/OnboardingSPA/steps/TheFork/index.js b/src/OnboardingSPA/steps/TheFork/index.js index 1ee659af7..81dcfbc8b 100644 --- a/src/OnboardingSPA/steps/TheFork/index.js +++ b/src/OnboardingSPA/steps/TheFork/index.js @@ -15,6 +15,12 @@ import HeadingWithSubHeading from '../../components/HeadingWithSubHeading/SiteGe import StartOptions from '../../components/StartOptions'; import getContents from './contents'; import SitegenAiStateHandler from '../../components/StateHandlers/SitegenAi'; +import { + OnboardingEvent, + sendOnboardingEvent, + trackOnboardingEvent, +} from '../../utils/analytics/hiive'; +import { ACTION_SITEGEN_FORK_OPTION_SELECTED } from '../../utils/analytics/hiive/constants'; const TheFork = () => { const { migrationUrl } = useSelect( ( select ) => { @@ -47,6 +53,16 @@ const TheFork = () => { ? window.nfdOnboarding.oldFlow : DEFAULT_FLOW; + const handleForkExit = () => { + sendOnboardingEvent( + new OnboardingEvent( + ACTION_SITEGEN_FORK_OPTION_SELECTED, + 'TUTORIAL' + ) + ); + + window.location.replace( pluginDashboardPage ); + }; const content = getContents(); return ( @@ -71,16 +87,27 @@ const TheFork = () => { href={ migrationUrl } target={ '_blank' } rel={ 'noreferrer' } + onClick={ () => + trackOnboardingEvent( + new OnboardingEvent( + ACTION_SITEGEN_FORK_OPTION_SELECTED, + 'MIGRATE' + ) + ) + } > { content.importtext } ) } - handleForkExit() } + onKeyDown={ () => handleForkExit() } > { content.exitToWordPress } - + ); diff --git a/src/OnboardingSPA/steps/TheFork/stylesheet.scss b/src/OnboardingSPA/steps/TheFork/stylesheet.scss index 4cdef6647..32cdfc1e0 100644 --- a/src/OnboardingSPA/steps/TheFork/stylesheet.scss +++ b/src/OnboardingSPA/steps/TheFork/stylesheet.scss @@ -55,10 +55,15 @@ &__exit { cursor: pointer; + text-decoration: underline; font-weight: 510; line-height: 20px; text-align: center; color: var(--nfd-onboarding-primary); + + &:hover { + color: var(--nfd-onboarding-sitegen-link-color); + } } } } diff --git a/src/OnboardingSPA/styles/_branding.scss b/src/OnboardingSPA/styles/_branding.scss index e8d40dd83..4e279a3e4 100644 --- a/src/OnboardingSPA/styles/_branding.scss +++ b/src/OnboardingSPA/styles/_branding.scss @@ -374,5 +374,6 @@ body { --nfd-onboarding-facebook-connect-button-background: #1877f2; --nfd-onboarding-facebook-connect-button-background-hover: #0065ea; --nfd-onboarding-facebook-connected-button-background: #3bb143; + --nfd-onboarding-sitegen-link-color: #2271b1; } } diff --git a/src/OnboardingSPA/utils/analytics/hiive/constants.js b/src/OnboardingSPA/utils/analytics/hiive/constants.js index 99766b533..4c8ef4f0e 100644 --- a/src/OnboardingSPA/utils/analytics/hiive/constants.js +++ b/src/OnboardingSPA/utils/analytics/hiive/constants.js @@ -20,6 +20,18 @@ export const ACTION_ONBOARDING_EXITED = 'onboarding_exited'; export const ACTION_ONBOARDING_CHAPTER_STARTED = 'onboarding_chapter_started'; export const ACTION_ONBOARDING_CHAPTER_COMPLETE = 'onboarding_chapter_complete'; export const ACTION_SOCIAL_ADDED = 'social_added'; + +export const ACTION_SITEGEN_FORK_OPTION_SELECTED = 'fork_option_selected'; +export const ACTION_SITEGEN_SITE_DETAILS_PROMPT_SET = 'site_details_prompt_set'; +export const ACTION_SITEGEN_SOCIAL_CONNECTED = 'social_connected'; +export const ACTION_SITEGEN_SOCIAL_CONNECT_SKIPPED = 'social_connect_skipped'; +export const ACTION_SITEGEN_LOGO_SKIPPED = 'logo_skipped'; +export const ACTION_SITEGEN_HOMEPAGE_SELECTED = 'homepage_selected'; +export const ACTION_SITEGEN_HOMEPAGE_REGENERATED = 'homepage_regenerated'; +export const ACTION_SITEGEN_HOMEPAGE_FAVORITED = 'homepage_favorited'; +export const ACTION_SITEGEN_HOMEPAGE_RENAMED = 'homepage_renamed'; +export const ACTION_SITEGEN_SIDEBAR_OPENED = 'sidebar_opened'; +export const ACTION_SITEGEN_SITE_GENERATION_TIME = 'site_generation_time'; export const CATEGORY = 'wonder_start'; export const ACTION_TO_LABEL_KEY_MAP = { @@ -41,4 +53,13 @@ export const ACTION_TO_LABEL_KEY_MAP = { [ ACTION_ONBOARDING_CHAPTER_STARTED ]: 'chapter', [ ACTION_ONBOARDING_CHAPTER_COMPLETE ]: 'chapter', [ ACTION_SOCIAL_ADDED ]: 'platform', + [ ACTION_SITEGEN_FORK_OPTION_SELECTED ]: 'flow', + [ ACTION_SITEGEN_SITE_DETAILS_PROMPT_SET ]: 'prompt', + [ ACTION_SITEGEN_SOCIAL_CONNECTED ]: 'platform', + [ ACTION_SITEGEN_HOMEPAGE_SELECTED ]: 'version', + [ ACTION_SITEGEN_HOMEPAGE_REGENERATED ]: 'version', + [ ACTION_SITEGEN_HOMEPAGE_FAVORITED ]: 'version', + [ ACTION_SITEGEN_SIDEBAR_OPENED ]: 'type', + [ ACTION_SITEGEN_HOMEPAGE_RENAMED ]: 'version', + [ ACTION_SITEGEN_SITE_GENERATION_TIME ]: 'time', }; diff --git a/src/constants.js b/src/constants.js index 0418b18ae..125041109 100644 --- a/src/constants.js +++ b/src/constants.js @@ -73,6 +73,9 @@ export const CHAPTER_DESIGN = 'design'; export const CHAPTER_LAYOUT_AND_CONTENT = 'layout_and_content'; export const CHAPTER_FEATURES = 'features'; export const CHAPTER_SITEGEN = 'sitegen'; +export const CHAPTER_SITEGEN_CORE = 'core'; +export const CHAPTER_SITEGEN_DESIGN = 'design'; +export const CHAPTER_SITEGEN_FEATURES = 'features'; export const THEME_DARK = 'dark'; export const THEME_LIGHT = 'light';