Some checks failed
CI / build-android (push) Blocked by required conditions
CI / lint (push) Successful in 3m18s
CI / intent-service-test (push) Successful in 4m8s
CI / build (push) Successful in 3m42s
CI / test (push) Failing after 10m11s
CI / e2e (push) Has been cancelled
Ticket #87 du chantier UI mobile & tablette. LeftoversBasket et WeekNavigator's CalendarPopover etaient tous les deux des popovers a largeur fixe (18-20rem), ancres right: 0, sans aucune gestion de bord d'ecran - sur un telephone etroit ils pouvaient deborder hors du viewport. Les deux sont declenches depuis l'en-tete du planning, un ecran central de l'usage quotidien - tres probablement la cause concrete derriere le retour terrain "je n'ai pas acces a tous les boutons" sur mobile qui a lance ce chantier. Les deux basculent desormais sur BottomSheet (ticket #91) sous le breakpoint phone via useIsMobileViewport() - meme contenu, juste une autre enveloppe (le popover flottant + son ecouteur de clic exterieur manuel restent inchanges sur desktop). Le clic-exterieur devient un no-op propre sur mobile plutot qu'un ecouteur qui ne fait jamais rien (le ref ne s'attache a rien dans la branche BottomSheet). Nouvelle cle i18n common.calendar.title ("Choisir une semaine") pour le titre de la feuille - pas de raccourci en decoupant une autre cle interpolee. Verifie en local : tsc -b --force, biome check, build de prod, suite Cypress e2e complete (142/142, 2 nouveaux tests phone dans leftovers-basket.cy.ts et planning-page.cy.ts) et composants (63/63). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
127 lines
4.4 KiB
TypeScript
127 lines
4.4 KiB
TypeScript
// Layout-mode spec for the planning header's leftovers basket — mocks
|
||
// `GET /planning` (this job has no live backend; apps/api's Mocha suite
|
||
// covers the real endpoints). Exercises the popover open/close, an
|
||
// outside click, and the "Jeter" button firing `PATCH .../discard-leftover`.
|
||
|
||
const authenticatedProfile = {
|
||
id: 1,
|
||
firstName: "Alice",
|
||
lastName: "Martin",
|
||
email: "alice@example.com",
|
||
tokenVersion: 0,
|
||
houseId: 1,
|
||
dietId: null,
|
||
};
|
||
|
||
/**
|
||
* A week with one fresh item that cooked 12 for 10 requested (pool of 2)
|
||
* and one leftovers item serving 1 of that pool — so the basket should
|
||
* offer 1 line with 1 portion still available.
|
||
*/
|
||
const planningWithLeftovers = {
|
||
id: 1,
|
||
startDate: "2026-08-17T00:00:00.000Z",
|
||
finishDate: "2026-08-23T00:00:00.000Z",
|
||
items: [
|
||
{
|
||
id: 1,
|
||
weekDay: "lundi",
|
||
meal: "diner",
|
||
portions: 12,
|
||
portionsRequested: 10,
|
||
discardedPortions: 0,
|
||
sourceItem: null,
|
||
recipe: { id: 1, name: "Lasagnes" },
|
||
},
|
||
{
|
||
id: 2,
|
||
weekDay: "mardi",
|
||
meal: "dejeuner",
|
||
portions: 1,
|
||
portionsRequested: 1,
|
||
discardedPortions: 0,
|
||
sourceItem: { id: 1 },
|
||
recipe: { id: 1, name: "Lasagnes" },
|
||
},
|
||
],
|
||
};
|
||
|
||
describe("Leftovers basket", () => {
|
||
beforeEach(() => {
|
||
cy.viewport(1600, 900);
|
||
cy.clock(new Date("2026-08-17T09:00:00Z"), ["Date"]);
|
||
cy.intercept("GET", "**/auth/me", { statusCode: 200, body: authenticatedProfile });
|
||
});
|
||
|
||
it("lists a week's available leftovers, opens and closes on an outside click", () => {
|
||
cy.intercept("GET", /\/planning\?/, { statusCode: 200, body: planningWithLeftovers });
|
||
cy.visit("/");
|
||
|
||
// Count badge = 1 fresh item with a remaining pool.
|
||
cy.get(".leftovers-basket__count").should("have.text", "1");
|
||
|
||
cy.get(".leftovers-basket__toggle").click();
|
||
cy.contains(".leftovers-basket__heading", "Restes disponibles").should("be.visible");
|
||
cy.contains(".leftovers-basket__line", "Lasagnes")
|
||
.should("contain.text", "Lundi")
|
||
.and("contain.text", "1 en restes");
|
||
|
||
// Clicking away from the popover closes it.
|
||
cy.get("h1").click();
|
||
cy.get(".leftovers-basket__popover").should("not.exist");
|
||
});
|
||
|
||
it("shows an empty state when nothing is left over", () => {
|
||
cy.intercept("GET", /\/planning\?/, {
|
||
statusCode: 200,
|
||
body: {
|
||
...planningWithLeftovers,
|
||
items: [{ ...planningWithLeftovers.items[0], portions: 10, portionsRequested: 10 }],
|
||
},
|
||
});
|
||
cy.visit("/");
|
||
|
||
cy.get(".leftovers-basket__count").should("not.exist");
|
||
cy.get(".leftovers-basket__toggle").click();
|
||
cy.contains(".leftovers-basket__empty", "Aucun reste cette semaine.").should("be.visible");
|
||
});
|
||
|
||
it("throws away a leftover pool via PATCH and drops it from the list", () => {
|
||
cy.intercept("GET", /\/planning\?/, { statusCode: 200, body: planningWithLeftovers });
|
||
cy.intercept("PATCH", "**/planning/items/1/discard-leftover", {
|
||
statusCode: 200,
|
||
body: {
|
||
...planningWithLeftovers.items[0],
|
||
discardedPortions: 1,
|
||
},
|
||
}).as("discard");
|
||
|
||
cy.visit("/");
|
||
cy.get(".leftovers-basket__toggle").click();
|
||
cy.contains(".leftovers-basket__line", "Lasagnes").find(".leftovers-basket__discard").click();
|
||
|
||
cy.wait("@discard");
|
||
// Pool was 1, now fully discarded -> the line is gone, the popover is empty.
|
||
cy.contains(".leftovers-basket__empty", "Aucun reste cette semaine.").should("be.visible");
|
||
cy.get(".leftovers-basket__count").should("not.exist");
|
||
});
|
||
|
||
it("opens inside a bottom sheet on a phone instead of the anchored popover", () => {
|
||
// Literal 390×844 rather than `cy.setViewport("phone")` (ticket #83) —
|
||
// that command doesn't exist on this ticket's own base yet; matches its
|
||
// PHONE_VIEWPORT value on purpose, worth switching to the real import
|
||
// once both have landed on `main`.
|
||
cy.viewport(390, 844);
|
||
cy.intercept("GET", /\/planning\?/, { statusCode: 200, body: planningWithLeftovers });
|
||
cy.visit("/");
|
||
|
||
cy.get(".leftovers-basket__toggle").click();
|
||
cy.get(".leftovers-basket__popover").should("not.exist");
|
||
cy.get(".bottom-sheet").should("be.visible");
|
||
cy.contains(".bottom-sheet", "Restes disponibles").should("be.visible");
|
||
cy.contains(".bottom-sheet .leftovers-basket__line", "Lasagnes").should("be.visible");
|
||
|
||
cy.get(".bottom-sheet__close").click();
|
||
cy.get(".bottom-sheet").should("not.exist");
|
||
});
|
||
});
|