feat(simulations): SimulationFlowProvider + SujetsPage + SujetCard
This commit is contained in:
parent
7902eec042
commit
782439b309
3 changed files with 278 additions and 0 deletions
117
src/features/simulations/state/SimulationFlowProvider.tsx
Normal file
117
src/features/simulations/state/SimulationFlowProvider.tsx
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
/**
|
||||
* Provider de flux simulation — partage l'état entre /simulation/ee et /sujets.
|
||||
*
|
||||
* Hérite de la state machine de useSimulation mais déplace la source de vérité
|
||||
* hors du hook pour qu'elle survive aux navigations React Router (Option A — cf.
|
||||
* plan de refonte UX "page /sujets avec cartes").
|
||||
*
|
||||
* Règle H : aucune logique métier — les mutations s'appuient sur entities/.
|
||||
*/
|
||||
|
||||
import { createContext, useContext, useState, type ReactNode } from 'react'
|
||||
import { useMutation } from '@tanstack/react-query'
|
||||
import { createSimulation } from '@/entities/production/api'
|
||||
import { correctEe } from '@/entities/report/api'
|
||||
import type {
|
||||
CreateSimulationPayload,
|
||||
Production,
|
||||
SujetData,
|
||||
Tache,
|
||||
} from '@/entities/production/types'
|
||||
import type { Report } from '@/entities/report/types'
|
||||
import type { ApiError } from '@/shared/types/api'
|
||||
|
||||
export type SimulationStep =
|
||||
| 'idle'
|
||||
| 'choosing-subject'
|
||||
| 'task-selected'
|
||||
| 'correcting'
|
||||
| 'done'
|
||||
|
||||
const TACHES_SANS_CATALOGUE: Tache[] = ['EO_T1']
|
||||
|
||||
interface FlowValue {
|
||||
step: SimulationStep
|
||||
production: Production | null
|
||||
sujet: SujetData | null
|
||||
report: Report | null
|
||||
isCreating: boolean
|
||||
isCorrecting: boolean
|
||||
createError: ApiError | null
|
||||
correctError: ApiError | null
|
||||
selectTask: (payload: CreateSimulationPayload) => void
|
||||
submitText: (texte: string) => void
|
||||
changeSubject: (sujet: SujetData) => void
|
||||
setStep: (step: SimulationStep) => void
|
||||
reset: () => void
|
||||
}
|
||||
|
||||
const SimulationFlowContext = createContext<FlowValue | null>(null)
|
||||
|
||||
export function SimulationFlowProvider({ children }: { children: ReactNode }) {
|
||||
const [step, setStep] = useState<SimulationStep>('idle')
|
||||
const [production, setProduction] = useState<Production | null>(null)
|
||||
|
||||
const createMutation = useMutation({
|
||||
mutationFn: createSimulation,
|
||||
onSuccess: (data) => {
|
||||
setProduction(data)
|
||||
setStep(TACHES_SANS_CATALOGUE.includes(data.tache) ? 'task-selected' : 'choosing-subject')
|
||||
},
|
||||
})
|
||||
|
||||
const correctMutation = useMutation({
|
||||
mutationFn: correctEe,
|
||||
onMutate: () => setStep('correcting'),
|
||||
onSuccess: () => setStep('done'),
|
||||
onError: () => setStep('task-selected'),
|
||||
})
|
||||
|
||||
function selectTask(payload: CreateSimulationPayload): void {
|
||||
createMutation.mutate(payload)
|
||||
}
|
||||
|
||||
function submitText(texte: string): void {
|
||||
if (!production) return
|
||||
correctMutation.mutate({ simulationId: production.id, contenu: texte, tache: production.tache })
|
||||
}
|
||||
|
||||
function changeSubject(sujet: SujetData): void {
|
||||
setProduction((p) => (p ? { ...p, sujet } : p))
|
||||
}
|
||||
|
||||
function reset(): void {
|
||||
setStep('idle')
|
||||
setProduction(null)
|
||||
createMutation.reset()
|
||||
correctMutation.reset()
|
||||
}
|
||||
|
||||
const value: FlowValue = {
|
||||
step,
|
||||
production,
|
||||
sujet: production?.sujet ?? null,
|
||||
report: (correctMutation.data ?? null) as Report | null,
|
||||
isCreating: createMutation.isPending,
|
||||
isCorrecting: correctMutation.isPending,
|
||||
createError: createMutation.error as ApiError | null,
|
||||
correctError: correctMutation.error as ApiError | null,
|
||||
selectTask,
|
||||
submitText,
|
||||
changeSubject,
|
||||
setStep,
|
||||
reset,
|
||||
}
|
||||
|
||||
return (
|
||||
<SimulationFlowContext.Provider value={value}>{children}</SimulationFlowContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
export function useSimulationFlow(): FlowValue {
|
||||
const ctx = useContext(SimulationFlowContext)
|
||||
if (!ctx) {
|
||||
throw new Error('useSimulationFlow doit être utilisé dans un <SimulationFlowProvider>.')
|
||||
}
|
||||
return ctx
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue