import { Button, ToggleControl } from '@wordpress/components'; import { useEffect, useState } from '@wordpress/element'; import { api } from '../api'; import type { PageViewCaptureFields, SetupStatusResponse } from '../types'; import PageViewCaptureSetting from './PageViewCaptureSetting'; type StepStatus = 'complete' | 'active' | 'locked'; function getStepStatus(complete: boolean, previousComplete: boolean): StepStatus { if (complete) return 'complete'; if (previousComplete) return 'active'; return 'locked'; } function StepIcon({ status }: { status: StepStatus }): JSX.Element { if (status === 'complete') { return ( ); } if (status === 'active') { return ( ); } return ( ); } interface CompletionInput { syncProducts: boolean; autoProtect: boolean; visibilityOnProtect: boolean; verifyDomain: boolean; pageViewCaptureDecided: boolean; } function getCompletion(input: CompletionInput) { return { syncProducts: input.syncProducts, autoProtect: input.syncProducts && input.autoProtect, visibility: input.syncProducts && input.visibilityOnProtect, verifyDomain: input.verifyDomain, pageViewCapture: input.pageViewCaptureDecided, }; } function summarizeCompletion(completion: ReturnType) { const values = Object.values(completion); const completed = values.filter(Boolean).length; return { completed, total: values.length, allComplete: completed === values.length }; } export default function SetupChecklist(): JSX.Element | null { const [status, setStatus] = useState(null); const [loading, setLoading] = useState(true); const [collapsed, setCollapsed] = useState(false); const [dismissing, setDismissing] = useState(false); const [syncingProducts, setSyncingProducts] = useState(false); const [autoProtect, setAutoProtect] = useState(false); const [visibilityOnProtect, setVisibilityOnProtect] = useState(false); const [togglingAutoProtect, setTogglingAutoProtect] = useState(false); const [togglingVisibility, setTogglingVisibility] = useState(false); useEffect(() => { loadStatus(); }, []); const loadStatus = async (): Promise => { try { const data = await api.get('/setup-status'); setStatus(data); setAutoProtect(data.auto_protect); setVisibilityOnProtect(data.visibility_on_protect); const { allComplete } = summarizeCompletion( getCompletion({ syncProducts: data.steps.sync_products, autoProtect: data.auto_protect, visibilityOnProtect: data.visibility_on_protect, verifyDomain: data.steps.verify_domain, pageViewCaptureDecided: data.page_view_capture_decided, }), ); if (allComplete) { setCollapsed(true); } } catch { // Silently ignore. } finally { setLoading(false); } }; const handleDismiss = async (): Promise => { setDismissing(true); try { await api.post('/setup-status/dismiss'); setStatus((prev) => (prev ? { ...prev, dismissed: true } : null)); } catch { // Silently ignore. } finally { setDismissing(false); } }; const handleSyncProducts = async (): Promise => { setSyncingProducts(true); try { await api.post('/products/sync'); // Reload status to reflect new completion state. await loadStatus(); } catch { // Silently ignore. } finally { setSyncingProducts(false); } }; const handleToggleAutoProtect = async (enabled: boolean): Promise => { setAutoProtect(enabled); setTogglingAutoProtect(true); try { await api.post('/settings', { auto_protect: enabled }); } catch { setAutoProtect(!enabled); } finally { setTogglingAutoProtect(false); } }; const handleToggleVisibility = async (enabled: boolean): Promise => { setVisibilityOnProtect(enabled); setTogglingVisibility(true); try { await api.post('/settings', { visibility_on_protect: enabled }); } catch { setVisibilityOnProtect(!enabled); } finally { setTogglingVisibility(false); } }; const handlePageViewCaptureSaved = (value: PageViewCaptureFields): void => { setStatus((prev) => (prev ? { ...prev, ...value } : null)); }; if (loading) { return null; } if (!status || status.dismissed) { return null; } const { steps } = status; const syncComplete = steps.sync_products; const verifyDomainComplete = steps.verify_domain; const allStepsComplete = syncComplete; const { completed: completedCount, total: totalSteps, allComplete, } = summarizeCompletion( getCompletion({ syncProducts: syncComplete, autoProtect, visibilityOnProtect, verifyDomain: verifyDomainComplete, pageViewCaptureDecided: status.page_view_capture_decided, }), ); return (

Setup checklist

{allComplete ? ( Complete ) : ( {completedCount} of {totalSteps} )}
{allComplete && !dismissing && ( )}
{!collapsed && (
{/* Step 1: Sync products to Mintall */}

Sync products to Mintall

{syncComplete && ( Done )}
{!syncComplete ? ( <>

Send all published products to Mintall so they exist on the platform. You can run this again from Settings whenever you add new products.

) : (

Products sent to Mintall. Run again from Settings after adding new products.

)}
{/* Step 2: Auto-protect your catalog */}

Auto-protect your catalog

{allStepsComplete && autoProtect && ( On )} {allStepsComplete && !autoProtect && ( Off )}
{!allStepsComplete ? (

Complete the previous steps to unlock.

) : ( <>

All current and future products are automatically protected — free.

)}
{/* Step 3: Auto AI visibility */}

Auto AI visibility

{allStepsComplete && visibilityOnProtect && ( On )} {allStepsComplete && !visibilityOnProtect && ( Off )}
{!allStepsComplete ? (

Complete the previous steps to unlock.

) : ( <>

AI visibility is automatically enabled on protect. Uses 1 credit per product.

)}
{/* Step 4: Verify your custom domain */}

Verify your custom domain

{verifyDomainComplete && status.domain_verification_status === 'verified' && ( Verified )}
{renderVerifyDomainBody(status)}

Page-view capture (optional)

{status.page_view_capture_decided && ( {status.page_view_capture ? 'On' : 'Off'} )}
)}
); } function renderVerifyDomainBody(status: SetupStatusResponse): JSX.Element { const { host_is_verifiable: hostIsVerifiable, current_site_host: currentHost, domain_verification_status: domainStatus, domain_verification_domain: registeredDomain, } = status; if (!hostIsVerifiable) { return ( <>

Your WordPress Site Address ({currentHost ?? 'unset'}) isn't a public domain, so DNS verification can't run yet. Update Settings → General → Site Address (URL){' '} to your custom domain (for example, https://shop.example.com ), then reconnect Mintall to register it.

); } if (domainStatus === 'verified') { return (

{registeredDomain ?? currentHost ?? 'Your domain'} is verified. Verified domains earn a trust boost on every product certificate.

); } let description: string; if (domainStatus === 'failed') { description = "Your DNS TXT record was found but the value doesn't match. Open Settings → Domain verification to view the correct value."; } else if (domainStatus === 'expired') { description = 'Your verification token has expired. Open Settings → Domain verification to reissue a new token.'; } else if (domainStatus === 'pending') { description = `Verification is in progress for ${ registeredDomain ?? currentHost ?? 'your domain' }. Finish adding the DNS TXT record in Settings → Domain verification.`; } else { description = `Prove you own ${ currentHost ?? 'your storefront domain' } by adding a DNS TXT record. Verified domains earn a trust boost on every product certificate.`; } return ( <>

{description}

); }