import {useEffect, memo, useMemo, useState} from "@wordpress/element"; import type { FC } from '@wordpress/element'; import Modal from "./Modal/Modal"; import ProgressBar from "./ProgressBar"; import ButtonInput from "./Inputs/ButtonInput"; import { ErrorBoundary } from './ErrorBoundary'; import useOnboardingStore from "../store/useOnboardingStore"; import ModalContent from "./Modal/ModalContent"; import { sprintf, __ } from '@wordpress/i18n'; import Icon from "../utils/Icon"; import {get_website_url} from "@/utils/lib.js"; import {updateAction} from "../utils/api"; /** * Onboarding component that guides users through a series of steps * @returns {JSX.Element} The Onboarding component */ const Onboarding: FC = () => { const [ConfettiExplosion, setConfettiExplosion] = useState(null); const [isExploding, setIsExploding] = useState(false); const { isOpen, isUpdating, currentStepIndex, steps, setOpen, setCurrentStepIndex, addSuccessStep, setSteps, onboardingData, setResponseMessage, setResponseSuccess, responseMessage, responseSuccess, updateEmail, updateStepSettings, installPlugins, validateLicense, footerMessage, settings, setValue, getSettings, isLastStep, trackingTestRunning, isInstalling, } = useOnboardingStore(); useEffect(() => { if ( !!isLastStep() ) { import ( "react-confetti-explosion").then( ({default: ConfettiExplosion}) => { setConfettiExplosion(() => ConfettiExplosion); }); setIsExploding(true); } }, [isLastStep()]); // Memoize the settings and visible steps to prevent unnecessary recalculations const visibleSteps = useMemo(() => onboardingData.steps?.filter(step => step.visible !== false) || [], [onboardingData.steps]); const currentStep = visibleSteps[currentStepIndex]; // Initialize steps only once when the component mounts useEffect(() => { if (visibleSteps.length > 0 && steps.length === 0) { setSteps(visibleSteps); } }, [visibleSteps, steps.length, setSteps]); useEffect(() => { if ( settings.length === 0 ) { getSettings(); } }, [settings]); const handleClose = () => { setOpen(false); updateAction({}, 'user_skipped_wizard'); }; const handlePrevious = () => { setCurrentStepIndex(currentStepIndex - 1); }; const validateAndContinue = async (e) => { let success = true; if ( currentStep.type === 'license' ) { success = await validateLicense(); } //save the current values if ( currentStep.type === 'settings' ) { await updateStepSettings(settings); } if ( currentStep.type === 'email' ) { await updateEmail(); } if (currentStep.type === 'plugins'){ //we don't wait for the plugins to be installed, so the user can continue. installPlugins(); } if ( !success ) { return; } await handleContinue(e); } const changeFieldValue = async (fieldId: string, value: string | boolean) => { setValue(fieldId, value); }; // Function to determine if the continue button should be disabled. const isContinueDisabled = () => { // For tracking test step, only disable continue button while test is running. if (currentStep?.id === 'tracking') { return trackingTestRunning; } // we don't want to close the modal during installation. Otherwise it might not complete. if ( isLastStep() && isInstalling ) { return true; } return false; }; const handleContinue = async (e) => { // make sure the response message is cleared setResponseMessage(''); setResponseSuccess(true); if (settings && currentStep.fields) { const atLeastOneFieldIsTrue = currentStep.fields.some((field: { id: string }) => { const value = settings[field.id]; return value === true || (typeof value === 'string' && value.trim() !== ''); }); if (atLeastOneFieldIsTrue) { addSuccessStep(currentStep.id); } } setCurrentStepIndex(currentStepIndex + 1); // If this is the last step, reload the page if this is so configured. if (currentStepIndex + 1 >= steps.length ) { await updateAction({}, 'user_completed_wizard'); if (onboardingData.reload_on_finish) { window.location.reload(); } } }; //open the modal when the component mounts useEffect(() => { setOpen(true); }, []); if (!currentStep) { return null; } const upgradeUrl = get_website_url(onboardingData.upgrade, { utm_source:onboardingData.prefix + '_onboarding', utm_content: 'upgrade' }); return (
{sprintf(__('Step %1$d of %2$d', 'burst-statistics'), currentStepIndex + 1, steps.length)}
{currentStep.title}
{responseMessage && (
{responseMessage}
)}
{ ( !!isLastStep() && !onboardingData.is_pro ) && ( {__('Check out Burst Pro', 'burst-statistics')} )} validateAndContinue(e)} key={currentStep.id + "continue"} > { (isUpdating || isInstalling) && }{currentStep.button.label} {( currentStepIndex > 0 && !isLastStep() ) && ( <> handleContinue(e)} key={currentStep.id + "skip"} > {__('Skip', 'burst-statistics')} handlePrevious() } key={currentStep.id + "previous"} > {__('Previous', 'burst-statistics')} )} {currentStepIndex === 0 && ( {__('Skip onboarding', 'burst-statistics')} )}
{footerMessage && (
{footerMessage}
)} } isOpen={isOpen} onClose={handleClose} footer={null} triggerClassName="" children={null} /> {isExploding && ConfettiExplosion &&
}
); }; export default memo(Onboarding);