diff --git a/src/lib/api.ts b/src/lib/api.ts index c76912d..8fb382e 100644 --- a/src/lib/api.ts +++ b/src/lib/api.ts @@ -232,7 +232,13 @@ export type Product = { input_mode: 'text' | 'datei'; }; -export type Format = { id: number; key: string; name: string; product: number }; +export type Format = { + id: number; key: string; name: string; product: number; + /** Familie fürs Ausrichtungs-Dropdown (z. B. A5, A6). Leer = eigener Eintrag. */ + family?: string | null; + /** Ausrichtung innerhalb der Familie. Leer = keine Wahl. */ + orientation?: 'hoch' | 'quer' | null; +}; /** * Produkt-Schlüssel, die für den angemeldeten Kunden individuell freigeschaltet @@ -274,11 +280,23 @@ export async function fetchFormats(): Promise { * öffentlichen Konfigurator bestellbar sind. Adress-Postkarten sind ausgenommen. */ export async function fetchCheckFormats(): Promise { - const data = await request( - '/items/formats?fields=id,key,name,product&filter[show_check][_eq]=true&limit=-1', + const felder = 'fields=id,key,name,product,family,orientation'; + try { + const data = await request( + `/items/formats?${felder}&filter[show_check][_eq]=true&limit=-1`, + { auth: false }, + ); + const rows: Format[] = data?.data ?? []; + if (rows.length) return rows; + } catch { + /* Feld show_check evtl. noch nicht angelegt → Fallback unten. */ + } + // Fallback (z. B. vor dem Directus-Bootstrap): aktive Formate, damit der Check nutzbar bleibt. + const aktiv = await request( + `/items/formats?${felder}&filter[active][_eq]=true&limit=-1`, { auth: false }, ); - return data?.data ?? []; + return aktiv?.data ?? []; } /* ── Preis & Bestellung (Extension skrift-orders) ─────────────────────────── */ diff --git a/src/routes/Textmenge.tsx b/src/routes/Textmenge.tsx index 970720c..8124c64 100644 --- a/src/routes/Textmenge.tsx +++ b/src/routes/Textmenge.tsx @@ -87,7 +87,9 @@ function overflowMeldung(overflow?: PreviewOverflow[]) { export default function Textmenge() { const [formate, setFormate] = useState([]); const [settings, setSettings] = useState(null); - const [format, setFormat] = useState('a4'); + // Format wird über Familie (A4/A5/A6/DIN lang) + optionale Ausrichtung (hoch/quer) gewählt. + const [familie, setFamilie] = useState(''); + const [ausrichtung, setAusrichtung] = useState(''); const [font, setFont] = useState('tilda'); const [realistic, setRealistic] = useState(true); const [text, setText] = useState(''); @@ -99,15 +101,45 @@ export default function Textmenge() { const [gross, setGross] = useState(false); useEffect(() => { - fetchCheckFormats() - .then((f) => { - setFormate(f); - setFormat(f.find((x) => x.key === 'a4')?.key ?? f[0]?.key ?? 'a4'); - }) - .catch(() => {}); + fetchCheckFormats().then(setFormate).catch(() => {}); fetchSettings().then(setSettings).catch(() => {}); }, []); + // Formate zu Familien gruppieren (gleiche family = ein Eintrag mit Ausrichtungen). + // Formate ohne family bilden je einen eigenen Eintrag (Label = Name). + const familien = useMemo(() => { + const map = new Map(); + for (const f of formate) { + const label = (f.family && f.family.trim()) || f.name; + if (!map.has(label)) map.set(label, []); + map.get(label)!.push(f); + } + return [...map.entries()].map(([label, items]) => ({ label, items })); + }, [formate]); + + // Aktuelle Familie + verfügbare Ausrichtungen + effektiv gewähltes Format. + const aktuelleFamilie = familien.find((fm) => fm.label === familie) ?? familien[0] ?? null; + const ausrichtungen = (aktuelleFamilie?.items ?? []).filter((f) => f.orientation); + const hatAusrichtung = ausrichtungen.length > 1; + const gewaehltesFormat = aktuelleFamilie + ? (hatAusrichtung + ? (aktuelleFamilie.items.find((f) => f.orientation === ausrichtung) ?? aktuelleFamilie.items[0]) + : aktuelleFamilie.items[0]) + : null; + const formatKey = gewaehltesFormat?.key ?? 'a4'; + + // Standardauswahl setzen / reparieren, wenn Formate geladen sind oder sich die Familie ändert. + useEffect(() => { + if (!familien.length) return; + const gueltig = familien.some((fm) => fm.label === familie); + if (!gueltig) { + const start = familien.find((fm) => fm.items.some((f) => f.key === 'a4')) ?? familien[0]; + setFamilie(start.label); + const ori = start.items.filter((f) => f.orientation); + setAusrichtung(ori.length > 1 ? (ori[0].orientation ?? '') : ''); + } + }, [familien, familie]); + // Escape schließt die Großansicht. useEffect(() => { if (!gross) return; @@ -142,7 +174,7 @@ export default function Textmenge() { setDoc(null); setFehler(null); setGross(false); - }, [text, font, format, realistic]); + }, [text, font, formatKey, realistic]); async function generieren() { if (!text.trim() || laedt) return; @@ -153,7 +185,7 @@ export default function Textmenge() { client_id: clientId(), text, font, - format, + format: formatKey, realistic, entries: [{}], }); @@ -185,13 +217,34 @@ export default function Textmenge() {
+ {hatAusrichtung && ( + + )}