/** * WEB-0b: Seiten-Editor der öffentlichen Webseite. * - Kopf: Titel, SEO-Beschreibung, Status (Entwurf/Veröffentlicht). * - Geordneter Block-Editor: Blöcke hinzufügen, bearbeiten, verschieben, löschen. * * Reihenfolge/Anlegen/Löschen rufen das Backend auf und laden danach neu; der * Editor wird über `key` neu montiert, sodass der lokale Zustand frisch aus den * geladenen Daten initialisiert wird (keine Prop→State-Synchronisation per Effekt). */ import { useState } from 'react' import { Link, useParams } from 'react-router-dom' import { de } from '../strings/de' import { ADDABLE_BLOCK_TYPES, addBlock, defaultBlockData, deleteBlock, getPage, reorderBlocks, updateBlock, updatePage, type Block, type BlockData, type BlockType, type GalleryImage, type Page, type PageStatus, } from '../api/pages' import { useApi, useMutation } from '../hooks/useApi' import './webseite.css' const asStr = (v: unknown): string => (typeof v === 'string' ? v : '') export default function WebseiteEditorPage() { const { slug = '' } = useParams<{ slug: string }>() const page = useApi(() => getPage(slug), [slug]) if (page.loading) return

{de.common.loading}

if (page.error || !page.data) { return (

{de.pages.webseite.title}

{page.error}
) } // Signatur der Blöcke -> erzwingt Neu-Montage nach Reload (frische Init). const signature = page.data.blocks.map((b) => `${b.id}:${b.order}`).join('|') return } function PageEditor({ page, reload }: { page: Page; reload: () => void }) { const t = de.pages.webseite const [title, setTitle] = useState(page.title) const [seo, setSeo] = useState(page.seoDescription ?? '') const [status, setStatus] = useState(page.status) const [savedHead, setSavedHead] = useState(false) const saveHead = useMutation(() => updatePage(page.id, { slug: page.slug, title, seoDescription: seo.trim() === '' ? null : seo, status, }), ) async function onSaveHead() { const r = await saveHead.run() if (r.ok) { setSavedHead(true) reload() } } const blocks = [...page.blocks].sort((a, b) => a.order - b.order) const adder = useMutation((type: BlockType) => addBlock(page.id, { type, data: defaultBlockData(type) }), ) async function onAdd(type: BlockType) { const r = await adder.run(type) if (r.ok) reload() } const remover = useMutation((id: string) => deleteBlock(id)) async function onDelete(id: string) { if (!window.confirm(t.blocks.confirmDelete)) return const r = await remover.run(id) if (r.ok) reload() } const reorder = useMutation((ids: string[]) => reorderBlocks(page.id, ids)) async function onMove(index: number, dir: -1 | 1) { const target = index + dir if (target < 0 || target >= blocks.length) return const ids = blocks.map((b) => b.id) ;[ids[index], ids[target]] = [ids[target], ids[index]] const r = await reorder.run(ids) if (r.ok) reload() } const busy = adder.pending || remover.pending || reorder.pending return (

{page.title}

/{page.slug}

{t.back}
{/* Seiten-Kopf bearbeiten */}