feat: enhance MainForm layout and user experience; add new components and improve form structure

feat: update i18n configuration to prioritize browser language; enhance language detection
feat: add new translation keys for form submission feedback in English and German
This commit is contained in:
2026-01-20 19:07:03 +01:00
parent fd37e40253
commit c985a20207
5 changed files with 247 additions and 151 deletions

View File

@@ -1,6 +1,7 @@
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import "./index.css";
import "./utils/i18n";
import App from "./App.tsx";
createRoot(document.getElementById("root")!).render(

View File

@@ -7,6 +7,8 @@ import {
CircularProgress,
Autocomplete,
Chip,
Box,
Paper,
} from "@mui/material";
import { useTranslation } from "react-i18next";
import { useState, useEffect } from "react";
@@ -115,168 +117,247 @@ export const MainForm = () => {
};
return (
<>
<Chip label={`${t("next-id")}#${nextID ?? "N/A"}`} />
<form
onSubmit={(e) => {
e.preventDefault();
handleSubmit();
}}
<Box className="min-h-screen bg-gray-800 flex items-center justify-center p-4">
<Paper
elevation={3}
className="w-full max-w-md p-6 rounded-lg"
sx={{ backgroundColor: "#fff" }}
>
<Autocomplete
disablePortal
options={users}
value={selectedUser}
sx={{ width: 300 }}
renderInput={(params) => <TextField {...params} label={t("user")} />}
onChange={(_event, value) => handleUserSelection(value)}
onKeyDown={(event) => {
if (event.key === "Enter") {
event.defaultMuiPrevented = true;
}
<form
onSubmit={(e) => {
e.preventDefault();
handleSubmit();
}}
/>
<TextField
required
id="first-name"
label={t("first-name")}
variant="filled"
value={formData.firstName}
onChange={handleChange}
name="firstName"
/>
<TextField
required
id="last-name"
label={t("last-name")}
variant="filled"
value={formData.lastName}
onChange={handleChange}
name="lastName"
/>
<TextField
required
id="email"
label={t("email")}
variant="filled"
type="email"
value={formData.email}
onChange={handleChange}
name="email"
/>
<TextField
required
id="phone-number"
label={t("phone-number")}
variant="filled"
type="tel"
value={formData.phoneNumber}
onChange={handleChange}
name="phoneNumber"
/>
<TextField
required
id="tickets"
type="number"
label={t("tickets")}
variant="filled"
value={formData.tickets}
onChange={handleChange}
name="tickets"
/>
<FormControlLabel
control={
<Checkbox
checked={invoice}
onChange={(e) => setInvoice(e.target.checked)}
/>
}
label={t("invoice")}
/>
{invoice && (
<>
className="flex flex-col gap-4"
>
{/* User Selection */}
<Autocomplete
disablePortal
options={users}
value={selectedUser}
fullWidth
renderInput={(params) => (
<TextField {...params} label={t("user")} variant="filled" />
)}
onChange={(_event, value) => handleUserSelection(value)}
onKeyDown={(event) => {
if (event.key === "Enter") {
event.defaultMuiPrevented = true;
}
}}
/>
{/* Next ID Chip */}
<Chip
label={`#${nextID ?? "N/A"}`}
color="primary"
sx={{
alignSelf: "flex-start",
fontWeight: "bold",
fontSize: "1rem",
py: 2,
px: 1,
}}
/>
{/* Name Fields - Two Columns */}
<Box className="grid grid-cols-2 gap-3">
<TextField
required
id="company-name"
label={t("company-name")}
variant="filled"
value={formData.companyName}
onChange={handleChange}
name="companyName"
/>
<TextField
required
id="first-name_invoice"
id="first-name"
label={t("first-name")}
variant="filled"
value={formData.cmpFirstName}
value={formData.firstName}
onChange={handleChange}
name="cmpFirstName"
name="firstName"
fullWidth
/>
<TextField
required
id="last-name_invoice"
id="last-name"
label={t("last-name")}
variant="filled"
value={formData.cpmLastName}
value={formData.lastName}
onChange={handleChange}
name="cpmLastName"
name="lastName"
fullWidth
/>
<TextField
required
id="street"
label={t("street")}
variant="filled"
value={formData.street}
onChange={handleChange}
name="street"
/>
<TextField
required
id="postal-code"
label={t("postal-code")}
variant="filled"
value={formData.postalCode}
onChange={handleChange}
name="postalCode"
/>
<TextField
required
id="phone-number_invoice"
label={t("phone-number")}
variant="filled"
type="tel"
value={formData.cpmPhoneNumber}
onChange={handleChange}
name="cpmPhoneNumber"
/>
<TextField
required
id="email_invoice"
label={t("email")}
variant="filled"
type="email"
value={formData.cpmEmail}
onChange={handleChange}
name="cpmEmail"
/>
</>
)}
{/* Payment methods - only one must be selected */}
<FormControlLabel control={<Checkbox />} label={t("cash")} />
<FormControlLabel control={<Checkbox />} label={t("paypal")} />
<FormControlLabel control={<Checkbox />} label={t("transfer")} />
{isLoading && <CircularProgress />}
<Button type="submit" variant="contained" disabled={isLoading}>
{t("submit")}
</Button>
</Box>
{msg && (
<Alert severity={msg.type}>
{msg.headline}: {msg.text}
</Alert>
)}
</form>
</>
{/* Email */}
<TextField
required
id="email"
label={t("email")}
variant="filled"
type="email"
value={formData.email}
onChange={handleChange}
name="email"
fullWidth
/>
{/* Phone Number */}
<TextField
required
id="phone-number"
label={t("phone-number")}
variant="filled"
type="tel"
value={formData.phoneNumber}
onChange={handleChange}
name="phoneNumber"
fullWidth
/>
{/* Tickets and Invoice Checkbox */}
<Box className="grid grid-cols-2 gap-3 items-center">
<TextField
required
id="tickets"
type="number"
label={t("tickets")}
variant="filled"
value={formData.tickets}
onChange={handleChange}
name="tickets"
fullWidth
inputProps={{ min: 1 }}
/>
<FormControlLabel
control={
<Checkbox
checked={invoice}
onChange={(e) => setInvoice(e.target.checked)}
/>
}
label={t("invoice")}
className="justify-end"
/>
</Box>
{/* Invoice Fields */}
{invoice && (
<Box className="flex flex-col gap-3 pt-2 border-t border-gray-200">
<TextField
required
id="company-name"
label={t("company-name")}
variant="filled"
value={formData.companyName}
onChange={handleChange}
name="companyName"
fullWidth
/>
{/* Invoice Name Fields - Two Columns */}
<Box className="grid grid-cols-2 gap-3">
<TextField
required
id="first-name_invoice"
label={t("first-name")}
variant="filled"
value={formData.cmpFirstName}
onChange={handleChange}
name="cmpFirstName"
fullWidth
/>
<TextField
required
id="last-name_invoice"
label={t("last-name")}
variant="filled"
value={formData.cpmLastName}
onChange={handleChange}
name="cpmLastName"
fullWidth
/>
</Box>
<TextField
required
id="street"
label={t("street")}
variant="filled"
value={formData.street}
onChange={handleChange}
name="street"
fullWidth
/>
<TextField
required
id="postal-code"
label={t("postal-code")}
variant="filled"
value={formData.postalCode}
onChange={handleChange}
name="postalCode"
fullWidth
/>
<TextField
required
id="phone-number_invoice"
label={t("phone-number")}
variant="filled"
type="tel"
value={formData.cpmPhoneNumber}
onChange={handleChange}
name="cpmPhoneNumber"
fullWidth
/>
<TextField
required
id="email_invoice"
label={t("email")}
variant="filled"
type="email"
value={formData.cpmEmail}
onChange={handleChange}
name="cpmEmail"
fullWidth
/>
</Box>
)}
{/* Payment Methods */}
<Box className="flex justify-center gap-4 pt-2">
<FormControlLabel control={<Checkbox />} label={t("cash")} />
<FormControlLabel control={<Checkbox />} label={t("paypal")} />
<FormControlLabel control={<Checkbox />} label={t("transfer")} />
</Box>
{/* Submit Button */}
<Button
type="submit"
variant="contained"
disabled={isLoading}
fullWidth
size="large"
sx={{
mt: 2,
py: 1.5,
textTransform: "uppercase",
fontWeight: "bold",
}}
>
{isLoading ? (
<CircularProgress size={24} color="inherit" />
) : (
t("submit")
)}
</Button>
{/* Alert Message */}
{msg && (
<Alert severity={msg.type} sx={{ mt: 2 }}>
{msg.headline}: {msg.text}
</Alert>
)}
</form>
</Paper>
</Box>
);
};

View File

@@ -22,7 +22,7 @@ i18n
.init({
resources,
fallbackLng: "en", // use en if detected lng is not available
lng: Cookies.get("language") || "en", // language to use, more information here: https://www.i18next.com/overview/configuration-options#languages-namespaces-resources
lng: Cookies.get("language") || navigator.language.split("-")[0] || "en", // Check cookie first, then browser language
// you can use the i18n.changeLanguage function to change the language manually: https://www.i18next.com/overview/api#changelanguage
// if you're using a language detector, do not define the lng option

View File

@@ -11,5 +11,12 @@
"submit": "Kaufen",
"failed-to-load-users": "Das Laden der Benutzer ist fehlgeschlagen.",
"user": "Benutzer",
"next-id": "Nächste Eintragsnummer: "
"next-id": "Nächste Eintragsnummer: ",
"form-submitted-successfully": "Formular erfolgreich übermittelt!",
"orm-submission-failed": "Formularübermittlung fehlgeschlagen.",
"success": "Erfolg",
"error": "Fehler",
"cash": "Bar",
"paypal": "PayPal",
"transfer": "Überweisung"
}

View File

@@ -11,5 +11,12 @@
"submit": "Buy",
"failed-to-load-users": "Failed to load users.",
"user": "User",
"next-id": "Next Entry Number: "
"next-id": "Next Entry Number: ",
"form-submitted-successfully": "Form submitted successfully!",
"orm-submission-failed": "Form submission failed.",
"success": "Success",
"error": "Error",
"cash": "Cash",
"paypal": "PayPal",
"transfer": "Bank Transfer"
}