since3-website/modules/landingPage/schema/contact-schema.ts
2026-09-25 18:53:25 +02:00

45 lines
1.4 KiB
TypeScript

import { z } from "zod"
// Shared between the server action and the form so both validate identically.
export const contactSchema = z.object({
name: z
.string()
.trim()
.min(2, "Bitte gib deinen Namen an."),
email: z
.string()
.trim()
// Zod's default email pattern rejects valid Unicode addresses (e.g. müller@example.de)
.pipe(
z.email({
pattern: z.regexes.unicodeEmail,
error: "Bitte gib eine gültige E-Mail-Adresse an.",
})
),
company: z.string().trim().max(120, "Maximal 120 Zeichen.").optional(),
message: z
.string()
.trim()
.min(20, "Erzähl uns in mindestens 20 Zeichen, worum es geht.")
.max(4000, "Maximal 4000 Zeichen."),
privacy: z.literal("on", {
error: "Bitte stimme der Verarbeitung deiner Angaben zu.",
}),
})
export type ContactInput = z.infer<typeof contactSchema>
export type ContactField = keyof ContactInput
export type ContactFormState = {
status: "idle" | "success" | "error"
message?: string
fieldErrors?: Partial<Record<ContactField, string[]>>
// Echoed back so the form keeps its values after a failed submit.
// `privacy` is separate from ContactField's string values: the checkbox
// needs a boolean, not the raw "on" the form field submits.
values?: Partial<Record<Exclude<ContactField, "privacy">, string>> & {
privacy?: boolean
}
}
export const initialContactState: ContactFormState = { status: "idle" }