/** * Page de simulation Expression Écrite. * * Orchestre les 3 étapes du flux : sélection de tâche → saisie → rapport. * Le choix du sujet est délégué à la page /sujets (refonte UX 2026-04-21). * * Règle D : quotas et permissions passent par canSimulate() — jamais de plan === '...' * Règle H : aucune logique métier — tout est dans useSimulation() et les entités. */ import { usePlan } from '@/features/dashboard/hooks/usePlan' import { Button } from '@/shared/ui/Button' import { useSimulation } from '../hooks/useSimulation' import { TaskSelector } from '../components/TaskSelector' import { SimulationForm } from '../components/SimulationForm' function SimulationSkeleton() { return (
{Array.from({ length: 6 }).map((_, i) => (
))}
) } export function SimulationPage() { const { data: planData, isLoading: isPlanLoading, isError: isPlanError, refetch: refetchPlan, } = usePlan() const { step, production, sujet, isCreating, isCorrecting, correctError, selectTask, submitText, goToSubjectPicker, reset, } = useSimulation() // Le reset sticky (step='done' ou 'choosing-subject' au retour) est déclenché // explicitement par les callers qui ramènent vers /simulation/ee : // - RapportPage.goToSimulations : reset() avant navigate // - SujetsPage bouton « ← Retour » : reset() avant navigate // Un useEffect réactif ici annulerait les transitions légitimes de // createMutation.onSuccess (idle → choosing-subject → navigate /sujets). return (
{isPlanLoading && } {isPlanError && (

Impossible de charger vos informations. Réessayez dans quelques instants.

)} {planData && step === 'idle' && ( )} {planData && (step === 'task-selected' || step === 'correcting') && production && ( )}
) }