MBO-Tech-IT-Webseite/modules/06-website-cms/files/components/admin/UeberUnsVerwaltung.tsx

110 lines
6.4 KiB
TypeScript

'use client'
import { useState, useEffect } from 'react'
interface Stat { id: string; wert: string; label: string; reihenfolge: number }
const inp: React.CSSProperties = { width: '100%', padding: '8px 12px', borderRadius: '6px', border: '1px solid var(--border-color)', background: 'var(--bg)', color: 'var(--text-primary)', fontSize: '14px', boxSizing: 'border-box' }
const lbl: React.CSSProperties = { fontSize: '11px', fontWeight: 600, textTransform: 'uppercase', letterSpacing: '1px', color: 'var(--text-muted)', display: 'block', marginBottom: '6px' }
export function UeberUnsVerwaltung() {
const [eyebrowText, setEyebrowText] = useState('Klein, aber fein')
const [absatz1, setAbsatz1] = useState('')
const [absatz2, setAbsatz2] = useState('')
const [bildUrl, setBildUrl] = useState<string | null>(null)
const [stats, setStats] = useState<Stat[]>([])
const [newStat, setNewStat] = useState({ wert: '', label: '' })
const [saving, setSaving] = useState(false)
const [saved, setSaved] = useState(false)
const [uploading, setUploading] = useState(false)
const [loading, setLoading] = useState(true)
useEffect(() => {
fetch('/api/admin/ueber-uns').then(r => r.json()).then(({ content: c, stats: s }) => {
if (c) { setEyebrowText(c.eyebrow_text ?? 'Klein, aber fein'); setAbsatz1(c.absatz1 ?? ''); setAbsatz2(c.absatz2 ?? ''); setBildUrl(c.bild_url ?? null) }
setStats(s ?? [])
setLoading(false)
})
}, [])
async function handleSave(e: React.FormEvent) {
e.preventDefault(); setSaving(true)
await fetch('/api/admin/ueber-uns', { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ eyebrow_text: eyebrowText, absatz1, absatz2, bild_url: bildUrl }) })
setSaving(false); setSaved(true); setTimeout(() => setSaved(false), 2000)
}
async function handleBildUpload(e: React.ChangeEvent<HTMLInputElement>) {
const file = e.target.files?.[0]
if (!file) return
setUploading(true)
const fd = new FormData(); fd.append('file', file)
const res = await fetch('/api/admin/ueber-uns/upload', { method: 'POST', body: fd })
const { url, error } = await res.json()
if (url) setBildUrl(url)
else alert(error ?? 'Upload fehlgeschlagen')
setUploading(false)
}
async function addStat() {
if (!newStat.wert.trim() || !newStat.label.trim()) return
const res = await fetch('/api/admin/ueber-uns/stats', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ ...newStat, reihenfolge: stats.length }) })
const { stat } = await res.json()
setStats(prev => [...prev, stat]); setNewStat({ wert: '', label: '' })
}
async function deleteStat(id: string) {
await fetch(`/api/admin/ueber-uns/stats/${id}`, { method: 'DELETE' })
setStats(prev => prev.filter(s => s.id !== id))
}
if (loading) return <p style={{ color: 'var(--text-muted)' }}>Lade</p>
return (
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '32px' }}>
<form onSubmit={handleSave} style={{ display: 'flex', flexDirection: 'column', gap: '16px' }}>
<div>
<label style={lbl}>Eyebrow-Text</label>
<input style={inp} value={eyebrowText} onChange={e => setEyebrowText(e.target.value)} placeholder="z. B. Klein, aber fein" />
</div>
<div>
<label style={lbl}>Absatz 1</label>
<textarea rows={4} style={{ ...inp, resize: 'vertical' }} value={absatz1} onChange={e => setAbsatz1(e.target.value)} />
</div>
<div>
<label style={lbl}>Absatz 2</label>
<textarea rows={4} style={{ ...inp, resize: 'vertical' }} value={absatz2} onChange={e => setAbsatz2(e.target.value)} />
</div>
<div>
<label style={lbl}>Sektionsbild</label>
{bildUrl && (
/* eslint-disable-next-line @next/next/no-img-element */
<img src={bildUrl} alt="Vorschau" style={{ width: '100%', height: '120px', objectFit: 'cover', borderRadius: '6px', marginBottom: '8px', border: '1px solid var(--border-color)' }} />
)}
<input type="file" accept="image/*" onChange={handleBildUpload} disabled={uploading} style={{ fontSize: '13px', color: 'var(--text-muted)' }} />
{uploading && <p style={{ fontSize: '12px', color: 'var(--text-muted)', marginTop: '4px' }}>Hochladen</p>}
</div>
<button type="submit" disabled={saving} style={{ padding: '10px', borderRadius: '6px', background: 'var(--accent)', color: '#fff', fontWeight: 700, border: 'none', cursor: 'pointer', fontSize: '14px' }}>
{saving ? 'Speichert…' : saved ? '✓ Gespeichert' : 'Speichern'}
</button>
</form>
<div>
<label style={lbl}>Statistiken</label>
<div style={{ display: 'flex', flexDirection: 'column', gap: '8px', marginBottom: '12px' }}>
{stats.map(s => (
<div key={s.id} style={{ display: 'grid', gridTemplateColumns: '1fr 1fr auto', gap: '8px', alignItems: 'center' }}>
<input style={inp} defaultValue={s.wert} onBlur={async e => { await fetch(`/api/admin/ueber-uns/stats/${s.id}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ wert: e.target.value }) }) }} />
<input style={inp} defaultValue={s.label} onBlur={async e => { await fetch(`/api/admin/ueber-uns/stats/${s.id}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ label: e.target.value }) }) }} />
<button onClick={() => deleteStat(s.id)} style={{ padding: '6px 10px', borderRadius: '6px', background: 'transparent', border: '1px solid rgba(220,38,38,0.3)', color: '#f87171', cursor: 'pointer', fontSize: '12px' }}></button>
</div>
))}
</div>
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr auto', gap: '8px', alignItems: 'center' }}>
<input style={inp} value={newStat.wert} onChange={e => setNewStat(p => ({ ...p, wert: e.target.value }))} placeholder="Wert (z. B. 2022)" />
<input style={inp} value={newStat.label} onChange={e => setNewStat(p => ({ ...p, label: e.target.value }))} placeholder="Label (z. B. Gegründet)" />
<button type="button" onClick={addStat} style={{ padding: '8px 14px', borderRadius: '6px', background: 'var(--accent)', color: '#fff', fontWeight: 700, border: 'none', cursor: 'pointer', fontSize: '13px' }}>+</button>
</div>
</div>
</div>
)
}