Aktueller Stand

This commit is contained in:
2026-01-15 23:18:42 +01:00
parent 46eae2a2a9
commit dcf45bac3d
32 changed files with 2625 additions and 395 deletions

View File

@@ -6,6 +6,7 @@ export default function AdminSystemSettings() {
const [apiKey, setApiKey] = useState("");
const [provider, setProvider] = useState("osm");
const [registrationEnabled, setRegistrationEnabled] = useState(true);
const [appName, setAppName] = useState("Vereinskalender");
const [logoFile, setLogoFile] = useState<File | null>(null);
const [logoVersion, setLogoVersion] = useState(() => Date.now());
const [hasLogo, setHasLogo] = useState<boolean | null>(null);
@@ -14,14 +15,21 @@ export default function AdminSystemSettings() {
const load = async () => {
try {
const response = await fetch("/api/settings/google-places");
if (!response.ok) {
const [placesResponse, appNameResponse] = await Promise.all([
fetch("/api/settings/system"),
fetch("/api/settings/app-name")
]);
if (!placesResponse.ok) {
throw new Error("Einstellungen konnten nicht geladen werden.");
}
const payload = await response.json();
const payload = await placesResponse.json();
setApiKey(payload.apiKey || "");
setProvider(payload.provider || "osm");
setRegistrationEnabled(payload.registrationEnabled !== false);
if (appNameResponse.ok) {
const appPayload = await appNameResponse.json();
setAppName(appPayload.name || "Vereinskalender");
}
} catch (err) {
setError((err as Error).message);
}
@@ -49,18 +57,31 @@ export default function AdminSystemSettings() {
setStatus(null);
setError(null);
const response = await fetch("/api/settings/google-places", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ apiKey, provider, registrationEnabled })
});
const [settingsResponse, appNameResponse] = await Promise.all([
fetch("/api/settings/system", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ apiKey, provider, registrationEnabled })
}),
fetch("/api/settings/app-name", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ name: appName })
})
]);
if (!response.ok) {
const data = await response.json();
if (!settingsResponse.ok) {
const data = await settingsResponse.json();
setError(data.error || "Speichern fehlgeschlagen.");
return;
}
if (!appNameResponse.ok) {
const data = await appNameResponse.json();
setError(data.error || "App-Name konnte nicht gespeichert werden.");
return;
}
setStatus("Gespeichert.");
};
@@ -141,20 +162,40 @@ export default function AdminSystemSettings() {
<p className="text-sm text-slate-500">Kein Logo hinterlegt.</p>
)}
<div className="flex flex-wrap items-center gap-3">
<input
type="file"
accept="image/png,image/jpeg,image/webp,image/svg+xml"
onChange={(event) =>
setLogoFile(event.currentTarget.files?.[0] || null)
}
className="block text-sm text-slate-600"
/>
<label className="btn-ghost cursor-pointer">
Datei auswählen
<input
type="file"
accept="image/png,image/jpeg,image/webp,image/svg+xml"
onChange={(event) =>
setLogoFile(event.currentTarget.files?.[0] || null)
}
className="sr-only"
/>
</label>
<span className="text-sm text-slate-600">
{logoFile ? logoFile.name : "Keine Datei ausgewählt"}
</span>
<button type="submit" className="btn-accent">
Logo hochladen
</button>
</div>
</form>
<form onSubmit={onSubmit} className="space-y-3">
<div className="space-y-2">
<label className="text-sm font-medium text-slate-700">
App-Name
</label>
<input
type="text"
value={appName}
onChange={(event) => setAppName(event.target.value)}
className="w-full rounded-xl border border-slate-300 px-3 py-2"
placeholder="Vereinskalender"
required
maxLength={60}
/>
</div>
<div className="space-y-2">
<label className="text-sm font-medium text-slate-700">
Ortsanbieter