Commit Graph

68 Commits

Author SHA1 Message Date
gilles 19c686b4be feat(ux): user-select global, swipe-gauche édition, clavier numérique, versionnage v0.4.0
- user-select:none global (index.css) + reset sur input/textarea/select
- ItemRow: swipe gauche → édition (fond bleu), suppression long press,
  bouton ✕ toujours visible sur mobile
- SwipeableRow: prop onSwipeLeft, révèle rightContent entre seuil/2 et seuil,
  déclenche onSwipeLeft au seuil complet
- TodosPage: onSwipeLeft → édition (remplace double-tap)
- inputMode=decimal sur tous les champs quantité et prix
- formatQty: affiche "2" au lieu de "2.000"
- Versionnage: __APP_VERSION__ injecté par Vite depuis package.json v0.4.0
- HomePage: version affichée à côté du titre (v0.4.0)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 07:38:23 +02:00
gilles f86dd01d95 feat(shopping): affichage stats d'achat dans le catalogue (dernier achat + intervalle moyen)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 07:13:08 +02:00
gilles dee7037d70 feat(shopping): stats achat produit + édition quantité article
Backend :
- Migration 004 : last_purchased_at (DATE) + avg_interval_days (NUMERIC)
  sur shopping.products
- update_item : met à jour les stats au premier cochage d'un article
  lié à un produit (moyenne mobile exp. 70/30)
- ProductResponse expose les deux nouveaux champs

Frontend :
- ItemRow : long press 500ms → onEdit() (mobile) ; crayon + croix (laptop)
- ShoppingPage : modal édition quantité/unité, état editingItem
- api/shopping.ts : Product inclut last_purchased_at + avg_interval_days

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 07:08:14 +02:00
gilles 377531d08e fix: recherche insensible à la casse et aux accents dans tous les filtres
- utils/search.ts : normalize() (NFD + minuscules) + matchesSearch()
- ShoppingPage filteredProducts : matchesSearch sur nom ET marque
- Backend searchProducts : ilike sur nom ET marque (or_)
- Notes FTS : déjà insensible nativement (plainto_tsquery)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 07:00:27 +02:00
gilles a86c14b0b9 feat(shopping): proposition d'ajout au catalogue pour les articles libres
Quand un article tapé n'existe pas dans le catalogue et qu'aucun produit
n'est sélectionné, une case "Ajouter au catalogue" apparaît (cochée par
défaut). Si cochée, le produit est créé via POST /api/shopping/products
avant l'ajout à la liste, avec l'unité pré-remplie si saisie.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 06:55:33 +02:00
gilles b92c74f641 chore: marque Phase 4 Notes comme terminée dans le plan
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 06:50:09 +02:00
gilles fdeb747f38 feat: Phase 4 — module Notes complet
Backend :
- schemas/notes.py : NoteCreate/Update/Response + AttachmentResponse
- api/notes.py : CRUD + FTS français (plainto_tsquery) + filtres rapides
  (has_photo/audio/gps/tag/category) + pièces jointes (image/audio)
- main.py : enregistrement /api/notes

Frontend :
- api/notes.ts : fetchNotes/create/update/delete + add/deleteAttachment
- NoteForm.tsx : titre, contenu, catégorie, tags CSV, GPS
- NotesPage.tsx : liste mobile (chronologique) + grille laptop, FAB +,
  enregistrement audio inline (MediaRecorder), upload photo, filtres rapides

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 06:49:46 +02:00
gilles c4634b5a27 chore: mise à jour suivi améliorations shopping
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 06:37:45 +02:00
gilles 7b1b6521e5 feat(shopping): photo par article dans le catalogue
- Upload photo (context=product → thumbnail 150×150) dans CatalogueModal
- Miniature affichée dans la liste et dans le formulaire
- Schémas ProductCreate/Update/Response exposent image_path + thumbnail_path
- Backend sert /media/* via StaticFiles (FastAPI)
- Proxy /media → backend dans vite.config et nginx.conf

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 06:37:33 +02:00
gilles 5dc335ad17 refactor(todos): FAB unique + pour créer une tâche (mobile et laptop)
Supprime le bouton "Nouvelle tâche" laptop, remplace par le même FAB
circulaire que mobile — position adaptée (bottom: 72px mobile, 24px laptop).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 06:31:04 +02:00
gilles 37e7f006d3 feat(shopping): sélecteur catalogue lors de l'ajout d'article
Liste scrollable alphabétique filtrée en temps réel, sélection en un tap
(pré-remplit l'unité), ou saisie libre si article hors catalogue.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 06:29:18 +02:00
gilles 4eb89165af fix(shopping): supprimer comparaison editing?.id dans la vue liste (narrowing TS)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 16:28:49 +02:00
gilles 4435412b21 docs: mise à jour listes d'améliorations implémentées
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 16:22:26 +02:00
gilles 85093f1b99 feat(shopping): refonte UX + CRUD catalogue/boutiques + champs enrichis
- UX : vue par défaut = liste en cours, landing si pas de liste (+ vert +
  baguette magique), suppression des vues "listes" et "mode magasin" séparés
- Articles cochés barrés et déplacés en bas, tri alphabétique par section
- Nom de liste auto avec numéro de semaine ISO (S21 2026)
- Wake lock activé dès qu'une liste est ouverte
- CRUD boutiques : POST/PATCH/DELETE /stores + modal Boutiques
- CRUD articles : POST/PATCH/DELETE /products + modal Catalogue
- Champs enrichis produits : description, prix, quantité/unité, boutique défaut
- Champs enrichis boutiques : url, store_type (alimentaire, bricolage…)
- Migration 003 : nouveaux champs en base

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 16:21:45 +02:00
gilles 925e077afe feat(todos): refonte formulaire + chips domaines + non-zoomable
- TodoForm : domaines en chips multi-select colorés, priorité en 3 boutons
  colorés (haute/moyenne/basse), date initialisée à aujourd'hui, description
  et URL toujours visibles, boutons photo et GPS
- TodosPage : suppression filtres domaine/priorité, tags colorés par domaine
  dans les lignes, userSelect:none, groupage multi-domaines
- todos.ts : ajout domains[], photo_path, gps_lat/lng dans les interfaces TS
- index.html : viewport maximum-scale=1.0, user-scalable=no

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 16:10:47 +02:00
gilles e9dfb6e293 feat(todos): domains[], photo_path, gps_lat/lng — modèle, schemas, API, tri par date
- Modèle SQLAlchemy : ajout de domains (ARRAY), photo_path, gps_lat, gps_lng ; import Float
- Schemas Pydantic : domain → domains dans TodoCreate, TodoUpdate, TodoResponse ; ajout photo_path, gps_lat, gps_lng
- API GET /api/todos : filtre domain (param URL) redirigé vers domains.contains([domain]) sur le champ ARRAY
- Tests : domain → domains dans les payloads POST ; assertion domains == ["informatique"] dans test_creer_todo
2026-05-24 16:04:21 +02:00
gilles a97894437a feat(todos): migration domains[], photo_path, gps_lat/lng 2026-05-24 16:01:18 +02:00
gilles 134f6ba5f5 docs: plan.md mis à jour — Phase 3 shopping , renommage phases suivantes 2026-05-24 15:54:45 +02:00
gilles e21349511d feat(shopping): bouton liste magique + modal édition liste avec suppression
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 15:52:44 +02:00
gilles da5eb4916e feat(shopping): endpoint génération liste magique (score fréquence V1)
Ajoute POST /api/shopping/lists/generate qui calcule un score retard/intervalle
par article (achats_with_lag CTE pour contourner la limite PostgreSQL sur
AVG+LAG imbriqués) et génère une liste draft avec les articles >= 0.7.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 15:50:30 +02:00
gilles 43736709a9 refactor(todos): formulaires création et édition migrés vers Modal 2026-05-24 15:47:48 +02:00
gilles 490d0d774f feat(shopping): page complète — listes, détail, mode magasin Wake Lock
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 15:46:27 +02:00
gilles 8211284c4a feat(shopping): composant ItemRow avec swipe-to-delete et mode magasin 2026-05-24 15:43:04 +02:00
gilles 9f2ca15303 feat(shopping): hook useWakeLock avec fallback gracieux 2026-05-24 15:41:34 +02:00
gilles ffe28cc4e3 feat(ui): composant Modal réutilisable (overlay + Escape) 2026-05-24 15:40:57 +02:00
gilles 1ca2d986ce feat(shopping): client API TypeScript typé 2026-05-24 15:39:32 +02:00
gilles e4c3edc72b test(shopping): 9 tests d'intégration CRUD listes et articles
Couvre : création liste, listing, ajout article custom, validation (422),
cocher/décocher, suppression, finish avec report des non cochés, 404, stores, recherche produits.
2026-05-24 15:37:15 +02:00
gilles 3e4c209417 fix(shopping): refresh(item, ["product"]) dans update_item pour éviter MissingGreenlet 2026-05-24 15:34:21 +02:00
gilles 917a57fadc feat(shopping): 10 endpoints CRUD listes et articles
Ajoute backend/app/api/shopping.py avec les routes :
- GET/POST /api/shopping/lists
- GET/PATCH/DELETE /api/shopping/lists/{id}
- POST/PATCH/DELETE /api/shopping/lists/{id}/items
- GET /api/shopping/stores
- GET /api/shopping/products
- POST /api/shopping/lists/{id}/finish (report des articles non cochés)

Enregistre le router dans main.py avec le prefix /api/shopping.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 15:32:45 +02:00
gilles f715061bb2 refactor(shopping): model_config sur tous les Response, suppression Field inutile 2026-05-24 15:30:26 +02:00
gilles 4e7a863431 feat(shopping): schémas Pydantic listes et articles + volume dev backend 2026-05-24 15:28:43 +02:00
gilles e3117f3aaf refactor(shopping): typage relation product avec syntaxe X | None (cohérence) 2026-05-24 15:27:07 +02:00
gilles 682b17f1f4 feat(shopping): relation product sur ListItem 2026-05-24 15:23:29 +02:00
gilles d6722bff97 docs: plan Phase 3 mis à jour — liste magique + modal édition liste 2026-05-24 15:17:45 +02:00
gilles 96e9375337 docs: plan Phase 3 — liste de courses (10 tâches) 2026-05-24 15:06:08 +02:00
gilles 134678a6f1 feat(todos): favicon maison + mode édition double-tap/double-clic
- Favicon SVG maison Gruvbox orange sur fond sombre
- TodoForm accepte initialValues et submitLabel pour l'édition
- SwipeableRow détecte le double-tap (< 300ms, sans déplacement)
- TodosPage : double-tap mobile / double-clic laptop ouvre l'édition

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 14:54:47 +02:00
gilles 6ef64dfe1c fix(home): tuiles d'accueil navigables via Link React Router
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 14:48:12 +02:00
gilles d31cde3d59 docs: commandes de démarrage claires dans le README
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 14:25:55 +02:00
gilles b87c96ceab chore: ajout .gitignore, CLAUDE.md, design system et docs Phase 2
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 14:10:18 +02:00
gilles 2b34abf4b0 fix: nginx proxy /api/ vers backend + routes shopping et notes manquantes
- Ajoute location /api/ dans nginx.conf pour proxifier les requêtes API
- Crée ShoppingPage et NotesPage (placeholders phase suivante)
- Enregistre les routes /shopping et /notes dans App.tsx

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 14:09:36 +02:00
gilles 04012f5817 fix(todos): typage union explicite pour l'état priority dans TodoForm 2026-05-24 13:20:32 +02:00
gilles 9d852c3bf1 fix(todos): handleResponse gère 204 No Content (suppression sans SyntaxError) 2026-05-24 12:37:03 +02:00
gilles 2e1f3a77fb fix(todos): types union TodoCreate, gestion erreurs handlers, transition SwipeableRow réactive
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 12:18:20 +02:00
gilles 8aeb45387d feat(todos): page TodosPage — vue mobile swipeable + vue laptop tableau filtrable
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 12:13:56 +02:00
gilles 580aab822a feat(todos): composant TodoForm (rapide mobile / étendu laptop) 2026-05-24 12:10:31 +02:00
gilles 9e6e0902ab feat(todos): composant SwipeableRow (swipe touch, seuil 80px) 2026-05-24 12:07:38 +02:00
gilles eea004f53b fix(todos): deleteTodo utilise handleResponse pour cohérence 2026-05-24 12:06:34 +02:00
gilles e89d2ff4f1 feat(todos): client API TypeScript — Todo interface + 5 fonctions fetch 2026-05-24 12:05:44 +02:00
gilles b5f0453cdd fix(todos): datetime query params typés FastAPI, ORDER BY déterministe
- Changer due_after/due_before de str | None vers datetime | None pour typage FastAPI
- FastAPI parse et valide automatiquement, retourne 422 si format invalide (pas 500)
- Supprimer le parsing manuel datetime.fromisoformat() qui levait ValueError brute
- Ajouter ORDER BY déterministe: due_date ASC NULLS LAST, created_at DESC
  évite les réordonnances aléatoires entre requêtes PostgreSQL

Tests: 15/15 passent ✓

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 12:02:37 +02:00
gilles a3704a2b27 feat(todos): endpoints CRUD + postpone — 15 tests passent
Ajoute les 5 endpoints REST (list, create, update, delete, postpone),
enregistre le routeur sur /api/todos, et corrige l'isolation des sessions
de test via NullPool + dependency_overrides dans conftest.py.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 09:20:53 +02:00