Files
gutscheintracker/app/settings/members.tsx
T

97 lines
3.0 KiB
TypeScript

"use client";
import { useEffect, useState } from "react";
type Member = { id: number; name: string };
export default function MembersSection() {
const [members, setMembers] = useState<Member[]>([]);
const [name, setName] = useState("");
const [error, setError] = useState("");
async function load() {
const res = await fetch("/api/members");
if (res.ok) setMembers(await res.json());
}
useEffect(() => {
load();
}, []);
async function add() {
setError("");
const value = name.trim();
if (!value) {
setError("Bitte einen Namen eingeben.");
return;
}
const res = await fetch("/api/members", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ name: value }),
});
if (!res.ok) {
setError(res.status === 409 ? "Dieser Name existiert bereits." : "Speichern fehlgeschlagen.");
return;
}
setName("");
load();
}
async function remove(id: number, memberName: string) {
if (!window.confirm(`„${memberName}“ aus der Haushaltsliste entfernen? Bereits erfasste Gutscheine behalten den Namen.`)) return;
const res = await fetch(`/api/members?id=${id}`, { method: "DELETE" });
if (res.ok) load();
}
return (
<section className="rounded-card border border-line bg-white p-5">
<h2 className="text-[15px] font-semibold tracking-tight">Haushaltsmitglieder</h2>
<p className="mt-1 text-sm text-muted">Wer einen Gutschein anlegt, wählt hier seinen Namen aus.</p>
<div className="mt-3 flex gap-2">
<input
value={name}
onChange={(e) => setName(e.target.value)}
onKeyDown={(e) => {
if (e.key === "Enter") {
e.preventDefault();
add();
}
}}
placeholder="Name hinzufügen"
aria-label="Name hinzufügen"
maxLength={100}
className="h-11 min-w-0 flex-1 rounded-field border border-line bg-white px-3.5 text-sm text-ink"
/>
<button
type="button"
onClick={add}
className="h-11 shrink-0 rounded-field bg-brand-600 px-5 text-sm font-semibold text-white transition-colors hover:bg-brand-700 active:scale-[0.99]"
>
Hinzufügen
</button>
</div>
{error && (
<p role="alert" className="mt-2 text-[13px] font-medium text-danger">
{error}
</p>
)}
{members.length > 0 && (
<ul className="mt-3 divide-y divide-line">
{members.map((m) => (
<li key={m.id} className="flex items-center justify-between py-2 text-sm">
<span className="font-medium">{m.name}</span>
<button
type="button"
onClick={() => remove(m.id, m.name)}
className="rounded-lg px-2 py-1 text-[13px] font-medium text-muted hover:text-danger"
>
Entfernen
</button>
</li>
))}
</ul>
)}
</section>
);
}