diff --git a/src/OnboardingSPA/chapters/sitegen.js b/src/OnboardingSPA/chapters/sitegen.js
new file mode 100644
index 000000000..12aef1f25
--- /dev/null
+++ b/src/OnboardingSPA/chapters/sitegen.js
@@ -0,0 +1,28 @@
+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,
+ stepSiteGenSiteLogo,
+ stepSiteGenSocialMedia,
+ 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/AdminBar/index.js b/src/OnboardingSPA/components/AdminBar/index.js
new file mode 100644
index 000000000..efa6c8b4c
--- /dev/null
+++ b/src/OnboardingSPA/components/AdminBar/index.js
@@ -0,0 +1,9 @@
+const AdminBar = () => {
+ return (
+
+ Admin Bar Goes Here
+
+ );
+};
+
+export default AdminBar;
diff --git a/src/OnboardingSPA/components/AdminBar/stylesheet.scss b/src/OnboardingSPA/components/AdminBar/stylesheet.scss
new file mode 100644
index 000000000..c87ab6c6c
--- /dev/null
+++ b/src/OnboardingSPA/components/AdminBar/stylesheet.scss
@@ -0,0 +1,12 @@
+.nfd-onboarding-header {
+
+ &__admin-bar {
+ height: 32px;
+ background-color: var(--nfd-onboarding-admin-bar-background);
+ width: 100%;
+ color: var(--nfd-onboarding-admin-bar-color);
+ margin: 0;
+ padding-left: 10px;
+ padding-top: 7px;
+ }
+}
diff --git a/src/OnboardingSPA/components/App/index.js b/src/OnboardingSPA/components/App/index.js
index 0bd68d32d..042a7be14 100644
--- a/src/OnboardingSPA/components/App/index.js
+++ b/src/OnboardingSPA/components/App/index.js
@@ -1,331 +1,24 @@
-import Header from '../Header';
-import Content from '../Content';
-import Drawer from '../Drawer';
-import Sidebar from '../Sidebar';
-import classNames from 'classnames';
-import { useLocation } from 'react-router-dom';
-import { setFlow } from '../../utils/api/flow';
-import { design as designChapter } from '../../chapters/design';
-import { getSettings, setSettings } from '../../utils/api/settings';
-import { isEmpty, updateWPSettings } from '../../utils/api/ecommerce';
-import { store as nfdOnboardingStore } from '../../store';
-
-// eslint-disable-next-line import/no-extraneous-dependencies
-import { kebabCase } from 'lodash';
-import { useViewportMatch } from '@wordpress/compose';
-import { useDispatch, useSelect } from '@wordpress/data';
-import { SlotFillProvider } from '@wordpress/components';
-import { useEffect, Fragment, useState } from '@wordpress/element';
import { FullscreenMode } from '@wordpress/interface';
-import { API_REQUEST } from '../../../constants';
-import NewfoldInterfaceSkeleton from '../NewfoldInterfaceSkeleton';
-import { HiiveAnalytics } from '@newfold-labs/js-utility-ui-analytics';
-import {
- OnboardingEvent,
- trackOnboardingEvent,
-} from '../../utils/analytics/hiive';
-import { injectInAllSteps } from '../../data/flows/utils';
-import {
- ACTION_FEATURE_ADDED,
- ACTION_LOGO_ADDED,
- ACTION_SITE_TITLE_SET,
- ACTION_SOCIAL_ADDED,
- ACTION_STARTER_PAGES_SELECTED,
- ACTION_TAGLINE_SET,
- CATEGORY,
-} from '../../utils/analytics/hiive/constants';
-import { socialMediaStoreToState } from '../SocialMediaForm/utils';
+import { SlotFillProvider } from '@wordpress/components';
+import { Fragment } from '@wordpress/element';
+
+import FlowStateHandler from '../StateHandlers/Flow';
/**
- * Primary app that renders the .
+ * Primary app that renders the .
*
* Is a child of the hash router and error boundary.
*
* @return {WPComponent} App Component
*/
const App = () => {
- const location = useLocation();
- const isLargeViewport = useViewportMatch( 'medium' );
- const pathname = kebabCase( location.pathname );
-
- const {
- isDrawerOpen,
- newfoldBrand,
- onboardingFlow,
- currentData,
- socialData,
- firstStep,
- allSteps,
- } = useSelect(
- ( select ) => {
- return {
- isDrawerOpen: select( nfdOnboardingStore ).isDrawerOpened(),
- newfoldBrand: select( nfdOnboardingStore ).getNewfoldBrand(),
- onboardingFlow:
- select( nfdOnboardingStore ).getOnboardingFlow(),
- currentData:
- select( nfdOnboardingStore ).getCurrentOnboardingData(),
- socialData:
- select( nfdOnboardingStore ).getOnboardingSocialData(),
- firstStep: select( nfdOnboardingStore ).getFirstStep(),
- allSteps: select( nfdOnboardingStore ).getAllSteps(),
- };
- },
- [ location.pathname ]
- );
-
- const [ isRequestPlaced, setIsRequestPlaced ] = useState( false );
- const [ didVisitBasicInfo, setDidVisitBasicInfo ] = useState( false );
- const [ didVisitEcommerce, setDidVisitEcommerce ] = useState( false );
- const {
- setActiveStep,
- setActiveFlow,
- updateAllSteps,
- flushQueue,
- enqueueRequest,
- setOnboardingSocialData,
- setCurrentOnboardingData,
- } = useDispatch( nfdOnboardingStore );
-
- async function syncSocialSettings() {
- const initialData = await getSettings();
- const result = await setSettings( socialData );
- setDidVisitBasicInfo( false );
- if ( result?.error !== null ) {
- return initialData?.body;
- }
- return result?.body;
- }
-
- async function syncStoreDetails() {
- const { address } = currentData.storeDetails;
- let payload = {};
- if ( address !== undefined ) {
- delete address.country;
- delete address.state;
- payload = address;
- }
- // if ( tax !== undefined ) {
- // delete tax.option;
- // delete tax.isStoreDetailsFilled;
- // payload = { ...payload, ...tax };
- // }
- if ( ! isEmpty( payload ) ) {
- await updateWPSettings( payload );
- }
- delete currentData.storeDetails.address;
- delete currentData.storeDetails.tax;
- setDidVisitEcommerce( false );
- }
-
- async function syncStoreToDB() {
- // The First Welcome Step doesn't have any Store changes
- const isFirstStep = location?.pathname === firstStep?.path;
- if ( currentData && ! isFirstStep ) {
- if ( ! isRequestPlaced ) {
- setIsRequestPlaced( true );
-
- if ( didVisitEcommerce ) {
- await syncStoreDetails();
- }
-
- // If Social Data is changed then sync it
- if ( didVisitBasicInfo ) {
- const socialDataResp = await syncSocialSettings();
-
- // If Social Data is changed then Sync that also to the store
- if ( socialDataResp ) {
- setOnboardingSocialData( socialDataResp );
- }
- }
- flushQueue();
- enqueueRequest( API_REQUEST.SET_FLOW, () =>
- setFlow( currentData )
- );
- setIsRequestPlaced( false );
- }
- }
-
- // Check if the Basic Info page was visited
- if ( location?.pathname.includes( 'basic-info' ) ) {
- setDidVisitBasicInfo( true );
- }
- if ( location?.pathname.includes( 'ecommerce' ) ) {
- setDidVisitEcommerce( true );
- }
- }
-
- function handleConditionalDesignStepsRoutes() {
- if (
- location?.pathname.includes( 'colors' ) ||
- location?.pathname.includes( 'fonts' )
- ) {
- const updates = injectInAllSteps(
- allSteps,
- designChapter.conditionalSteps
- );
- updateAllSteps( updates.allSteps );
- if ( ! currentData.data.customDesign ) {
- currentData.data.customDesign = true;
- setCurrentOnboardingData( currentData );
- }
- }
- }
-
- const handlePreviousStepTracking = () => {
- const previousStep = window.nfdOnboarding?.previousStep;
- if ( typeof previousStep !== 'object' ) {
- window.nfdOnboarding.previousStep = {
- path: location.pathname,
- url: window.location.href,
- };
- HiiveAnalytics.dispatchEvents( CATEGORY );
- return;
- }
-
- const previousStepPath = previousStep.path;
- const previousStepURL = previousStep.url;
-
- if ( previousStepPath.includes( 'basic-info' ) ) {
- const siteTitle = currentData.data.blogName;
- const siteDescription = currentData.data.blogDescription;
- const siteLogo = currentData.data.siteLogo.url;
- if ( siteTitle ) {
- trackOnboardingEvent(
- new OnboardingEvent(
- ACTION_SITE_TITLE_SET,
- siteTitle,
- {},
- previousStepURL
- )
- );
- }
-
- if ( siteDescription ) {
- trackOnboardingEvent(
- new OnboardingEvent(
- ACTION_TAGLINE_SET,
- siteDescription,
- {},
- previousStepURL
- )
- );
- }
-
- if ( siteLogo ) {
- trackOnboardingEvent(
- new OnboardingEvent(
- ACTION_LOGO_ADDED,
- undefined,
- {},
- previousStepURL
- )
- );
- }
-
- const platforms = Object.keys(
- socialMediaStoreToState( socialData )
- );
- if ( platforms.length ) {
- platforms.forEach( ( platform ) => {
- trackOnboardingEvent(
- new OnboardingEvent(
- ACTION_SOCIAL_ADDED,
- platform,
- {},
- previousStepURL
- )
- );
- } );
- }
- }
-
- if ( previousStepPath.includes( 'site-pages' ) ) {
- const sitePages = currentData.data.sitePages?.other;
- if ( ! sitePages || false === sitePages ) {
- trackOnboardingEvent(
- new OnboardingEvent(
- ACTION_STARTER_PAGES_SELECTED,
- [],
- {
- count: 0,
- },
- previousStepURL
- )
- );
- } else {
- trackOnboardingEvent(
- new OnboardingEvent(
- ACTION_STARTER_PAGES_SELECTED,
- sitePages.map( ( sitePage ) => sitePage.title ),
- {
- count: sitePages.length,
- },
- previousStepURL
- )
- );
- }
- }
-
- if ( previousStepPath.includes( 'site-features' ) ) {
- const siteFeatures = currentData.data.siteFeatures;
- for ( const siteFeature in siteFeatures ) {
- if ( false !== siteFeatures[ siteFeature ] ) {
- trackOnboardingEvent(
- new OnboardingEvent(
- ACTION_FEATURE_ADDED,
- siteFeature,
- {},
- previousStepURL
- )
- );
- }
- }
- }
-
- window.nfdOnboarding.previousStep = {
- path: location.pathname,
- url: window.location.href,
- };
-
- HiiveAnalytics.dispatchEvents( CATEGORY );
- };
-
- useEffect( () => {
- document.body.classList.add( `nfd-brand-${ newfoldBrand }` );
- }, [ newfoldBrand ] );
-
- useEffect( () => {
- syncStoreToDB();
- handlePreviousStepTracking();
- handleConditionalDesignStepsRoutes();
- if ( location.pathname.includes( '/step' ) ) {
- setActiveFlow( onboardingFlow );
- setActiveStep( location.pathname );
- }
- }, [ location.pathname, onboardingFlow ] );
-
return (
- }
- drawer={ }
- content={ }
- sidebar={ }
- />
+
);
};
-
export default App;
diff --git a/src/OnboardingSPA/components/Button/ButtonDark/index.js b/src/OnboardingSPA/components/Button/ButtonDark/index.js
new file mode 100644
index 000000000..e1393b5b6
--- /dev/null
+++ b/src/OnboardingSPA/components/Button/ButtonDark/index.js
@@ -0,0 +1,15 @@
+import { Button } from '@wordpress/components';
+import classNames from 'classnames';
+
+const ButtonDark = ( { children, onClick } ) => {
+ return (
+
+ );
+};
+
+export default ButtonDark;
diff --git a/src/OnboardingSPA/components/Button/ButtonDark/stylesheet.scss b/src/OnboardingSPA/components/Button/ButtonDark/stylesheet.scss
new file mode 100644
index 000000000..1f886eac0
--- /dev/null
+++ b/src/OnboardingSPA/components/Button/ButtonDark/stylesheet.scss
@@ -0,0 +1,11 @@
+.nfd-onboarding-button {
+
+ &--dark {
+ background-color: var(--nfd-onboarding-navigation-back-background);
+ width: 74px;
+ height: 36px;
+ color: var(--nfd-onboarding-primary);
+ border-radius: 8px;
+ padding: 0, 13px, 0 13px;
+ }
+}
diff --git a/src/OnboardingSPA/components/Content/index.js b/src/OnboardingSPA/components/Content/index.js
index 46a050b79..aaf90e31c 100644
--- a/src/OnboardingSPA/components/Content/index.js
+++ b/src/OnboardingSPA/components/Content/index.js
@@ -1,9 +1,8 @@
import { Route, Routes } from 'react-router-dom';
import { Fragment, memo, Suspense, useCallback } from '@wordpress/element';
+import { useSelect } from '@wordpress/data';
import { store as nfdOnboardingStore } from '../../store';
-import { useSelect } from '@wordpress/data';
-import FlowStateHandler from '../StateHandlers/Flow';
/**
* Primary content area within the .
@@ -32,9 +31,7 @@ const Content = () => {
return (
}>
-
- { getMappedPages( routes ) }
-
+ { getMappedPages( routes ) }
);
diff --git a/src/OnboardingSPA/components/Drawer/DrawerPanel/index.js b/src/OnboardingSPA/components/Drawer/DrawerPanel/index.js
index ec939542e..fb3320091 100644
--- a/src/OnboardingSPA/components/Drawer/DrawerPanel/index.js
+++ b/src/OnboardingSPA/components/Drawer/DrawerPanel/index.js
@@ -34,11 +34,12 @@ import WithDesignBack from './WithDesignBack';
const DrawerPanel = () => {
const { isDrawerOpen, drawerView } = useSelect( ( select ) => {
- const { isDrawerOpened, getDrawerView } = select( nfdOnboardingStore );
+ const { isDrawerOpened, getActiveDrawerView } =
+ select( nfdOnboardingStore );
return {
isDrawerOpen: isDrawerOpened(),
- drawerView: getDrawerView(),
+ drawerView: getActiveDrawerView(),
};
}, [] );
diff --git a/src/OnboardingSPA/components/Drawer/DrawerToggle/index.js b/src/OnboardingSPA/components/Drawer/DrawerToggle/index.js
index cfc95b188..354b9146b 100644
--- a/src/OnboardingSPA/components/Drawer/DrawerToggle/index.js
+++ b/src/OnboardingSPA/components/Drawer/DrawerToggle/index.js
@@ -1,3 +1,4 @@
+// eslint-disable-next-line @wordpress/no-unsafe-wp-apis
import { Button, __unstableMotion as motion } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { useEffect, useRef } from '@wordpress/element';
@@ -7,13 +8,18 @@ import classNames from 'classnames';
import { store as nfdOnboardingStore } from '../../../store';
const DrawerToggle = ( { isOpen } ) => {
- const { isDrawerOpen, isDrawerSuppressed } = useSelect( ( select ) => {
- return {
- isDrawerOpen: select( nfdOnboardingStore ).isDrawerOpened(),
- isDrawerSuppressed:
- select( nfdOnboardingStore ).isDrawerSuppressed(),
- };
- }, [] );
+ const { isDrawerOpen, isDrawerSuppressed, activeDrawerView } = useSelect(
+ ( select ) => {
+ return {
+ isDrawerOpen: select( nfdOnboardingStore ).isDrawerOpened(),
+ isDrawerSuppressed:
+ select( nfdOnboardingStore ).isDrawerSuppressed(),
+ activeDrawerView:
+ select( nfdOnboardingStore ).getActiveDrawerView(),
+ };
+ },
+ []
+ );
const { setIsDrawerOpened } = useDispatch( nfdOnboardingStore );
@@ -21,40 +27,45 @@ const DrawerToggle = ( { isOpen } ) => {
useEffect( () => {
if ( ! isDrawerOpen ) {
- drawerToggleRef.current.focus();
+ drawerToggleRef?.current?.focus();
}
}, [ isDrawerOpen ] );
const toggleDrawer = () => {
- isDrawerSuppressed || setIsDrawerOpened( ! isDrawerOpen );
+ if ( isDrawerSuppressed ) {
+ return;
+ }
+ setIsDrawerOpened( ! isDrawerOpen );
};
return (
-
-
-
+
+
+ )
);
};
diff --git a/src/OnboardingSPA/components/Header/components/HeaderEnd.js b/src/OnboardingSPA/components/Header/components/SiteBuildHeader/HeaderEnd.js
similarity index 79%
rename from src/OnboardingSPA/components/Header/components/HeaderEnd.js
rename to src/OnboardingSPA/components/Header/components/SiteBuildHeader/HeaderEnd.js
index 3c0f9fcf3..fca052189 100644
--- a/src/OnboardingSPA/components/Header/components/HeaderEnd.js
+++ b/src/OnboardingSPA/components/Header/components/SiteBuildHeader/HeaderEnd.js
@@ -2,9 +2,9 @@ import { Fragment } from '@wordpress/element';
import { Slot } from '@wordpress/components';
import { useSelect } from '@wordpress/data';
-import StepNavigation from '../step-navigation';
-import { store as nfdOnboardingStore } from '../../../store';
-import { SIDEBAR_MENU_SLOTFILL_PREFIX } from '../../../../constants';
+import StepNavigation from './step-navigation';
+import { store as nfdOnboardingStore } from '../../../../store';
+import { SIDEBAR_MENU_SLOTFILL_PREFIX } from '../../../../../constants';
const HeaderEnd = () => {
const { sidebars, isHeaderNavigationEnabled } = useSelect( ( select ) => {
diff --git a/src/OnboardingSPA/components/Header/components/SiteBuildHeader/index.js b/src/OnboardingSPA/components/Header/components/SiteBuildHeader/index.js
new file mode 100644
index 000000000..e41262533
--- /dev/null
+++ b/src/OnboardingSPA/components/Header/components/SiteBuildHeader/index.js
@@ -0,0 +1,20 @@
+import { memo } from '@wordpress/element';
+import { Fill } from '@wordpress/components';
+
+import HeaderEnd from './HeaderEnd';
+import { HEADER_END, HEADER_SITEBUILD } from '../../../../../constants';
+
+/**
+ * Interface header rendered into header render prop in .
+ *
+ * @return {WPComponent} Header
+ */
+const SiteBuildHeader = () => {
+ return (
+
+
+
+ );
+};
+
+export default memo( SiteBuildHeader );
diff --git a/src/OnboardingSPA/components/Header/step-navigation.js b/src/OnboardingSPA/components/Header/components/SiteBuildHeader/step-navigation.js
similarity index 90%
rename from src/OnboardingSPA/components/Header/step-navigation.js
rename to src/OnboardingSPA/components/Header/components/SiteBuildHeader/step-navigation.js
index 9e8371a23..538225de9 100644
--- a/src/OnboardingSPA/components/Header/step-navigation.js
+++ b/src/OnboardingSPA/components/Header/components/SiteBuildHeader/step-navigation.js
@@ -4,15 +4,15 @@ import { Button, ButtonGroup } from '@wordpress/components';
import { Icon, chevronLeft, chevronRight } from '@wordpress/icons';
import { __ } from '@wordpress/i18n';
-import { setFlow } from '../../utils/api/flow';
-import { store as nfdOnboardingStore } from '../../store';
-import { pluginDashboardPage } from '../../../constants';
-import { activateInitialPlugins } from '../../utils/api/plugins';
+import { setFlow } from '../../../../utils/api/flow';
+import { store as nfdOnboardingStore } from '../../../../store';
+import { pluginDashboardPage } from '../../../../../constants';
+import { activateInitialPlugins } from '../../../../utils/api/plugins';
import {
OnboardingEvent,
sendOnboardingEvent,
-} from '../../utils/analytics/hiive';
-import { ACTION_ONBOARDING_COMPLETE } from '../../utils/analytics/hiive/constants';
+} from '../../../../utils/analytics/hiive';
+import { ACTION_ONBOARDING_COMPLETE } from '../../../../utils/analytics/hiive/constants';
/**
* Back step Navigation button.
diff --git a/src/OnboardingSPA/components/Header/components/SiteGenHeader/index.js b/src/OnboardingSPA/components/Header/components/SiteGenHeader/index.js
new file mode 100644
index 000000000..2f0027111
--- /dev/null
+++ b/src/OnboardingSPA/components/Header/components/SiteGenHeader/index.js
@@ -0,0 +1,59 @@
+import { memo } from '@wordpress/element';
+import AdminBar from '../../../AdminBar';
+import ProgressBar from '../../../ProgressBar';
+
+import { Fill } from '@wordpress/components';
+import {
+ HEADER_SITEGEN,
+ HEADER_START,
+ HEADER_TOP,
+} from '../../../../../constants';
+
+import { useSelect } from '@wordpress/data';
+import { store as nfdOnboardingStore } from '../../../../store';
+import StepNavigation from './step-navigation';
+
+// eslint-disable-next-line import/no-extraneous-dependencies
+import { findIndex } from 'lodash';
+
+/**
+ * Interface header rendered into header render prop in .
+ *
+ * @return {WPComponent} Header
+ */
+const SiteGenHeader = () => {
+ const { isHeaderNavigationEnabled, currentStep, allSteps } = useSelect(
+ ( select ) => {
+ return {
+ currentStep: select( nfdOnboardingStore ).getCurrentStep(),
+ isHeaderNavigationEnabled:
+ select( nfdOnboardingStore ).isHeaderNavigationEnabled(),
+ allSteps: select( nfdOnboardingStore ).getAllSteps(),
+ };
+ }
+ );
+
+ const currentStepIndex = findIndex( allSteps, {
+ path: currentStep.path,
+ } );
+ const progress = ( currentStepIndex / allSteps.length ) * 100;
+
+ return (
+ <>
+
+ <>
+
+ { isHeaderNavigationEnabled && (
+
+ ) }
+ >
+
+
+ <>{ isHeaderNavigationEnabled && }>
+
+ { currentStep?.header && }
+ >
+ );
+};
+
+export default memo( SiteGenHeader );
diff --git a/src/OnboardingSPA/components/Header/components/SiteGenHeader/step-navigation.js b/src/OnboardingSPA/components/Header/components/SiteGenHeader/step-navigation.js
new file mode 100644
index 000000000..b66548465
--- /dev/null
+++ b/src/OnboardingSPA/components/Header/components/SiteGenHeader/step-navigation.js
@@ -0,0 +1,59 @@
+import { useSelect, useDispatch } from '@wordpress/data';
+import { useNavigate } from 'react-router-dom';
+import { Icon, chevronLeft } from '@wordpress/icons';
+import { __ } from '@wordpress/i18n';
+
+import { store as nfdOnboardingStore } from '../../../../store';
+import ButtonDark from '../../../Button/ButtonDark';
+
+/**
+ * Back step Navigation button.
+ *
+ * @param {*} param0
+ *
+ * @return {WPComponent} Back Component
+ */
+const Back = ( { path, showErrorDialog } ) => {
+ const { setNavErrorContinuePath } = useDispatch( nfdOnboardingStore );
+ const navigate = useNavigate();
+ const navigateBack = () => {
+ if ( showErrorDialog !== false ) {
+ setNavErrorContinuePath( path );
+ } else {
+ navigate( path, { state: { origin: 'header' } } );
+ }
+ };
+ return (
+
+
+ { __( 'Back', 'wp-module-onboarding' ) }
+
+ );
+};
+
+/**
+ * Step buttons presented in Header.
+ *
+ * @return {WPComponent} StepNavigation Component
+ */
+const StepNavigation = () => {
+ const { previousStep, showErrorDialog } = useSelect( ( select ) => {
+ return {
+ previousStep: select( nfdOnboardingStore ).getPreviousStep(),
+ showErrorDialog: select( nfdOnboardingStore ).getShowErrorDialog(),
+ };
+ }, [] );
+ const isFirstStep = null === previousStep || false === previousStep;
+ return (
+
+ { isFirstStep ? null : (
+
+ ) }
+
+ );
+};
+
+export default StepNavigation;
diff --git a/src/OnboardingSPA/components/Header/index.js b/src/OnboardingSPA/components/Header/index.js
index 079332dfc..5950c1f4b 100644
--- a/src/OnboardingSPA/components/Header/index.js
+++ b/src/OnboardingSPA/components/Header/index.js
@@ -1,23 +1,60 @@
-import { memo } from '@wordpress/element';
+import { Slot } from '@wordpress/components';
+import { Fragment, Suspense } from '@wordpress/element';
+import { useSelect } from '@wordpress/data';
-import HeaderEnd from './components/HeaderEnd';
+import { store as nfdOnboardingStore } from '../../store';
+import {
+ HEADER_CENTER,
+ HEADER_END,
+ HEADER_START,
+ HEADER_TOP,
+} from '../../../constants';
-/**
- * Interface header rendered into header render prop in .
- *
- * @return {WPComponent} Header
- */
const Header = () => {
+ const { headers, headerActiveView, isHeaderEnabled } = useSelect(
+ ( select ) => {
+ return {
+ headers: select( nfdOnboardingStore ).getHeaders(),
+ headerActiveView:
+ select( nfdOnboardingStore ).getHeaderActiveView(),
+ isHeaderEnabled: select( nfdOnboardingStore ).isHeaderEnabled(),
+ };
+ }
+ );
+
return (
-
-
- { /* Centered Header Slot */ }
-
-
-
-
-
+ <>
+ }>
+ { headers.map( ( header ) => {
+ return (
+
+
+
+ );
+ } ) }
+
+
+ { isHeaderEnabled && (
+
+ ) }
+ >
);
};
-export default memo( Header );
+export default Header;
diff --git a/src/OnboardingSPA/components/NewfoldInterfaceSkeleton/SiteBuild/index.js b/src/OnboardingSPA/components/NewfoldInterfaceSkeleton/SiteBuild/index.js
new file mode 100644
index 000000000..6384313b7
--- /dev/null
+++ b/src/OnboardingSPA/components/NewfoldInterfaceSkeleton/SiteBuild/index.js
@@ -0,0 +1,447 @@
+import Header from '../../Header';
+import Content from '../../Content';
+import Drawer from '../../Drawer';
+import Sidebar from '../../Sidebar';
+import classNames from 'classnames';
+import { useLocation } from 'react-router-dom';
+import { setFlow } from '../../../utils/api/flow';
+import { design as designChapter } from '../../../chapters/design';
+import {
+ getSettings,
+ setSettings,
+ initialize as initializeSettings,
+} from '../../../utils/api/settings';
+import { isEmpty, updateWPSettings } from '../../../utils/api/ecommerce';
+import { store as nfdOnboardingStore } from '../../../store';
+import { getQueryParam } from '../../../utils';
+import { useEffect, useState } from '@wordpress/element';
+
+// eslint-disable-next-line import/no-extraneous-dependencies
+import { kebabCase } from 'lodash';
+import { useViewportMatch } from '@wordpress/compose';
+import { useDispatch, useSelect } from '@wordpress/data';
+
+import { API_REQUEST } from '../../../../constants';
+import NewfoldInterfaceSkeleton from '../index';
+import { HiiveAnalytics } from '@newfold-labs/js-utility-ui-analytics';
+import {
+ getChapterFromId,
+ getChaptersFromTopPriorityAndExperienceLevel,
+ stateToStore,
+} from '../../../chapters/utils';
+import { resolveGetDataForFlow, getInitialChapters } from '../../../data/flows';
+import {
+ OnboardingEvent,
+ trackOnboardingEvent,
+} from '../../../utils/analytics/hiive';
+import { injectInAllSteps } from '../../../data/flows/utils';
+import {
+ ACTION_ONBOARDING_CHAPTER_COMPLETE,
+ ACTION_ONBOARDING_CHAPTER_STARTED,
+ ACTION_ONBOARDING_STARTED,
+ ACTION_FEATURE_ADDED,
+ ACTION_LOGO_ADDED,
+ ACTION_SITE_TITLE_SET,
+ ACTION_SOCIAL_ADDED,
+ ACTION_STARTER_PAGES_SELECTED,
+ ACTION_TAGLINE_SET,
+ CATEGORY,
+} from '../../../utils/analytics/hiive/constants';
+import { socialMediaStoreToState } from '../../SocialMediaForm/utils';
+import { init as initializePlugins } from '../../../utils/api/plugins';
+import { init as initializeThemes } from '../../../utils/api/themes';
+import { trigger as cronTrigger } from '../../../utils/api/cronTrigger';
+import { stepTheFork } from '../../../steps/TheFork/step';
+
+const SiteBuild = () => {
+ const location = useLocation();
+ const isLargeViewport = useViewportMatch( 'medium' );
+ const pathname = kebabCase( location.pathname );
+
+ const {
+ isDrawerOpen,
+ newfoldBrand,
+ onboardingFlow,
+ currentData,
+ currentStep,
+ lastChapter,
+ socialData,
+ firstStep,
+ allSteps,
+ experienceLevel,
+ topPriority,
+ brandConfig,
+ initialize,
+ pluginInstallHash,
+ } = useSelect(
+ ( select ) => {
+ return {
+ isDrawerOpen: select( nfdOnboardingStore ).isDrawerOpened(),
+ newfoldBrand: select( nfdOnboardingStore ).getNewfoldBrand(),
+ onboardingFlow:
+ select( nfdOnboardingStore ).getOnboardingFlow(),
+ currentData:
+ select( nfdOnboardingStore ).getCurrentOnboardingData(),
+ socialData:
+ select( nfdOnboardingStore ).getOnboardingSocialData(),
+ firstStep: select( nfdOnboardingStore ).getFirstStep(),
+ allSteps: select( nfdOnboardingStore ).getAllSteps(),
+ topPriority: select( nfdOnboardingStore ).getTopPriority(),
+ experienceLevel:
+ select( nfdOnboardingStore ).getExperienceLevel(),
+ currentStep: select( nfdOnboardingStore ).getCurrentStep(),
+ lastChapter: select( nfdOnboardingStore ).getCurrentChapter(),
+ brandConfig:
+ select( nfdOnboardingStore ).getNewfoldBrandConfig(),
+ initialize: select( nfdOnboardingStore ).getInitialize(),
+ pluginInstallHash:
+ select( nfdOnboardingStore ).getPluginInstallHash(),
+ };
+ },
+ [ location.pathname ]
+ );
+
+ const [ isRequestPlaced, setIsRequestPlaced ] = useState( false );
+ const [ didVisitBasicInfo, setDidVisitBasicInfo ] = useState( false );
+ const [ didVisitEcommerce, setDidVisitEcommerce ] = useState( false );
+ const {
+ setActiveChapter,
+ flushQueue,
+ enqueueRequest,
+ setOnboardingSocialData,
+ updateAllSteps,
+ updateRoutes,
+ updateTopSteps,
+ updateDesignRoutes,
+ setCurrentOnboardingData,
+ } = useDispatch( nfdOnboardingStore );
+
+ async function syncSocialSettings() {
+ const initialData = await getSettings();
+ const result = await setSettings( socialData );
+ setDidVisitBasicInfo( false );
+ if ( result?.error !== null ) {
+ return initialData?.body;
+ }
+ return result?.body;
+ }
+
+ async function syncStoreDetails() {
+ const { address } = currentData.storeDetails;
+ let payload = {};
+ if ( address !== undefined ) {
+ delete address.country;
+ delete address.state;
+ payload = address;
+ }
+ // if ( tax !== undefined ) {
+ // delete tax.option;
+ // delete tax.isStoreDetailsFilled;
+ // payload = { ...payload, ...tax };
+ // }
+ if ( ! isEmpty( payload ) ) {
+ await updateWPSettings( payload );
+ }
+ delete currentData.storeDetails.address;
+ delete currentData.storeDetails.tax;
+ setDidVisitEcommerce( false );
+ }
+
+ async function syncStoreToDB() {
+ // The First Welcome Step doesn't have any Store changes
+ const isFirstStep = location?.pathname === firstStep?.path;
+ if ( currentData && ! isFirstStep ) {
+ if ( ! isRequestPlaced ) {
+ setIsRequestPlaced( true );
+
+ if ( didVisitEcommerce ) {
+ await syncStoreDetails();
+ }
+
+ // If Social Data is changed then sync it
+ if ( didVisitBasicInfo ) {
+ const socialDataResp = await syncSocialSettings();
+
+ // If Social Data is changed then Sync that also to the store
+ if ( socialDataResp ) {
+ setOnboardingSocialData( socialDataResp );
+ }
+ }
+ flushQueue();
+ enqueueRequest( API_REQUEST.SET_FLOW, () =>
+ setFlow( currentData )
+ );
+ setIsRequestPlaced( false );
+ }
+ }
+
+ // Check if the Basic Info page was visited
+ if ( location?.pathname.includes( 'basic-info' ) ) {
+ setDidVisitBasicInfo( true );
+ }
+ if ( location?.pathname.includes( 'ecommerce' ) ) {
+ setDidVisitEcommerce( true );
+ }
+ }
+
+ function handleConditionalDesignStepsRoutes() {
+ if (
+ location?.pathname.includes( 'colors' ) ||
+ location?.pathname.includes( 'fonts' )
+ ) {
+ const updates = injectInAllSteps(
+ allSteps,
+ designChapter.conditionalSteps
+ );
+ updateAllSteps( updates.allSteps );
+ if ( ! currentData.data.customDesign ) {
+ currentData.data.customDesign = true;
+ setCurrentOnboardingData( currentData );
+ }
+ }
+ }
+
+ const handlePreviousStepTracking = () => {
+ const previousStep = window.nfdOnboarding?.previousStep;
+ if ( typeof previousStep !== 'object' ) {
+ window.nfdOnboarding.previousStep = {
+ path: location.pathname,
+ url: window.location.href,
+ };
+ HiiveAnalytics.dispatchEvents( CATEGORY );
+ return;
+ }
+
+ const previousStepPath = previousStep.path;
+ const previousStepURL = previousStep.url;
+
+ if ( previousStepPath.includes( 'basic-info' ) ) {
+ const siteTitle = currentData.data.blogName;
+ const siteDescription = currentData.data.blogDescription;
+ const siteLogo = currentData.data.siteLogo.url;
+ if ( siteTitle ) {
+ trackOnboardingEvent(
+ new OnboardingEvent(
+ ACTION_SITE_TITLE_SET,
+ siteTitle,
+ {},
+ previousStepURL
+ )
+ );
+ }
+
+ if ( siteDescription ) {
+ trackOnboardingEvent(
+ new OnboardingEvent(
+ ACTION_TAGLINE_SET,
+ siteDescription,
+ {},
+ previousStepURL
+ )
+ );
+ }
+
+ if ( siteLogo ) {
+ trackOnboardingEvent(
+ new OnboardingEvent(
+ ACTION_LOGO_ADDED,
+ undefined,
+ {},
+ previousStepURL
+ )
+ );
+ }
+
+ const platforms = Object.keys(
+ socialMediaStoreToState( socialData )
+ );
+ if ( platforms.length ) {
+ platforms.forEach( ( platform ) => {
+ trackOnboardingEvent(
+ new OnboardingEvent(
+ ACTION_SOCIAL_ADDED,
+ platform,
+ {},
+ previousStepURL
+ )
+ );
+ } );
+ }
+ }
+
+ if ( previousStepPath.includes( 'site-pages' ) ) {
+ const sitePages = currentData.data.sitePages?.other;
+ if ( ! sitePages || false === sitePages ) {
+ trackOnboardingEvent(
+ new OnboardingEvent(
+ ACTION_STARTER_PAGES_SELECTED,
+ [],
+ {
+ count: 0,
+ },
+ previousStepURL
+ )
+ );
+ } else {
+ trackOnboardingEvent(
+ new OnboardingEvent(
+ ACTION_STARTER_PAGES_SELECTED,
+ sitePages.map( ( sitePage ) => sitePage.title ),
+ {
+ count: sitePages.length,
+ },
+ previousStepURL
+ )
+ );
+ }
+ }
+
+ if ( previousStepPath.includes( 'site-features' ) ) {
+ const siteFeatures = currentData.data.siteFeatures;
+ for ( const siteFeature in siteFeatures ) {
+ if ( false !== siteFeatures[ siteFeature ] ) {
+ trackOnboardingEvent(
+ new OnboardingEvent(
+ ACTION_FEATURE_ADDED,
+ siteFeature,
+ {},
+ previousStepURL
+ )
+ );
+ }
+ }
+ }
+
+ window.nfdOnboarding.previousStep = {
+ path: location.pathname,
+ url: window.location.href,
+ };
+
+ HiiveAnalytics.dispatchEvents( CATEGORY );
+ };
+
+ const trackChapters = () => {
+ if ( location.pathname === firstStep.path ) {
+ trackOnboardingEvent(
+ new OnboardingEvent( ACTION_ONBOARDING_STARTED )
+ );
+ }
+
+ const currentChapter = currentStep?.chapter;
+
+ if ( lastChapter !== currentChapter ) {
+ if ( lastChapter ) {
+ currentData.data.chapters[ lastChapter ].completed = true;
+ trackOnboardingEvent(
+ new OnboardingEvent(
+ ACTION_ONBOARDING_CHAPTER_COMPLETE,
+ lastChapter
+ )
+ );
+ }
+
+ if ( currentChapter ) {
+ currentData.data.chapters[ currentChapter ].completed = false;
+ trackOnboardingEvent(
+ new OnboardingEvent(
+ ACTION_ONBOARDING_CHAPTER_STARTED,
+ currentChapter
+ )
+ );
+ }
+
+ setActiveChapter( currentChapter );
+ }
+
+ if ( currentChapter ) {
+ currentData.data.chapters[ currentChapter ].lastStep =
+ currentStep?.path ?? '';
+ }
+ };
+
+ useEffect( () => {
+ trackChapters();
+ }, [ currentStep ] );
+
+ const prioritizeFlow = () => {
+ const currentFlow = window.nfdOnboarding.currentFlow;
+ const initialChapters = getInitialChapters( currentFlow );
+ const chapterQueryArg = getQueryParam( 'chapter' );
+
+ let chapters;
+ if ( chapterQueryArg ) {
+ chapters = getChapterFromId( chapterQueryArg );
+ } else {
+ chapters = getChaptersFromTopPriorityAndExperienceLevel(
+ initialChapters,
+ topPriority,
+ experienceLevel
+ );
+ }
+
+ const getData = resolveGetDataForFlow( currentFlow );
+ const data = getData( chapters, chapterQueryArg );
+
+ currentData.data.chapters = stateToStore(
+ initialChapters,
+ currentData.data.chapters,
+ currentStep
+ );
+
+ setCurrentOnboardingData( currentData );
+ updateAllSteps( data.steps );
+ updateTopSteps( data.topSteps );
+ updateRoutes( data.routes );
+ updateDesignRoutes( data.designRoutes );
+ };
+
+ useEffect( () => {
+ if ( initialize ) {
+ initializePlugins( pluginInstallHash );
+ initializeThemes();
+ initializeSettings();
+ setInterval( cronTrigger, 45000 );
+ }
+ }, [ initialize ] );
+
+ useEffect( () => {
+ if ( false !== brandConfig?.prioritization ) {
+ return prioritizeFlow();
+ }
+ }, [ experienceLevel, topPriority ] );
+
+ useEffect( () => {
+ document.body.classList.add( `nfd-brand-${ newfoldBrand }` );
+ }, [ newfoldBrand ] );
+
+ useEffect( () => {
+ syncStoreToDB();
+ handlePreviousStepTracking();
+ handleConditionalDesignStepsRoutes();
+ }, [ location.pathname, onboardingFlow ] );
+ return (
+ }
+ drawer={ }
+ content={ }
+ sidebar={ }
+ />
+ );
+};
+
+export default SiteBuild;
diff --git a/src/OnboardingSPA/components/NewfoldInterfaceSkeleton/SiteGen/index.js b/src/OnboardingSPA/components/NewfoldInterfaceSkeleton/SiteGen/index.js
new file mode 100644
index 000000000..87e29e351
--- /dev/null
+++ b/src/OnboardingSPA/components/NewfoldInterfaceSkeleton/SiteGen/index.js
@@ -0,0 +1,21 @@
+import NewfoldInterfaceSkeleton from '../index';
+import Header from '../../Header';
+import Content from '../../Content';
+import Sidebar from '../../Sidebar';
+import classNames from 'classnames';
+
+const SiteGen = () => {
+ return (
+ }
+ content={ }
+ sidebar={ }
+ />
+ );
+};
+
+export default SiteGen;
diff --git a/src/OnboardingSPA/components/NewfoldInterfaceSkeleton/style.scss b/src/OnboardingSPA/components/NewfoldInterfaceSkeleton/style.scss
index b805ea042..7d47de994 100644
--- a/src/OnboardingSPA/components/NewfoldInterfaceSkeleton/style.scss
+++ b/src/OnboardingSPA/components/NewfoldInterfaceSkeleton/style.scss
@@ -184,3 +184,10 @@ html.nfd-interface-interface-skeleton__html-container {
bottom: 0;
}
}
+
+.nfd-onboarding-skeleton {
+
+ &--sitegen {
+ background-image: var(--sitegen-background);
+ }
+}
diff --git a/src/OnboardingSPA/components/ProgressBar/index.js b/src/OnboardingSPA/components/ProgressBar/index.js
new file mode 100644
index 000000000..404f746f4
--- /dev/null
+++ b/src/OnboardingSPA/components/ProgressBar/index.js
@@ -0,0 +1,12 @@
+const ProgressBar = ( { progress = 20 } ) => {
+ return (
+
+ );
+};
+
+export default ProgressBar;
diff --git a/src/OnboardingSPA/components/ProgressBar/stylesheet.scss b/src/OnboardingSPA/components/ProgressBar/stylesheet.scss
new file mode 100644
index 000000000..bb8490289
--- /dev/null
+++ b/src/OnboardingSPA/components/ProgressBar/stylesheet.scss
@@ -0,0 +1,13 @@
+.nfd-onboarding-header {
+
+ &__progress-bar {
+ width: 100%;
+ background-color: var(--nfd-onboarding-progress-bar-background);
+ height: 16px;
+
+ &__progress {
+ background-color: var(--nfd-onboarding-progress-bar-fill);
+ height: 16px;
+ }
+ }
+}
diff --git a/src/OnboardingSPA/components/SiteGenPlaceholder/index.js b/src/OnboardingSPA/components/SiteGenPlaceholder/index.js
new file mode 100644
index 000000000..ceebd3913
--- /dev/null
+++ b/src/OnboardingSPA/components/SiteGenPlaceholder/index.js
@@ -0,0 +1,31 @@
+import { useNavigate } from 'react-router-dom';
+
+import { useSelect } from '@wordpress/data';
+import { Button } from '@wordpress/components';
+import { store as nfdOnboardingStore } from '../../store';
+
+const SiteGenPlaceholder = ( { heading } ) => {
+ const navigate = useNavigate();
+ const { nextStep } = useSelect( ( select ) => {
+ return {
+ nextStep: select( nfdOnboardingStore ).getNextStep(),
+ };
+ } );
+ return (
+
+
+ { heading }
+
+
+
+ );
+};
+
+export default SiteGenPlaceholder;
diff --git a/src/OnboardingSPA/components/SiteGenPlaceholder/stylesheet.scss b/src/OnboardingSPA/components/SiteGenPlaceholder/stylesheet.scss
new file mode 100644
index 000000000..741c92f2a
--- /dev/null
+++ b/src/OnboardingSPA/components/SiteGenPlaceholder/stylesheet.scss
@@ -0,0 +1,25 @@
+.nfd-onboarding-placeholder {
+
+ &--site-gen {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+
+ &__heading {
+ color: var(--nfd-onboarding-primary);
+ font-size: 70px;
+ }
+
+ &__button {
+ display: block;
+ background-color: var(--nfd-onboarding-primary);
+ color: var(--nfd-onboarding-secondary);
+ text-align: center;
+ width: 164px;
+ height: 50px;
+ font-size: 15px;
+ margin-top: 24px;
+ }
+ }
+}
diff --git a/src/OnboardingSPA/components/StateHandlers/Flow/index.js b/src/OnboardingSPA/components/StateHandlers/Flow/index.js
index 865602156..2adc29f72 100644
--- a/src/OnboardingSPA/components/StateHandlers/Flow/index.js
+++ b/src/OnboardingSPA/components/StateHandlers/Flow/index.js
@@ -2,69 +2,37 @@ import { useEffect, useState } from '@wordpress/element';
import { useLocation } from 'react-router-dom';
import { useSelect, useDispatch } from '@wordpress/data';
import { getFragment } from '@wordpress/url';
+import { HiiveAnalytics } from '@newfold-labs/js-utility-ui-analytics';
import { store as nfdOnboardingStore } from '../../../store';
import { switchFlow } from '../../../utils/api/flow';
import { MAX_RETRIES_FLOW_SWITCH } from '../../../../constants';
-import {
- getChapterFromId,
- getChaptersFromTopPriorityAndExperienceLevel,
- stateToStore,
-} from '../../../chapters/utils';
-import { resolveGetDataForFlow, getInitialChapters } from '../../../data/flows';
-import {
- OnboardingEvent,
- trackOnboardingEvent,
-} from '../../../utils/analytics/hiive';
-import {
- ACTION_ONBOARDING_CHAPTER_COMPLETE,
- ACTION_ONBOARDING_CHAPTER_STARTED,
- ACTION_ONBOARDING_STARTED,
-} from '../../../utils/analytics/hiive/constants';
import { ECOMMERCE_FLOW } from '../../../data/flows/constants';
-import { getQueryParam, removeQueryParam } from '../../../utils';
+import { removeQueryParam } from '../../../utils';
import { commerce } from '../../../chapters/commerce';
import EcommerceStepLoader from '../../Loaders/Step/Ecommerce';
-import { HiiveAnalytics } from '@newfold-labs/js-utility-ui-analytics';
+import SiteBuild from '../../NewfoldInterfaceSkeleton/SiteBuild';
+import SiteGen from '../../NewfoldInterfaceSkeleton/SiteGen';
+import { validateFlow } from '../../../data/flows/utils';
-const FlowStateHandler = ( { children } ) => {
+const FlowStateHandler = () => {
const location = useLocation();
-
const [ newFlow, setNewFlow ] = useState( false );
- const {
- brandConfig,
- experienceLevel,
- topPriority,
- currentData,
- currentStep,
- lastChapter,
- firstStep,
- } = useSelect( ( select ) => {
+ const { brandConfig, onboardingFlow } = useSelect( ( select ) => {
return {
- brandName: select( nfdOnboardingStore ).getNewfoldBrandName(),
brandConfig: select( nfdOnboardingStore ).getNewfoldBrandConfig(),
- experienceLevel: select( nfdOnboardingStore ).getExperienceLevel(),
- topPriority: select( nfdOnboardingStore ).getTopPriority(),
- currentData:
- select( nfdOnboardingStore ).getCurrentOnboardingData(),
- lastChapter: select( nfdOnboardingStore ).getCurrentChapter(),
- currentStep: select( nfdOnboardingStore ).getCurrentStep(),
- firstStep: select( nfdOnboardingStore ).getFirstStep(),
+ onboardingFlow: select( nfdOnboardingStore ).getOnboardingFlow(),
};
}, [] );
const {
- updateAllSteps,
- updateRoutes,
- updateTopSteps,
- updateDesignRoutes,
- setCurrentOnboardingData,
- setActiveChapter,
setIsDrawerOpened,
setIsDrawerSuppressed,
setIsHeaderNavigationEnabled,
setSidebarActiveView,
+ setActiveFlow,
+ setActiveStep,
} = useDispatch( nfdOnboardingStore );
const handleCommerceFlow = async ( flow, retries = 0 ) => {
@@ -90,101 +58,16 @@ const FlowStateHandler = ( { children } ) => {
};
const switchToNewFlow = async ( flow ) => {
- const enabledFlows = brandConfig?.enabled_flows ?? {};
- if ( ! ( flow in enabledFlows ) || enabledFlows[ flow ] !== true ) {
+ if ( ! validateFlow( brandConfig, flow ) ) {
return;
}
switch ( flow ) {
case ECOMMERCE_FLOW:
- handleCommerceFlow( flow );
- break;
- default:
- setNewFlow( false );
+ return handleCommerceFlow( flow );
}
};
- const prioritizeFlow = () => {
- const currentFlow = window.nfdOnboarding.currentFlow;
- const initialChapters = getInitialChapters( currentFlow );
- const chapterQueryArg = getQueryParam( 'chapter' );
-
- let chapters;
- if ( chapterQueryArg ) {
- chapters = getChapterFromId( chapterQueryArg );
- } else {
- chapters = getChaptersFromTopPriorityAndExperienceLevel(
- initialChapters,
- topPriority,
- experienceLevel
- );
- }
-
- const getData = resolveGetDataForFlow( currentFlow );
- const data = getData( chapters, chapterQueryArg );
-
- currentData.data.chapters = stateToStore(
- initialChapters,
- currentData.data.chapters,
- currentStep
- );
-
- setCurrentOnboardingData( currentData );
- updateAllSteps( data.steps );
- updateTopSteps( data.topSteps );
- updateRoutes( data.routes );
- updateDesignRoutes( data.designRoutes );
- };
-
- const trackChapters = () => {
- if ( location.pathname === firstStep.path ) {
- trackOnboardingEvent(
- new OnboardingEvent( ACTION_ONBOARDING_STARTED )
- );
- }
-
- const currentChapter = currentStep?.chapter;
-
- if ( lastChapter !== currentChapter ) {
- if ( lastChapter ) {
- currentData.data.chapters[ lastChapter ].completed = true;
- trackOnboardingEvent(
- new OnboardingEvent(
- ACTION_ONBOARDING_CHAPTER_COMPLETE,
- lastChapter
- )
- );
- }
-
- if ( currentChapter ) {
- currentData.data.chapters[ currentChapter ].completed = false;
- trackOnboardingEvent(
- new OnboardingEvent(
- ACTION_ONBOARDING_CHAPTER_STARTED,
- currentChapter
- )
- );
- }
-
- setActiveChapter( currentChapter );
- }
-
- if ( currentChapter ) {
- currentData.data.chapters[ currentChapter ].lastStep =
- currentStep?.path ?? '';
- }
- };
-
- useEffect( () => {
- if ( false !== brandConfig?.prioritization ) {
- return prioritizeFlow();
- }
- }, [ experienceLevel, topPriority ] );
-
- useEffect( () => {
- trackChapters();
- }, [ currentStep ] );
-
const disableNavigation = () => {
setIsDrawerOpened( false );
setIsDrawerSuppressed( true );
@@ -199,6 +82,9 @@ const FlowStateHandler = ( { children } ) => {
setNewFlow( flow );
switchToNewFlow( flow );
window.nfdOnboarding.newFlow = undefined;
+ } else if ( location.pathname.includes( '/step' ) ) {
+ setActiveFlow( onboardingFlow );
+ setActiveStep( location.pathname );
}
}, [ location.pathname ] );
@@ -207,8 +93,14 @@ const FlowStateHandler = ( { children } ) => {
switch ( newFlow ) {
case 'ecommerce':
return ;
- default:
- return children;
+ }
+
+ switch ( window.nfdOnboarding.currentFlow ) {
+ case 'wp-setup':
+ case 'ecommerce':
+ return ;
+ case 'sitegen':
+ return ;
}
};
diff --git a/src/OnboardingSPA/data/flows/constants.js b/src/OnboardingSPA/data/flows/constants.js
index d4bf6e8e4..0f8760156 100644
--- a/src/OnboardingSPA/data/flows/constants.js
+++ b/src/OnboardingSPA/data/flows/constants.js
@@ -1,2 +1,3 @@
export const DEFAULT_FLOW = 'wp-setup';
export const ECOMMERCE_FLOW = 'ecommerce';
+export const SITEGEN_FLOW = 'sitegen';
diff --git a/src/OnboardingSPA/data/flows/default.js b/src/OnboardingSPA/data/flows/default.js
index 4cee09c68..f7b3740c1 100644
--- a/src/OnboardingSPA/data/flows/default.js
+++ b/src/OnboardingSPA/data/flows/default.js
@@ -12,6 +12,7 @@ import { PseudoStep } from '../models/PseudoStep';
import { indexPage } from '../../pages/IndexPage/page';
import { brush } from '@wordpress/icons';
import { __ } from '@wordpress/i18n';
+import { stepTheFork } from '../../steps/TheFork/step';
export const pages = [ indexPage, errorPage ];
@@ -19,6 +20,7 @@ export const initialChapters = [ demographic, design, layoutContent, features ];
export const getSteps = ( chapters = initialChapters ) => {
let steps = [];
+ steps.push( stepTheFork );
steps.push( stepWelcome );
chapters.forEach( ( chapter ) => {
steps = steps.concat( [
@@ -32,6 +34,7 @@ export const getSteps = ( chapters = initialChapters ) => {
export const getRoutes = ( chapters = initialChapters ) => {
let routes = [ ...pages ];
+ routes.push( stepTheFork );
routes.push( stepWelcome );
chapters.forEach( ( chapter ) => {
routes = routes.concat( [
diff --git a/src/OnboardingSPA/data/flows/ecommerce.js b/src/OnboardingSPA/data/flows/ecommerce.js
index 68842cd98..68bca7e04 100644
--- a/src/OnboardingSPA/data/flows/ecommerce.js
+++ b/src/OnboardingSPA/data/flows/ecommerce.js
@@ -18,6 +18,7 @@ import { layoutContent } from '../../chapters/layoutContent';
import { filter } from 'lodash';
import { store } from '@wordpress/icons';
import { __ } from '@wordpress/i18n';
+import { stepTheFork } from '../../steps/TheFork/step';
export const pages = [ indexPage, errorPage ];
@@ -31,6 +32,7 @@ export const initialChapters = [
export const getSteps = ( chapters = initialChapters ) => {
let steps = [];
+ steps.push( stepTheFork );
steps.push( stepWelcome );
chapters.forEach( ( chapter ) => {
steps = steps.concat( [
@@ -41,14 +43,13 @@ export const getSteps = ( chapters = initialChapters ) => {
steps = steps.concat( [ stepComplete, stepWhatNext ] );
// TODO: Filter to be removed once Chapter Prioritization is enabled.
return filter( steps, ( step ) => {
- return (
- ! step.path.includes( '/wp-setup/step/top-priority' )
- );
+ return ! step.path.includes( '/wp-setup/step/top-priority' );
} );
};
export const getRoutes = ( chapters = initialChapters ) => {
let routes = [ ...pages ];
+ routes.push( stepTheFork );
routes.push( stepWelcome );
chapters.forEach( ( chapter ) => {
routes = routes.concat( [
@@ -60,9 +61,7 @@ export const getRoutes = ( chapters = initialChapters ) => {
routes = routes.concat( [ stepComplete, stepWhatNext ] );
// TODO: Filter to be removed once Chapter Prioritization is enabled.
return filter( routes, ( route ) => {
- return (
- ! route.path.includes( '/wp-setup/step/top-priority' )
- );
+ return ! route.path.includes( '/wp-setup/step/top-priority' );
} );
};
@@ -90,7 +89,7 @@ export const getTopSteps = ( steps ) => {
return (
step instanceof PseudoStep ||
( ! step.path.includes( '/ecommerce/step' ) &&
- ! step.path.includes( '/wp-setup/step/top-priority' ) ) // TODO: Filter to be removed once Chapter Prioritization is enabled.
+ ! step.path.includes( '/wp-setup/step/top-priority' ) ) // TODO: Filter to be removed once Chapter Prioritization is enabled.
);
} );
};
diff --git a/src/OnboardingSPA/data/flows/index.js b/src/OnboardingSPA/data/flows/index.js
index ea7748d4d..717ddcde0 100644
--- a/src/OnboardingSPA/data/flows/index.js
+++ b/src/OnboardingSPA/data/flows/index.js
@@ -1,4 +1,4 @@
-import { DEFAULT_FLOW, ECOMMERCE_FLOW } from './constants';
+import { DEFAULT_FLOW, ECOMMERCE_FLOW, SITEGEN_FLOW } from './constants';
import {
getRoutes as defaultGetRoutes,
getSteps as defaultGetSteps,
@@ -16,6 +16,15 @@ import {
getData as ecommerceGetData,
} from './ecommerce';
+import {
+ getSteps as sitegenGetSteps,
+ getRoutes as sitegenGetRoutes,
+ getTopSteps as sitegenGetTopSteps,
+ getDesignRoutes as sitegenGetDesignRoutes,
+ initialChapters as sitegenInitialChapters,
+ getData as sitegenGetData,
+} from './sitegen';
+
export const getCurrentFlow = () => {
return window.nfdOnboarding.currentFlow ?? DEFAULT_FLOW;
};
@@ -37,6 +46,14 @@ const routerMap = {
getData: ecommerceGetData,
getDesignRoutes: defaultGetDesignRoutes,
},
+ [ SITEGEN_FLOW ]: {
+ getRoutes: sitegenGetRoutes,
+ getSteps: sitegenGetSteps,
+ chapters: sitegenInitialChapters,
+ getData: sitegenGetData,
+ getTopSteps: sitegenGetTopSteps,
+ getDesignRoutes: sitegenGetDesignRoutes,
+ },
};
export const initialRoutes = routerMap[ getCurrentFlow() ].getRoutes();
diff --git a/src/OnboardingSPA/data/flows/sitegen.js b/src/OnboardingSPA/data/flows/sitegen.js
new file mode 100644
index 000000000..c0a078b3e
--- /dev/null
+++ b/src/OnboardingSPA/data/flows/sitegen.js
@@ -0,0 +1,48 @@
+import { sitegen } from '../../chapters/sitegen';
+import { errorPage } from '../../pages/ErrorPage/page';
+import { indexPage } from '../../pages/IndexPage/page';
+import { stepTheFork } from '../../steps/TheFork/step';
+
+export const pages = [ indexPage, errorPage ];
+
+export const initialChapters = [ sitegen ];
+
+export const getSteps = ( chapters = initialChapters ) => {
+ let steps = [];
+ steps.push( stepTheFork );
+ chapters.forEach( ( chapter ) => {
+ steps = steps.concat( [
+ ...chapter.steps,
+ // ...chapter.interstitialSteps,
+ ] );
+ } );
+ return steps;
+};
+
+export const getRoutes = ( chapters = initialChapters ) => {
+ let routes = [ ...pages ];
+ routes.push( stepTheFork );
+ chapters.forEach( ( chapter ) => {
+ routes = routes.concat( [
+ ...chapter.steps,
+ ...chapter.conditionalSteps,
+ // ...chapter.interstitialSteps,
+ ] );
+ } );
+ return routes;
+};
+
+export const getData = () => {
+ return {
+ steps: getSteps(),
+ routes: getRoutes(),
+ };
+};
+
+export const getTopSteps = () => {
+ return [];
+};
+
+export const getDesignRoutes = () => {
+ return [];
+};
diff --git a/src/OnboardingSPA/data/flows/utils.js b/src/OnboardingSPA/data/flows/utils.js
index a9367343b..4fe3d68d0 100644
--- a/src/OnboardingSPA/data/flows/utils.js
+++ b/src/OnboardingSPA/data/flows/utils.js
@@ -42,3 +42,11 @@ export const addAfterChapter = ( chapters, chapterOne, chapterTwo ) => {
chapters.splice( position + 1, 0, chapterTwo );
return chapters;
};
+
+export const validateFlow = ( brandConfig, flow ) => {
+ const enabledFlows = brandConfig?.enabled_flows ?? {};
+ if ( ! ( flow in enabledFlows ) || enabledFlows[ flow ] !== true ) {
+ return false;
+ }
+ return true;
+};
diff --git a/src/OnboardingSPA/data/headers/index.js b/src/OnboardingSPA/data/headers/index.js
new file mode 100644
index 000000000..12c7b2af3
--- /dev/null
+++ b/src/OnboardingSPA/data/headers/index.js
@@ -0,0 +1,24 @@
+import { lazy } from '@wordpress/element';
+
+import { HEADER_SITEBUILD, HEADER_SITEGEN } from '../../../constants';
+
+const SiteGenHeader = lazy( () =>
+ import( '../../components/Header/components/SiteGenHeader' )
+);
+
+const SiteBuildHeader = lazy( () =>
+ import( '../../components/Header/components/SiteBuildHeader' )
+);
+
+export const headers = [
+ {
+ id: HEADER_SITEGEN,
+ header: SiteGenHeader,
+ enabled: true,
+ },
+ {
+ id: HEADER_SITEBUILD,
+ header: SiteBuildHeader,
+ enabled: true,
+ },
+];
diff --git a/src/OnboardingSPA/data/models/Step.js b/src/OnboardingSPA/data/models/Step.js
index 6407a8586..e532f6002 100644
--- a/src/OnboardingSPA/data/models/Step.js
+++ b/src/OnboardingSPA/data/models/Step.js
@@ -6,6 +6,7 @@ export class Step {
icon,
drawerView,
sidebars,
+ header,
data,
} ) {
this.path = path;
@@ -15,5 +16,6 @@ export class Step {
this.drawerView = drawerView;
this.sidebars = sidebars;
this.data = data;
+ this.header = header;
}
}
diff --git a/src/OnboardingSPA/data/translations/index.js b/src/OnboardingSPA/data/translations/index.js
index 585b6c1d6..2c05800b4 100644
--- a/src/OnboardingSPA/data/translations/index.js
+++ b/src/OnboardingSPA/data/translations/index.js
@@ -1,5 +1,5 @@
import { _x } from '@wordpress/i18n';
-import { DEFAULT_FLOW, ECOMMERCE_FLOW } from '../flows/constants';
+import { DEFAULT_FLOW, ECOMMERCE_FLOW, SITEGEN_FLOW } from '../flows/constants';
export const translationMap = {
[ DEFAULT_FLOW ]: {
@@ -18,4 +18,12 @@ export const translationMap = {
noun: _x( 'store', 'noun', 'wp-module-onboarding' ),
},
},
+ [ SITEGEN_FLOW ]: {
+ site: {
+ noun: _x( 'site', 'noun', 'wp-module-onboarding' ),
+ },
+ website: {
+ noun: _x( 'website', 'noun', 'wp-module-onboarding' ),
+ },
+ },
};
diff --git a/src/OnboardingSPA/index.js b/src/OnboardingSPA/index.js
index 1348ab20f..72d17d521 100644
--- a/src/OnboardingSPA/index.js
+++ b/src/OnboardingSPA/index.js
@@ -1,10 +1,6 @@
import './styles/app.scss';
import { store as nfdOnboardingStore } from './store'; /* must import prior to App! */
import { getFlow } from './utils/api/flow';
-import { init as initializePlugins } from './utils/api/plugins';
-import { init as initializeThemes } from './utils/api/themes';
-import { trigger as cronTrigger } from './utils/api/cronTrigger';
-import { initialize as initializeSettings } from './utils/api/settings';
import { DESIGN_STEPS_THEME } from '../constants';
import App from './components/App';
@@ -43,10 +39,6 @@ const initializeFlowData = ( currentData ) => {
* @param {Object} runtime - Expects runtime data from window.nfdOnboarding.
*/
export async function initializeNFDOnboarding( id, runtime ) {
- initializePlugins();
- initializeThemes();
- setInterval( cronTrigger, 45000 );
-
const DOM_TARGET = document.getElementById( id );
dispatch( nfdOnboardingStore ).setRuntime( runtime );
if ( runtime.previewSettings.settings.preRequisites?.themes ) {
@@ -67,7 +59,6 @@ export async function initializeNFDOnboarding( id, runtime ) {
if ( null !== DOM_TARGET && 'undefined' !== typeof render ) {
render( , DOM_TARGET );
- initializeSettings();
} else {
// eslint-disable-next-line no-console
console.log( 'Could not find mount element or wp.element.render().' );
diff --git a/src/OnboardingSPA/static/images/sitegen-bg.png b/src/OnboardingSPA/static/images/sitegen-bg.png
new file mode 100644
index 000000000..c36c9b9ba
Binary files /dev/null and b/src/OnboardingSPA/static/images/sitegen-bg.png differ
diff --git a/src/OnboardingSPA/steps/GetStarted/Welcome/index.js b/src/OnboardingSPA/steps/GetStarted/Welcome/index.js
index 2bf5620ec..356bc66a7 100644
--- a/src/OnboardingSPA/steps/GetStarted/Welcome/index.js
+++ b/src/OnboardingSPA/steps/GetStarted/Welcome/index.js
@@ -13,6 +13,7 @@ import TabPanelHover from '../../../components/TabPanelHover';
import {
VIEW_NAV_GET_STARTED,
SIDEBAR_LEARN_MORE,
+ HEADER_SITEBUILD,
} from '../../../../constants';
import getContents from './contents';
import ButtonWhite from '../../../components/Button/ButtonWhite';
@@ -33,6 +34,8 @@ const StepWelcome = () => {
setSidebarActiveView,
setIsDrawerSuppressed,
setIsHeaderNavigationEnabled,
+ setHeaderActiveView,
+ setIsHeaderEnabled,
} = useDispatch( nfdOnboardingStore );
useEffect( () => {
@@ -40,6 +43,8 @@ const StepWelcome = () => {
setIsHeaderNavigationEnabled( true );
setIsDrawerSuppressed( true );
setDrawerActiveView( VIEW_NAV_GET_STARTED );
+ setHeaderActiveView( HEADER_SITEBUILD );
+ setIsHeaderEnabled( true );
}, [] );
const content = getContents( brandName );
diff --git a/src/OnboardingSPA/steps/SiteGen/Building/index.js b/src/OnboardingSPA/steps/SiteGen/Building/index.js
new file mode 100644
index 000000000..80c6b9bbc
--- /dev/null
+++ b/src/OnboardingSPA/steps/SiteGen/Building/index.js
@@ -0,0 +1,35 @@
+import CommonLayout from '../../../components/Layouts/Common';
+
+import { useEffect } from '@wordpress/element';
+
+import { useDispatch } from '@wordpress/data';
+import { store as nfdOnboardingStore } from '../../../store';
+import { HEADER_SITEGEN } from '../../../../constants';
+
+import SiteGenPlaceholder from '../../../components/SiteGenPlaceholder';
+
+const SiteGenBuilding = () => {
+ const {
+ setIsHeaderEnabled,
+ setSidebarActiveView,
+ setHeaderActiveView,
+ setDrawerActiveView,
+ } = useDispatch( nfdOnboardingStore );
+
+ useEffect( () => {
+ setIsHeaderEnabled( true );
+ setSidebarActiveView( false );
+ setHeaderActiveView( HEADER_SITEGEN );
+ setDrawerActiveView( false );
+ } );
+ return (
+
+
+
+ );
+};
+
+export default SiteGenBuilding;
diff --git a/src/OnboardingSPA/steps/SiteGen/Building/step.js b/src/OnboardingSPA/steps/SiteGen/Building/step.js
new file mode 100644
index 000000000..2cd24d672
--- /dev/null
+++ b/src/OnboardingSPA/steps/SiteGen/Building/step.js
@@ -0,0 +1,18 @@
+import { copy } from '@wordpress/icons';
+import { lazy } from '@wordpress/element';
+import { __ } from '@wordpress/i18n';
+import { Step } from '../../../data/models/Step';
+
+const SiteGenBuilding = lazy( () => import( './index' ) );
+
+export const stepSiteGenBuilding = new Step( {
+ path: '/sitegen/step/building',
+ title: __( 'Page Layouts', 'wp-module-onboarding' ),
+ Component: SiteGenBuilding,
+ icon: copy,
+ sidebars: {
+ LearnMore: {
+ SidebarComponents: [],
+ },
+ },
+} );
diff --git a/src/OnboardingSPA/steps/SiteGen/Editor/index.js b/src/OnboardingSPA/steps/SiteGen/Editor/index.js
new file mode 100644
index 000000000..05fc7fee6
--- /dev/null
+++ b/src/OnboardingSPA/steps/SiteGen/Editor/index.js
@@ -0,0 +1,35 @@
+import CommonLayout from '../../../components/Layouts/Common';
+
+import { useEffect } from '@wordpress/element';
+
+import { useDispatch } from '@wordpress/data';
+import { store as nfdOnboardingStore } from '../../../store';
+import { HEADER_SITEGEN } from '../../../../constants';
+
+import SiteGenPlaceholder from '../../../components/SiteGenPlaceholder';
+
+const StepSiteGenEditor = () => {
+ const {
+ setIsHeaderEnabled,
+ setSidebarActiveView,
+ setHeaderActiveView,
+ setDrawerActiveView,
+ } = useDispatch( nfdOnboardingStore );
+
+ useEffect( () => {
+ setIsHeaderEnabled( true );
+ setSidebarActiveView( false );
+ setHeaderActiveView( HEADER_SITEGEN );
+ setDrawerActiveView( false );
+ } );
+ return (
+
+
+
+ );
+};
+
+export default StepSiteGenEditor;
diff --git a/src/OnboardingSPA/steps/SiteGen/Editor/step.js b/src/OnboardingSPA/steps/SiteGen/Editor/step.js
new file mode 100644
index 000000000..ab25039d9
--- /dev/null
+++ b/src/OnboardingSPA/steps/SiteGen/Editor/step.js
@@ -0,0 +1,18 @@
+import { copy } from '@wordpress/icons';
+import { lazy } from '@wordpress/element';
+import { __ } from '@wordpress/i18n';
+import { Step } from '../../../data/models/Step';
+
+const StepSiteGenEditor = lazy( () => import( './index' ) );
+
+export const stepSiteGenEditor = new Step( {
+ path: '/sitegen/step/editor',
+ title: __( 'Page Layouts', 'wp-module-onboarding' ),
+ Component: StepSiteGenEditor,
+ icon: copy,
+ sidebars: {
+ LearnMore: {
+ SidebarComponents: [],
+ },
+ },
+} );
diff --git a/src/OnboardingSPA/steps/SiteGen/Experience/index.js b/src/OnboardingSPA/steps/SiteGen/Experience/index.js
new file mode 100644
index 000000000..1e2d51463
--- /dev/null
+++ b/src/OnboardingSPA/steps/SiteGen/Experience/index.js
@@ -0,0 +1,35 @@
+import CommonLayout from '../../../components/Layouts/Common';
+
+import { useEffect } from '@wordpress/element';
+
+import { useDispatch } from '@wordpress/data';
+import { store as nfdOnboardingStore } from '../../../store';
+import { HEADER_SITEGEN } from '../../../../constants';
+
+import SiteGenPlaceholder from '../../../components/SiteGenPlaceholder';
+
+const SiteGenExperience = () => {
+ const {
+ setIsHeaderEnabled,
+ setSidebarActiveView,
+ setHeaderActiveView,
+ setDrawerActiveView,
+ } = useDispatch( nfdOnboardingStore );
+
+ useEffect( () => {
+ setIsHeaderEnabled( true );
+ setSidebarActiveView( false );
+ setHeaderActiveView( HEADER_SITEGEN );
+ setDrawerActiveView( false );
+ } );
+ return (
+
+
+
+ );
+};
+
+export default SiteGenExperience;
diff --git a/src/OnboardingSPA/steps/SiteGen/Experience/step.js b/src/OnboardingSPA/steps/SiteGen/Experience/step.js
new file mode 100644
index 000000000..d0a216dd1
--- /dev/null
+++ b/src/OnboardingSPA/steps/SiteGen/Experience/step.js
@@ -0,0 +1,18 @@
+import { copy } from '@wordpress/icons';
+import { lazy } from '@wordpress/element';
+import { __ } from '@wordpress/i18n';
+import { Step } from '../../../data/models/Step';
+
+const SiteGenExperience = lazy( () => import( './index' ) );
+
+export const stepSiteGenExperience = new Step( {
+ path: '/sitegen/step/experience',
+ title: __( 'Page Layouts', 'wp-module-onboarding' ),
+ Component: SiteGenExperience,
+ icon: copy,
+ sidebars: {
+ LearnMore: {
+ SidebarComponents: [],
+ },
+ },
+} );
diff --git a/src/OnboardingSPA/steps/SiteGen/Preview/index.js b/src/OnboardingSPA/steps/SiteGen/Preview/index.js
new file mode 100644
index 000000000..f16ba778e
--- /dev/null
+++ b/src/OnboardingSPA/steps/SiteGen/Preview/index.js
@@ -0,0 +1,35 @@
+import CommonLayout from '../../../components/Layouts/Common';
+
+import { useEffect } from '@wordpress/element';
+
+import { useDispatch } from '@wordpress/data';
+import { store as nfdOnboardingStore } from '../../../store';
+import { HEADER_SITEGEN } from '../../../../constants';
+
+import SiteGenPlaceholder from '../../../components/SiteGenPlaceholder';
+
+const SiteGenPreview = () => {
+ const {
+ setIsHeaderEnabled,
+ setSidebarActiveView,
+ setHeaderActiveView,
+ setDrawerActiveView,
+ } = useDispatch( nfdOnboardingStore );
+
+ useEffect( () => {
+ setIsHeaderEnabled( true );
+ setSidebarActiveView( false );
+ setHeaderActiveView( HEADER_SITEGEN );
+ setDrawerActiveView( false );
+ } );
+ return (
+
+
+
+ );
+};
+
+export default SiteGenPreview;
diff --git a/src/OnboardingSPA/steps/SiteGen/Preview/step.js b/src/OnboardingSPA/steps/SiteGen/Preview/step.js
new file mode 100644
index 000000000..ca992dc40
--- /dev/null
+++ b/src/OnboardingSPA/steps/SiteGen/Preview/step.js
@@ -0,0 +1,18 @@
+import { copy } from '@wordpress/icons';
+import { lazy } from '@wordpress/element';
+import { __ } from '@wordpress/i18n';
+import { Step } from '../../../data/models/Step';
+
+const SiteGenPreview = lazy( () => import( './index' ) );
+
+export const stepSiteGenPreview = new Step( {
+ path: '/sitegen/step/preview',
+ title: __( 'Page Layouts', 'wp-module-onboarding' ),
+ Component: SiteGenPreview,
+ icon: copy,
+ sidebars: {
+ LearnMore: {
+ SidebarComponents: [],
+ },
+ },
+} );
diff --git a/src/OnboardingSPA/steps/SiteGen/SiteDetails/index.js b/src/OnboardingSPA/steps/SiteGen/SiteDetails/index.js
new file mode 100644
index 000000000..06fea7cac
--- /dev/null
+++ b/src/OnboardingSPA/steps/SiteGen/SiteDetails/index.js
@@ -0,0 +1,35 @@
+import CommonLayout from '../../../components/Layouts/Common';
+
+import { useEffect } from '@wordpress/element';
+
+import { useDispatch } from '@wordpress/data';
+import { store as nfdOnboardingStore } from '../../../store';
+import { HEADER_SITEGEN } from '../../../../constants';
+
+import SiteGenPlaceholder from '../../../components/SiteGenPlaceholder';
+
+const SiteGenSiteDetails = () => {
+ const {
+ setIsHeaderEnabled,
+ setSidebarActiveView,
+ setHeaderActiveView,
+ setDrawerActiveView,
+ } = useDispatch( nfdOnboardingStore );
+
+ useEffect( () => {
+ setIsHeaderEnabled( true );
+ setSidebarActiveView( false );
+ setHeaderActiveView( HEADER_SITEGEN );
+ setDrawerActiveView( false );
+ } );
+ return (
+
+
+
+ );
+};
+
+export default SiteGenSiteDetails;
diff --git a/src/OnboardingSPA/steps/SiteGen/SiteDetails/step.js b/src/OnboardingSPA/steps/SiteGen/SiteDetails/step.js
new file mode 100644
index 000000000..7f6cbd78a
--- /dev/null
+++ b/src/OnboardingSPA/steps/SiteGen/SiteDetails/step.js
@@ -0,0 +1,18 @@
+import { copy } from '@wordpress/icons';
+import { lazy } from '@wordpress/element';
+import { __ } from '@wordpress/i18n';
+import { Step } from '../../../data/models/Step';
+
+const SiteGenSiteDetails = lazy( () => import( './index' ) );
+
+export const stepSiteGenSiteDetails = new Step( {
+ path: '/sitegen/step/site-details',
+ title: __( 'Site Details', 'wp-module-onboarding' ),
+ Component: SiteGenSiteDetails,
+ icon: copy,
+ sidebars: {
+ LearnMore: {
+ SidebarComponents: [],
+ },
+ },
+} );
diff --git a/src/OnboardingSPA/steps/SiteGen/SiteLogo/index.js b/src/OnboardingSPA/steps/SiteGen/SiteLogo/index.js
new file mode 100644
index 000000000..f7dbff317
--- /dev/null
+++ b/src/OnboardingSPA/steps/SiteGen/SiteLogo/index.js
@@ -0,0 +1,35 @@
+import CommonLayout from '../../../components/Layouts/Common';
+
+import { useEffect } from '@wordpress/element';
+
+import { useDispatch } from '@wordpress/data';
+import { store as nfdOnboardingStore } from '../../../store';
+import { HEADER_SITEGEN } from '../../../../constants';
+
+import SiteGenPlaceholder from '../../../components/SiteGenPlaceholder';
+
+const SiteGenSiteLogo = () => {
+ const {
+ setIsHeaderEnabled,
+ setSidebarActiveView,
+ setHeaderActiveView,
+ setDrawerActiveView,
+ } = useDispatch( nfdOnboardingStore );
+
+ useEffect( () => {
+ setIsHeaderEnabled( true );
+ setSidebarActiveView( false );
+ setHeaderActiveView( HEADER_SITEGEN );
+ setDrawerActiveView( false );
+ } );
+ return (
+
+
+
+ );
+};
+
+export default SiteGenSiteLogo;
diff --git a/src/OnboardingSPA/steps/SiteGen/SiteLogo/step.js b/src/OnboardingSPA/steps/SiteGen/SiteLogo/step.js
new file mode 100644
index 000000000..ca6a0f0c2
--- /dev/null
+++ b/src/OnboardingSPA/steps/SiteGen/SiteLogo/step.js
@@ -0,0 +1,18 @@
+import { copy } from '@wordpress/icons';
+import { lazy } from '@wordpress/element';
+import { __ } from '@wordpress/i18n';
+import { Step } from '../../../data/models/Step';
+
+const SiteGenSiteLogo = lazy( () => import( './index' ) );
+
+export const stepSiteGenSiteLogo = new Step( {
+ path: '/sitgen/step/site-logo',
+ title: __( 'Page Layouts', 'wp-module-onboarding' ),
+ Component: SiteGenSiteLogo,
+ icon: copy,
+ sidebars: {
+ LearnMore: {
+ SidebarComponents: [],
+ },
+ },
+} );
diff --git a/src/OnboardingSPA/steps/SiteGen/SocialMedia/index.js b/src/OnboardingSPA/steps/SiteGen/SocialMedia/index.js
new file mode 100644
index 000000000..71b19295a
--- /dev/null
+++ b/src/OnboardingSPA/steps/SiteGen/SocialMedia/index.js
@@ -0,0 +1,35 @@
+import CommonLayout from '../../../components/Layouts/Common';
+
+import { useEffect } from '@wordpress/element';
+
+import { useDispatch } from '@wordpress/data';
+import { store as nfdOnboardingStore } from '../../../store';
+import { HEADER_SITEGEN } from '../../../../constants';
+
+import SiteGenPlaceholder from '../../../components/SiteGenPlaceholder';
+
+const SiteGenSiteSocialMedia = () => {
+ const {
+ setIsHeaderEnabled,
+ setSidebarActiveView,
+ setHeaderActiveView,
+ setDrawerActiveView,
+ } = useDispatch( nfdOnboardingStore );
+
+ useEffect( () => {
+ setIsHeaderEnabled( true );
+ setSidebarActiveView( false );
+ setHeaderActiveView( HEADER_SITEGEN );
+ setDrawerActiveView( false );
+ } );
+ return (
+
+
+
+ );
+};
+
+export default SiteGenSiteSocialMedia;
diff --git a/src/OnboardingSPA/steps/SiteGen/SocialMedia/step.js b/src/OnboardingSPA/steps/SiteGen/SocialMedia/step.js
new file mode 100644
index 000000000..cee374291
--- /dev/null
+++ b/src/OnboardingSPA/steps/SiteGen/SocialMedia/step.js
@@ -0,0 +1,18 @@
+import { copy } from '@wordpress/icons';
+import { lazy } from '@wordpress/element';
+import { __ } from '@wordpress/i18n';
+import { Step } from '../../../data/models/Step';
+
+const SiteGenSiteSocialMedia = lazy( () => import( './index' ) );
+
+export const stepSiteGenSocialMedia = new Step( {
+ path: '/sitegen/step/social-media',
+ title: __( 'Page Layouts', 'wp-module-onboarding' ),
+ Component: SiteGenSiteSocialMedia,
+ icon: copy,
+ sidebars: {
+ LearnMore: {
+ SidebarComponents: [],
+ },
+ },
+} );
diff --git a/src/OnboardingSPA/steps/SiteGen/Welcome/index.js b/src/OnboardingSPA/steps/SiteGen/Welcome/index.js
new file mode 100644
index 000000000..fdd0279b8
--- /dev/null
+++ b/src/OnboardingSPA/steps/SiteGen/Welcome/index.js
@@ -0,0 +1,37 @@
+import CommonLayout from '../../../components/Layouts/Common';
+
+import { useEffect } from '@wordpress/element';
+
+import { useDispatch } from '@wordpress/data';
+import { store as nfdOnboardingStore } from '../../../store';
+import { HEADER_SITEGEN } from '../../../../constants';
+
+import SiteGenPlaceholder from '../../../components/SiteGenPlaceholder';
+
+const SiteGenWelcome = () => {
+ const {
+ setIsHeaderEnabled,
+ setSidebarActiveView,
+ setHeaderActiveView,
+ setDrawerActiveView,
+ setIsHeaderNavigationEnabled,
+ } = useDispatch( nfdOnboardingStore );
+
+ useEffect( () => {
+ setIsHeaderEnabled( true );
+ setSidebarActiveView( false );
+ setHeaderActiveView( HEADER_SITEGEN );
+ setIsHeaderNavigationEnabled( true );
+ setDrawerActiveView( false );
+ } );
+ return (
+
+
+
+ );
+};
+
+export default SiteGenWelcome;
diff --git a/src/OnboardingSPA/steps/SiteGen/Welcome/step.js b/src/OnboardingSPA/steps/SiteGen/Welcome/step.js
new file mode 100644
index 000000000..705b3f04f
--- /dev/null
+++ b/src/OnboardingSPA/steps/SiteGen/Welcome/step.js
@@ -0,0 +1,18 @@
+import { copy } from '@wordpress/icons';
+import { lazy } from '@wordpress/element';
+import { __ } from '@wordpress/i18n';
+import { Step } from '../../../data/models/Step';
+
+const SiteGenWelcome = lazy( () => import( './index' ) );
+
+export const stepSiteGenWelcome = new Step( {
+ path: '/sitegen/step/welcome',
+ title: __( 'Welcome', 'wp-module-onboarding' ),
+ Component: SiteGenWelcome,
+ icon: copy,
+ sidebars: {
+ LearnMore: {
+ SidebarComponents: [],
+ },
+ },
+} );
diff --git a/src/OnboardingSPA/steps/TheFork/index.js b/src/OnboardingSPA/steps/TheFork/index.js
new file mode 100644
index 000000000..0ba4458c5
--- /dev/null
+++ b/src/OnboardingSPA/steps/TheFork/index.js
@@ -0,0 +1,103 @@
+import CommonLayout from '../../components/Layouts/Common';
+
+import { useEffect } from '@wordpress/element';
+
+import { useSelect, useDispatch } from '@wordpress/data';
+import { store as nfdOnboardingStore } from '../../store';
+import { HEADER_SITEGEN } from '../../../constants';
+
+import { useNavigate } from 'react-router-dom';
+
+import { Button } from '@wordpress/components';
+import { SITEGEN_FLOW } from '../../data/flows/constants';
+
+import { resolveGetDataForFlow } from '../../data/flows';
+import { validateFlow } from '../../data/flows/utils';
+
+const TheFork = () => {
+ const navigate = useNavigate();
+ const { brandConfig, migrationUrl } = useSelect( ( select ) => {
+ return {
+ brandConfig: select( nfdOnboardingStore ).getNewfoldBrandConfig(),
+ migrationUrl: select( nfdOnboardingStore ).getMigrationUrl(),
+ };
+ } );
+
+ const {
+ setIsHeaderEnabled,
+ setSidebarActiveView,
+ setHeaderActiveView,
+ setDrawerActiveView,
+ setIsHeaderNavigationEnabled,
+ updateAllSteps,
+ updateTopSteps,
+ updateRoutes,
+ updateDesignRoutes,
+ updateInitialize,
+ } = useDispatch( nfdOnboardingStore );
+
+ const switchFlow = ( newFlow ) => {
+ if ( ! validateFlow( brandConfig, newFlow ) ) {
+ return false;
+ }
+ const currentFlow = window.nfdOnboarding.currentFlow;
+ const getData = resolveGetDataForFlow( newFlow );
+ const data = getData();
+ updateAllSteps( data.steps );
+ updateTopSteps( data?.topSteps );
+ updateRoutes( data.routes );
+ updateDesignRoutes( data?.designRoutes );
+ if ( SITEGEN_FLOW !== currentFlow ) {
+ window.nfdOnboarding.oldFlow = currentFlow;
+ }
+ window.nfdOnboarding.currentFlow = newFlow;
+ updateInitialize( true );
+ navigate( data.steps[ 1 ].path );
+ };
+
+ useEffect( () => {
+ setIsHeaderEnabled( false );
+ setSidebarActiveView( false );
+ setIsHeaderNavigationEnabled( false );
+ setHeaderActiveView( HEADER_SITEGEN );
+ setDrawerActiveView( false );
+ } );
+
+ const oldFlow = window.nfdOnboarding?.oldFlow
+ ? window.nfdOnboarding.oldFlow
+ : window.nfdOnboarding.currentFlow;
+ return (
+
+
+ The Fork
+
+
+
+
+ { migrationUrl && (
+
+ ) }
+
+
+ );
+};
+
+export default TheFork;
diff --git a/src/OnboardingSPA/steps/TheFork/step.js b/src/OnboardingSPA/steps/TheFork/step.js
new file mode 100644
index 000000000..143f79615
--- /dev/null
+++ b/src/OnboardingSPA/steps/TheFork/step.js
@@ -0,0 +1,18 @@
+import { copy } from '@wordpress/icons';
+import { lazy } from '@wordpress/element';
+import { __ } from '@wordpress/i18n';
+import { Step } from '../../data/models/Step';
+
+const StepTheFork = lazy( () => import( './index' ) );
+
+export const stepTheFork = new Step( {
+ path: '/wp-setup/step/fork',
+ title: __( 'Page Layouts', 'wp-module-onboarding' ),
+ Component: StepTheFork,
+ icon: copy,
+ sidebars: {
+ LearnMore: {
+ SidebarComponents: [],
+ },
+ },
+} );
diff --git a/src/OnboardingSPA/steps/TheFork/stylesheet.scss b/src/OnboardingSPA/steps/TheFork/stylesheet.scss
new file mode 100644
index 000000000..2a0641235
--- /dev/null
+++ b/src/OnboardingSPA/steps/TheFork/stylesheet.scss
@@ -0,0 +1,35 @@
+.nfd-onboarding-step {
+
+ &--site-gen {
+
+ &__fork {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+
+ &__heading {
+ color: var(--nfd-onboarding-primary);
+ font-size: 70px;
+ }
+
+ &__buttons {
+ display: flex;
+ flex-direction: row;
+ justify-content: center;
+ align-items: center;
+
+ &__button {
+ display: block;
+ background-color: var(--nfd-onboarding-primary);
+ color: var(--nfd-onboarding-secondary);
+ text-align: center;
+ width: 200px;
+ height: 50px;
+ font-size: 15px;
+ margin: 24px;
+ }
+ }
+ }
+ }
+}
diff --git a/src/OnboardingSPA/store/actions.js b/src/OnboardingSPA/store/actions.js
index 482925ccc..1d5d057ed 100644
--- a/src/OnboardingSPA/store/actions.js
+++ b/src/OnboardingSPA/store/actions.js
@@ -147,6 +147,13 @@ export function updateThemeStatus( themeStatus ) {
};
}
+export function updateInitialize( initialize ) {
+ return {
+ type: 'UPDATE_INITIALIZE',
+ initialize,
+ };
+}
+
export function setIsSidebarOpened( isOpen ) {
return {
type: 'SET_SIDEBAR_OPENED',
@@ -168,6 +175,20 @@ export function setIsHeaderNavigationEnabled( isNavigationEnabled ) {
};
}
+export function setIsHeaderEnabled( isEnabled ) {
+ return {
+ type: 'SET_HEADER_ENABLED',
+ isEnabled,
+ };
+}
+
+export function setHeaderActiveView( view ) {
+ return {
+ type: 'SET_HEADER_ACTIVE_VIEW',
+ view,
+ };
+}
+
export function updatePreviewSettings( previewSettings ) {
return {
type: 'SET_PREVIEW_SETTINGS',
diff --git a/src/OnboardingSPA/store/reducer.js b/src/OnboardingSPA/store/reducer.js
index f987fba16..7e79658c4 100644
--- a/src/OnboardingSPA/store/reducer.js
+++ b/src/OnboardingSPA/store/reducer.js
@@ -1,6 +1,10 @@
import { combineReducers } from '@wordpress/data';
-import { VIEW_NAV_PRIMARY, THEME_STATUS_INIT } from '../../constants';
+import {
+ VIEW_NAV_PRIMARY,
+ THEME_STATUS_INIT,
+ HEADER_SITEBUILD,
+} from '../../constants';
import {
initialDesignRoutes,
@@ -9,6 +13,7 @@ import {
initialTopSteps,
} from '../data/flows/index';
import { sidebars } from '../data/sidebars/index';
+import { headers } from '../data/headers';
import apiQueueExecutor from '../utils/api-queuer/api-queue-executor';
import { DEFAULT_FLOW } from '../data/flows/constants';
@@ -190,7 +195,13 @@ export function sidebar(
}
export function header(
- state = { isNavigationEnabled: true, menu: '' },
+ state = {
+ isNavigationEnabled: true,
+ menu: '',
+ isEnabled: true,
+ headers,
+ view: HEADER_SITEBUILD,
+ },
action
) {
switch ( action.type ) {
@@ -199,11 +210,21 @@ export function header(
...state,
isNavigationEnabled: action.isNavigationEnabled,
};
+ case 'SET_HEADER_ENABLED':
+ return {
+ ...state,
+ isEnabled: action.isEnabled,
+ };
case 'UPDATE_HEADER_MENU_DATA':
return {
...state,
menu: action.menu,
};
+ case 'SET_HEADER_ACTIVE_VIEW':
+ return {
+ ...state,
+ view: action.view,
+ };
}
return state;
}
@@ -231,6 +252,7 @@ export function runtime( state = {}, action ) {
export function settings(
state = {
themeStatus: THEME_STATUS_INIT,
+ initialize: false,
},
action
) {
@@ -245,6 +267,11 @@ export function settings(
...state,
themeStatus: action.themeStatus,
};
+ case 'UPDATE_INITIALIZE':
+ return {
+ ...state,
+ initialize: action.initialize,
+ };
}
return state;
diff --git a/src/OnboardingSPA/store/selectors.js b/src/OnboardingSPA/store/selectors.js
index a024b3cc9..f74172be4 100644
--- a/src/OnboardingSPA/store/selectors.js
+++ b/src/OnboardingSPA/store/selectors.js
@@ -9,7 +9,7 @@ import { DEFAULT_FLOW } from '../data/flows/constants';
* @param {*} state
* @return {string} Drawer View
*/
-export function getDrawerView( state ) {
+export function getActiveDrawerView( state ) {
return state.drawer.view;
}
@@ -37,6 +37,18 @@ export function isHeaderNavigationEnabled( state ) {
return state.header.isNavigationEnabled;
}
+export function isHeaderEnabled( state ) {
+ return state.header.isEnabled;
+}
+
+export function getHeaders( state ) {
+ return state.header.headers;
+}
+
+export function getHeaderActiveView( state ) {
+ return state.header.view;
+}
+
/**
* Gets current Newfold brand
*
@@ -255,6 +267,10 @@ export function getThemeStatus( state ) {
return state.settings.themeStatus;
}
+export function getInitialize( state ) {
+ return state.settings.initialize;
+}
+
export function getStepPreviewData( state ) {
return state.runtime.previewSettings.stepPreviewData;
}
diff --git a/src/OnboardingSPA/styles/_branding.scss b/src/OnboardingSPA/styles/_branding.scss
index fb4630d56..3f3ff7a55 100644
--- a/src/OnboardingSPA/styles/_branding.scss
+++ b/src/OnboardingSPA/styles/_branding.scss
@@ -294,4 +294,14 @@ body {
}
}
}
+
+ .nfd-onboarding-sitegen-dark {
+ --nfd-onboarding-admin-bar-background: #1d2327;
+ --nfd-onboarding-admin-bar-color: #c3c4c7;
+ --nfd-onboarding-navigation-back-background: rgba(54, 62, 68, 0.35);
+ --nfd-onboarding-primary: #fff;
+ --nfd-onboarding-secondary: #000;
+ --nfd-onboarding-progress-bar-background: #353a40;
+ --nfd-onboarding-progress-bar-fill: #0060f0;
+ }
}
diff --git a/src/OnboardingSPA/styles/_icons.scss b/src/OnboardingSPA/styles/_icons.scss
index 31501c2a6..8e66fd4b8 100644
--- a/src/OnboardingSPA/styles/_icons.scss
+++ b/src/OnboardingSPA/styles/_icons.scss
@@ -36,4 +36,6 @@ body {
--site-features-share: url(../static/icons/site-features/share.svg);
--site-features-wishlist: url(../static/icons/site-features/wishlist.svg);
--site-features-comingsoon: url(../static/icons/site-features/comingsoon.svg);
+
+ --sitegen-background: url(../static/images/sitegen-bg.png);
}
diff --git a/src/OnboardingSPA/styles/app.scss b/src/OnboardingSPA/styles/app.scss
index b92bb1b7f..992bea2af 100644
--- a/src/OnboardingSPA/styles/app.scss
+++ b/src/OnboardingSPA/styles/app.scss
@@ -43,6 +43,10 @@
@import "../components/Loaders/Chapter/Interstitial/stylesheet";
@import "../components/Grid/stylesheet";
@import "../components/ComingSoon/stylesheet";
+@import "../components/AdminBar/stylesheet";
+@import "../components/ProgressBar/stylesheet";
+@import "../components/Button/ButtonDark/stylesheet";
+@import "../components//SiteGenPlaceholder/stylesheet.scss";
// CSS for Pages
@import "../steps/BasicInfo/stylesheet";
@@ -57,6 +61,7 @@
@import "../steps/DesignFonts/stylesheet";
@import "../steps/DesignHeaderMenu/stylesheet";
@import "../steps/SiteFeatures/stylesheet";
+@import "../steps/TheFork/stylesheet";
.nfd-onboarding-container {
display: flex;
diff --git a/src/OnboardingSPA/utils/api/plugins.js b/src/OnboardingSPA/utils/api/plugins.js
index de03704e2..cf18ea854 100644
--- a/src/OnboardingSPA/utils/api/plugins.js
+++ b/src/OnboardingSPA/utils/api/plugins.js
@@ -5,7 +5,7 @@ import { getQueryParam } from '../index';
import { resolve } from './resolve';
import { NFD_PLUGINS_QUERY_PARAM } from '../../../constants';
-export const init = () => {
+export const init = ( pluginInstallHash ) => {
// Backend should have done the initialization if this param is present.
if ( getQueryParam( NFD_PLUGINS_QUERY_PARAM ) ) {
return true;
@@ -14,7 +14,9 @@ export const init = () => {
url: onboardingRestURL( 'plugins/initialize' ),
method: 'POST',
headers: {
- 'X-NFD-INSTALLER': window.nfdOnboarding.pluginInstallHash,
+ 'X-NFD-INSTALLER': pluginInstallHash
+ ? pluginInstallHash
+ : window.nfdOnboarding.pluginInstallHash,
},
} ).catch( ( error ) => {
// eslint-disable-next-line no-console
diff --git a/src/constants.js b/src/constants.js
index fcee9448c..238d3911b 100644
--- a/src/constants.js
+++ b/src/constants.js
@@ -38,6 +38,12 @@ export const VIEW_NAV_ECOMMERCE_STORE_INFO = 'nav-ecommerce-store-info';
export const SIDEBAR_SLOTFILL_PREFIX = 'Sidebar';
export const SIDEBAR_MENU_SLOTFILL_PREFIX = 'HeaderMenu';
export const SIDEBAR_LEARN_MORE = 'LearnMore';
+export const HEADER_SITEBUILD = 'HeaderSiteBuild';
+export const HEADER_SITEGEN = 'HeaderSiteGen';
+export const HEADER_TOP = 'HeaderTop';
+export const HEADER_START = 'HeaderStart';
+export const HEADER_CENTER = 'HeaderCenter';
+export const HEADER_END = 'HeaderEnd';
export const MAX_RETRIES_API_QUEUER = 2;
export const MAX_RETRIES_SETTINGS_INIT = 2;
@@ -58,6 +64,7 @@ export const CHAPTER_COMMERCE = 'commerce';
export const CHAPTER_DESIGN = 'design';
export const CHAPTER_LAYOUT_AND_CONTENT = 'layout_and_content';
export const CHAPTER_FEATURES = 'features';
+export const CHAPTER_SITEGEN = 'sitegen';
/**
* All views for the component.