feat(dashboard): forgotten-bills alert (THI-329, epic final brick)#229
Conversation
…s (THI-329, epic final brick)
The payment ledger is per-period, so checkboxes naturally reset on month
rollover — which also silently hides last month's untracked bills. The
dashboard bills card now opens with a calm warning when bills due LAST month
were never ticked: 'N factures de {mois} n'ont jamais été cochées — vérifie
qu'elles ont bien été payées.'
- snapshot reads the PREVIOUS period's charge_payments too (year-wrap aware)
and exposes previousPeriod + previousMonthPaidChargeIds;
- new pure countUnpaidForPeriod(charges, paidIds, period) in the domain;
- alert text stays text-foreground (AA both themes), warning tint decorative
only — same dark-safety rule as the overdue badge.
Design note: the June spec's manual 'reset month' button became moot — the
per-period ledger IS the reset (each month starts unticked); per-bill
untick already covers corrections. Dropped with rationale (PR body).
i18n: dashboard.upcomingBills.forgottenAlert x5. Tests: 5 domain + 2 card;
full suite 1494 green. Also ships the 2026-07-19 session handoff mirror.
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Guide du·de la relecteur·riceImplémente l’alerte « factures oubliées » sur le tableau de bord en étendant le snapshot de workspace avec les données de paiements de la période précédente, en ajoutant un helper de domaine pur pour compter les charges impayées sur cette période, en raccordant le résultat à la carte des prochaines factures, et en couvrant le nouveau comportement par des tests et de la documentation. Diagramme de séquence pour le calcul et le rendu de l’alerte « factures oubliées »sequenceDiagram
actor User
participant DashboardPage
participant getWorkspaceSnapshot
participant supabase
participant countUnpaidForPeriod
participant ProchainesFacturesCard
User->>DashboardPage: request dashboard
DashboardPage->>getWorkspaceSnapshot: getWorkspaceSnapshot()
getWorkspaceSnapshot->>supabase: select charge_payments (currentYear,currentMonth)
getWorkspaceSnapshot->>supabase: select charge_payments (previousYear,previousMonth)
supabase-->>getWorkspaceSnapshot: snapshot with previousPeriod, previousMonthPaidChargeIds
getWorkspaceSnapshot-->>DashboardPage: WorkspaceSnapshot
DashboardPage->>countUnpaidForPeriod: countUnpaidForPeriod(snapshot.charges, Set(previousMonthPaidChargeIds), snapshot.previousPeriod)
countUnpaidForPeriod-->>DashboardPage: forgottenCount
DashboardPage->>ProchainesFacturesCard: ProchainesFacturesCard({charges, payments, todayIso, locale, forgottenCount, forgottenMonthLabel})
alt [forgottenCount > 0]
ProchainesFacturesCard->>ProchainesFacturesCard: render forgottenAlert
end
Modifications au niveau des fichiers
Conseils et commandesInteragir avec Sourcery
Personnaliser votre expérienceAccédez à votre dashboard pour :
Obtenir de l’aide
Original review guide in EnglishReviewer's GuideImplements the "forgotten bills" alert on the dashboard by extending the workspace snapshot with previous-period payment data, adding a pure domain helper to count unpaid charges for that period, wiring the result into the upcoming bills card, and covering the new behavior with tests and docs. Sequence diagram for forgotten-bills alert computation and renderingsequenceDiagram
actor User
participant DashboardPage
participant getWorkspaceSnapshot
participant supabase
participant countUnpaidForPeriod
participant ProchainesFacturesCard
User->>DashboardPage: request dashboard
DashboardPage->>getWorkspaceSnapshot: getWorkspaceSnapshot()
getWorkspaceSnapshot->>supabase: select charge_payments (currentYear,currentMonth)
getWorkspaceSnapshot->>supabase: select charge_payments (previousYear,previousMonth)
supabase-->>getWorkspaceSnapshot: snapshot with previousPeriod, previousMonthPaidChargeIds
getWorkspaceSnapshot-->>DashboardPage: WorkspaceSnapshot
DashboardPage->>countUnpaidForPeriod: countUnpaidForPeriod(snapshot.charges, Set(previousMonthPaidChargeIds), snapshot.previousPeriod)
countUnpaidForPeriod-->>DashboardPage: forgottenCount
DashboardPage->>ProchainesFacturesCard: ProchainesFacturesCard({charges, payments, todayIso, locale, forgottenCount, forgottenMonthLabel})
alt [forgottenCount > 0]
ProchainesFacturesCard->>ProchainesFacturesCard: render forgottenAlert
end
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - j'ai trouvé 1 problème et laissé quelques commentaires de haut niveau :
- Si la requête des paiements du mois précédent échoue,
previousMonthPaidChargeIdsdevient silencieusement vide, ce qui va surcompter les factures « oubliées » et afficher une alerte trompeuse ; envisagez de court-circuiter l’alerte (par exemple en passantforgottenCount = 0ou un indicateur de désactivation) lorsquepreviousMonthPaymentsRes.errorest présent.
Prompt pour les agents IA
Veuillez traiter les commentaires de cette revue de code :
## Commentaires généraux
- Si la requête des paiements du mois précédent échoue, `previousMonthPaidChargeIds` devient silencieusement vide, ce qui va surcompter les factures « oubliées » et afficher une alerte trompeuse ; envisagez de court-circuiter l’alerte (par exemple en passant `forgottenCount = 0` ou un indicateur de désactivation) lorsque `previousMonthPaymentsRes.error` est présent.
## Commentaires individuels
### Commentaire 1
<location path="src/components/dashboard/__tests__/ProchainesFacturesCard.test.tsx" line_range="188-195" />
<code_context>
expect(screen.getByTestId('prochaines-factures-watched-hint')).toBeInTheDocument();
});
+ it('renders the forgotten-bills alert when last month left unticked bills', async () => {
+ await renderCard({
+ charges: [makeCharge()],
+ forgottenCount: 2,
+ forgottenMonthLabel: 'juin',
+ });
+ expect(screen.getByTestId('prochaines-factures-forgotten')).toHaveTextContent(/juin/);
+ });
+
</code_context>
<issue_to_address>
**suggestion (testing):** Renforcer l’assertion de l’alerte sur les factures oubliées pour couvrir le nombre dynamique ainsi que le libellé du mois
Ce test vérifie uniquement que le libellé du mois (« juin ») apparaît dans l’alerte, mais le texte est également paramétré par `forgottenCount`. En conséquence, il ne détecterait pas les régressions où le nombre est manquant ou incorrect alors que le mois est toujours présent. Merci de mettre à jour l’assertion pour couvrir à la fois le mois et le nombre (par exemple via une expression régulière sur la chaîne localisée complète ou des attentes combinées sur `textContent`).
```suggestion
it('renders the forgotten-bills alert when last month left unticked bills', async () => {
await renderCard({
charges: [makeCharge()],
forgottenCount: 2,
forgottenMonthLabel: 'juin',
});
const alert = screen.getByTestId('prochaines-factures-forgotten');
expect(alert).toHaveTextContent(/2/);
expect(alert).toHaveTextContent(/juin/);
});
```
</issue_to_address>Sourcery est gratuit pour l’open source – si vous appréciez nos revues, pensez à les partager ✨
Original comment in English
Hey - I've found 1 issue, and left some high level feedback:
- If the previous-month payments query fails,
previousMonthPaidChargeIdssilently becomes empty, which will overcount "forgotten" bills and show a misleading alert; consider short-circuiting the alert (e.g. passingforgottenCount = 0or a disabled flag) whenpreviousMonthPaymentsRes.erroris present.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- If the previous-month payments query fails, `previousMonthPaidChargeIds` silently becomes empty, which will overcount "forgotten" bills and show a misleading alert; consider short-circuiting the alert (e.g. passing `forgottenCount = 0` or a disabled flag) when `previousMonthPaymentsRes.error` is present.
## Individual Comments
### Comment 1
<location path="src/components/dashboard/__tests__/ProchainesFacturesCard.test.tsx" line_range="188-195" />
<code_context>
expect(screen.getByTestId('prochaines-factures-watched-hint')).toBeInTheDocument();
});
+ it('renders the forgotten-bills alert when last month left unticked bills', async () => {
+ await renderCard({
+ charges: [makeCharge()],
+ forgottenCount: 2,
+ forgottenMonthLabel: 'juin',
+ });
+ expect(screen.getByTestId('prochaines-factures-forgotten')).toHaveTextContent(/juin/);
+ });
+
</code_context>
<issue_to_address>
**suggestion (testing):** Strengthen the forgotten-bills alert assertion to cover the dynamic count as well as the month label
This test only verifies that the month label (« juin ») appears in the alert, but the copy is also parameterized by `forgottenCount`. As a result, it wouldn’t catch regressions where the count is missing or wrong while the month is still present. Please update the assertion to cover both month and count (e.g. via a regex on the full localized string or combined expectations on `textContent`).
```suggestion
it('renders the forgotten-bills alert when last month left unticked bills', async () => {
await renderCard({
charges: [makeCharge()],
forgottenCount: 2,
forgottenMonthLabel: 'juin',
});
const alert = screen.getByTestId('prochaines-factures-forgotten');
expect(alert).toHaveTextContent(/2/);
expect(alert).toHaveTextContent(/juin/);
});
```
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
…month asserts (Sourcery #229) The naive regex mock could not render ICU plurals, so the forgotten-alert copy was only assertable by fragments. getTranslations now delegates to next-intl's createTranslator (real ICU) — the tests assert the exact user-facing copy in both plural ('2 factures de juin n'ont jamais été cochées') and singular forms. 12 card tests green.
Alerte « factures oubliées » — dernière brique de l'epic Factures cohérentes (THI-329)
Ta demande de juin (P5) : « en auto ça ne garantit pas que toutes les factures sont bien payées le mois précédent, il faut un moyen de prévenir quand on a oublié une facture ».
Ce que ça fait
La card factures du dashboard s'ouvre désormais sur un bandeau calme quand des factures dues le mois précédent n'ont jamais été cochées :
countUnpaidForPeriod(charges, paidIds, period).foreground(AA les 2 thèmes), teinte warning purement décorative — même règle dark-safe que le badge « En retard ».Décision produit à valider (documentée, réversible)
La spec de juin prévoyait aussi un bouton « Réinitialiser le mois ». Je l'ai abandonné avec rationale : le ledger est par période → les coches repartent à zéro naturellement chaque mois (le « reset auto » existe de fait), et décocher une facture individuellement couvre les corrections. Un bouton bulk-décocher le mois courant n'aurait pas d'usage réel identifié. Si tu le veux quand même, dis-le — ajout trivial.
Tests
5 domaine + 2 card ; suite complète 1494 verte ; typecheck/lint/build clean. UI-only + lecture élargie (aucune migration, aucune Server Action).
Smoke @Thierry
Cas concret : tes factures de juin étant toutes cochées (16/16), le bandeau ne doit pas apparaître. Pour le voir : décoche une facture de juin depuis… (impossible — juin est passé 😉) → il apparaîtra naturellement le 1er août si tu oublies des coches en juillet.
🤖 Generated with Claude Code
Summary by Sourcery
Ajouter une alerte sur le tableau de bord qui met en avant les factures dues le mois précédent qui n’ont jamais été marquées comme payées, complétant la partie « factures oubliées » de l’épopée des factures.
Nouvelles fonctionnalités :
Améliorations :
Tests :
Original summary in English
Summary by Sourcery
Add a dashboard alert that surfaces bills due in the previous month that were never marked as paid, completing the forgotten-bills piece of the invoices epic.
New Features:
Enhancements:
Tests: