diff --git a/composer.json b/composer.json index 8ef4232fb..1582f6730 100644 --- a/composer.json +++ b/composer.json @@ -23,20 +23,28 @@ } }, "repositories": [ - { - "type": "composer", - "url": "https://newfold-labs.github.io/satis/", - "only": [ - "newfold-labs/*" - ] - } - ], + { + "type": "composer", + "url": "https://newfold-labs.github.io/satis/", + "only": [ + "newfold-labs/*" + ] + }, + { + "type": "vcs", + "url": "git@github.com:InstaWP/connect-helpers.git", + "only": [ + "instawp/*" + ] + } + ], "require": { "mustache/mustache": "^2.14", "wp-cli/wp-config-transformer": "^1.3", "newfold-labs/wp-module-onboarding-data": "^1.1", "newfold-labs/wp-module-patterns": "^1.0", "newfold-labs/wp-module-facebook": "^1.0", + "newfold-labs/wp-module-migration": "^1.0", "wp-forge/helpers": "^2.0" }, "require-dev": { diff --git a/composer.lock b/composer.lock index d7a05ffd1..613b417a3 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "266ed5a568de4b6ce9d1aaf3170a4648", + "content-hash": "6316eb1600bb1a3c247bbee69ee79ddf", "packages": [ { "name": "doctrine/inflector", @@ -102,6 +102,54 @@ ], "time": "2021-04-16T17:34:40+00:00" }, + { + "name": "instawp/connect-helpers", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/InstaWP/connect-helpers.git", + "reference": "34e9bdeb65e07a926dbeef41f90fac8a5a50a312" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/InstaWP/connect-helpers/zipball/34e9bdeb65e07a926dbeef41f90fac8a5a50a312", + "reference": "34e9bdeb65e07a926dbeef41f90fac8a5a50a312", + "shasum": "" + }, + "require": { + "php": ">= 5.6", + "wp-cli/wp-config-transformer": "^1.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "InstaWP\\Connect\\Helpers\\": "src/" + } + }, + "scripts": { + "build": [ + "composer dump-autoload" + ], + "build-nd": [ + "composer dump-autoload --no-dev" + ] + }, + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Sayan Datta", + "email": "sayan@instawp.com" + } + ], + "description": "CLI Package for InstaWP Remote Features", + "support": { + "source": "https://github.com/InstaWP/connect-helpers/tree/1.0.0", + "issues": "https://github.com/InstaWP/connect-helpers/issues" + }, + "time": "2024-05-02T13:07:03+00:00" + }, { "name": "mustache/mustache", "version": "v2.14.2", @@ -402,16 +450,16 @@ }, { "name": "newfold-labs/wp-module-facebook", - "version": "v1.0.6", + "version": "v1.0.7", "source": { "type": "git", "url": "https://github.com/newfold-labs/wp-module-facebook.git", - "reference": "55acbb2732e333eb0890943b35a54141eb74700b" + "reference": "77a433621894590b3d38c511d880d830fb3b4b64" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/newfold-labs/wp-module-facebook/zipball/55acbb2732e333eb0890943b35a54141eb74700b", - "reference": "55acbb2732e333eb0890943b35a54141eb74700b", + "url": "https://api.github.com/repos/newfold-labs/wp-module-facebook/zipball/77a433621894590b3d38c511d880d830fb3b4b64", + "reference": "77a433621894590b3d38c511d880d830fb3b4b64", "shasum": "" }, "require": { @@ -437,10 +485,10 @@ } ], "support": { - "source": "https://github.com/newfold-labs/wp-module-facebook/tree/v1.0.6", + "source": "https://github.com/newfold-labs/wp-module-facebook/tree/v1.0.7", "issues": "https://github.com/newfold-labs/wp-module-facebook/issues" }, - "time": "2024-02-12T08:48:41+00:00" + "time": "2024-05-03T10:09:41+00:00" }, { "name": "newfold-labs/wp-module-install-checker", @@ -569,6 +617,60 @@ }, "time": "2022-10-03T20:07:41+00:00" }, + { + "name": "newfold-labs/wp-module-migration", + "version": "v1.0.1", + "source": { + "type": "git", + "url": "https://github.com/newfold-labs/wp-module-migration.git", + "reference": "06bef1f285797a89d5e7561af564eb0caa954317" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/newfold-labs/wp-module-migration/zipball/06bef1f285797a89d5e7561af564eb0caa954317", + "reference": "06bef1f285797a89d5e7561af564eb0caa954317", + "shasum": "" + }, + "require": { + "instawp/connect-helpers": "1.0.0", + "newfold-labs/wp-module-loader": "^1.0.10" + }, + "require-dev": { + "newfold-labs/wp-php-standards": "^1.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "NewfoldLabs\\WP\\Module\\Migration\\": "includes/" + }, + "files": [ + "bootstrap.php" + ] + }, + "scripts": { + "i18n": [ + "vendor/bin/wp i18n make-pot . ./languages/wp-module-ecommerce.pot --headers='{\"Report-Msgid-Bugs-To\":\"https://github.com/newfold-labs/wp-module-ecommerce/issues\",\"POT-Creation-Date\":null}' --exclude=node_modules,src,tests" + ], + "fix": [ + "vendor/bin/phpcbf --standard=phpcs.xml ." + ], + "lint": [ + "vendor/bin/phpcs --standard=phpcs.xml -s ." + ] + }, + "authors": [ + { + "name": "Beyond", + "email": "team-spartans@newfold.com" + } + ], + "description": "Initiates the migration process", + "support": { + "source": "https://github.com/newfold-labs/wp-module-migration/tree/v1.0.1", + "issues": "https://github.com/newfold-labs/wp-module-migration/issues" + }, + "time": "2024-05-03T08:33:23+00:00" + }, { "name": "newfold-labs/wp-module-onboarding-data", "version": "1.1.8", diff --git a/src/OnboardingSPA/components/ErrorState/Step/SiteGen/contents.js b/src/OnboardingSPA/components/ErrorState/Step/SiteGen/contents.js index ee1df09aa..e0cb3585b 100644 --- a/src/OnboardingSPA/components/ErrorState/Step/SiteGen/contents.js +++ b/src/OnboardingSPA/components/ErrorState/Step/SiteGen/contents.js @@ -1,24 +1,44 @@ // WordPress import { __ } from '@wordpress/i18n'; -const getContents = () => { - return { - heading: __( - "Sorry, we're having trouble communicating with our AI service.", - 'wp-module-onboarding' - ), - subHeading: __( - 'Do you keep getting this error?', - 'wp-module-onboarding' - ), - message: __( - 'If you continue to get this error, you may either continue creating your site without using our AI assistant, or you can ', - 'wp-module-onboarding' - ), - buttonText: __( 'Try again', 'wp-module-onboarding' ), - buttonSkip: __( 'Continue without AI', 'wp-module-onboarding' ), - buttonExit: __( 'exit to WordPress', 'wp-module-onboarding' ), +const getContents = ( type ) => { + const content = { + siteGenErrorContent: { + heading: __( + "Sorry, we're having trouble communicating with our AI service.", + 'wp-module-onboarding' + ), + subHeading: __( + 'Do you keep getting this error?', + 'wp-module-onboarding' + ), + message: __( + 'If you continue to get this error, you may either continue creating your site without using our AI assistant, or you can ', + 'wp-module-onboarding' + ), + buttonText: __( 'Try again', 'wp-module-onboarding' ), + buttonSkip: __( 'Continue without AI', 'wp-module-onboarding' ), + buttonExit: __( 'exit to WordPress', 'wp-module-onboarding' ), + }, + siteMigrationErrorContent: { + heading: __( + "Sorry, we're having trouble starting the site transfer process.", + 'wp-module-onboarding' + ), + subHeading: __( + 'Do you keep getting this error?', + 'wp-module-onboarding' + ), + message: __( + 'If you continue to get this error, please contact our support team at 1-888-401-4678.', + 'wp-module-onboarding' + ), + buttonText: __( 'Try again', 'wp-module-onboarding' ), + buttonExit: __( 'Go back', 'wp-module-onboarding' ), + }, }; + + return content[ type ] || {}; }; export default getContents; diff --git a/src/OnboardingSPA/components/ErrorState/Step/SiteGen/index.js b/src/OnboardingSPA/components/ErrorState/Step/SiteGen/index.js index c95180184..8076c124a 100644 --- a/src/OnboardingSPA/components/ErrorState/Step/SiteGen/index.js +++ b/src/OnboardingSPA/components/ErrorState/Step/SiteGen/index.js @@ -6,15 +6,17 @@ import { Button, Fill } from '@wordpress/components'; // Third-party import { useNavigate } from 'react-router-dom'; +import classNames from 'classnames'; // Classes and functions import getContents from './contents'; -import { validateFlow } from '../../../../data/flows/utils'; +import { validateFlow, removeFromAllSteps } from '../../../../data/flows/utils'; import { resolveGetDataForFlow } from '../../../../data/flows'; // Components import CommonLayout from '../../../Layouts/Common'; import OrbAnimation from '../../../OrbAnimation'; +import { stepSiteGenMigration } from '../../../../steps/SiteGen/Migration/step'; // Misc import { store as nfdOnboardingStore } from '../../../../store'; @@ -55,13 +57,20 @@ const SiteGenStepErrorState = () => { setSidebarActiveView( false ); }, [] ); - const { brandConfig, currentData } = useSelect( ( select ) => { - return { - brandConfig: select( nfdOnboardingStore ).getNewfoldBrandConfig(), - currentData: - select( nfdOnboardingStore ).getCurrentOnboardingData(), - }; - } ); + const { brandConfig, currentData, currentStep, previousStep, allSteps } = + useSelect( ( select ) => { + return { + brandConfig: + select( nfdOnboardingStore ).getNewfoldBrandConfig(), + currentData: + select( nfdOnboardingStore ).getCurrentOnboardingData(), + currentStep: select( nfdOnboardingStore ).getCurrentStep(), + previousStep: select( nfdOnboardingStore ).getPreviousStep(), + allSteps: select( nfdOnboardingStore ).getAllSteps(), + }; + } ); + + const isMigrationStep = currentStep?.path === stepSiteGenMigration?.path; const oldFlow = window.nfdOnboarding?.oldFlow ? window.nfdOnboarding.oldFlow @@ -95,10 +104,26 @@ const SiteGenStepErrorState = () => { updateSiteGenErrorStatus( false ); }; - const content = getContents(); + const handleGoBack = () => { + updateSiteGenErrorStatus( false ); + const updates = removeFromAllSteps( allSteps, [ + stepSiteGenMigration, + ] ); + updateAllSteps( updates.allSteps ); + navigate( previousStep.path ); + }; + + const content = ! isMigrationStep + ? getContents( 'siteGenErrorContent' ) + : getContents( 'siteMigrationErrorContent' ); return ( - +
@@ -114,24 +139,26 @@ const SiteGenStepErrorState = () => {

{ content.message } - - { content.buttonExit } - + { ! isMigrationStep && ( + + { content.buttonExit } + + ) }

-
- - { isLargeViewport ? ( + { isMigrationStep ? ( +
+ - ) : ( - +
+ ) : ( +
+ + { isLargeViewport ? ( - - ) } -
+ ) : ( + + + + ) } +
+ ) }
); diff --git a/src/OnboardingSPA/components/ErrorState/Step/SiteGen/stylesheet.scss b/src/OnboardingSPA/components/ErrorState/Step/SiteGen/stylesheet.scss index 7cbb89bd7..dc8a4c22a 100644 --- a/src/OnboardingSPA/components/ErrorState/Step/SiteGen/stylesheet.scss +++ b/src/OnboardingSPA/components/ErrorState/Step/SiteGen/stylesheet.scss @@ -137,5 +137,19 @@ } } + + &__migrationerror { + + .nfd-onboarding-step--site-gen__error__container { + width: 610px; + + &__buttons { + + @media (max-width: #{ ($break-small) }) { + justify-content: end; + } + } + } + } } } diff --git a/src/OnboardingSPA/components/Header/components/SiteGenHeader/index.js b/src/OnboardingSPA/components/Header/components/SiteGenHeader/index.js index a75ec317f..fcb7418ab 100644 --- a/src/OnboardingSPA/components/Header/components/SiteGenHeader/index.js +++ b/src/OnboardingSPA/components/Header/components/SiteGenHeader/index.js @@ -16,6 +16,7 @@ import StepNavigation from './step-navigation'; // eslint-disable-next-line import/no-extraneous-dependencies import { findIndex } from 'lodash'; +import { stepSiteGenMigration } from '../../../../steps/SiteGen/Migration/step'; /** * Interface header rendered into header render prop in . @@ -45,9 +46,10 @@ const SiteGenHeader = () => { <> - { currentStep !== stepTheFork && ( - - ) } + { currentStep !== stepTheFork && + currentStep !== stepSiteGenMigration && ( + + ) } diff --git a/src/OnboardingSPA/components/Header/components/SiteGenHeader/step-navigation.js b/src/OnboardingSPA/components/Header/components/SiteGenHeader/step-navigation.js index 600d552b5..055680e90 100644 --- a/src/OnboardingSPA/components/Header/components/SiteGenHeader/step-navigation.js +++ b/src/OnboardingSPA/components/Header/components/SiteGenHeader/step-navigation.js @@ -51,7 +51,7 @@ const StepNavigation = () => { }, [] ); const isFirstStep = null === previousStep || false === previousStep; - const isPreviewStep = currentStep.path === stepSiteGenPreview.path; + const isPreviewStep = currentStep?.path === stepSiteGenPreview?.path; return (
diff --git a/src/OnboardingSPA/components/HeadingWithSubHeading/SiteGen/stylesheet.scss b/src/OnboardingSPA/components/HeadingWithSubHeading/SiteGen/stylesheet.scss index f50f38677..ceac6db21 100644 --- a/src/OnboardingSPA/components/HeadingWithSubHeading/SiteGen/stylesheet.scss +++ b/src/OnboardingSPA/components/HeadingWithSubHeading/SiteGen/stylesheet.scss @@ -12,6 +12,11 @@ color: var(--nfd-onboarding-primary); margin: 35px 35px 15px 35px !important; font-size: 30px; + + @media (max-width: #{ ($break-small) }) { + line-height: 1.5; + margin: 35px 15px 15px 15px !important; + } } &__subtitle { diff --git a/src/OnboardingSPA/components/NewfoldInterfaceSkeleton/SiteBuild/index.js b/src/OnboardingSPA/components/NewfoldInterfaceSkeleton/SiteBuild/index.js index 954a9a660..d2ea85fc1 100644 --- a/src/OnboardingSPA/components/NewfoldInterfaceSkeleton/SiteBuild/index.js +++ b/src/OnboardingSPA/components/NewfoldInterfaceSkeleton/SiteBuild/index.js @@ -1,9 +1,33 @@ +// Wordpress +import { useEffect, useState } from '@wordpress/element'; +import { useViewportMatch } from '@wordpress/compose'; +import { useDispatch, useSelect } from '@wordpress/data'; + +// Third part +import classNames from 'classnames'; +import { useLocation } from 'react-router-dom'; +// eslint-disable-next-line import/no-extraneous-dependencies +import { kebabCase } from 'lodash'; + +// Components 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 Footer from '../../Footer'; +import NewfoldInterfaceSkeleton from '../index'; +import { ThemeProvider } from '../../ThemeContextProvider'; +import { stepTheFork } from '../../../steps/TheFork/step'; +import { stepSiteGenMigration } from '../../../steps/SiteGen/Migration/step'; + +// classes +import { HiiveAnalytics } from '@newfold-labs/js-utility-ui-analytics'; +import themeToggleHOC from '../themeToggleHOC'; +import { init as initializePlugins } from '../../../utils/api/plugins'; +import { init as initializeThemes } from '../../../utils/api/themes'; +import { trigger as cronTrigger } from '../../../utils/api/cronTrigger'; + +// Misc. import { setFlow } from '../../../utils/api/flow'; import { design as designChapter } from '../../../chapters/design'; import { @@ -14,16 +38,7 @@ import { 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, @@ -48,13 +63,6 @@ import { 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'; -import { ThemeProvider } from '../../ThemeContextProvider'; -import themeToggleHOC from '../themeToggleHOC'; -import Footer from '../../Footer'; const SiteBuild = () => { const location = useLocation(); @@ -431,6 +439,7 @@ const SiteBuild = () => { const isForkStep = currentStep === stepTheFork || + currentStep === stepSiteGenMigration || window.nfdOnboarding.currentFlow === 'sitegen'; // wrapping the NewfoldInterfaceSkeleton with the HOC to make 'theme' available const ThemedNewfoldInterfaceSkeleton = themeToggleHOC( diff --git a/src/OnboardingSPA/components/StateHandlers/SiteGen/index.js b/src/OnboardingSPA/components/StateHandlers/SiteGen/index.js index ee03184fd..1d4eb579e 100644 --- a/src/OnboardingSPA/components/StateHandlers/SiteGen/index.js +++ b/src/OnboardingSPA/components/StateHandlers/SiteGen/index.js @@ -19,6 +19,7 @@ import { SITEGEN_FLOW } from '../../../data/flows/constants'; const SiteGenStateHandler = ( { children } ) => { const { siteGenErrorStatus } = useSelect( ( select ) => { return { + currentStepPath: select( nfdOnboardingStore ).getCurrentStepPath(), siteGenErrorStatus: select( nfdOnboardingStore ).getSiteGenErrorStatus(), }; diff --git a/src/OnboardingSPA/data/flows/default.js b/src/OnboardingSPA/data/flows/default.js index f7b3740c1..a82bfff5b 100644 --- a/src/OnboardingSPA/data/flows/default.js +++ b/src/OnboardingSPA/data/flows/default.js @@ -13,6 +13,7 @@ import { indexPage } from '../../pages/IndexPage/page'; import { brush } from '@wordpress/icons'; import { __ } from '@wordpress/i18n'; import { stepTheFork } from '../../steps/TheFork/step'; +import { stepSiteGenMigration } from '../../steps/SiteGen/Migration/step'; export const pages = [ indexPage, errorPage ]; @@ -36,6 +37,7 @@ export const getRoutes = ( chapters = initialChapters ) => { let routes = [ ...pages ]; routes.push( stepTheFork ); routes.push( stepWelcome ); + routes.push( stepSiteGenMigration ); chapters.forEach( ( chapter ) => { routes = routes.concat( [ ...chapter.steps, diff --git a/src/OnboardingSPA/data/flows/ecommerce.js b/src/OnboardingSPA/data/flows/ecommerce.js index 68bca7e04..2908e15fa 100644 --- a/src/OnboardingSPA/data/flows/ecommerce.js +++ b/src/OnboardingSPA/data/flows/ecommerce.js @@ -19,6 +19,7 @@ import { filter } from 'lodash'; import { store } from '@wordpress/icons'; import { __ } from '@wordpress/i18n'; import { stepTheFork } from '../../steps/TheFork/step'; +import { stepSiteGenMigration } from '../../steps/SiteGen/Migration/step'; export const pages = [ indexPage, errorPage ]; @@ -51,6 +52,7 @@ export const getRoutes = ( chapters = initialChapters ) => { let routes = [ ...pages ]; routes.push( stepTheFork ); routes.push( stepWelcome ); + routes.push( stepSiteGenMigration ); chapters.forEach( ( chapter ) => { routes = routes.concat( [ ...chapter.steps, diff --git a/src/OnboardingSPA/data/flows/sitegen.js b/src/OnboardingSPA/data/flows/sitegen.js index 525ddc303..5426f04b5 100644 --- a/src/OnboardingSPA/data/flows/sitegen.js +++ b/src/OnboardingSPA/data/flows/sitegen.js @@ -5,6 +5,7 @@ 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'; +import { stepSiteGenMigration } from '../../steps/SiteGen/Migration/step'; export const pages = [ indexPage, errorPage ]; @@ -24,7 +25,7 @@ export const getSteps = ( chapters = initialChapters ) => { export const getRoutes = ( chapters = initialChapters ) => { let routes = [ ...pages ]; - routes.push( stepTheFork, stepSiteGenWelcome ); + routes.push( stepTheFork, stepSiteGenMigration, stepSiteGenWelcome ); chapters.forEach( ( chapter ) => { routes = routes.concat( [ ...chapter.steps, diff --git a/src/OnboardingSPA/data/flows/utils.js b/src/OnboardingSPA/data/flows/utils.js index 2736a2a98..241fd1ac7 100644 --- a/src/OnboardingSPA/data/flows/utils.js +++ b/src/OnboardingSPA/data/flows/utils.js @@ -1,6 +1,7 @@ // eslint-disable-next-line import/no-extraneous-dependencies import { filter } from 'lodash'; import { stepDesignThemeStylesPreview } from '../../steps/DesignThemeStyles/Preview/step'; +import { stepSiteGenMigration } from '../../steps/SiteGen/Migration/step'; export const injectInAllSteps = ( allSteps, conditionalSteps ) => { const updates = removeFromAllSteps( allSteps, conditionalSteps ); @@ -76,3 +77,9 @@ export const removeFromRoutes = ( routes, conditionalSteps ) => { ), }; }; + +export const injectMigrationStep = ( allSteps, targetStep ) => { + return { + allSteps: addAfter( allSteps, targetStep, [ stepSiteGenMigration ] ), + }; +}; diff --git a/src/OnboardingSPA/steps/GetStarted/Welcome/index.js b/src/OnboardingSPA/steps/GetStarted/Welcome/index.js index 356bc66a7..f75a0fb2d 100644 --- a/src/OnboardingSPA/steps/GetStarted/Welcome/index.js +++ b/src/OnboardingSPA/steps/GetStarted/Welcome/index.js @@ -1,15 +1,19 @@ -import { store as nfdOnboardingStore } from '../../../store'; -import { useLocation } from 'react-router-dom'; -import { useSelect, useDispatch } from '@wordpress/data'; +// Wordpress import { useEffect } from '@wordpress/element'; +import { useSelect, useDispatch } from '@wordpress/data'; import { chevronRight, external } from '@wordpress/icons'; +import { useLocation, useNavigate } from 'react-router-dom'; +// Components import CommonLayout from '../../../components/Layouts/Common'; import NewfoldLargeCard from '../../../components/NewfoldLargeCard'; import CardHeader from '../../../components/CardHeader'; import NavCardButton from '../../../components/Button/NavCardButton'; import Tab from '../../../components/Tab'; import TabPanelHover from '../../../components/TabPanelHover'; + +// Misc +import { store as nfdOnboardingStore } from '../../../store'; import { VIEW_NAV_GET_STARTED, SIDEBAR_LEARN_MORE, @@ -17,14 +21,28 @@ import { } from '../../../../constants'; import getContents from './contents'; import ButtonWhite from '../../../components/Button/ButtonWhite'; +import { + injectMigrationStep, + removeFromAllSteps, +} from '../../../data/flows/utils'; +import { stepWelcome } from './step'; +import { stepSiteGenMigration } from '../../../steps/SiteGen/Migration/step'; +import { + OnboardingEvent, + trackOnboardingEvent, +} from '../../../utils/analytics/hiive'; +import { ACTION_SITEGEN_FORK_OPTION_SELECTED } from '../../../utils/analytics/hiive/constants'; const StepWelcome = () => { const location = useLocation(); - const { brandName, migrationUrl } = useSelect( + const navigate = useNavigate(); + const { brandName, migrationUrl, allSteps, canMigrateSite } = useSelect( ( select ) => { return { brandName: select( nfdOnboardingStore ).getNewfoldBrandName(), migrationUrl: select( nfdOnboardingStore ).getMigrationUrl(), + allSteps: select( nfdOnboardingStore ).getAllSteps(), + canMigrateSite: select( nfdOnboardingStore ).canMigrateSite(), }; }, [ location.pathname ] @@ -36,6 +54,7 @@ const StepWelcome = () => { setIsHeaderNavigationEnabled, setHeaderActiveView, setIsHeaderEnabled, + updateAllSteps, } = useDispatch( nfdOnboardingStore ); useEffect( () => { @@ -47,6 +66,29 @@ const StepWelcome = () => { setIsHeaderEnabled( true ); }, [] ); + useEffect( () => { + const updates = removeFromAllSteps( allSteps, [ + stepSiteGenMigration, + ] ); + updateAllSteps( updates.allSteps ); + }, [] ); + + const handleMigration = () => { + if ( canMigrateSite ) { + const updates = injectMigrationStep( allSteps, stepWelcome ); + updateAllSteps( updates.allSteps ); + navigate( stepSiteGenMigration.path ); + } else { + window.open( migrationUrl, '_blank' ); + } + trackOnboardingEvent( + new OnboardingEvent( + ACTION_SITEGEN_FORK_OPTION_SELECTED, + 'MIGRATE' + ) + ); + }; + const content = getContents( brandName ); return ( @@ -78,14 +120,14 @@ const StepWelcome = () => { { ( tab ) =>
{ tab.content }
}
- { migrationUrl && ( + { ( migrationUrl || canMigrateSite ) && ( - window.open( migrationUrl, '_blank' ) - } + onClick={ () => { + handleMigration( migrationUrl ); + } } /> ) } { + return { + heading: sprintf( + /* translators: %s: to replace Brand name */ + __( + "Let's migrate your existing site to %s", + 'wp-module-onboarding' + ), + currentBrandName + ), + description: __( + 'Please wait a few seconds while we get your new account ready to import your existing WordPress site. ', + 'wp-module-onboarding' + ), + importText: __( 'Preparing your account', 'wp-module-onboarding' ), + }; +}; + +export default getContents; diff --git a/src/OnboardingSPA/steps/SiteGen/Migration/index.js b/src/OnboardingSPA/steps/SiteGen/Migration/index.js new file mode 100644 index 000000000..86a4eed32 --- /dev/null +++ b/src/OnboardingSPA/steps/SiteGen/Migration/index.js @@ -0,0 +1,130 @@ +// Wordpress +import { useEffect } from '@wordpress/element'; +import { useDispatch, useSelect } from '@wordpress/data'; + +// Classes and fucntions +import getContents from './contents'; +import { getSiteMigrateUrl } from '../../../utils/api/siteGen'; + +//Components +import CommonLayout from '../../../components/Layouts/Common'; +import HeadingWithSubHeading from '../../../components/HeadingWithSubHeading/SiteGen'; +import { SiteGenStateHandler } from '../../../components/StateHandlers'; +import { stepTheFork } from '../../TheFork/step'; +import { stepSiteGenMigration } from './step'; +import { stepWelcome } from '../../GetStarted/Welcome/step'; + +//Misc. +import { injectMigrationStep } from '../../../data/flows/utils'; +import { store as nfdOnboardingStore } from '../../../store'; +import { FOOTER_SITEGEN, HEADER_SITEGEN } from '../../../../constants'; +import { + OnboardingEvent, + trackOnboardingEvent, +} from '../../../utils/analytics/hiive'; +import { SITEGEN_FLOW } from '../../../data/flows/constants'; +import { ACTION_MIGRATION_INITIATED } from '../../../utils/analytics/hiive/constants'; + +const StepSiteGenMigration = () => { + const { + setIsHeaderEnabled, + setSidebarActiveView, + setHeaderActiveView, + setDrawerActiveView, + setIsHeaderNavigationEnabled, + setFooterActiveView, + setHideFooterNav, + updateSiteGenErrorStatus, + updateAllSteps, + } = useDispatch( nfdOnboardingStore ); + + const { siteGenErrorStatus, allSteps, canMigrateSite, currentBrandName } = + useSelect( ( select ) => { + return { + siteGenErrorStatus: + select( nfdOnboardingStore ).getSiteGenErrorStatus(), + allSteps: select( nfdOnboardingStore ).getAllSteps(), + canMigrateSite: select( nfdOnboardingStore ).canMigrateSite(), + currentBrandName: + select( nfdOnboardingStore ).getNewfoldBrandName(), + }; + } ); + + const loadData = async () => { + try { + if ( canMigrateSite ) { + const response = await getSiteMigrateUrl(); + const migrateUrl = response?.body?.data?.redirect_url; + if ( migrateUrl ) { + trackOnboardingEvent( + new OnboardingEvent( + ACTION_MIGRATION_INITIATED, + migrateUrl + ) + ); + window.open( migrateUrl, '_self' ); + } else { + updateSiteGenErrorStatus( true ); + } + } else { + updateSiteGenErrorStatus( true ); + } + } catch ( error ) { + // eslint-disable-next-line no-console + console.error( 'Failed to fetch migration URL:', error ); + updateSiteGenErrorStatus( true ); + } + }; + + useEffect( () => { + const hasMigrateStep = allSteps.filter( + ( step ) => step === stepSiteGenMigration + ); + if ( hasMigrateStep?.length === 0 ) { + let updates; + if ( window.nfdOnboarding.currentFlow === SITEGEN_FLOW ) { + updates = injectMigrationStep( allSteps, stepTheFork ); + } else { + updates = injectMigrationStep( allSteps, stepWelcome ); + } + updateAllSteps( updates.allSteps ); + } + + setHideFooterNav( true ); + setIsHeaderEnabled( false ); + setSidebarActiveView( false ); + setIsHeaderNavigationEnabled( false ); + setHeaderActiveView( HEADER_SITEGEN ); + setDrawerActiveView( false ); + setFooterActiveView( FOOTER_SITEGEN ); + }, [] ); + + useEffect( () => { + if ( siteGenErrorStatus === false ) { + loadData(); + } + }, [ siteGenErrorStatus ] ); + + const content = getContents( currentBrandName ); + return ( + + + +
+
+

+ { content?.importText } +

+
+

+ { content?.description } +

+
+
+ ); +}; + +export default StepSiteGenMigration; diff --git a/src/OnboardingSPA/steps/SiteGen/Migration/step.js b/src/OnboardingSPA/steps/SiteGen/Migration/step.js new file mode 100644 index 000000000..840a223c4 --- /dev/null +++ b/src/OnboardingSPA/steps/SiteGen/Migration/step.js @@ -0,0 +1,19 @@ +import { copy } from '@wordpress/icons'; +import { lazy } from '@wordpress/element'; +import { __ } from '@wordpress/i18n'; +import { Step } from '../../../data/models/Step'; + +const StepSiteGenMigration = lazy( () => import( './index' ) ); + +export const stepSiteGenMigration = new Step( { + path: '/sitegen/step/migration', + title: __( 'Migration', 'wp-module-onboarding' ), + Component: StepSiteGenMigration, + icon: copy, + drawerNavigation: false, + sidebars: { + LearnMore: { + SidebarComponents: [], + }, + }, +} ); diff --git a/src/OnboardingSPA/steps/SiteGen/Migration/stylesheet.scss b/src/OnboardingSPA/steps/SiteGen/Migration/stylesheet.scss new file mode 100644 index 000000000..80296dd94 --- /dev/null +++ b/src/OnboardingSPA/steps/SiteGen/Migration/stylesheet.scss @@ -0,0 +1,62 @@ +.nfd-onboarding-step { + + &--site-gen { + + &__migration { + + flex-direction: column; + justify-content: flex-start; + font-weight: 500; + padding: 30px 15px; + + &__description { + font-size: 18px; + color: var(--nfd-onboarding-primary); + margin: 50px 0; + text-align: center; + + @media (max-width: #{ ($break-small) }) { + font-size: 16px; + } + } + + &--container { + display: flex; + align-items: center; + border-radius: 10px; + gap: 24px; + padding: 10px; + background-color: var(--nfd-onboarding-card-background); + justify-content: center; + width: 100%; + max-width: 436px; + + &__importtext { + color: var(--nfd-onboarding-primary); + font-size: 16px; + font-weight: 500; + } + + &__loader { + border: 4px solid var(--nfd-onboarding-progress-bar-background); + border-top: 4px solid var(--nfd-onboarding-progress-bar-fill); + border-radius: 50%; + width: 20px; + height: 20px; + animation: spin 2s linear infinite; + } + + @keyframes spin { + + 0% { + transform: rotate(0deg); + } + + 100% { + transform: rotate(360deg); + } + } + } + } + } +} diff --git a/src/OnboardingSPA/steps/TheFork/index.js b/src/OnboardingSPA/steps/TheFork/index.js index 71698c9e7..8bbb5cf88 100644 --- a/src/OnboardingSPA/steps/TheFork/index.js +++ b/src/OnboardingSPA/steps/TheFork/index.js @@ -1,14 +1,18 @@ // WordPress import { useEffect } from '@wordpress/element'; import { useSelect, useDispatch } from '@wordpress/data'; +import { useNavigate } from 'react-router-dom'; // Classes and functions import getContents from './contents'; +import { injectMigrationStep } from '../../data/flows/utils'; // Components import StartOptions from '../../components/StartOptions'; import CommonLayout from '../../components/Layouts/Common'; import HeadingWithSubHeading from '../../components/HeadingWithSubHeading/SiteGen/index'; +import { stepSiteGenMigration } from '../../steps/SiteGen/Migration/step'; +import { stepTheFork } from './step'; // Misc import { @@ -26,12 +30,17 @@ import { store as nfdOnboardingStore } from '../../store'; import { DEFAULT_FLOW } from '../../data/flows/constants'; const TheFork = () => { - const { migrationUrl } = useSelect( ( select ) => { - return { - migrationUrl: select( nfdOnboardingStore ).getMigrationUrl(), - }; - } ); - + const { migrationUrl, canMigrateSite, allSteps } = useSelect( + ( select ) => { + return { + migrationUrl: select( nfdOnboardingStore ).getMigrationUrl(), + canMigrateSite: select( nfdOnboardingStore ).canMigrateSite(), + allSteps: select( nfdOnboardingStore ).getAllSteps(), + currentStep: select( nfdOnboardingStore ).getCurrentStep(), + routes: select( nfdOnboardingStore ).getRoutes(), + }; + } + ); const { setIsHeaderEnabled, setSidebarActiveView, @@ -40,6 +49,7 @@ const TheFork = () => { setIsHeaderNavigationEnabled, setFooterActiveView, setHideFooterNav, + updateAllSteps, } = useDispatch( nfdOnboardingStore ); useEffect( () => { @@ -67,6 +77,24 @@ const TheFork = () => { window.location.replace( pluginDashboardPage ); }; const content = getContents(); + const navigate = useNavigate(); + + const handleMigration = () => { + if ( canMigrateSite ) { + const updates = injectMigrationStep( allSteps, stepTheFork ); + updateAllSteps( updates.allSteps ); + navigate( stepSiteGenMigration.path ); + } else { + window.open( migrationUrl, '_blank' ); + } + trackOnboardingEvent( + new OnboardingEvent( + ACTION_SITEGEN_FORK_OPTION_SELECTED, + 'MIGRATE' + ) + ); + }; + return ( { />

- { migrationUrl && ( - - trackOnboardingEvent( - new OnboardingEvent( - ACTION_SITEGEN_FORK_OPTION_SELECTED, - 'MIGRATE' - ) - ) - } + onClick={ () => { + handleMigration(); + } } + onKeyUp={ ( event ) => { + if ( event.key === 'Enter' ) { + handleMigration(); + } + } } + tabIndex={ 0 } + role="button" + aria-label="Trigger site migration" > { content.importtext } - +
) } { return ( @@ -10,9 +15,11 @@ export const onboardingRestURL = ( api ) => { }; export const installerRestURL = ( api ) => { - return ( - `${ installerRestBase }/${ api }` - ); + return `${ installerRestBase }/${ api }`; +}; + +export const migrateRestURL = ( api ) => { + return `${ migrateRestBase }/${ api }`; }; export const wpRestURL = ( api ) => { diff --git a/src/OnboardingSPA/utils/api/siteGen.js b/src/OnboardingSPA/utils/api/siteGen.js index 70a403dbc..c03c5241c 100644 --- a/src/OnboardingSPA/utils/api/siteGen.js +++ b/src/OnboardingSPA/utils/api/siteGen.js @@ -1,7 +1,7 @@ import apiFetch from '@wordpress/api-fetch'; import { resolve } from './resolve.js'; -import { onboardingRestURL } from './common'; +import { onboardingRestURL, migrateRestURL } from './common'; export async function getSiteGenIdentifiers() { return await resolve( @@ -90,3 +90,11 @@ export async function publishSitemapPages( siteDescription ) { } ).then() ); } + +export async function getSiteMigrateUrl() { + return await resolve( + apiFetch( { + url: migrateRestURL( 'migrate/connect' ), + } ).then() + ); +} diff --git a/src/constants.js b/src/constants.js index 125041109..25a6c3443 100644 --- a/src/constants.js +++ b/src/constants.js @@ -10,9 +10,11 @@ export const wpRestURL = window.nfdOnboarding.restUrl; export const wpRestRoute = 'wp/v2'; export const onboardingRestRoute = 'newfold-onboarding/v1'; export const installerRestRoute = 'newfold-installer/v1'; +export const migrationRestRoute = 'newfold-migration/v1'; export const wpRestBase = `${ wpRestURL }/${ wpRestRoute }`; export const onboardingRestBase = `${ wpRestURL }/${ onboardingRestRoute }`; export const installerRestBase = `${ wpRestURL }/${ installerRestRoute }`; +export const migrateRestBase = `${ wpRestURL }/${ migrationRestRoute }`; export const wpAdminPage = addQueryArgs( `${ wpAdminUrl }index.php`, window.nfdOnboarding.currentBrand?.dashboardRedirectParams