All checks were successful
La liste de courses était volontairement en lecture seule. Elle gagne un
état « acheté » par article, utile en magasin (au doigt sur mobile).
- `shopping-list-progress.ts` (nouveau) : `ShoppingListProgressStore`,
calqué sur `CookingProgressStore` — `localStorage` uniquement, par
semaine (clé `batchcooking:shoppingListChecked:<weekStart>`), aucun état
serveur. Une coche n'est jamais autoritaire (la liste est recalculée
depuis le planning à chaque visite) et se perd sans dommage.
- `ShoppingListPage.tsx` : chaque ligne devient un `CheckboxOption` ;
`<ShoppingListItems key={weekKey}>` remonte à chaque changement de
semaine (checklist réinitialisée). Clé d'article = `ingredientId-unitId`
(déjà la `key` React de la ligne).
- `shopping-list-page.scss` : override scopé du look « carte sélectionnable »
global — un article coché est barré et estompé, pas surligné en primary.
Cible tactile ≥ 44 px sous le breakpoint phone.
- `specs/frontend-architecture.md` : la note « délibérément en lecture
seule » est remplacée.
Tests : `shopping-list.feature` — nouveau scénario « cocher un article »
(coché → barré, persiste au reload, n'affecte pas les autres).
`shopping-list-page.cy.ts` — la cible tactile de la ligne (le label
`CheckboxOption`) fait 16 px de padding + ≥ 44 px de haut sur téléphone.
Local : `pnpm lint` + `pnpm --filter web build` OK, `shopping-list.feature`
4/4, `shopping-list-page.cy.ts` 1/1.
Closes #109
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
44 lines
2.3 KiB
Gherkin
44 lines
2.3 KiB
Gherkin
Feature: Shopping list
|
|
As a signed-in user
|
|
I want to see every ingredient needed for this week's planned recipes, already summed
|
|
So that I know what to buy without recomputing it myself
|
|
|
|
Background:
|
|
Given I am signed in as "Alice" "Martin"
|
|
And today is frozen at "2026-08-17T09:00:00.000Z"
|
|
|
|
Scenario: Nothing planned this week shows the empty message, not an error
|
|
Given the shopping list for "2026-08-17" is empty
|
|
When I visit "/liste-de-courses"
|
|
Then I should see "Aucun ingrédient à acheter pour cette semaine — ajoutez des recettes à votre planning."
|
|
|
|
Scenario: Ingredients are grouped by aisle, in canonical order, each with its summed quantity
|
|
Given the shopping list for "2026-08-17" contains:
|
|
| ingredientKey | icon | category | quantity | unitKey |
|
|
| egg | EGG | dairyAndCheese | 6 | piece |
|
|
| tomato | VEGETABLE | freshProduce | 400 | gram |
|
|
When I visit "/liste-de-courses"
|
|
Then the shopping list group "Produits frais" should appear before "Crémerie & fromage"
|
|
And the shopping list should show "Tomate" at quantity "400 g"
|
|
And the shopping list should show "Oeuf" at quantity "6 unité"
|
|
|
|
Scenario: Navigating to another week fetches and shows that week's own list
|
|
Given the shopping list for "2026-08-17" is empty
|
|
And the shopping list for "2026-08-24" contains:
|
|
| ingredientKey | icon | category | quantity | unitKey |
|
|
| onion | VEGETABLE | freshProduce | 1 | kilogram |
|
|
When I visit "/liste-de-courses"
|
|
And I click the next week arrow
|
|
Then the shopping list should show "Oignon" at quantity "1 kg"
|
|
|
|
Scenario: Ticking an item marks it as in the cart, and the tick survives a reload
|
|
Given the shopping list for "2026-08-17" contains:
|
|
| ingredientKey | icon | category | quantity | unitKey |
|
|
| tomato | VEGETABLE | freshProduce | 400 | gram |
|
|
| onion | VEGETABLE | freshProduce | 2 | piece |
|
|
When I visit "/liste-de-courses"
|
|
And I tick the shopping list item "Tomate"
|
|
Then the shopping list item "Tomate" should be ticked
|
|
And the shopping list item "Oignon" should not be ticked
|
|
When I reload the page
|
|
Then the shopping list item "Tomate" should be ticked
|