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

110 lines
7.8 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'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>
)
}