"use client"; import { RepeatIcon } from "lucide-react"; import { Field, FieldDescription, FieldError, FieldGroup, FieldLabel } from "@/components/ui/field"; import { Input } from "@/components/ui/input"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Switch } from "@/components/ui/switch"; import { Textarea } from "@/components/ui/textarea"; import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group"; import { CALENDARS, calendarById } from "@/lib/calendars"; import { repeatLabel } from "@/lib/event-display"; import { setCalendar, setStart, type EventForm as EventFormState, type EventFormErrors } from "@/lib/event-form"; import { cn } from "@/lib/utils"; /** Element ids, so the sheet can focus the first field with an error. */ export const fieldId = (field: keyof EventFormState): string => `event-${field}`; const CALENDAR_ITEMS = CALENDARS.map((c) => ({ value: String(c.id), label: c.label })); /** * The event's fields. Presentational: every rule (end follows start, the * birthday recurrence, validation) lives in lib/event-form.ts, and the sheet * owns the state. * * Inputs are the browser's native date/time pickers, which are the good ones * on phones. The URL field is plain text with a URL keyboard rather than * type="url", whose built-in validation would reject "nachklang.art" before * normaliseUrl() could accept it. */ export function EventForm({ form, errors, disabled, onChange, }: { form: EventFormState; /** Only the errors to show - empty until the first save attempt. */ errors: EventFormErrors; disabled: boolean; onChange: (form: EventFormState) => void; }) { const set = (key: K, value: EventFormState[K]) => onChange({ ...form, [key]: value }); const forcedRepeat = calendarById(form.calendarId)?.forcedRepeatFrequency; const invalid = (field: keyof EventFormState) => (errors[field] ? true : undefined); return ( Kalender {errors.calendarId} Titel set("name", e.target.value)} disabled={disabled} aria-invalid={invalid("name")} autoComplete="off" /> {errors.name} Ganztägig set("wholeDay", checked)} disabled={disabled} /> onChange(setStart(form, date, form.startTime))} onTime={(time) => onChange(setStart(form, form.startDate, time))} /> set("endDate", date)} onTime={(time) => set("endTime", time)} /> {form.repeatFrequency && (

{forcedRepeat ? `Wiederholt sich ${repeatLabel(form.repeatFrequency)} – das gilt für alle Termine im Kalender „${calendarById(form.calendarId)?.label}“.` : `Wiederholt sich ${repeatLabel(form.repeatFrequency)}.`}

)} Ort set("location", e.target.value)} disabled={disabled} /> Link set("url", e.target.value)} disabled={disabled} aria-invalid={invalid("url")} inputMode="url" autoCapitalize="off" autoCorrect="off" spellCheck={false} placeholder="z. B. nachklang.art/konzert" /> {errors.url} Beschreibung