import { useTranslation } from "react-i18next"; import { useState, useEffect } from "react"; import Cookies from "js-cookie"; import { Sheet, Input, Button, Checkbox, Chip, IconButton, Alert, Typography, FormControl, FormLabel, ButtonGroup, CircularProgress, } from "@mui/joy"; import { submitFormData } from "../utils/api/form"; import type { FormData, Message } from "../config/interfaces.config"; import PersonIcon from "@mui/icons-material/Person"; import QrCodeIcon from "@mui/icons-material/QrCode"; import TranslateIcon from "@mui/icons-material/Translate"; import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; import { confirmUser, fetchUsers } from "../utils/api/users"; import { QRcodeModal } from "../components/modals/QR-CodeModal"; import { SelectUserModal } from "../components/modals/SelectUserModal"; import { useForm } from "@tanstack/react-form"; import { changeTranslation } from "../utils/uxFncs"; import { createFormSchema } from "../config/interfaces.config"; import type { ZodObject, ZodRawShape } from "zod"; import { TextField } from "../components/TextField"; const PAYMENT_METHODS = ["bar", "paypal", "andere"] as const; const PAYMENT_LABELS: Record = { bar: "Cash", paypal: "PayPal", andere: "Transfer", }; /** * Validates a single field against the full Zod schema. * Returns the first error message for that field, or undefined if valid. */ function validateFieldWithZod( schema: ZodObject, fieldName: string, allValues: Record, ): string | undefined { const result = schema.safeParse(allValues); if (result.success) return undefined; const issue = result.error.issues.find( (i) => i.path.length === 1 && i.path[0] === fieldName, ); return issue?.message; } export const MainForm = () => { const { t } = useTranslation(); const queryClient = useQueryClient(); const [invoice, setInvoice] = useState(false); const [msg, setMsg] = useState(null); const [selectedUser, setSelectedUser] = useState(null); const [showSelectUser, setShowSelectUser] = useState(false); const [QRmodal, setQRmodal] = useState(false); const formSchema = createFormSchema(t, invoice); const makeFieldValidator = (fieldName: string) => ({ onSubmit: ({ fieldApi, }: { fieldApi: { form: { state: { values: Record } } }; }) => { const allValues = fieldApi.form.state.values; return validateFieldWithZod(formSchema, fieldName, allValues); }, onBlur: ({ fieldApi, }: { fieldApi: { form: { state: { values: Record } } }; }) => { const allValues = fieldApi.form.state.values; return validateFieldWithZod(formSchema, fieldName, allValues); }, }); const { Field, Subscribe, handleSubmit, setFieldValue } = useForm({ defaultValues: { firstName: "", lastName: "", email: "", phoneNumber: "", tickets: 1, companyName: "", cmpFirstName: "", cpmLastName: "", cpmEmail: "", cpmPhoneNumber: "", street: "", postalCode: "", paymentMethod: "", }, onSubmit: async ({ value }) => { const result = formSchema.safeParse(value); if (!result.success) return; mutateForm(value as FormData); }, }); const getErrors = (field: { state: { meta: { errorMap: Record } }; }) => { const normalizeErrors = (value: unknown) => { if (Array.isArray(value)) return value as string[]; if (typeof value === "string" && value.length > 0) return [value]; return [] as string[]; }; const blurErrors = normalizeErrors(field.state.meta.errorMap["onBlur"]); const submitErrors = normalizeErrors(field.state.meta.errorMap["onSubmit"]); return [...blurErrors, ...submitErrors].filter(Boolean); }; useEffect(() => { const savedUser = Cookies.get("selectedUser"); if (savedUser) { setSelectedUser(savedUser); } else { setMsg({ type: "warning", headline: t("set-username-headline"), text: t("set-username-text"), }); } }, []); const { data: usernameData, isLoading: usernameDataIsLoading } = useQuery({ queryKey: ["users"], queryFn: fetchUsers, }); const { data: userData } = useQuery({ queryKey: ["user", selectedUser], enabled: !!selectedUser, queryFn: () => confirmUser(selectedUser), }); const { mutate: mutateForm, isPending: mutateFormIsPending } = useMutation({ mutationFn: (values: FormData) => submitFormData(values, selectedUser), onSuccess: (_, values) => { queryClient.invalidateQueries({ queryKey: ["user", selectedUser] }); document.location.href = `/success?id=${nextID}&tickets=${values.tickets}`; }, onError: () => { queryClient.invalidateQueries({ queryKey: ["user", selectedUser] }); setMsg({ type: "danger", headline: t("error"), text: t("form-submission-failed"), }); }, }); const nextID = userData?.nextID ?? "N/A"; const handleUserSelection = (username: string | null) => { if (username == null || username == "") { return; } setSelectedUser(username); }; return ( <>
setShowSelectUser(true)}> setQRmodal(true)}> {`${t("greeting")} ${userData?.fullname ?? t("loading")}`}
{ e.preventDefault(); handleSubmit(); }} className="flex flex-col gap-4" > #{nextID ?? "N/A"} {/* Name row */}
{(field) => ( )} {(field) => ( )}
{(field) => ( )} {(field) => ( )} {/* Tickets + Invoice toggle */}
{t("tickets")} {(field) => { const errors = getErrors(field); return ( <> field.handleChange(Number(e.target.value)) } slotProps={{ input: { min: 1 } }} variant="soft" sx={{ borderRadius: "10px" }} /> {errors.length > 0 && ( {errors[0]} )} ); }}
{ const checked = e.target.checked; setInvoice(checked); if (!checked) { setFieldValue("companyName", ""); setFieldValue("cmpFirstName", ""); setFieldValue("cpmLastName", ""); setFieldValue("cpmEmail", ""); setFieldValue("cpmPhoneNumber", ""); setFieldValue("street", ""); setFieldValue("postalCode", ""); } }} label={t("invoice")} variant="outlined" />
{/* Invoice details (conditional) */} {invoice && (
{t("invoice-details")} {(field) => ( )}
{(field) => ( )} {(field) => ( )}
{(field) => ( )} {(field) => ( )} {(field) => ( )} {(field) => ( )}
)} {/* Payment method selection */} {t("select-payment-method")} state.values.paymentMethod}> {(paymentMethod) => (
{PAYMENT_METHODS.map((method) => ( ))}
)}
{mutateFormIsPending ? (
) : ( state.values.paymentMethod}> {(paymentMethod) => ( )} )} {msg && ( {msg.headline} {msg.text} )}
); };