Files
talktime/frontend/src/components/dashboard/CreateOrganizationForm.tsx
T
patrickandClaude Sonnet 5 1c013b301c feat: generalize UI wording — Verein→Organisation, Mannschaft→Team
Makes the German UI labels domain-neutral (Verein/Firma both fit "Organisation"),
Mannschaft was pure sports vocabulary and is replaced with Team.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0143yYvjesjHndBACoweyK67
2026-09-11 18:35:54 +02:00

105 lines
3.2 KiB
TypeScript

import { useState } from "react";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { useAuth } from "@/lib/auth-context";
import { useOrganization } from "@/lib/organization-context";
const createOrganizationSchema = z.object({
name: z.string().min(2, "Mindestens 2 Zeichen"),
slug: z
.string()
.min(2, "Mindestens 2 Zeichen")
.regex(/^[a-z0-9-]+$/, "Nur Kleinbuchstaben, Ziffern und Bindestriche"),
});
type CreateOrganizationValues = z.infer<typeof createOrganizationSchema>;
export function CreateOrganizationForm() {
const { token } = useAuth();
const { refresh } = useOrganization();
const [error, setError] = useState<string | null>(null);
const form = useForm<CreateOrganizationValues>({
resolver: zodResolver(createOrganizationSchema),
defaultValues: { name: "", slug: "" },
});
async function onSubmit(values: CreateOrganizationValues) {
setError(null);
try {
const res = await fetch("/api/organizations", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
},
body: JSON.stringify(values),
});
if (!res.ok) {
const body = (await res.json()) as { error?: string };
throw new Error(body.error ?? `Fehler (${res.status})`);
}
form.reset();
await refresh();
} catch (err) {
setError((err as Error).message);
}
}
return (
<Card className="max-w-sm">
<CardHeader>
<CardTitle className="text-lg">Organisation anlegen</CardTitle>
</CardHeader>
<CardContent>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4" noValidate>
<FormField
control={form.control}
name="name"
render={({ field }) => (
<FormItem>
<FormLabel>Name</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="slug"
render={({ field }) => (
<FormItem>
<FormLabel>Kurzname (URL)</FormLabel>
<FormControl>
<Input placeholder="sv-musterstadt" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
{error && <p className="text-sm text-destructive">{error}</p>}
<Button type="submit" disabled={form.formState.isSubmitting}>
{form.formState.isSubmitting ? "Lege an…" : "Organisation anlegen"}
</Button>
</form>
</Form>
</CardContent>
</Card>
);
}