/** * ReadinessGateModal * * Shown when the user clicks a paid plan while their account isn't ready for * billing: profile incomplete (missing address / VAT ID) and/or email not * confirmed. Keeps the user on /dashboard/subscription so they don't lose the * plan-selection context. * * Reads readiness from AuthenticatedUserStore directly — pure client state, * no network at display time. Server-side 409 (PROFILE_INCOMPLETE / * EMAIL_NOT_VERIFIED) remains defense-in-depth for tampered clients. * * (c) 2026 TWWIM UG. All rights reserved. (www.twwim.com) */ import { AlertTriangle, MailCheck, Pencil, X, Loader2 } from 'lucide-react'; import { Link } from '@tanstack/react-router'; import { useAuthenticatedUser } from '@/features/auth/hooks/useAuthenticatedUser'; import { useProfile, useResendVerification } from '@/features/profile/hooks/useProfile'; import { useTranslation } from '@/i18n/TranslationProvider'; const FIELD_LABEL_KEYS: Record = { 'address.street': 'profileCompleteness.field.street', 'address.zip': 'profileCompleteness.field.zip', 'address.city': 'profileCompleteness.field.city', 'address.country': 'profileCompleteness.field.country', 'vatId': 'profileCompleteness.field.vatId', 'legalForm': 'profileCompleteness.field.legalForm', 'registerCourt': 'profileCompleteness.field.registerCourt', 'registerNumber': 'profileCompleteness.field.registerNumber', 'directorName': 'profileCompleteness.field.directorName', }; interface ReadinessGateModalProps { onClose: () => void; } export function ReadinessGateModal({ onClose }: ReadinessGateModalProps) { const { t } = useTranslation(); const authed = useAuthenticatedUser(); const { data: profile } = useProfile(); const resendMutation = useResendVerification(); if (!authed) return null; const { account } = authed; const needsProfile = !account.isProfileComplete; const needsVerify = !account.emailVerified; // If somehow opened while ready, close silently — caller should not have // shown us, but don't trap the user in a dead modal either. if (!needsProfile && !needsVerify) { onClose(); return null; } const editPath = profile?.isPersonal ? '/dashboard/profile' : '/dashboard/company'; const missingFieldLabels = account.missingProfileFields .map((key) => FIELD_LABEL_KEYS[key]) .filter(Boolean) .map((key) => t(key!)); return ( <>