From d395a04193179672cd70b374a33267626b01952b Mon Sep 17 00:00:00 2001 From: Hermann_Kitio Date: Tue, 21 Apr 2026 03:51:16 +0300 Subject: [PATCH] feat(production): types SimulationState + API autosave/updateSujet (FTD-21) --- src/entities/production/api.ts | 45 +++++++++++++++++++++++++++++++- src/entities/production/types.ts | 45 +++++++++++++++++++++++++++++++- 2 files changed, 88 insertions(+), 2 deletions(-) diff --git a/src/entities/production/api.ts b/src/entities/production/api.ts index a7ea0b0..a325a4b 100644 --- a/src/entities/production/api.ts +++ b/src/entities/production/api.ts @@ -9,7 +9,13 @@ */ import { apiFetch } from '@/shared/lib/api-client' -import type { CreateSimulationPayload, Production, SujetData, Tache } from './types' +import type { + CreateSimulationPayload, + Production, + SimulationState, + SujetData, + Tache, +} from './types' /** Crée une nouvelle simulation. Endpoint : `POST /simulations` (HTTP 201). */ export function createSimulation(payload: CreateSimulationPayload): Promise { @@ -21,6 +27,43 @@ export function getSimulation(id: string): Promise { return apiFetch(`/simulations/${id}`) } +/** + * FTD-21 — récupère l'état complet d'une simulation (contenu + sujet + rapport). + * Utilisé par `SimulationFlowProvider` pour restaurer une session depuis + * `localStorage.expria_simulation_id` au mount. + * + * Si `rapport === null` → simulation en cours, restaurer `/simulation/ee`. + * Sinon → simulation terminée, rediriger vers `/rapport/:id`. + */ +export function getSimulationState(id: string): Promise { + return apiFetch(`/simulations/${id}`) +} + +/** + * FTD-21 — autosave du contenu (debounce 30 s + beforeunload). + * Endpoint : `PATCH /simulations/:id/contenu`. + * Ne retourne rien : le client conserve déjà le texte localement. + */ +export async function autosaveContenu(id: string, contenu: string): Promise { + await apiFetch<{ ok: true }>(`/simulations/${id}/contenu`, { + method: 'PATCH', + body: { contenu }, + }) +} + +/** + * FTD-21 — persiste un changement de sujet côté backend. + * Endpoint : `PATCH /simulations/:id/sujet`. + * Appelé depuis `SimulationFlowProvider.changeSubject` quand l'utilisateur + * choisit un autre sujet via `/sujets`. + */ +export async function updateSujet(id: string, sujetId: string): Promise { + await apiFetch<{ sujet: SujetData }>(`/simulations/${id}/sujet`, { + method: 'PATCH', + body: { sujet_id: sujetId }, + }) +} + /** * Mappe une Tache vers les paramètres de la route `GET /sujets`. * Retourne `null` pour les tâches sans catalogue de sujets côté base diff --git a/src/entities/production/types.ts b/src/entities/production/types.ts index 4321ad7..6bcb186 100644 --- a/src/entities/production/types.ts +++ b/src/entities/production/types.ts @@ -37,8 +37,12 @@ export interface SujetData { } /** - * Réponse du backend pour `POST /simulations` (HTTP 201) et `GET /simulations/:id`. + * Réponse du backend pour `POST /simulations` (HTTP 201). * Format confirmé par l'audit backend 2026-04-17 (cf. ARCHITECTURE.md §5). + * + * FTD-21 : `contenu` et `sujet_id` sont persistés côté backend pour permettre + * la restauration de session. Ils ne sont pas retournés par `POST /simulations` + * mais peuvent être hydratés via `getSimulationState(id)` pour le resume. */ export interface Production { id: string @@ -46,6 +50,8 @@ export interface Production { mode: Mode created_at: string sujet: SujetData | null + contenu?: string + sujet_id?: string } /** Corps de la requête `POST /simulations`. */ @@ -53,3 +59,40 @@ export interface CreateSimulationPayload { tache: Tache mode: Mode } + +/** + * Réponse du backend pour `GET /simulations/:id` (FTD-21). + * + * Contrairement au `Report` pur, cette réponse porte : + * - le contenu textuel en cours (pour restaurer la textarea) + * - le sujet joint (pour restaurer `SujetDisplay`) + * - le rapport si disponible (sinon `null` → simulation en cours) + * + * Si `rapport === null`, le frontend restaure la session `/simulation/ee`. + * Sinon, il redirige vers `/rapport/:id`. + */ +export interface SimulationState { + simulation_id: string + tache: Tache + mode: Mode + created_at: string + contenu: string | null + sujet: SujetData | null + rapport: SimulationRapport | null +} + +/** + * Rapport tel que stocké par le backend (sans `simulation_id` — porté par SimulationState). + * Miroir de `EERapport` côté backend ; ré-exposé ici pour éviter l'import circulaire + * avec `entities/report/types.ts`. + */ +export interface SimulationRapport { + score: number + nclc: number + feedback_court: string + criteres: { nom: string; score: number; commentaire: string }[] + erreurs: string[] + modele: string + idees: string[] + exercices: string[] +}