'use client'; import { useState, useEffect } from 'react'; import { useRouter } from 'next/navigation'; import { fetchJson } from '../../../lib/api'; import { parseErrorResponse } from '../../../lib/error-handler'; import type { Product } from '../../../features/inventory/types'; import Navigation from '../../Navigation'; import { UNIT_OPTIONS } from '../../../lib/units'; type ProductSuggestion = { productId: number; productName: string; score: number; }; type ParsedIngredientRow = { rawName: string; quantity: number; unit: string; note?: string; suggestions: ProductSuggestion[]; selectedProductId: number; editedQuantity: string; editedUnit: string; editedNote: string; }; type ParseResult = { name: string; description?: string; instructions?: string; ingredients: ParsedIngredientRow[]; }; type Step = 'input' | 'review' | 'saving'; export default function WriteRecipePage() { const router = useRouter(); const [step, setStep] = useState('input'); const [markdown, setMarkdown] = useState(''); const [parsed, setParsed] = useState(null); const [editedName, setEditedName] = useState(''); const [editedDescription, setEditedDescription] = useState(''); const [editedInstructions, setEditedInstructions] = useState(''); const [ingredients, setIngredients] = useState([]); const [allProducts, setAllProducts] = useState([]); const [isParsing, setIsParsing] = useState(false); const [isSaving, setIsSaving] = useState(false); const [error, setError] = useState(null); const [showDebugPanel, setShowDebugPanel] = useState(false); useEffect(() => { // Hämta produkter från databas fetchJson('/api/products') .then(setAllProducts) .catch(console.error); // Kontrollera om det finns förifylld Markdown från snabbimport const prefilledMarkdown = sessionStorage.getItem('prefilled_markdown'); const prefilledImageUrl = sessionStorage.getItem('prefilled_image_url'); if (prefilledImageUrl) { setImageUrl(prefilledImageUrl); sessionStorage.removeItem('prefilled_image_url'); } if (prefilledMarkdown) { setMarkdown(prefilledMarkdown); sessionStorage.removeItem('prefilled_markdown'); // Auto-parse markdown från snabbimport setIsParsing(true); (async () => { try { const res = await fetch('/api/parse-markdown-proxy', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ markdown: prefilledMarkdown }), }); if (!res.ok) { const errorText = await res.text(); throw new Error(errorText || 'Kunde inte tolka recept'); } const data = await res.json(); const rows: ParsedIngredientRow[] = data.ingredients.map( (ing: Omit) => ({ ...ing, selectedProductId: ing.suggestions[0]?.productId ?? 0, editedQuantity: String(ing.quantity), editedUnit: ing.unit, editedNote: ing.note ?? '', }), ); setParsed(data); setEditedName(data.name); setEditedDescription(data.description ?? ''); setEditedInstructions(data.instructions ?? ''); setIngredients(rows); setStep('review'); } catch (err) { const message = err instanceof Error ? err.message : 'Något gick fel vid tolkning.'; setError(message); } finally { setIsParsing(false); } })(); } }, []); const handleParse = async () => { if (!markdown.trim()) return; setIsParsing(true); setError(null); try { const res = await fetch('/api/parse-markdown-proxy', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ markdown }), }); if (!res.ok) { const errorMessage = await parseErrorResponse(res); throw new Error(errorMessage); } const data = await res.json(); const rows: ParsedIngredientRow[] = data.ingredients.map( (ing: Omit) => ({ ...ing, selectedProductId: ing.suggestions[0]?.productId ?? 0, editedQuantity: String(ing.quantity), editedUnit: ing.unit, editedNote: ing.note ?? '', }), ); setParsed(data); setEditedName(data.name); setEditedDescription(data.description ?? ''); setEditedInstructions(data.instructions ?? ''); setIngredients(rows); setStep('review'); } catch (err) { const message = err instanceof Error ? err.message : 'Något gick fel vid tolkning.'; setError(message); } finally { setIsParsing(false); } }; const updateIngredient = (index: number, field: keyof ParsedIngredientRow, value: string | number) => { setIngredients((prev) => { const updated = [...prev]; updated[index] = { ...updated[index], [field]: value }; return updated; }); }; const removeIngredient = (index: number) => { setIngredients((prev) => prev.filter((_, i) => i !== index)); }; const handleSave = async () => { setIsSaving(true); setError(null); const validIngredients = ingredients.filter((ing) => ing.selectedProductId > 0); if (validIngredients.length === 0) { setError('Minst en ingrediens med vald produkt krävs.'); setIsSaving(false); return; } const body = { name: editedName, description: editedDescription || undefined, instructions: editedInstructions || undefined, imageUrl: imageUrl || undefined, ingredients: validIngredients.map((ing) => ({ productId: ing.selectedProductId, quantity: Number(ing.editedQuantity), unit: ing.editedUnit, note: ing.editedNote || undefined, })), }; try { const res = await fetch('/api/recipes', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body), }); if (!res.ok) { const errorMessage = await parseErrorResponse(res); throw new Error(errorMessage); } router.push('/recipes'); } catch (err) { const message = err instanceof Error ? err.message : 'Något gick fel vid sparning.'; setError(message); } finally { setIsSaving(false); } }; return (

Skriv in recept

Skriv receptet i Markdown-format — nama, ingredienser och instruktioner.

{/* Steg-indikator */}
1. Skriv 2. Granska 3. Spara
{error && (

{error}

)} {/* STEG 1: Markdown-inmatning */} {step === 'input' && (
Förväntat format:
{`# Receptnamn

Valfri beskrivning av receptet.

## Ingredienser
- 500 g köttfärs
- 1 st lök
- 2 msk tomatpuré
- 1 dl grädde (vispgrädde)

## Tillvägagångssätt
Stek löken i lite smör. Tillsätt köttfärsen...`}