/** * useReadinessGate * * Single source of truth for the "can this account take a billing action" * gate. A user must have: * - a verified email (account.emailVerified) * - a complete profile (account.isProfileComplete — driven by domain * checkProfileCompleteness, which now covers Pflichtangaben for * non-PERSONAL accounts) * * Both handleSelectPlan (new plan choice) and handleCompletePending (pay * an existing pending transaction) must funnel through this — silently * routing an incomplete user to /dashboard/checkout was the bug. * * (c) 2026 TWWIM UG. All rights reserved. (www.twwim.com) */ import { useCallback } from 'react'; import { useAuthenticatedUser } from '@/features/auth/hooks/useAuthenticatedUser'; export interface ReadinessGate { /** True when the user can proceed to a billing action without intervention. */ ready: boolean; /** * Wraps a billing action so it only runs when the gate is open. When the * gate is closed, calls `onBlocked` (typically `() => setShowReadinessModal(true)`) * and returns false so the caller can short-circuit. */ attempt: (proceed: () => void, onBlocked: () => void) => boolean; } export function useReadinessGate(): ReadinessGate { const authed = useAuthenticatedUser(); const account = authed?.account; const ready = !!account && account.isProfileComplete && account.emailVerified; const attempt = useCallback( (proceed: () => void, onBlocked: () => void): boolean => { if (!ready) { onBlocked(); return false; } proceed(); return true; }, [ready], ); return { ready, attempt }; }