Contexte
Intègre le panneau latéral "Représentation équilibrée" dans mon-espace : 4 états (A non commencée / B en cours / C transmise modifiable / D lecture seule), boutons Déclarer/Reprendre/Modifier/Consulter, téléchargement PDF, deadline. Branche le lien DeclarationLink type="representation" actuellement placeholder sur cette nouvelle infra. Issue parent #3287. Dépend de #3291, #3298.
La distinction entre état C (modifiable) et D (lecture seule) est déterminée par la deadline repeqModificationDeadline stockée dans la table campaign_deadlines (cf. #3288, décision architecturale Q2). Le panneau lit cette deadline via getRepeqModificationDeadline(campaignDeadlines, year) depuis ~/modules/domain (cf. #3289).
Fichiers impactés
packages/app/src/modules/my-space/RepresentationProcessPanel.tsx (création)
packages/app/src/modules/my-space/RepresentationProcessPanel.module.scss (création — ou réutiliser DeclarationProcessPanel.module.scss si identique)
packages/app/src/modules/my-space/representationProcessState.ts (création — computeRepresentationPanelVariant, computeRepresentationCtaHref)
packages/app/src/modules/my-space/__tests__/RepresentationProcessPanel.test.tsx (création)
packages/app/src/modules/my-space/__tests__/representationProcessState.test.ts (création)
packages/app/src/modules/my-space/DeclarationLink.tsx (modification — type="representation" ouvre RepresentationProcessPanel)
packages/app/src/modules/my-space/CompanyDeclarationsPage.tsx (modification — charger la repeq de l'année + rendre RepresentationProcessPanel avec la deadline)
packages/app/src/modules/my-space/types.ts (modification — étendre DeclarationItem si besoin pour repeq fields ou créer un RepresentationItem)
packages/app/src/modules/my-space/buildDeclarationList.ts (modification — intégrer les repeq pour chaque année)
packages/app/src/server/api/routers/company.ts (modification — getWithDeclarations joint la table repeq et remplit les champs)
Changement attendu
representationProcessState.ts :
computeRepresentationPanelVariant(declaration: RepresentationItem | undefined, modificationDeadline: Date, now?: Date): "start" | "in_progress" | "submitted_modifiable" | "read_only" — pattern computePanelVariant adapté aux 4 états :
- "start" si pas de ligne ou status
draft/to_complete.
- "in_progress" si
status === "in_progress".
- "submitted_modifiable" si
submitted && !isDeadlinePassed(modificationDeadline, now).
- "read_only" si
submitted && isDeadlinePassed(modificationDeadline, now).
now est injecté pour la testabilité (pattern déjà en usage dans declarationProcessState).
computeRepresentationCtaHref(declaration, siren) — retourne /representation-equilibree/etape/N où N = currentStep si in_progress, /etape/1 sinon ; pour "submitted_modifiable", pointe vers /etape/1 (accès direct RGAA N°15/N°17).
RepresentationProcessPanel : pattern DeclarationProcessPanel adapté.
- Dialog DSFR (
<dialog role="dialog" aria-labelledby>).
- Props :
{ variant, year, lastActionDate, siren, ctaHref, modificationDeadline }.
- Selon variant :
- A (start) : alerte info "Déclarez chaque année…" + deadline (
getRepeqDeclarationDeadline(year)) + lien "En savoir plus" + bouton "Déclarer" primaire.
- B (in_progress) : stepper vertical 4 étapes (reproduit le pattern
VerticalStepper ou en crée un nouveau RepresentationVerticalStepper si les étapes diffèrent trop) + bouton "Reprendre la déclaration" primaire.
- C (submitted_modifiable) : alerte success + deadline (format DSFR à partir de
modificationDeadline passée en prop) + <DownloadRepeqPdfButton /> + 2 boutons ("Modifier" primaire → /etape/1, "Consulter" secondaire → /representation-equilibree/{siren}/{year}).
- D (read_only) : alerte info +
<DownloadRepeqPdfButton /> + bouton unique "Consulter" secondaire.
- DeclarationLink : remplace le placeholder actuel (
type === "representation" → bouton inerte) par un bouton qui ouvre REPRESENTATION_PROCESS_PANEL_ID (même pattern que remuneration).
- CompanyDeclarationsPage : ajoute
<RepresentationProcessPanel {...} /> après DeclarationProcessPanel. Calcule la variant via computeRepresentationPanelVariant(repeqItem, getRepeqModificationDeadline(campaignDeadlines, year)).
- Company router
getWithDeclarations : modifie la requête pour joindre la table representationEquilibreeDeclarations et renvoyer pour chaque année un item de type "representation" avec les champs pertinents (status, currentStep, updatedAt, submittedAt). Intègre dans buildDeclarationList (étendre pour supporter les 2 types déjà prévus dans EXPECTED_DECLARATION_TYPES).
- Types : étend
DeclarationItem pour supporter type: "representation" avec les champs minimaux { type, siren, year, status, currentStep, updatedAt, submittedAt }. Les champs actuels spécifiques rémunération (compliancePath, secondDeclarationStatus, etc.) restent optionnels/nullables pour les lignes repeq.
- Tests :
representationProcessState.test.ts : 4 cas de variants (start / in_progress / submitted_modifiable avec deadline future / read_only avec deadline dépassée) + 2 cas de ctaHref.
RepresentationProcessPanel.test.tsx : rendu des 4 états (snapshot ou assertions ciblées). Assertion clé : état D (read_only) n'affiche pas le bouton "Modifier".
DeclarationLink.test.tsx (existant) : ajout d'un test que type="representation" rend un bouton aria-controls={REPRESENTATION_PROCESS_PANEL_ID}.
buildDeclarationList.test.ts : ajout de lignes repeq en plus de remuneration.
Scénarios de test
- S1 — État A, clic "Déclarer" → panneau ouvert, bouton primaire route
/representation-equilibree/etape/1.
- S11 — État C (deadline non dépassée), clic "Modifier" → route
/representation-equilibree/etape/1 (accès direct, pas via récap).
- S12 — État D (deadline dépassée), pas de bouton "Modifier", seul "Consulter" + PDF.
Références visuelles
Desktop

Mobile

Annexe pipeline (lecture locale par code-dev / design-validator) :
/tmp/egapro-mocks/epic-3287/screenshots/mon-espace-side-panel-desktop.png
/tmp/egapro-mocks/epic-3287/screenshots/mon-espace-side-panel-mobile.png
Critères d'acceptation
Depends on
Contexte
Intègre le panneau latéral "Représentation équilibrée" dans mon-espace : 4 états (A non commencée / B en cours / C transmise modifiable / D lecture seule), boutons Déclarer/Reprendre/Modifier/Consulter, téléchargement PDF, deadline. Branche le lien
DeclarationLink type="representation"actuellement placeholder sur cette nouvelle infra. Issue parent #3287. Dépend de #3291, #3298.La distinction entre état C (modifiable) et D (lecture seule) est déterminée par la deadline
repeqModificationDeadlinestockée dans la tablecampaign_deadlines(cf. #3288, décision architecturale Q2). Le panneau lit cette deadline viagetRepeqModificationDeadline(campaignDeadlines, year)depuis~/modules/domain(cf. #3289).Fichiers impactés
packages/app/src/modules/my-space/RepresentationProcessPanel.tsx(création)packages/app/src/modules/my-space/RepresentationProcessPanel.module.scss(création — ou réutiliserDeclarationProcessPanel.module.scsssi identique)packages/app/src/modules/my-space/representationProcessState.ts(création —computeRepresentationPanelVariant,computeRepresentationCtaHref)packages/app/src/modules/my-space/__tests__/RepresentationProcessPanel.test.tsx(création)packages/app/src/modules/my-space/__tests__/representationProcessState.test.ts(création)packages/app/src/modules/my-space/DeclarationLink.tsx(modification — type="representation" ouvreRepresentationProcessPanel)packages/app/src/modules/my-space/CompanyDeclarationsPage.tsx(modification — charger la repeq de l'année + rendreRepresentationProcessPanelavec la deadline)packages/app/src/modules/my-space/types.ts(modification — étendreDeclarationItemsi besoin pour repeq fields ou créer unRepresentationItem)packages/app/src/modules/my-space/buildDeclarationList.ts(modification — intégrer les repeq pour chaque année)packages/app/src/server/api/routers/company.ts(modification —getWithDeclarationsjoint la table repeq et remplit les champs)Changement attendu
representationProcessState.ts:computeRepresentationPanelVariant(declaration: RepresentationItem | undefined, modificationDeadline: Date, now?: Date): "start" | "in_progress" | "submitted_modifiable" | "read_only"— patterncomputePanelVariantadapté aux 4 états :draft/to_complete.status === "in_progress".submitted&&!isDeadlinePassed(modificationDeadline, now).submitted&&isDeadlinePassed(modificationDeadline, now).nowest injecté pour la testabilité (pattern déjà en usage dansdeclarationProcessState).computeRepresentationCtaHref(declaration, siren)— retourne/representation-equilibree/etape/Noù N =currentStepsi in_progress,/etape/1sinon ; pour "submitted_modifiable", pointe vers/etape/1(accès direct RGAA N°15/N°17).RepresentationProcessPanel: patternDeclarationProcessPaneladapté.<dialog role="dialog" aria-labelledby>).{ variant, year, lastActionDate, siren, ctaHref, modificationDeadline }.getRepeqDeclarationDeadline(year)) + lien "En savoir plus" + bouton "Déclarer" primaire.VerticalStepperou en crée un nouveauRepresentationVerticalSteppersi les étapes diffèrent trop) + bouton "Reprendre la déclaration" primaire.modificationDeadlinepassée en prop) +<DownloadRepeqPdfButton />+ 2 boutons ("Modifier" primaire →/etape/1, "Consulter" secondaire →/representation-equilibree/{siren}/{year}).<DownloadRepeqPdfButton />+ bouton unique "Consulter" secondaire.type === "representation"→ bouton inerte) par un bouton qui ouvreREPRESENTATION_PROCESS_PANEL_ID(même pattern que remuneration).<RepresentationProcessPanel {...} />aprèsDeclarationProcessPanel. Calcule la variant viacomputeRepresentationPanelVariant(repeqItem, getRepeqModificationDeadline(campaignDeadlines, year)).getWithDeclarations: modifie la requête pour joindre la tablerepresentationEquilibreeDeclarationset renvoyer pour chaque année un item de type"representation"avec les champs pertinents (status,currentStep,updatedAt,submittedAt). Intègre dansbuildDeclarationList(étendre pour supporter les 2 types déjà prévus dansEXPECTED_DECLARATION_TYPES).DeclarationItempour supportertype: "representation"avec les champs minimaux{ type, siren, year, status, currentStep, updatedAt, submittedAt }. Les champs actuels spécifiques rémunération (compliancePath,secondDeclarationStatus, etc.) restent optionnels/nullables pour les lignes repeq.representationProcessState.test.ts: 4 cas de variants (start / in_progress / submitted_modifiable avec deadline future / read_only avec deadline dépassée) + 2 cas de ctaHref.RepresentationProcessPanel.test.tsx: rendu des 4 états (snapshot ou assertions ciblées). Assertion clé : état D (read_only) n'affiche pas le bouton "Modifier".DeclarationLink.test.tsx(existant) : ajout d'un test quetype="representation"rend un boutonaria-controls={REPRESENTATION_PROCESS_PANEL_ID}.buildDeclarationList.test.ts: ajout de lignes repeq en plus de remuneration.Scénarios de test
/representation-equilibree/etape/1./representation-equilibree/etape/1(accès direct, pas via récap).Références visuelles
Desktop

Mobile

Annexe pipeline (lecture locale par code-dev / design-validator) :
/tmp/egapro-mocks/epic-3287/screenshots/mon-espace-side-panel-desktop.png/tmp/egapro-mocks/epic-3287/screenshots/mon-espace-side-panel-mobile.pngCritères d'acceptation
getRepeqModificationDeadline(campaignDeadlines, year)depuis~/modules/domain(pas de date hardcodée)fr-alertaffichée dans le panneau (info deadline, succès transmission) possède unfr-alert__titleconforme DSFR (RGAA N°33)pnpm typecheck+pnpm lint:check+pnpm format:check+pnpm testvertsrole="dialog"+aria-modal+aria-labelledbymon-espace-side-panel-*.pngpour les 4 étatsDepends on