feat: Implement quick import feature for recipes

- Added QuickImportController and QuickImportService to handle recipe imports from URLs and file paths.
- Created QuickImportModule to encapsulate the quick import functionality.
- Developed frontend ImportFilePage for users to upload files or enter URLs for recipe import.
- Integrated API proxy to communicate with the backend for quick import requests.
- Implemented WriteRecipePage for users to manually input recipes with Markdown support.
- Added page routing for the new import and write recipe functionalities.
This commit is contained in:
Nils-Johan Gynther
2026-04-12 07:41:18 +02:00
parent ea971c2f63
commit 4f183df711
12 changed files with 1379 additions and 61 deletions
+83 -47
View File
@@ -52,10 +52,11 @@ Recipe App är en fullstack-applikation för hantering av hemmavaror, recept och
| | `actions.ts` | Server actions för inventarie |
| **Recept** | `app/recipes/page.tsx` | Lista recept |
| | `RecipePreview.tsx` | Receptförhandsvisning med inventariestatus |
| **Skapa recept** | `app/recipes/create/page.tsx` | Receptkreation (manual form) |
| | `app/recipes/create/CreateRecipePage.tsx` | Komponenter för receptskapande |
| **Importera recept** | `app/recipes/import/page.tsx` | Startpunkt för Markdown-import |
| | `app/recipes/import/ImportRecipePage.tsx` | 3-stegsvyn för Markdown-import |
| **Lägg till recept** | `app/recipes/create/page.tsx` | Meny för receptskaping (val mellan två vägar) |
| **Skriv in recept** | `app/recipes/write/page.tsx` | Startpunkt för Markdown-inmatning |
| | `app/recipes/write/WriteRecipePage.tsx` | Komponenter för receptskapande (Markdown-baserat, 3-steg) |
| **Importera från fil** | `app/recipes/import/page.tsx` | Startpunkt för fil/länk-import |
| | `app/recipes/import/ImportFilePage.tsx` | Komponenter för fil-/länk-import (PDF, URL, etc) |
| **Recipe detail** | `app/recipes/[id]/` | Enskilt recept (detaljer, redigering) |
| **Admin: Produkter** | `app/admin/products/page.tsx` | Produktadmin-panel |
| | `AdminProductList.tsx` | Lista produkter, sök, sortera |
@@ -67,7 +68,7 @@ Recipe App är en fullstack-applikation för hantering av hemmavaror, recept och
| Route | Metod | Syfte |
|-------|-------|-------|
| `/api/parse-markdown-proxy` | POST | Proxies `POST /api/recipes/parse-markdown` (Markdown-tolkning) |
| `/api/parse-markdown-proxy` | POST | Proxies `POST /api/recipes/parse-markdown` (Markdown-tolkning för skriv-in-recept) |
| `/api/inventory-history-proxy` | GET | Proxies konsumtionshistorik |
| `/api/recipe-preview-proxy` | GET | Proxies receptförhandsvisning |
| `/api/admin/merge-preview-proxy` | GET | Proxies produktmerge-preview |
@@ -126,6 +127,10 @@ backend/src/
│ ├── update-product.dto.ts
│ ├── merge-products.dto.ts
│ └── update-canonical-name.dto.ts
├── quick-import/ # NYT: Snabbimport-modul
│ ├── quick-import.controller.ts # POST /api/quick-import
│ ├── quick-import.service.ts # ICA-skrapning, PDF-stöd
│ └── quick-import.module.ts # Module definition
└── recipes/
├── recipes.controller.ts # Recept endpoints
├── recipes.service.ts # Recept + Markdown-parsing
@@ -205,6 +210,8 @@ GET /api/inventory/:id/consumption-history Konsumtionshistorik
### 🍽️ Recept-endpoints
```
POST /api/quick-import SNITT: Snabbimport (ICA-skrapning)
Body: { input: string (URL eller filsökväg) }
POST /api/recipes/parse-markdown Tolka Markdown-recept (matchningslogik)
GET /api/recipes Lista alla recept
POST /api/recipes Skapa nytt recept
@@ -329,15 +336,61 @@ model RecipeIngredient {
---
## Receptimport via Markdown — Detaljerad arkitektur
## Receptimport och receptskaping — Detaljerad arkitektur
### Syfte
### Syfte och struktur
Användaren kan importera ett recept skrivet i Markdown-format istället för att fylla i formularet manuellt. Systemet:
1. Tolkar Markdown-format (namn, beskrivning, ingredienser, instruktioner)
2. Matchar varje ingrediens mot produktdatabasen (intelligenta matchningar)
3. Låter användaren granska förslag och välja rätt produkt
4. Sparar receptet med valida ingredienser
Recipe App erbjuder tre vägar för att lägga till recept:
1. **Snabbimport** — Klistra in ICA-länk för automatisk skrapning (ny feature)
2. **Skriv in recept** (`/recipes/write`) — Markdown-baserad inmatning där användaren skriver receptet i enkelt format
3. **Importera från fil** (`/recipes/import`) — Ladda upp PDF, länk eller andra receptkällor (under utveckling)
Alla vägar möjliggör automatisk matchning av ingredienser mot databasen.
### Strukturöversikt
#### Snabbimport-fältet
**Frontend: `/recipes/create/page.tsx`**
- Ovanför de två huvudvalen visas ett gult inmatningsfält för snabbimport
- Användaren klistrar in en ICA-receptlänk eller filsökväg
- Vid submit:
1. Frontend skickar till `/api/quick-import-proxy`
2. Proxy proxiar till backend `POST /api/quick-import`
3. Backend returnerar Markdown-text
4. Frontend sparar i `sessionStorage('recipeMarkdown')`
5. Omdirigera till `/recipes/write` med förifylld Markdown
**Backend: `QuickImportService` (ny modul)**
- Ansvarig för ICA-skrapning, PDF-tolkning, URL-validering
- **Huvudmetod:** `importFromInput(input: string)` — Detekterar input-typ och delegerar
- **ICA-specifik:**
- Validerar URL (måste vara ICA.se)
- Fetchar HTML via `fetch()`
- Parsar HTML med regex för: receptnamn, ingredienser, instruktioner
- Konverterar till Markdown-format
- **Felhantering:** Specifika felmeddelanden per scenario
- **PDF-support:** Stubben för framtida integration (throwError: "PDF-import är under utveckling")
- **Error-strategi:**
- `400 Bad Request` — Tomt input, inte URL/fil
- `400 Bad Request` — Länken är inte från ICA.se
- `503 Service Unavailable` — Network-fel vid hämtning (HTTP-fel från ICA)
- `400 Bad Request` — HTML-parsing misslyckades (receptnamn/ingredienser inte hittade)
**API-endpoint:**
```
POST /api/quick-import
Input: { input: string }
Output: { markdown: string, source: 'ica' | 'pdf' | 'other' }
```
**Proxy-route (Next.js):**
- `/api/quick-import-proxy` — Proxies till backend
- Hanterar error-konvertering (BE HTTP → FE error message)
- Returnerar Markdown eller JSON-error
### Markdown-format och parsningsregler
### Markdown-format och parsningsregler
@@ -486,44 +539,27 @@ Top 5: Max 5 förslag per ingrediens
}
```
#### 3. Frontend: `/recipes/import` page
#### 3. Frontend: Receptskapsidor
**Komponenter:**
- `ImportRecipePage.tsx` — Main client component (3-steps state machine)
- Använder `/api/parse-markdown-proxy` för backend-anrop (Next.js proxy)
**Huvudmeny: `/recipes/create/page.tsx`**
- Presenterar två val-kort (card-baserad UI)
- "Skriv in recept" → `/recipes/write`
- "Importera från fil/länk" → `/recipes/import`
**Steg 1: Klistra in Markdown**
- `<textarea>` för råtext
- Knapp: "Tolka recept" → POST /api/parse-markdown-proxy
- Error handling med svenska meddelanden
**Skriv in recept: `/recipes/write/WriteRecipePage.tsx`**
- Main client component (3-steps state machine)
- Samma logik som tidigare `ImportRecipePage`
- **Steg 1:** Markdown-inmatning
- **Steg 2:** Granska ingredienser, välj produkter
- **Steg 3:** Spara recept
- Använder `/api/parse-markdown-proxy` för backend-anrop
**Steg 2: Granska och välj**
- Redigerbara fält: namn, beskrivning, instruktioner
- För varje ingrediens:
- Visar föreslagna produkter (top 5, prioriterad ordning)
- Fallback: Dropdown med alla produkter i DB
- Redigerbara fält: quantity, unit, note
- Visuell markering (gul ram) för ingredienser utan vald produkt
- Knapp: "Ta bort ingrediens"
- Validering: Minst 1 ingrediens måste ha vald produkt
**Steg 3: Spara**
- POST /api/recipes med:
```json
{
"name": "...",
"description": "... " eller undefined,
"instructions": "..." eller undefined,
"ingredients": [
{ "productId": 12, "quantity": 500, "unit": "g", "note": "vispgrädde" },
{ "productId": 34, "quantity": 1, "unit": "st", "note": undefined }
]
}
```
- Efter framgång: navigera till receptlistan
**Enhetsstöd i UI:**
- Dropdown-alternativ: g, kg, hg, ml, dl, l, st, tsk, msk
**Importera från fil: `/recipes/import/ImportFilePage.tsx`**
- Tabs/toggle mellan två metoder:
1. **Fil-upload** — Dra-och-släpp eller välja PDF/TXT/DOCX
2. **URL-import** — Ange länk till receptsida
- Placeholder för framtida integration
- Visar tips för att använda "Skriv in recept" tills dessa funktioner är klara
#### 4. API-proxy-route (Next.js)