All checks were successful
Build & Deploy / deploy (push) Successful in 23s
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
106 lines
4.9 KiB
TypeScript
106 lines
4.9 KiB
TypeScript
import { useEffect, useState } from 'react';
|
||
import { useParams } from 'react-router-dom';
|
||
import { ApiError, fetchFreigabe, sendFreigabe, freigabeLayoutUrl, type Freigabe } from '../lib/api';
|
||
|
||
/**
|
||
* Öffentliche Motiv-Freigabe (Direktlink mit Einmal-Token, kein Login nötig).
|
||
* Zeigt den A6-Entwurf und lässt den Kunden freigeben oder einen Änderungswunsch
|
||
* hinterlegen. Erst nach Freigabe geht die Karte in den Druck.
|
||
*/
|
||
export default function FreigabeSeite() {
|
||
const { token = '' } = useParams();
|
||
const [data, setData] = useState<Freigabe | null>(null);
|
||
const [status, setStatus] = useState<'laedt' | 'da' | 'fehler'>('laedt');
|
||
const [fehler, setFehler] = useState('');
|
||
const [modus, setModus] = useState<'ansicht' | 'aendern'>('ansicht');
|
||
const [note, setNote] = useState('');
|
||
const [sendet, setSendet] = useState(false);
|
||
const [ergebnis, setErgebnis] = useState<'approved' | 'changes' | null>(null);
|
||
|
||
useEffect(() => {
|
||
fetchFreigabe(token)
|
||
.then((d) => { setData(d); setStatus('da'); if (d.status === 'approved' || d.status === 'changes') setErgebnis(d.status); })
|
||
.catch((e) => { setStatus('fehler'); setFehler(e instanceof ApiError ? e.message : 'Freigabe-Link ungültig oder abgelaufen.'); });
|
||
}, [token]);
|
||
|
||
async function absenden(action: 'approve' | 'changes') {
|
||
if (action === 'changes' && !note.trim()) { setFehler('Bitte beschreiben Sie kurz Ihren Änderungswunsch.'); return; }
|
||
setFehler(''); setSendet(true);
|
||
try {
|
||
await sendFreigabe(token, action, action === 'changes' ? note.trim() : undefined);
|
||
setErgebnis(action === 'approve' ? 'approved' : 'changes');
|
||
} catch (e) {
|
||
setFehler(e instanceof ApiError ? e.message : 'Konnte nicht gespeichert werden.');
|
||
} finally { setSendet(false); }
|
||
}
|
||
|
||
if (status === 'laedt') return <div className="sk-view"><p className="sk-note">Lädt …</p></div>;
|
||
if (status === 'fehler') return (
|
||
<div className="sk-view">
|
||
<h1>Freigabe</h1>
|
||
<p className="sk-error">{fehler}</p>
|
||
</div>
|
||
);
|
||
|
||
const d = data!;
|
||
const vorschau = (
|
||
<div style={{
|
||
margin: 'var(--sk-space-4) 0', maxWidth: 520, aspectRatio: '148 / 105', width: '100%',
|
||
border: '1px solid var(--sk-border)', borderRadius: 'var(--sk-radius)', overflow: 'hidden',
|
||
background: '#f4f6fa', boxShadow: '0 2px 10px rgba(0,0,0,.08)',
|
||
}}>
|
||
{d.has_layout
|
||
? <img src={freigabeLayoutUrl(token)} alt="A6-Entwurf" style={{ width: '100%', height: '100%', objectFit: 'contain', display: 'block' }} />
|
||
: <div style={{ display: 'grid', placeItems: 'center', height: '100%' }}><span className="sk-note">Entwurf wird noch erstellt …</span></div>}
|
||
</div>
|
||
);
|
||
|
||
if (ergebnis === 'approved') return (
|
||
<div className="sk-view">
|
||
<h1>Vielen Dank!</h1>
|
||
<p>Sie haben den Entwurf zu <strong>{d.order_number}</strong> freigegeben. Ihre Karte geht jetzt in den Druck.</p>
|
||
{vorschau}
|
||
</div>
|
||
);
|
||
if (ergebnis === 'changes') return (
|
||
<div className="sk-view">
|
||
<h1>Änderungswunsch erhalten</h1>
|
||
<p>Danke – wir haben Ihren Änderungswunsch zu <strong>{d.order_number}</strong> notiert und melden uns mit einem neuen Entwurf.</p>
|
||
{vorschau}
|
||
</div>
|
||
);
|
||
|
||
return (
|
||
<div className="sk-view">
|
||
<h1>Ihr Postkarten-Entwurf</h1>
|
||
<p className="sk-note">Bestellung {d.order_number} · {d.product}. Bitte prüfen Sie den Druck-Entwurf (A6). Erst nach Ihrer Freigabe geht die Karte in den Druck.</p>
|
||
{vorschau}
|
||
|
||
{fehler && <p className="sk-error" style={{ margin: '0 0 var(--sk-space-3)' }}>{fehler}</p>}
|
||
|
||
{modus === 'ansicht' ? (
|
||
<div style={{ display: 'flex', gap: 'var(--sk-space-3)', flexWrap: 'wrap' }}>
|
||
<button className="sk-btn sk-btn--primary" disabled={sendet} onClick={() => absenden('approve')}>
|
||
{sendet ? 'Wird gesendet …' : '✓ Entwurf freigeben'}
|
||
</button>
|
||
<button className="sk-btn" disabled={sendet} onClick={() => { setModus('aendern'); setFehler(''); }}>
|
||
Änderung wünschen
|
||
</button>
|
||
</div>
|
||
) : (
|
||
<div className="sk-field">
|
||
<label className="sk-label" htmlFor="f-note">Was sollen wir ändern?</label>
|
||
<textarea id="f-note" className="sk-input" rows={4} value={note} onChange={(e) => setNote(e.target.value)}
|
||
placeholder="z. B. Motiv etwas größer, anderer Ausschnitt, Text ergänzen …" />
|
||
<div style={{ display: 'flex', gap: 'var(--sk-space-3)', flexWrap: 'wrap', marginTop: 'var(--sk-space-3)' }}>
|
||
<button className="sk-btn sk-btn--primary" disabled={sendet} onClick={() => absenden('changes')}>
|
||
{sendet ? 'Wird gesendet …' : 'Änderungswunsch senden'}
|
||
</button>
|
||
<button className="sk-btn" disabled={sendet} onClick={() => { setModus('ansicht'); setFehler(''); }}>Zurück</button>
|
||
</div>
|
||
</div>
|
||
)}
|
||
</div>
|
||
);
|
||
}
|