Commit Graph

53 Commits

Author SHA1 Message Date
gilles 4e5e6f7c36 fix(nginx): ^~ sur /media/ pour éviter le matching regex des .webp
La règle ~* \.(webp|...) prenait priorité sur /media/ et servait
les images uploadées depuis le HTML statique au lieu de les proxifier
vers le backend — causant un 404 sur toutes les photos d'articles.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 13:12:24 +02:00
gilles aa9ac2a6ea feat(shopping): tags sur les articles du catalogue
- Migration 006 : colonne tags TEXT[] sur shopping.products
- Modèle SQLAlchemy + schémas Pydantic mis à jour (ProductCreate/Update/Response)
- Interface TypeScript Product/ProductCreate/ProductUpdate avec tags?: string[]
- CatalogueModal : chip input (Entrée/virgule pour ajouter, clic pour supprimer, Backspace pour retirer le dernier)
- Recherche dans le catalogue et le bottom sheet étendue aux tags (insensible aux accents)
- Tags affichés en pills dans la liste du catalogue

v0.4.12

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 12:57:25 +02:00
gilles 8e878e2e5a fix(catalogue): recherche insensible aux accents — filtrage côté client v0.4.11
Le backend utilisait ILIKE (insensible à la casse uniquement) — "iles" ne
trouvait pas "Îles flottantes". Passage au filtrage client avec matchesSearch
(normalize NFD) identique au bottom sheet. Charge tous les produits une fois
puis filtre sur name, brand et category sans aller-retour serveur.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 12:16:10 +02:00
gilles 606145f9ed ux(nav): supprimer le cercle dock du slot bouton action v0.4.10
Le cercle de fond était visible derrière le FAB — deux cercles superposés.
Slot conservé (flex, positionnement) mais sans visuel propre.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 10:31:41 +02:00
gilles 58b5de15bb fix(shopping): augmenter limite catalogue 50→500 — tous les articles visibles
Avec 119 articles en base et limit=50, les articles en fin de liste
alphabétique (Îles flottantes, Éponge…) n'apparaissaient pas dans
le bottom sheet. Limite portée à 500 côté backend ET frontend.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 10:28:09 +02:00
gilles 6677604ad1 chore: bump version v0.4.9
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 10:21:14 +02:00
gilles 264dd180ee fix(shopping): capitalisation 1re lettre — catalogue + migration BDD v0.4.9
- CatalogueModal : cleanForm() capitalise désormais le nom avant envoi API
  (création et modification d'article)
- Migration 005 : met à jour shopping.products.name et
  shopping.list_items.custom_name pour capitaliser les données existantes

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 10:21:03 +02:00
gilles 52771644de fix(shopping): rafraîchir le catalogue après fermeture du modal Articles
Les produits créés/modifiés via le modal Catalogue n'apparaissaient pas
dans le bottom sheet car products n'était chargé qu'au montage de la page.
refreshProducts() est désormais appelé à chaque fermeture du CatalogueModal.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 10:18:15 +02:00
gilles 4ce5d92bba fix(shopping): accolade manquante dans le map des articles libres
Fermeture incorrecte du .map(s => { return (...) }) — le } de la
fonction arrow était absent, causant une erreur TS1005 au build.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 10:09:26 +02:00
gilles cbb2d81279 feat(nav): bouton action intégré dans la navbar v0.4.8
- ActionButtonContext : contexte React permettant aux pages d'injecter
  leur bouton action dans la navbar (Shopping=fa-cart-plus, Todos/Notes=+)
- BottomNav : 5e slot dédié avec dock circulaire visuel permanent ;
  bouton rendu 10px au-dessus du centre du slot (effet soulevé)
- Layout : ActionButtonProvider + overflow visible sur le conteneur nav
- Pages : useEffect enregistre/vide le bouton action — plus de FAB flottant
  sur le contenu, liste entièrement visible

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 10:02:03 +02:00
gilles d6d3acd1fe ux(fab): repositionner le bouton action sur la nav bar v0.4.7
FAB déplacé sur la barre de nav (bottom: 10px) au lieu de flotter
au-dessus de la liste — liste entièrement visible sur Shopping,
Todos et Notes. paddingBottom liste réduit à 64px (hauteur nav seule).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 09:51:33 +02:00
gilles 880f7f2125 fix+ux(shopping): suppression via bottom sheet, majuscule auto, icône FAB v0.4.6
- Bug: décrémentation à 0 d'un article pré-chargé (existingItemId) conserve
  la sélection à qty=0 (marqué pour DELETE) → bouton ✓ devient accessible
  Visuel: fond rouge + barré + opacité 0.6 pour les articles à supprimer
- UX: première lettre en majuscule auto lors de l'ajout d'un article libre
- UX: FAB remplace '+' par fa-cart-plus pour mieux signifier l'ajout à la liste

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 09:39:37 +02:00
gilles a1ecd0945e feat(shopping): optimisation bottom sheet — icônes haut, tab bar couverte v0.4.5
- Boutons Annuler (fa-xmark, outline err) et Valider (fa-check, ok)
  déplacés en haut du sheet, pill shape, touch target 48px
- Suppression du bouton sticky en bas
- zIndex sheet 70 > tab bar 50 : bottom sheet couvre la nav
- maxHeight 85dvh → 92dvh pour exploiter l'espace libéré
- Poignée de drag supprimée

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 09:22:59 +02:00
gilles a949a22cca feat(shopping): pré-remplissage bottom sheet + toggle catalogue v0.4.4
- openAddSheet() pré-charge les articles non cochés de la liste courante
  (qty existante, PATCH si modifiée / POST si nouvel article)
- Toggle "Ajouter au catalogue" sur les articles libres nouvellement saisis
  (coché par défaut, créé via createProduct puis lié en product_id)
- Bouton "Confirmer (N)" comptant uniquement les actions réelles
  (new items + existing avec qty modifiée)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 09:10:46 +02:00
gilles 56f0815667 feat(shopping): bottom sheet multi-select — quantités inline +/- par article v0.4.3
- QtyControls: boutons +/- design system (var(--ok)/var(--err)/var(--bg-5))
- qty=0 → article non sélectionné, seul "+" visible (var(--ok) plein)
- qty>0 → fond teinté vert, "−" + valeur mono + "+" ; "−" retire si qty atteint 1
- Quantité transmise à addItem lors de la confirmation
- Articles libres : même comportement +/- en tête de liste

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 08:50:22 +02:00
gilles 8b2081764e chore: bump version v0.4.2 (UX: swipe-edit, bottom-sheet multi-select, user-select)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 08:08:35 +02:00
gilles c9cf452585 feat(shopping): bottom sheet multi-select pour l'ajout d'articles
- BottomSheet.tsx: panneau ancré en bas, max-height 85dvh (clavier-aware),
  centré sur laptop (max-width 600px), backdrop, drag handle visuel
- ShoppingPage: remplace le modal centré par le BottomSheet multi-select
  · sélection multiple avec toggle (cercle vert + fond teinté)
  · articles libres affichés en tête avec tag "article libre"
  · bouton "Ajouter (N)" sticky, grisé à 0 sélection
  · pas d'autoFocus → liste visible d'emblée, clavier fermé
  · FAB + masqué quand le sheet est ouvert

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 08:06:48 +02:00
gilles a821b27fc6 fix(shopping): champ recherche article — autoComplete off, liste adaptative dvh
- autocomplete/autocorrect/autocapitalize off + spellCheck false sur le
  champ de recherche → supprime la barre de suggestions iOS et le popup autofill
- maxHeight liste: min(240px, 35dvh) → reste visible quand le clavier est ouvert

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 07:42:20 +02:00
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 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 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 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 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 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 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 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 0903115687 feat: dockerfile frontend nginx + cache statique 2026-05-24 05:23:16 +02:00
gilles 25a31f1f24 feat: layout responsive mobile (bottom nav) / laptop (sidebar) + page d'accueil 2026-05-24 05:22:45 +02:00