From ae8d8af1df5895f7f572a71ca8a9f48065e8f503 Mon Sep 17 00:00:00 2001 From: Hermann_Kitio Date: Tue, 21 Apr 2026 04:52:51 +0300 Subject: [PATCH] =?UTF-8?q?feat(simulations):=20resume=20session=20+=20Rap?= =?UTF-8?q?portPage=20tol=C3=A8re=20rapport=3Dnull=20(FTD-21)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/entities/report/api.ts | 21 ++++++++++-- .../simulations/pages/RapportPage.tsx | 32 +++++++++++++++++-- 2 files changed, 48 insertions(+), 5 deletions(-) diff --git a/src/entities/report/api.ts b/src/entities/report/api.ts index fc6b9bf..cfd382a 100644 --- a/src/entities/report/api.ts +++ b/src/entities/report/api.ts @@ -11,11 +11,28 @@ */ import { apiFetch } from '@/shared/lib/api-client' +import { getSimulationState } from '@/entities/production/api' import type { CorrectEePayload, CorrectEoPayload, Report } from './types' -/** Récupère un rapport existant. Endpoint : `GET /simulations/:id`. */ +/** + * Récupère un rapport existant. Endpoint : `GET /simulations/:id`. + * + * FTD-21 : depuis l'assouplissement de `getById` côté backend (tolère `rapport=null` + * pour permettre le resume), on unwrap le champ `rapport` du `SimulationState`. + * Si la simulation est encore en cours (`rapport === null`), on lève une erreur + * typée `REPORT_NOT_READY` que RapportPage catche pour rediriger vers /simulation/ee. + */ export function getReport(id: string): Promise { - return apiFetch(`/simulations/${id}`) + return getSimulationState(id).then((state) => { + if (state.rapport === null) { + throw { + error: true, + code: 'REPORT_NOT_READY', + message: 'Simulation en cours — rédaction pas encore corrigée.', + } + } + return { ...state.rapport, simulation_id: state.simulation_id } + }) } const CORRECTION_TIMEOUT_MS = 30_000 diff --git a/src/features/simulations/pages/RapportPage.tsx b/src/features/simulations/pages/RapportPage.tsx index 2a8f5ed..2f86b7a 100644 --- a/src/features/simulations/pages/RapportPage.tsx +++ b/src/features/simulations/pages/RapportPage.tsx @@ -11,6 +11,7 @@ * Règle H : logique de floutage dans entities/report/lib.ts. */ +import { useEffect } from 'react' import ReactMarkdown from 'react-markdown' import { Link, useNavigate, useParams } from 'react-router-dom' import { useQuery } from '@tanstack/react-query' @@ -23,6 +24,15 @@ import { Badge } from '@/shared/ui/Badge' import { Button } from '@/shared/ui/Button' import type { Critere } from '@/entities/report/types' +function isReportNotReady(err: unknown): boolean { + return ( + typeof err === 'object' && + err !== null && + 'code' in err && + (err as { code: unknown }).code === 'REPORT_NOT_READY' + ) +} + // ── Composants internes ────────────────────────────────────────────────────── function RapportSkeleton() { @@ -105,7 +115,16 @@ export function RapportPage() { const { id = '' } = useParams<{ id: string }>() const navigate = useNavigate() - const { rapport, isLoading, isError } = useRapport(id) + const { rapport, isLoading, isError, error } = useRapport(id) + const isInProgress = isError && isReportNotReady(error) + + // FTD-21 — si la simulation n'est pas encore corrigée, rediriger vers /simulation/ee. + // Le SimulationFlowProvider restaurera la session via localStorage si présent. + useEffect(() => { + if (isInProgress) { + navigate('/simulation/ee', { replace: true }) + } + }, [isInProgress, navigate]) const { data: planData, @@ -137,8 +156,15 @@ export function RapportPage() { {/* Loading */} {(isLoading || isPlanLoading) && } - {/* Erreur */} - {(isError || isPlanError) && !isLoading && !isPlanLoading && ( + {/* FTD-21 — simulation en cours : message discret avant redirection via useEffect */} + {isInProgress && ( +

+ Votre simulation est en cours. +

+ )} + + {/* Erreur (hors "en cours" déjà géré au-dessus) */} + {(isError || isPlanError) && !isInProgress && !isLoading && !isPlanLoading && (