/** * OnboardingCard: Quick setup guide for new users. * Displays a progress bar, expandable steps, and benefits. * State persists via plugin settings API. */ import { __ } from '@wordpress/i18n'; import { useState, useCallback, useMemo, useEffect } from '@wordpress/element'; import { Card, CardBody, Flex, FlexItem, Button, Icon, } from '@wordpress/components'; import { close, check, payment, shipping, tag } from '@wordpress/icons'; import { useWindowSize } from '../../shared/hooks'; import { getCourierLogo } from '../../shared/utils/getAsset'; import { getPluginSettingsPageUrl } from '../../shared/utils'; export interface OnboardingCardProps { /** Whether user is connected to Parcel2Go account. */ isConnected: boolean; /** Persisted onboarding current step from settings. */ currentStep?: number; /** Whether P2G login is loading. */ loginLoading?: boolean; /** Whether onboarding card is loading. */ isLoading?: boolean; /** Callback to start P2G login flow. */ onLinkAccount: () => void; /** Callback when user dismisses the onboarding card. */ onDismiss: () => void; /** Callback when user skips a step (persists to DB). */ onSkipStep?: (step: number) => void; /** Whether user has default service settings configured. */ hasDefaultServiceSettings: boolean; } /** Icon for incomplete step (unfilled circle). */ const IncompleteStepIcon = () => ( ); /** Icon for completed step (green check). */ const CompletedStepIcon = () => ( ); export default function OnboardingCard({ isConnected, currentStep = 1, loginLoading = false, isLoading = false, onLinkAccount, onDismiss, onSkipStep, hasDefaultServiceSettings, }: OnboardingCardProps) { const { isMdOrUp } = useWindowSize(); const [openStep, setOpenStep] = useState(null); const guideImage = getCourierLogo('guide'); // Step completion: 1 = always done, 2 = when connected, 3 = always optional const steps = useMemo( () => [ { step: 1, title: __( 'Import orders and check out as a guest', 'parcel2go-shipping' ), description: __( 'Your WooCommerce orders are ready. You can ship them without creating a Parcel2Go account.', 'parcel2go-shipping' ), completed: true, }, { step: 2, title: __( 'Sign up or link your Parcel2Go account (Optional)', 'parcel2go-shipping' ), description: __( 'Unlock exclusive features when you create a free account', 'parcel2go-shipping' ), completed: isConnected || currentStep >= 2, action: !isConnected ? { label: __('Link P2G Account', 'parcel2go-shipping'), onClick: onLinkAccount, } : undefined, }, { step: 3, title: __( "Set your default shipping rules once you've linked your P2G account (Optional)", 'parcel2go-shipping' ), description: __( 'Configure your default sender address, package sizes, and preferred couriers.', 'parcel2go-shipping' ), completed: hasDefaultServiceSettings || currentStep >= 3, action: isConnected ? { label: __('Default Settings', 'parcel2go-shipping'), onClick: () => window.location.assign(getPluginSettingsPageUrl('default-services')), } : undefined, }, ], [currentStep, isConnected, onLinkAccount, hasDefaultServiceSettings] ); const completedCount = steps.filter((s) => s.completed).length; const totalSteps = steps.length; const progressPercent = (completedCount / totalSteps) * 100; const handleToggleStep = useCallback((step: number) => { setOpenStep((prev) => (prev === step ? null : step)); }, []); const benefits = [ { icon: payment, iconColor: '#007cba', title: __('PrePay', 'parcel2go-shipping'), description: __( 'Speed up bookings, for easier payments without the need for card details at checkout. Earn 2% bonus credit on top-ups over £100.', 'parcel2go-shipping' ), }, { icon: tag, iconColor: '#9b59b6', title: __('Exclusive Rates', 'parcel2go-shipping'), description: __( 'Discounted rates for you with trusted couriers like Evri and UPS.', 'parcel2go-shipping' ), }, { icon: shipping, iconColor: '#00a32a', title: __('Bulk Shipping', 'parcel2go-shipping'), description: __( 'Ship multiple orders in one go and access bulk labels, saving time with easy fulfilment.', 'parcel2go-shipping' ), }, ]; const handleSkipStep = useCallback( (step: number) => { setOpenStep(null); onSkipStep?.(step); }, [onSkipStep] ); return ( {/* Header with title and close button */} {__('Quick setup guide', 'parcel2go-shipping')} {/* Progress bar */} {completedCount} {__('of', 'parcel2go-shipping')}{' '} {totalSteps}{' '} {__('tasks complete', 'parcel2go-shipping')} {/* Steps list */} {steps.map((step) => { const isOpen = openStep === step.step; const isStep2 = step.step === 2; return ( handleToggleStep(step.step) } aria-expanded={isOpen} style={{ display: 'flex', alignItems: 'center', gap: 12, width: '100%', padding: '12px 0', background: 'none', border: 'none', cursor: 'pointer', textAlign: 'left', fontSize: 14, color: '#1d2327', }} > {step.completed ? ( ) : ( )} {step.title} {isOpen && !step.completed && step.step > 1 && ( handleSkipStep(step.step) } > {__('Skip', 'parcel2go-shipping')} )} {isOpen && ( {step.description && ( {step.description} )} {step.action && ( {step.action.label} )} {/* Benefits and illustration inside Step 2 */} {isStep2 && ( {benefits.map( (benefit) => ( { benefit.title } { benefit.description } ) )} )} {isStep2 && isMdOrUp && ( )} )} ); })} ); }
{step.description}