Contexte
Crée la page de confirmation de transmission /representation-equilibree/transmise/[year] + l'email d'accusé de réception (template Brevo via sendReceipt). Déclenché après submit (ticket 09). L'email est envoyé avec le PDF récap en pièce jointe. Issue parent #3287. Dépend de #TICKET_ROUTER, #TICKET_PDF, #TICKET_STEP4.
Fichiers impactés
packages/app/src/app/representation-equilibree/transmise/[year]/page.tsx (création)
packages/app/src/modules/representation-equilibree/TransmittedPage.tsx (création)
packages/app/src/modules/representation-equilibree/__tests__/TransmittedPage.test.tsx (création)
packages/app/src/modules/mail/templates/repeqReceipt.ts (création)
packages/app/src/modules/mail/buildReceiptAttachments.ts (modification — ajouter buildRepeqAttachments)
packages/app/src/modules/mail/sendReceipt.ts (modification — étendre ReceiptKind avec "repeq", ajouter branche template + attachments)
packages/app/src/modules/mail/__tests__/templates.test.ts (modification — couvrir repeq)
packages/app/src/server/api/routers/representationEquilibree.ts (modification — submit déclenche sendReceipt({ kind: "repeq", ... }))
Changement attendu
- Template email (
repeqReceipt.ts) : pattern declarationReceipt.ts, sujet "Accusé de réception — Représentation équilibrée {year}", HTML concis (via wrapEmail) reprenant SIREN formaté + année + rappel que le PDF est en pièce jointe. Un seul CTA optionnel vers /representation-equilibree/[siren]/[year] (page consultation, ticket 14).
- Attachment (
buildReceiptAttachments.ts) : buildRepeqAttachments(siren, year) — appelle buildRepeqPdfData, renderToBuffer(RepeqPdfDocument({ data })), retourne un MailAttachment avec filename representation-equilibree-{siren}-{year}.pdf.
sendReceipt.ts : étend ReceiptKind = "declaration" | "secondDeclaration" | "cseOpinion" | "repeq". buildTemplate et buildAttachments gèrent la branche "repeq".
- Router
submit : après persistance du status = "submitted", appelle await sendReceipt({ kind: "repeq", to: session.user.email, siren, year, userId: session.user.id, isResend: false }). Ne bloque pas la mutation si l'envoi échoue (déjà géré par sendReceipt via try/catch interne). Audit logging : MAIL_RECEIPT_SEND / MAIL_RECEIPT_RESEND existent déjà et seront loguées par sendReceipt.
TransmittedPage (client/server component mix) :
- Server : fetch
api.representationEquilibree.getBySirenAndYear pour vérifier que la déclaration existe et est submitted, sinon notFound().
- Bannière
CompanyBanner.
fr-alert--success : "Votre déclaration a bien été transmise." + "Un email de confirmation a été envoyé à {userEmail}."
<dl> récap : Numéro de transmission (= declarationId raccourci), Date de transmission, Année, Modifiable jusqu'au getRepeqDeclarationDeadline(year).
- Callout DSFR avec bouton
<DownloadRepeqPdfButton year={year} /> (RGAA N°17bis — vérifier que le download fonctionne bien).
- Liste "Et maintenant ?" : 2-3 étapes (publier sur site, info CSE).
- 2 boutons : "Retour à mon espace" primaire + "Consulter le récap" secondaire (lien vers
/representation-equilibree/[siren]/[year]).
- Route
transmise/[year]/page.tsx : params: Promise<{ year: string }>, récupère l'année, rend <TransmittedPage year={year} />.
- Tests :
templates.test.ts : branche "repeq" génère sujet et HTML attendus avec SIREN formaté.
TransmittedPage.test.tsx : rendu avec une déclaration transmise → présence de fr-alert--success, du PDF button, du lien vers consultation. Rendu avec déclaration non submitted → 404.
Scénarios de test
- S10 — Après submit, l'utilisateur arrive sur
/representation-equilibree/transmise/{year}, reçoit un email + peut télécharger le PDF.
- RGAA N°17bis — test unitaire : le bouton PDF est bien un
<a href download> (pas un <button> qui pourrait bugger).
Références visuelles
Desktop

Mobile

Annexe pipeline (lecture locale par code-dev / design-validator) :
/tmp/egapro-mocks/epic-3287/screenshots/transmission-success-desktop.png
/tmp/egapro-mocks/epic-3287/screenshots/transmission-success-mobile.png
Critères d'acceptation
Contexte
Crée la page de confirmation de transmission
/representation-equilibree/transmise/[year]+ l'email d'accusé de réception (template Brevo viasendReceipt). Déclenché aprèssubmit(ticket 09). L'email est envoyé avec le PDF récap en pièce jointe. Issue parent #3287. Dépend de #TICKET_ROUTER, #TICKET_PDF, #TICKET_STEP4.Fichiers impactés
packages/app/src/app/representation-equilibree/transmise/[year]/page.tsx(création)packages/app/src/modules/representation-equilibree/TransmittedPage.tsx(création)packages/app/src/modules/representation-equilibree/__tests__/TransmittedPage.test.tsx(création)packages/app/src/modules/mail/templates/repeqReceipt.ts(création)packages/app/src/modules/mail/buildReceiptAttachments.ts(modification — ajouterbuildRepeqAttachments)packages/app/src/modules/mail/sendReceipt.ts(modification — étendreReceiptKindavec"repeq", ajouter branche template + attachments)packages/app/src/modules/mail/__tests__/templates.test.ts(modification — couvrir repeq)packages/app/src/server/api/routers/representationEquilibree.ts(modification —submitdéclenchesendReceipt({ kind: "repeq", ... }))Changement attendu
repeqReceipt.ts) : patterndeclarationReceipt.ts, sujet "Accusé de réception — Représentation équilibrée {year}", HTML concis (viawrapEmail) reprenant SIREN formaté + année + rappel que le PDF est en pièce jointe. Un seul CTA optionnel vers/representation-equilibree/[siren]/[year](page consultation, ticket 14).buildReceiptAttachments.ts) :buildRepeqAttachments(siren, year)— appellebuildRepeqPdfData,renderToBuffer(RepeqPdfDocument({ data })), retourne unMailAttachmentavec filenamerepresentation-equilibree-{siren}-{year}.pdf.sendReceipt.ts: étendReceiptKind = "declaration" | "secondDeclaration" | "cseOpinion" | "repeq".buildTemplateetbuildAttachmentsgèrent la branche"repeq".submit: après persistance dustatus = "submitted", appelleawait sendReceipt({ kind: "repeq", to: session.user.email, siren, year, userId: session.user.id, isResend: false }). Ne bloque pas la mutation si l'envoi échoue (déjà géré parsendReceiptvia try/catch interne). Audit logging :MAIL_RECEIPT_SEND/MAIL_RECEIPT_RESENDexistent déjà et seront loguées parsendReceipt.TransmittedPage(client/server component mix) :api.representationEquilibree.getBySirenAndYearpour vérifier que la déclaration existe et estsubmitted, sinonnotFound().CompanyBanner.fr-alert--success: "Votre déclaration a bien été transmise." + "Un email de confirmation a été envoyé à {userEmail}."<dl>récap : Numéro de transmission (=declarationIdraccourci), Date de transmission, Année, Modifiable jusqu'augetRepeqDeclarationDeadline(year).<DownloadRepeqPdfButton year={year} />(RGAA N°17bis — vérifier que le download fonctionne bien)./representation-equilibree/[siren]/[year]).transmise/[year]/page.tsx:params: Promise<{ year: string }>, récupère l'année, rend<TransmittedPage year={year} />.templates.test.ts: branche"repeq"génère sujet et HTML attendus avec SIREN formaté.TransmittedPage.test.tsx: rendu avec une déclaration transmise → présence defr-alert--success, du PDF button, du lien vers consultation. Rendu avec déclaration non submitted → 404.Scénarios de test
/representation-equilibree/transmise/{year}, reçoit un email + peut télécharger le PDF.<a href download>(pas un<button>qui pourrait bugger).Références visuelles
Desktop

Mobile

Annexe pipeline (lecture locale par code-dev / design-validator) :
/tmp/egapro-mocks/epic-3287/screenshots/transmission-success-desktop.png/tmp/egapro-mocks/epic-3287/screenshots/transmission-success-mobile.pngCritères d'acceptation
/representation-equilibree/transmise/{year}rend la page de confirmationsubmitne plante pas si l'envoi email échouedownload)fr-alert__titleconforme DSFR (RGAA N°33)pnpm typecheck+pnpm lint:check+pnpm format:check+pnpm testvertstransmission-success-*.png