feat(import): implement recipe import functionality with file and URL support

Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
Nils-Johan Gynther
2026-04-22 21:31:25 +02:00
parent 8ebf119d39
commit 81117fbcb7
11 changed files with 617 additions and 13 deletions
+76 -2
View File
@@ -72,8 +72,82 @@ Adminfloden migreras efter att ovanstaende ar verifierat.
- [x] Swipe-för-±1 på inventarielistan (SwipeableInventoryTile med visuell ledtråd).
## Fas 6 - Import parity
- URL/PDF/bild via befintliga endpoints.
- Tydlig hantering av langkorande anrop och fel.
### Analys (2026-04-22)
**Två separata flöden — samma skärm med flikar:**
#### 6a — Recept-import
- Endpoint: `POST /api/quick-import`
- Lägen: (1) filuppladdning med `multipart/form-data`, fält `file`, max 10 MB,
accepterade typer: PDF, PNG, JPG, JPEG, WEBP, BMP;
(2) URL via JSON-body `{ input: string }`.
- Svar: `{ markdown: string, source: 'ica'|'pdf'|'image'|'other', imageUrl?: string }`.
- På lyckat resultat: navigera till `/recipes/create` med markdown-texten förifylld.
- **Kräver**: `CreateRecipeScreen` måste utökas med en valfri `initialMarkdown`-parameter
som skickas via GoRouter `extra` (undviker persistent state-provider för tillfällig data).
#### 6b — Kvitto-import
- Endpoint: `POST /api/receipt-import`
- Läge: filuppladdning, `multipart/form-data`, fält `file`, max 15 MB,
typer: JPEG, PNG, WebP, HEIC/HEIF, PDF.
- Svar: `ParsedReceiptItem[]` med fälten `rawName`, `quantity`, `unit`,
`price?`, `matchedProductId?`, `matchedProductName?`,
`suggestedProductId?`, `suggestedProductName?`, `categorySuggestion?`.
- På lyckat resultat: granskningssteg där användaren bekräftar/skippar rader
och väljer produkt (via `ProductPickerField`), sedan bulk-spara till inventarie.
- Komplexitetsgrad: hög — granskningsvyn är det tyngsta steget.
**Nytt paket som krävs:**
- `file_picker: ^8.0.0` — hanterar filval på Flutter web (ger `Uint8List bytes`,
ingen filsökväg). Läggs till i `pubspec.yaml`.
**Fil-/mappstruktur:**
```
flutter/lib/features/import/
domain/
quick_import_result.dart # { markdown, source, imageUrl? }
parsed_receipt_item.dart # { rawName, quantity, unit, ... }
data/
import_repository.dart # API-anrop (multipart + JSON URL-läge)
import_providers.dart # Riverpod-providers
presentation/
import_screen.dart # TabBar: "Recept" | "Kvitto"
recipe_import_tab.dart # Fas 6a — fil + URL, laddningsindikator
receipt_import_tab.dart # Fas 6b — fil, parse, granskning, spara
```
**Router och shell:**
- Ny route `/import` inuti `ShellRoute` i `app_router.dart`.
- Ny nav-destination "Importera" med ikon `Icons.upload_file_outlined` i `app_shell.dart`,
placeras efter "Baslager" och innan "Profil".
**Felhantering:**
- Multipart-uppladdning kan ta 530 s (OCR, LLM) — `LinearProgressIndicator`
med text "Tolkar…" under hela anropet, inte en vanlig spinner.
- Timeout via `http`-klienten: sätt `Duration(seconds: 120)` för import-anrop.
- Nätverks- och serverfel mappas via befintlig `mapErrorToUserMessage`.
**Genomförandeordning:**
1. Lägg till `file_picker` i `pubspec.yaml`.
2. Utöka `CreateRecipeScreen` med `initialMarkdown`-parameter + GoRouter extra-stöd.
3. Bygg `domain/` + `data/` (modeller, repository, providers).
4. Bygg `recipe_import_tab.dart` (fas 6a — enklare).
5. Registrera route, lägg till nav-destination, verifiera end-to-end.
6. Bygg `receipt_import_tab.dart` (fas 6b — granskningssteg sist).
### Deluppgifter
- [x] Lägg till `file_picker: ^8.0.0` i `pubspec.yaml`.
- [x] Utöka `CreateRecipeScreen` med optional `initialMarkdown` via GoRouter `extra`.
- [x] Skapa `domain/quick_import_result.dart` och `domain/parsed_receipt_item.dart`.
- [x] Skapa `data/import_repository.dart` med multipart-upload + JSON URL-metoder.
- [x] Skapa `data/import_providers.dart`.
- [x] Bygg `presentation/recipe_import_tab.dart` (fil + URL, lång laddningsindikator).
- [x] Bygg `presentation/import_screen.dart` med TabBar.
- [x] Registrera `/import` i router och lägg till nav-destination i AppShell.
- [ ] Verifiera recept-import end-to-end (fil + URL → create-screen).
- [ ] Bygg `presentation/receipt_import_tab.dart` (uppladdning + granskningssteg).
- [ ] Verifiera kvitto-import end-to-end (fil → parse → granska → inventarie).
## Fas 7 - Profil/admin parity
- Profil for alla anvandare.