1+ import type { ReactNode } from "react" ;
2+
13import type { CampaignDeadlines } from "~/modules/domain" ;
2- import { formatLongDate , isDeadlinePassed } from "~/modules/domain" ;
4+ import { isDeadlinePassed } from "~/modules/domain" ;
35import type { PanelVariant } from "./DeclarationProcessPanel" ;
46import styles from "./DeclarationProcessPanel.module.scss" ;
57
@@ -45,7 +47,7 @@ export function VerticalStepper({
4547} ) {
4648 return (
4749 < div className = { `${ styles . stepper } fr-mb-4w` } >
48- < div className = { styles . stepRow } >
50+ < div className = { ` ${ styles . stepRow } ${ stepRowClass ( step1 ) } ` } >
4951 < StepCircle number = { 1 } status = { step1 } />
5052 < Step1Content
5153 campaignDeadlines = { campaignDeadlines }
@@ -55,30 +57,52 @@ export function VerticalStepper({
5557 year = { year }
5658 />
5759 </ div >
58- < div className = { styles . stepLine } />
59- < div className = { styles . stepRow } >
60+ < div className = { `${ styles . stepRow } ${ stepRowClass ( step2 ) } ` } >
6061 < StepCircle number = { 2 } status = { step2 } />
6162 < Step2Content
6263 campaignDeadlines = { campaignDeadlines }
6364 compliancePath = { compliancePath }
6465 secondDeclarationSubmitted = { secondDeclarationSubmitted }
6566 siren = { siren }
67+ status = { step2 }
6668 variant = { variant }
6769 />
6870 </ div >
69- < div className = { styles . stepLine } />
70- < div className = { styles . stepRow } >
71+ < div className = { `${ styles . stepRow } ${ stepRowClass ( step3 ) } ` } >
7172 < StepCircle number = { 3 } status = { step3 } />
7273 < Step3Content
7374 campaignDeadlines = { campaignDeadlines }
7475 siren = { siren }
76+ status = { step3 }
7577 variant = { variant }
7678 />
7779 </ div >
7880 </ div >
7981 ) ;
8082}
8183
84+ function stepRowClass ( status : StepStatus ) : string {
85+ if ( status === "complete" ) return styles . stepRowComplete ?? "" ;
86+ if ( status === "current" ) return styles . stepRowCurrent ?? "" ;
87+ return "" ;
88+ }
89+
90+ function StepTitle ( {
91+ children,
92+ status,
93+ } : {
94+ children : ReactNode ;
95+ status : StepStatus ;
96+ } ) {
97+ return (
98+ < p
99+ className = { `fr-text--bold fr-mb-0 ${ status === "pending" ? "fr-text-mention--grey" : "" } ` . trim ( ) }
100+ >
101+ { children }
102+ </ p >
103+ ) ;
104+ }
105+
82106function StepCircle ( {
83107 status,
84108 number,
@@ -126,14 +150,17 @@ function Step1Content({
126150 year : number ;
127151} ) {
128152 const refYear = year - 1 ;
153+ const title = (
154+ < StepTitle status = { status } >
155+ Déclaration des indicateurs de rémunération
156+ </ StepTitle >
157+ ) ;
129158
130159 if ( variant === "start" ) {
131160 return (
132161 < div className = { styles . stepContent } >
133162 < div >
134- < p className = "fr-text--bold fr-mb-0" >
135- Déclaration des indicateurs de rémunération
136- </ p >
163+ { title }
137164 < p className = "fr-text--sm fr-text-mention--grey fr-mb-0" >
138165 Période de référence : 01/01/{ refYear } - 31/12/{ refYear } .
139166 </ p >
@@ -159,54 +186,53 @@ function Step1Content({
159186 if ( status === "complete" ) {
160187 return (
161188 < div className = { styles . stepContent } >
162- < p className = "fr-text--bold fr-mb-0" >
163- Déclaration des indicateurs de rémunération
164- </ p >
165- { variant !== "closed" && (
166- < TransmittedRow
167- downloadHref = "/api/declaration-pdf"
168- label = "Votre déclaration a été transmise"
169- modifiableUntil = { campaignDeadlines . decl1ModificationDeadline }
170- modifyHref = { `/declaration-remuneration/etape/1?siren=${ siren } ` }
171- />
172- ) }
189+ { title }
190+ < TransmittedRow
191+ downloadHref = "/api/declaration-pdf"
192+ label = "Votre déclaration a été transmise"
193+ modifiableUntil = { campaignDeadlines . decl1ModificationDeadline }
194+ modifyHref = { `/declaration-remuneration/etape/1?siren=${ siren } ` }
195+ />
173196 </ div >
174197 ) ;
175198 }
176199
177- return (
178- < p className = "fr-text--bold fr-mb-0" >
179- Déclaration des indicateurs de rémunération
180- </ p >
181- ) ;
200+ return title ;
182201}
183202
184203function Step2Content ( {
185204 campaignDeadlines,
186205 compliancePath,
187206 secondDeclarationSubmitted,
188207 siren,
208+ status,
189209 variant,
190210} : {
191211 campaignDeadlines : CampaignDeadlines ;
192212 compliancePath : string | null ;
193213 secondDeclarationSubmitted : boolean ;
194214 siren : string ;
215+ status : StepStatus ;
195216 variant : PanelVariant ;
196217} ) {
197218 const title = (
198- < p className = "fr-text--bold fr-mb-0" >
219+ < StepTitle status = { status } >
199220 Parcours de mise en conformité pour l'indicateur par catégorie de salariés
200221 si écarts ≥ 5 %
201- </ p >
222+ </ StepTitle >
202223 ) ;
203224
204- if ( variant === "closed" || variant === " start") {
225+ if ( variant === "start" ) {
205226 return title ;
206227 }
207228
208229 if ( variant === "compliance_choice" ) {
209- return < div className = { styles . stepContent } > { title } </ div > ;
230+ return (
231+ < div className = { styles . stepContent } >
232+ { title }
233+ < DeadlineRow date = { campaignDeadlines . decl2ModificationDeadline } />
234+ </ div >
235+ ) ;
210236 }
211237
212238 if ( variant === "compliance" ) {
@@ -223,15 +249,32 @@ function Step2Content({
223249 }
224250
225251 if ( variant === "evaluation" ) {
252+ const secondDeclTransmittedRow = secondDeclarationSubmitted ? (
253+ < TransmittedRow
254+ downloadHref = "/api/declaration-pdf?type=correction"
255+ label = "Votre seconde déclaration a été transmise"
256+ modifiableUntil = { campaignDeadlines . decl2ModificationDeadline }
257+ modifyHref = { `/declaration-remuneration/parcours-conformite/etape/1?siren=${ siren } ` }
258+ />
259+ ) : null ;
260+
261+ // Second-round choice pending: user did corrective_action + 2nd declaration
262+ // but has not committed to joint evaluation yet. Show transmitted row +
263+ // choice deadline, no "Évaluation conjointe" bullet.
264+ if ( compliancePath === "corrective_action" ) {
265+ return (
266+ < div className = { styles . stepContent } >
267+ { title }
268+ { secondDeclTransmittedRow }
269+ < DeadlineRow date = { campaignDeadlines . decl2JustificationDeadline } />
270+ </ div >
271+ ) ;
272+ }
273+
226274 return (
227275 < div className = { styles . stepContent } >
228276 { title }
229- < TransmittedRow
230- downloadHref = "/api/declaration-pdf?type=correction"
231- label = "Votre seconde déclaration a été transmise"
232- modifiableUntil = { campaignDeadlines . decl2ModificationDeadline }
233- modifyHref = { `/declaration-remuneration/parcours-conformite/etape/1?siren=${ siren } ` }
234- />
277+ { secondDeclTransmittedRow }
235278 < div className = { styles . bulletItem } >
236279 < span aria-hidden = "true" className = { styles . bullet } />
237280 < p className = "fr-mb-0" > Évaluation conjointe des rémunérations</ p >
@@ -241,7 +284,7 @@ function Step2Content({
241284 ) ;
242285 }
243286
244- // cse variant : step 2 is complete — show what was actually done
287+ // cse / closed variants : step 2 is complete — show what was actually done
245288 return (
246289 < div className = { styles . stepContent } >
247290 { title }
@@ -273,14 +316,16 @@ function Step2Content({
273316function Step3Content ( {
274317 campaignDeadlines,
275318 siren,
319+ status,
276320 variant,
277321} : {
278322 campaignDeadlines : CampaignDeadlines ;
279323 siren : string ;
324+ status : StepStatus ;
280325 variant : PanelVariant ;
281326} ) {
282327 const title = (
283- < p className = "fr-text--bold fr-mb-0" > Déposer le ou les avis du CSE</ p >
328+ < StepTitle status = { status } > Déposer le ou les avis du CSE</ StepTitle >
284329 ) ;
285330
286331 if (
@@ -329,16 +374,14 @@ function TransmittedRow({
329374
330375 return (
331376 < div className = { styles . transmittedRow } >
332- < span
333- aria-hidden = "true"
334- className = "fr-icon-check-line fr-icon--sm fr-mt-1v"
335- />
377+ < span aria-hidden = "true" className = "fr-icon-check-line fr-icon--sm" />
336378 < div className = { styles . transmittedInfo } >
337379 < p className = "fr-mb-0" > { label } </ p >
338380 < p className = "fr-text-mention--grey fr-mb-0" >
339381 { deadlinePassed
340- ? `Modification close depuis le ${ formatLongDate ( modifiableUntil ) } `
341- : `Modifiable jusqu'au ${ formatLongDate ( modifiableUntil ) } ` }
382+ ? "Modification close depuis le "
383+ : "Modifiable jusqu'au " }
384+ < OrdinalLongDate date = { modifiableUntil } />
342385 </ p >
343386 </ div >
344387 < div className = { styles . transmittedActions } >
@@ -367,8 +410,24 @@ function DeadlineRow({ date }: { date: Date }) {
367410 < div className = { styles . deadlineRow } >
368411 < span aria-hidden = "true" className = "fr-icon-calendar-line fr-icon--sm" />
369412 < p className = "fr-text--sm fr-text-mention--grey fr-mb-0" >
370- Échéance : { formatLongDate ( date ) }
413+ Échéance : < OrdinalLongDate date = { date } />
371414 </ p >
372415 </ div >
373416 ) ;
374417}
418+
419+ function OrdinalLongDate ( { date } : { date : Date } ) {
420+ const day = date . getUTCDate ( ) ;
421+ const suffix = day === 1 ? "er" : "e" ;
422+ const monthYear = new Intl . DateTimeFormat ( "fr-FR" , {
423+ month : "long" ,
424+ year : "numeric" ,
425+ timeZone : "UTC" ,
426+ } ) . format ( date ) ;
427+ return (
428+ < >
429+ { day }
430+ < sup > { suffix } </ sup > { monthYear }
431+ </ >
432+ ) ;
433+ }
0 commit comments