fix(rapport): patch temporaire conclusion conseil_nclc quand NCLC dépassé (FTD-40, FTD-41)

This commit is contained in:
Hermann_Kitio 2026-04-25 21:16:00 +03:00
parent 822b02a2d1
commit 06fbfe3f9b
4 changed files with 148 additions and 33 deletions

View file

@ -9,13 +9,20 @@
import ReactMarkdown from 'react-markdown'
import { Card } from '@/shared/ui/Card'
import type { ConseilNclc } from '@/entities/report/types'
import type { ConseilNclc, NclcCible } from '@/entities/report/types'
interface Props {
conseil: ConseilNclc
nclc: number
nclcCible: NclcCible
}
export function ConseilNclcCallout({ conseil }: Props) {
export function ConseilNclcCallout({ conseil, nclc, nclcCible }: Props) {
// PATCH TEMPORAIRE — à retirer quand FTD-40 (fix prompt backend) est résolu.
// Le prompt maître DeepSeek génère un message d'encouragement vers `nclcCible`
// même quand `nclc > nclcCible` ; on substitue alors un texte cohérent.
const depasse = nclc > nclcCible
return (
<section aria-label="Plan d'action NCLC">
<h2 className="mb-3 text-base font-semibold text-ink-primary">Plan d'action NCLC</h2>
@ -35,9 +42,16 @@ export function ConseilNclcCallout({ conseil }: Props) {
Action prioritaire
</p>
<div className="text-sm leading-relaxed text-ink-primary">
<ReactMarkdown disallowedElements={['script', 'iframe']}>
{conseil.action_prioritaire}
</ReactMarkdown>
{depasse ? (
<p>
Excellent travail vous avez dépassé votre objectif. Continuez sur cette lancée
pour viser NCLC {nclc + 1} !
</p>
) : (
<ReactMarkdown disallowedElements={['script', 'iframe']}>
{conseil.action_prioritaire}
</ReactMarkdown>
)}
</div>
</div>
</Card>

View file

@ -0,0 +1,43 @@
/**
* Tests ConseilNclcCallout (Sprint 4.5).
*
* Couvre le patch temporaire FTD-40 :
* - nclc < cible : affiche action_prioritaire backend
* - nclc = cible : affiche action_prioritaire backend
* - nclc > cible : substitue le texte par « Excellent travail NCLC {nclc+1} »
*/
import { describe, it, expect, afterEach } from 'vitest'
import { render, screen, cleanup } from '@testing-library/react'
import { ConseilNclcCallout } from '../ConseilNclcCallout'
import type { ConseilNclc } from '@/entities/report/types'
afterEach(cleanup)
const conseil: ConseilNclc = {
nclc_cible: 'NCLC 9',
ecart: '2 points',
action_prioritaire: 'Concentre-toi sur les connecteurs logiques pour atteindre NCLC 9.',
}
describe('ConseilNclcCallout — patch FTD-40', () => {
it('nclc < cible : rend action_prioritaire backend', () => {
render(<ConseilNclcCallout conseil={conseil} nclc={8} nclcCible={9} />)
expect(screen.getByText(/connecteurs logiques/i)).toBeInTheDocument()
})
it('nclc = cible : rend action_prioritaire backend', () => {
render(<ConseilNclcCallout conseil={conseil} nclc={9} nclcCible={9} />)
expect(screen.getByText(/connecteurs logiques/i)).toBeInTheDocument()
})
it('nclc > cible : substitue par texte fixe avec NCLC {nclc+1}', () => {
render(<ConseilNclcCallout conseil={conseil} nclc={10} nclcCible={9} />)
expect(
screen.getByText(
/Excellent travail — vous avez dépassé votre objectif\. Continuez sur cette lancée pour viser NCLC 11 !/,
),
).toBeInTheDocument()
expect(screen.queryByText(/connecteurs logiques/i)).not.toBeInTheDocument()
})
})

View file

@ -268,7 +268,11 @@ export function RapportPage() {
<CriteresSection rapport={rapport} />
</BlurredSection>
<ConseilNclcCallout conseil={rapport.conseil_nclc} />
<ConseilNclcCallout
conseil={rapport.conseil_nclc}
nclc={rapport.nclc}
nclcCible={rapport.nclc_cible}
/>
<BlurredSection
visible={isSectionVisible(planData.plan, 'exercices')}