Skip to content

Commit 19fcd32

Browse files
authored
fix(my-space): update side panel step colors and second-round choice state (#3207) (#3280)
1 parent 41e4e53 commit 19fcd32

4 files changed

Lines changed: 192 additions & 57 deletions

File tree

packages/app/src/e2e/declaration-process-panel.e2e.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,35 @@ test.describe("Declaration process panel", () => {
9595
});
9696
});
9797

98+
test.describe("Variant: evaluation (corrective_action, 2nd decl submitted, second-round choice pending)", () => {
99+
test.beforeAll(async () => {
100+
await setDeclarationComplianceState({
101+
compliancePath: "corrective_action",
102+
secondDeclarationStatus: "submitted",
103+
});
104+
});
105+
106+
test("shows second declaration transmitted without evaluation conjointe bullet", async ({
107+
page,
108+
}) => {
109+
await page.context().clearCookies();
110+
await loginWithProConnect(page);
111+
await waitForDsfrModal(page, PANEL_ID);
112+
113+
const panel = page.locator(`#${PANEL_ID}`);
114+
const remuButton = page.getByRole("button", { name: "Rémunération" });
115+
await expect(remuButton.first()).toBeVisible();
116+
await clickAndExpectDialogOpen(page, remuButton.first(), PANEL_ID);
117+
118+
await expect(
119+
panel.getByText("Votre seconde déclaration a été transmise"),
120+
).toBeVisible();
121+
await expect(
122+
panel.getByText("Évaluation conjointe des rémunérations"),
123+
).toHaveCount(0);
124+
});
125+
});
126+
98127
test.describe("Variant: evaluation (joint_evaluation path, file not uploaded)", () => {
99128
test.beforeAll(async () => {
100129
await setDeclarationComplianceState({

packages/app/src/modules/my-space/DeclarationProcessPanel.module.scss

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,34 @@
4444
}
4545

4646
.stepRow {
47+
position: relative;
4748
display: flex;
4849
gap: 1rem;
4950
align-items: flex-start;
5051
}
5152

53+
.stepRow:not(:last-child) {
54+
padding-bottom: 1rem;
55+
}
56+
57+
.stepRow:not(:last-child)::before {
58+
content: "";
59+
position: absolute;
60+
left: 13.5px;
61+
top: 28px;
62+
bottom: 0;
63+
width: 1px;
64+
background-color: var(--border-default-grey);
65+
}
66+
67+
.stepRowComplete:not(:last-child)::before {
68+
background-color: var(--background-flat-success);
69+
}
70+
71+
.stepRowCurrent:not(:last-child)::before {
72+
background-color: var(--background-action-high-info);
73+
}
74+
5275
.stepCircle {
5376
width: 28px;
5477
height: 28px;
@@ -64,7 +87,7 @@
6487
}
6588

6689
.stepCircleCurrent {
67-
background-color: var(--blue-france-main-525);
90+
background-color: var(--background-action-high-info);
6891
}
6992

7093
.stepCirclePending {
@@ -75,13 +98,6 @@
7598
background-color: var(--background-flat-success);
7699
}
77100

78-
.stepLine {
79-
width: 1px;
80-
min-height: 1rem;
81-
margin-left: 14px;
82-
background-color: var(--border-default-grey);
83-
}
84-
85101
.stepContent {
86102
display: flex;
87103
flex-direction: column;
@@ -94,7 +110,7 @@
94110
.transmittedRow {
95111
display: flex;
96112
gap: 0.5rem;
97-
align-items: center;
113+
align-items: flex-start;
98114
width: 100%;
99115
}
100116

packages/app/src/modules/my-space/VerticalStepper.tsx

Lines changed: 103 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
import type { ReactNode } from "react";
2+
13
import type { CampaignDeadlines } from "~/modules/domain";
2-
import { formatLongDate, isDeadlinePassed } from "~/modules/domain";
4+
import { isDeadlinePassed } from "~/modules/domain";
35
import type { PanelVariant } from "./DeclarationProcessPanel";
46
import 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+
82106
function 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

184203
function 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 &ge; 5&nbsp;%
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({
273316
function 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

Comments
 (0)