import { useEffect, useState } from 'react' import { FaCopy, FaSpinner } from 'react-icons/fa6' import { Button } from '../ui' import { getZeitenErsatz, patchZeitenTeam } from '../../lib/teamApi' import { KEINE_ZEITEN_TEXT, ersatzKnoepfe, ersatzKopieren, ersatzMeldung, navSelektorFehler, teamBody, teamFormular, teamGeaendert, teamSpeichernFehler, } from '../../lib/zeitenView' // Panel "Öffnungszeiten live" unter der Zeile im Reiter "Funktionen": Team-Einstellungen der Website-Leisten (nur das Team ändert sie) // und "Ersatz-HTML kopieren" je Plan. Entscheidungen, Texte und Prüfungen stehen in zeitenView (rein, getestet); hier wird nur verdrahtet. // Texte stehen ausschließlich als React-Textknoten da (nie als HTML). Die Hülle (area-row funktionen-panel) liegt als eigene Zeile außerhalb // des Fünf-Spalten-Rasters, wie die Einbauanleitung des Terminplaners. export default function ZeitenPanel({ customerId, projectId, feature, onSaved, onReload }) { const start = teamFormular(feature) const [form, setForm] = useState(start) const [busy, setBusy] = useState(false) const [meldung, setMeldung] = useState(null) // { ok, text, neuLaden? } zum Speichern const [ersatz, setErsatz] = useState({ kurz: null, busy: false, meldung: null, html: '' }) // Neuer Stand vom Server (nach dem Speichern oder Neuladen): Formular auf die gespeicherten Werte setzen useEffect(() => { setForm({ navSelektor: start.navSelektor, kontaktleisteAus: start.kontaktleisteAus, hinweisleisteAus: start.hinweisleisteAus }) }, [feature.teamVersion, start.navSelektor, start.kontaktleisteAus, start.hinweisleisteAus]) // Eine Eingabe macht "Gespeichert." und alte Fehler unpassend; die Aufforderung zum Neuladen bleibt, bis sie befolgt wird const aendern = (teil) => { setMeldung((m) => (m?.neuLaden ? m : null)) setForm((f) => ({ ...f, ...teil })) } const selektorFehler = navSelektorFehler(form.navSelektor) const geaendert = teamGeaendert(form, feature) const speichern = async (event) => { event.preventDefault() if (selektorFehler || !geaendert) return setBusy(true) setMeldung(null) try { const antwort = await patchZeitenTeam(customerId, teamBody({ projectId, teamVersion: feature.teamVersion, ...form })) onSaved(projectId, antwort) setMeldung({ ok: true, text: 'Gespeichert.' }) } catch (err) { const { text, neuLaden } = teamSpeichernFehler(err) setMeldung({ ok: false, text, neuLaden }) } finally { setBusy(false) } } const kopieren = async ({ kurz, bezeichnung }) => { setErsatz({ kurz, busy: true, meldung: null, html: '' }) try { const { html } = await getZeitenErsatz(customerId, projectId, kurz) const ergebnis = await ersatzKopieren(html, typeof navigator === 'undefined' ? undefined : navigator.clipboard) setErsatz({ kurz, busy: false, meldung: ersatzMeldung(ergebnis, feature.plaene?.length > 1 ? bezeichnung : ''), html: ergebnis === 'manuell' ? html : '' }) } catch (err) { setErsatz({ kurz, busy: false, meldung: { ok: false, text: err?.message || 'Ersatz-HTML konnte nicht geladen werden.' }, html: '' }) } } const knoepfe = ersatzKnoepfe(feature) return (
Öffnungszeiten live Einstellungen des Teams (der Kunde sieht und ändert sie nicht)
Nur nötig, wenn die Hinweis-Leiste den festen Header der Website überlappt: CSS-Selektor des Headers.
{selektorFehler &&
{selektorFehler}
}
{meldung && {meldung.text}} {meldung?.neuLaden && ( )}
Ersatz-HTML Wochentabelle des Plans für den Platzhalter der Website (Einbau)
{knoepfe.length === 0 ? (
{KEINE_ZEITEN_TEXT}
) : (
{knoepfe.map((k) => ( ))}
)} {ersatz.meldung &&
{ersatz.meldung.text}
} {ersatz.html && (