269 lines
8.4 KiB
TypeScript
269 lines
8.4 KiB
TypeScript
'use client';
|
|
|
|
import Link from 'next/link';
|
|
import { useRouter } from 'next/navigation';
|
|
import { useState } from 'react';
|
|
import Navigation from '../../Navigation';
|
|
import { parseErrorResponse } from '../../../lib/error-handler';
|
|
|
|
export default function ImportFilePage() {
|
|
const router = useRouter();
|
|
const [selectedMethod, setSelectedMethod] = useState<'file' | 'url' | null>('file');
|
|
const [selectedFile, setSelectedFile] = useState<File | null>(null);
|
|
const [url, setUrl] = useState('');
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
const handleFileSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
|
|
e.preventDefault();
|
|
|
|
if (!selectedFile) {
|
|
setError('Välj en PDF eller bildfil först.');
|
|
return;
|
|
}
|
|
|
|
setError(null);
|
|
setIsLoading(true);
|
|
|
|
try {
|
|
const formData = new FormData();
|
|
formData.append('file', selectedFile);
|
|
|
|
const res = await fetch('/api/quick-import-proxy', {
|
|
method: 'POST',
|
|
body: formData,
|
|
});
|
|
|
|
if (!res.ok) {
|
|
const errorMessage = await parseErrorResponse(res);
|
|
throw new Error(errorMessage);
|
|
}
|
|
|
|
const data = await res.json();
|
|
sessionStorage.setItem('prefilled_markdown', data.markdown ?? '');
|
|
router.push('/recipes/write');
|
|
} catch (err) {
|
|
setError(err instanceof Error ? err.message : 'Importen misslyckades.');
|
|
} finally {
|
|
setIsLoading(false);
|
|
}
|
|
};
|
|
|
|
const handleUrlSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
|
|
e.preventDefault();
|
|
|
|
if (!url.trim()) {
|
|
setError('Vänligen ange en URL.');
|
|
return;
|
|
}
|
|
|
|
setError(null);
|
|
setIsLoading(true);
|
|
|
|
try {
|
|
const res = await fetch('/api/quick-import-proxy', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ input: url.trim() }),
|
|
});
|
|
|
|
if (!res.ok) {
|
|
const errorMessage = await parseErrorResponse(res);
|
|
throw new Error(errorMessage);
|
|
}
|
|
|
|
const data = await res.json();
|
|
sessionStorage.setItem('prefilled_markdown', data.markdown ?? '');
|
|
router.push('/recipes/write');
|
|
} catch (err) {
|
|
setError(err instanceof Error ? err.message : 'Importen misslyckades.');
|
|
} finally {
|
|
setIsLoading(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<main style={{ padding: '1rem', maxWidth: '900px', margin: '0 auto' }}>
|
|
<Navigation />
|
|
<h1 style={{ marginBottom: '0.5rem' }}>Importera från fil eller länk</h1>
|
|
<p style={{ color: '#666', marginBottom: '1.5rem' }}>
|
|
Ladda upp en PDF eller bild för OCR, eller ange en receptlänk.
|
|
</p>
|
|
|
|
{error && (
|
|
<div
|
|
style={{
|
|
background: '#fef2f2',
|
|
border: '1px solid #fca5a5',
|
|
borderRadius: '6px',
|
|
padding: '1rem',
|
|
marginBottom: '1.5rem',
|
|
color: '#dc2626',
|
|
fontSize: '0.95rem',
|
|
}}
|
|
>
|
|
{error}
|
|
</div>
|
|
)}
|
|
|
|
<div
|
|
style={{
|
|
display: 'grid',
|
|
gridTemplateColumns: 'repeat(auto-fit, minmax(350px, 1fr))',
|
|
gap: '1.5rem',
|
|
marginBottom: '2rem',
|
|
}}
|
|
>
|
|
<div
|
|
onClick={() => setSelectedMethod('file')}
|
|
style={{
|
|
padding: '2rem',
|
|
border: selectedMethod === 'file' ? '2px solid #0070f3' : '2px solid #e5e7eb',
|
|
borderRadius: '8px',
|
|
background: selectedMethod === 'file' ? '#f0f9ff' : '#f9fafb',
|
|
cursor: 'pointer',
|
|
}}
|
|
>
|
|
<h2 style={{ margin: '0 0 1rem 0', fontSize: '1.2rem', color: '#0070f3' }}>
|
|
Ladda upp PDF eller bild
|
|
</h2>
|
|
<p style={{ color: '#666', margin: '0 0 1rem 0', fontSize: '0.95rem' }}>
|
|
Stöd för PDF, PNG, JPG, JPEG, WEBP och BMP.
|
|
</p>
|
|
|
|
{selectedMethod === 'file' && (
|
|
<form onSubmit={handleFileSubmit} style={{ display: 'grid', gap: '0.75rem' }}>
|
|
<input
|
|
type="file"
|
|
accept=".pdf,.png,.jpg,.jpeg,.webp,.bmp"
|
|
onChange={(e) => setSelectedFile(e.target.files?.[0] ?? null)}
|
|
style={{
|
|
padding: '0.75rem',
|
|
background: 'white',
|
|
border: '1px solid #cbd5e1',
|
|
borderRadius: '6px',
|
|
}}
|
|
/>
|
|
<button
|
|
type="submit"
|
|
disabled={!selectedFile || isLoading}
|
|
style={{
|
|
padding: '0.75rem',
|
|
background: '#0070f3',
|
|
color: 'white',
|
|
border: 'none',
|
|
borderRadius: '4px',
|
|
cursor: !selectedFile || isLoading ? 'not-allowed' : 'pointer',
|
|
opacity: !selectedFile || isLoading ? 0.6 : 1,
|
|
fontWeight: 600,
|
|
}}
|
|
>
|
|
{isLoading ? 'Importerar...' : 'Importera fil'}
|
|
</button>
|
|
</form>
|
|
)}
|
|
</div>
|
|
|
|
<div
|
|
onClick={() => setSelectedMethod('url')}
|
|
style={{
|
|
padding: '2rem',
|
|
border: selectedMethod === 'url' ? '2px solid #10b981' : '2px solid #e5e7eb',
|
|
borderRadius: '8px',
|
|
background: selectedMethod === 'url' ? '#f0fdf4' : '#f9fafb',
|
|
cursor: 'pointer',
|
|
}}
|
|
>
|
|
<h2 style={{ margin: '0 0 1rem 0', fontSize: '1.2rem', color: '#10b981' }}>
|
|
Länk till recept
|
|
</h2>
|
|
<p style={{ color: '#666', margin: '0 0 1rem 0', fontSize: '0.95rem' }}>
|
|
Ange URL till exempelvis ICA eller en annan receptsida.
|
|
</p>
|
|
|
|
{selectedMethod === 'url' && (
|
|
<form onSubmit={handleUrlSubmit} style={{ display: 'grid', gap: '0.75rem' }}>
|
|
<input
|
|
type="url"
|
|
value={url}
|
|
onChange={(e) => setUrl(e.target.value)}
|
|
placeholder="https://exempel.se/recept/..."
|
|
style={{
|
|
width: '100%',
|
|
padding: '0.75rem',
|
|
border: '1px solid #d1d5db',
|
|
borderRadius: '6px',
|
|
fontSize: '0.9rem',
|
|
boxSizing: 'border-box',
|
|
}}
|
|
/>
|
|
<button
|
|
type="submit"
|
|
disabled={!url.trim() || isLoading}
|
|
style={{
|
|
width: '100%',
|
|
padding: '0.75rem',
|
|
background: '#10b981',
|
|
color: 'white',
|
|
border: 'none',
|
|
borderRadius: '4px',
|
|
cursor: !url.trim() || isLoading ? 'not-allowed' : 'pointer',
|
|
opacity: !url.trim() || isLoading ? 0.6 : 1,
|
|
fontWeight: 600,
|
|
fontSize: '0.95rem',
|
|
}}
|
|
>
|
|
{isLoading ? 'Importerar...' : 'Importera från länk'}
|
|
</button>
|
|
</form>
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
<div
|
|
style={{
|
|
background: '#f0fdf4',
|
|
border: '1px solid #86efac',
|
|
borderRadius: '6px',
|
|
padding: '1rem',
|
|
marginBottom: '1.5rem',
|
|
color: '#166534',
|
|
fontSize: '0.9rem',
|
|
}}
|
|
>
|
|
Efter import öppnas receptet automatiskt i redigeringsläget.
|
|
</div>
|
|
|
|
<div style={{ display: 'flex', gap: '1rem' }}>
|
|
<Link
|
|
href="/recipes/create"
|
|
style={{
|
|
padding: '0.75rem 1.5rem',
|
|
background: 'transparent',
|
|
border: '1px solid #ddd',
|
|
borderRadius: '4px',
|
|
textDecoration: 'none',
|
|
color: '#333',
|
|
fontWeight: 500,
|
|
}}
|
|
>
|
|
Tillbaka
|
|
</Link>
|
|
<Link
|
|
href="/recipes/write"
|
|
style={{
|
|
padding: '0.75rem 1.5rem',
|
|
background: '#0070f3',
|
|
color: 'white',
|
|
borderRadius: '4px',
|
|
textDecoration: 'none',
|
|
fontWeight: 500,
|
|
}}
|
|
>
|
|
Skriv in recept istället
|
|
</Link>
|
|
</div>
|
|
</main>
|
|
);
|
|
}
|