110 lines
7.8 KiB
TypeScript
110 lines
7.8 KiB
TypeScript
'use client'
|
||
import { useState, useEffect } from 'react'
|
||
|
||
interface KontaktInfo { telefon: string; email: string; adresse_zeile1: string; adresse_zeile2: string; formular_empfaenger: string }
|
||
interface Oeffnungszeit { id: string; tag: string; von: string; bis: string; reihenfolge: number }
|
||
interface SocialLink { id: string; platform: string; url: 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 KontaktVerwaltung() {
|
||
const [info, setInfo] = useState<KontaktInfo>({ telefon: '', email: '', adresse_zeile1: '', adresse_zeile2: '', formular_empfaenger: '' })
|
||
const [zeiten, setZeiten] = useState<Oeffnungszeit[]>([])
|
||
const [social, setSocial] = useState<SocialLink[]>([])
|
||
const [newZeit, setNewZeit] = useState({ tag: '', von: '', bis: '' })
|
||
const [newSocial, setNewSocial] = useState({ platform: '', url: '' })
|
||
const [saving, setSaving] = useState(false)
|
||
const [saved, setSaved] = useState(false)
|
||
const [loading, setLoading] = useState(true)
|
||
|
||
useEffect(() => {
|
||
fetch('/api/admin/kontakt').then(r => r.json()).then(({ info: i, oeffnungszeiten: z, social: s }) => {
|
||
if (i) setInfo(i)
|
||
setZeiten(z ?? []); setSocial(s ?? []); setLoading(false)
|
||
})
|
||
}, [])
|
||
|
||
async function handleSave(e: React.FormEvent) {
|
||
e.preventDefault(); setSaving(true)
|
||
await fetch('/api/admin/kontakt', { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(info) })
|
||
setSaving(false); setSaved(true); setTimeout(() => setSaved(false), 2000)
|
||
}
|
||
|
||
async function addZeit() {
|
||
if (!newZeit.tag || !newZeit.von || !newZeit.bis) return
|
||
const res = await fetch('/api/admin/kontakt/oeffnungszeiten', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ ...newZeit, reihenfolge: zeiten.length }) })
|
||
const { eintrag } = await res.json()
|
||
setZeiten(prev => [...prev, eintrag]); setNewZeit({ tag: '', von: '', bis: '' })
|
||
}
|
||
|
||
async function deleteZeit(id: string) {
|
||
await fetch(`/api/admin/kontakt/oeffnungszeiten/${id}`, { method: 'DELETE' })
|
||
setZeiten(prev => prev.filter(z => z.id !== id))
|
||
}
|
||
|
||
async function addSocial() {
|
||
if (!newSocial.platform || !newSocial.url) return
|
||
const res = await fetch('/api/admin/kontakt/social', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ ...newSocial, reihenfolge: social.length }) })
|
||
const { eintrag } = await res.json()
|
||
setSocial(prev => [...prev, eintrag]); setNewSocial({ platform: '', url: '' })
|
||
}
|
||
|
||
async function deleteSocial(id: string) {
|
||
await fetch(`/api/admin/kontakt/social/${id}`, { method: 'DELETE' })
|
||
setSocial(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' }}>
|
||
<div style={{ display: 'flex', flexDirection: 'column', gap: '24px' }}>
|
||
<form onSubmit={handleSave} style={{ display: 'flex', flexDirection: 'column', gap: '12px' }}>
|
||
<label style={lbl}>Kontaktinfos</label>
|
||
{([['telefon', 'Telefon'], ['email', 'E-Mail (Anzeige)'], ['adresse_zeile1', 'Adresse Zeile 1'], ['adresse_zeile2', 'Adresse Zeile 2'], ['formular_empfaenger', 'Formular-Empfänger (E-Mail)']] as [keyof KontaktInfo, string][]).map(([key, placeholder]) => (
|
||
<input key={key} style={inp} value={info[key]} onChange={e => setInfo(p => ({ ...p, [key]: e.target.value }))} placeholder={placeholder} />
|
||
))}
|
||
<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}>Social Media</label>
|
||
{social.map(s => (
|
||
<div key={s.id} style={{ display: 'grid', gridTemplateColumns: '80px 1fr auto', gap: '8px', marginBottom: '6px', alignItems: 'center' }}>
|
||
<span style={{ fontSize: '13px', color: 'var(--text-muted)' }}>{s.platform}</span>
|
||
<input style={inp} defaultValue={s.url} onBlur={async e => { await fetch(`/api/admin/kontakt/social/${s.id}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ url: e.target.value }) }) }} />
|
||
<button onClick={() => deleteSocial(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 style={{ display: 'grid', gridTemplateColumns: '1fr 2fr auto', gap: '8px', marginTop: '8px' }}>
|
||
<input style={inp} value={newSocial.platform} onChange={e => setNewSocial(p => ({ ...p, platform: e.target.value }))} placeholder="Instagram" />
|
||
<input style={inp} value={newSocial.url} onChange={e => setNewSocial(p => ({ ...p, url: e.target.value }))} placeholder="https://…" />
|
||
<button type="button" onClick={addSocial} style={{ padding: '8px 14px', borderRadius: '6px', background: 'var(--accent)', color: '#fff', fontWeight: 700, border: 'none', cursor: 'pointer', fontSize: '13px' }}>+</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div>
|
||
<label style={lbl}>Öffnungszeiten</label>
|
||
{zeiten.map(z => (
|
||
<div key={z.id} style={{ display: 'grid', gridTemplateColumns: '1fr 70px 70px auto', gap: '8px', marginBottom: '6px', alignItems: 'center' }}>
|
||
<input style={inp} defaultValue={z.tag} onBlur={async e => { await fetch(`/api/admin/kontakt/oeffnungszeiten/${z.id}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ tag: e.target.value }) }) }} />
|
||
<input style={inp} defaultValue={z.von} onBlur={async e => { await fetch(`/api/admin/kontakt/oeffnungszeiten/${z.id}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ von: e.target.value }) }) }} placeholder="8:00" />
|
||
<input style={inp} defaultValue={z.bis} onBlur={async e => { await fetch(`/api/admin/kontakt/oeffnungszeiten/${z.id}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ bis: e.target.value }) }) }} placeholder="18:00" />
|
||
<button onClick={() => deleteZeit(z.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 style={{ display: 'grid', gridTemplateColumns: '1fr 70px 70px auto', gap: '8px', marginTop: '8px' }}>
|
||
<input style={inp} value={newZeit.tag} onChange={e => setNewZeit(p => ({ ...p, tag: e.target.value }))} placeholder="Montag – Freitag" />
|
||
<input style={inp} value={newZeit.von} onChange={e => setNewZeit(p => ({ ...p, von: e.target.value }))} placeholder="8:00" />
|
||
<input style={inp} value={newZeit.bis} onChange={e => setNewZeit(p => ({ ...p, bis: e.target.value }))} placeholder="18:00" />
|
||
<button type="button" onClick={addZeit} style={{ padding: '8px 14px', borderRadius: '6px', background: 'var(--accent)', color: '#fff', fontWeight: 700, border: 'none', cursor: 'pointer', fontSize: '13px' }}>+</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)
|
||
}
|