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:
@@ -1,6 +1,7 @@
|
|||||||
import { StrictMode } from "react";
|
import { StrictMode } from "react";
|
||||||
import { createRoot } from "react-dom/client";
|
import { createRoot } from "react-dom/client";
|
||||||
import "./index.css";
|
import "./index.css";
|
||||||
|
import "./utils/i18n";
|
||||||
import App from "./App.tsx";
|
import App from "./App.tsx";
|
||||||
|
|
||||||
createRoot(document.getElementById("root")!).render(
|
createRoot(document.getElementById("root")!).render(
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import {
|
|||||||
CircularProgress,
|
CircularProgress,
|
||||||
Autocomplete,
|
Autocomplete,
|
||||||
Chip,
|
Chip,
|
||||||
|
Box,
|
||||||
|
Paper,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
@@ -115,20 +117,28 @@ export const MainForm = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<Box className="min-h-screen bg-gray-800 flex items-center justify-center p-4">
|
||||||
<Chip label={`${t("next-id")}#${nextID ?? "N/A"}`} />
|
<Paper
|
||||||
|
elevation={3}
|
||||||
|
className="w-full max-w-md p-6 rounded-lg"
|
||||||
|
sx={{ backgroundColor: "#fff" }}
|
||||||
|
>
|
||||||
<form
|
<form
|
||||||
onSubmit={(e) => {
|
onSubmit={(e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
handleSubmit();
|
handleSubmit();
|
||||||
}}
|
}}
|
||||||
|
className="flex flex-col gap-4"
|
||||||
>
|
>
|
||||||
|
{/* User Selection */}
|
||||||
<Autocomplete
|
<Autocomplete
|
||||||
disablePortal
|
disablePortal
|
||||||
options={users}
|
options={users}
|
||||||
value={selectedUser}
|
value={selectedUser}
|
||||||
sx={{ width: 300 }}
|
fullWidth
|
||||||
renderInput={(params) => <TextField {...params} label={t("user")} />}
|
renderInput={(params) => (
|
||||||
|
<TextField {...params} label={t("user")} variant="filled" />
|
||||||
|
)}
|
||||||
onChange={(_event, value) => handleUserSelection(value)}
|
onChange={(_event, value) => handleUserSelection(value)}
|
||||||
onKeyDown={(event) => {
|
onKeyDown={(event) => {
|
||||||
if (event.key === "Enter") {
|
if (event.key === "Enter") {
|
||||||
@@ -136,6 +146,22 @@ export const MainForm = () => {
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{/* 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
|
<TextField
|
||||||
required
|
required
|
||||||
id="first-name"
|
id="first-name"
|
||||||
@@ -144,6 +170,7 @@ export const MainForm = () => {
|
|||||||
value={formData.firstName}
|
value={formData.firstName}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
name="firstName"
|
name="firstName"
|
||||||
|
fullWidth
|
||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
required
|
required
|
||||||
@@ -153,7 +180,11 @@ export const MainForm = () => {
|
|||||||
value={formData.lastName}
|
value={formData.lastName}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
name="lastName"
|
name="lastName"
|
||||||
|
fullWidth
|
||||||
/>
|
/>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Email */}
|
||||||
<TextField
|
<TextField
|
||||||
required
|
required
|
||||||
id="email"
|
id="email"
|
||||||
@@ -163,7 +194,10 @@ export const MainForm = () => {
|
|||||||
value={formData.email}
|
value={formData.email}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
name="email"
|
name="email"
|
||||||
|
fullWidth
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{/* Phone Number */}
|
||||||
<TextField
|
<TextField
|
||||||
required
|
required
|
||||||
id="phone-number"
|
id="phone-number"
|
||||||
@@ -173,7 +207,11 @@ export const MainForm = () => {
|
|||||||
value={formData.phoneNumber}
|
value={formData.phoneNumber}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
name="phoneNumber"
|
name="phoneNumber"
|
||||||
|
fullWidth
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{/* Tickets and Invoice Checkbox */}
|
||||||
|
<Box className="grid grid-cols-2 gap-3 items-center">
|
||||||
<TextField
|
<TextField
|
||||||
required
|
required
|
||||||
id="tickets"
|
id="tickets"
|
||||||
@@ -183,6 +221,8 @@ export const MainForm = () => {
|
|||||||
value={formData.tickets}
|
value={formData.tickets}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
name="tickets"
|
name="tickets"
|
||||||
|
fullWidth
|
||||||
|
inputProps={{ min: 1 }}
|
||||||
/>
|
/>
|
||||||
<FormControlLabel
|
<FormControlLabel
|
||||||
control={
|
control={
|
||||||
@@ -192,9 +232,13 @@ export const MainForm = () => {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
label={t("invoice")}
|
label={t("invoice")}
|
||||||
|
className="justify-end"
|
||||||
/>
|
/>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Invoice Fields */}
|
||||||
{invoice && (
|
{invoice && (
|
||||||
<>
|
<Box className="flex flex-col gap-3 pt-2 border-t border-gray-200">
|
||||||
<TextField
|
<TextField
|
||||||
required
|
required
|
||||||
id="company-name"
|
id="company-name"
|
||||||
@@ -203,7 +247,11 @@ export const MainForm = () => {
|
|||||||
value={formData.companyName}
|
value={formData.companyName}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
name="companyName"
|
name="companyName"
|
||||||
|
fullWidth
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{/* Invoice Name Fields - Two Columns */}
|
||||||
|
<Box className="grid grid-cols-2 gap-3">
|
||||||
<TextField
|
<TextField
|
||||||
required
|
required
|
||||||
id="first-name_invoice"
|
id="first-name_invoice"
|
||||||
@@ -212,6 +260,7 @@ export const MainForm = () => {
|
|||||||
value={formData.cmpFirstName}
|
value={formData.cmpFirstName}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
name="cmpFirstName"
|
name="cmpFirstName"
|
||||||
|
fullWidth
|
||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
required
|
required
|
||||||
@@ -221,7 +270,10 @@ export const MainForm = () => {
|
|||||||
value={formData.cpmLastName}
|
value={formData.cpmLastName}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
name="cpmLastName"
|
name="cpmLastName"
|
||||||
|
fullWidth
|
||||||
/>
|
/>
|
||||||
|
</Box>
|
||||||
|
|
||||||
<TextField
|
<TextField
|
||||||
required
|
required
|
||||||
id="street"
|
id="street"
|
||||||
@@ -230,7 +282,9 @@ export const MainForm = () => {
|
|||||||
value={formData.street}
|
value={formData.street}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
name="street"
|
name="street"
|
||||||
|
fullWidth
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<TextField
|
<TextField
|
||||||
required
|
required
|
||||||
id="postal-code"
|
id="postal-code"
|
||||||
@@ -239,7 +293,9 @@ export const MainForm = () => {
|
|||||||
value={formData.postalCode}
|
value={formData.postalCode}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
name="postalCode"
|
name="postalCode"
|
||||||
|
fullWidth
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<TextField
|
<TextField
|
||||||
required
|
required
|
||||||
id="phone-number_invoice"
|
id="phone-number_invoice"
|
||||||
@@ -249,7 +305,9 @@ export const MainForm = () => {
|
|||||||
value={formData.cpmPhoneNumber}
|
value={formData.cpmPhoneNumber}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
name="cpmPhoneNumber"
|
name="cpmPhoneNumber"
|
||||||
|
fullWidth
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<TextField
|
<TextField
|
||||||
required
|
required
|
||||||
id="email_invoice"
|
id="email_invoice"
|
||||||
@@ -259,24 +317,47 @@ export const MainForm = () => {
|
|||||||
value={formData.cpmEmail}
|
value={formData.cpmEmail}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
name="cpmEmail"
|
name="cpmEmail"
|
||||||
|
fullWidth
|
||||||
/>
|
/>
|
||||||
</>
|
</Box>
|
||||||
)}
|
)}
|
||||||
{/* Payment methods - only one must be selected */}
|
|
||||||
|
{/* Payment Methods */}
|
||||||
|
<Box className="flex justify-center gap-4 pt-2">
|
||||||
<FormControlLabel control={<Checkbox />} label={t("cash")} />
|
<FormControlLabel control={<Checkbox />} label={t("cash")} />
|
||||||
<FormControlLabel control={<Checkbox />} label={t("paypal")} />
|
<FormControlLabel control={<Checkbox />} label={t("paypal")} />
|
||||||
<FormControlLabel control={<Checkbox />} label={t("transfer")} />
|
<FormControlLabel control={<Checkbox />} label={t("transfer")} />
|
||||||
{isLoading && <CircularProgress />}
|
</Box>
|
||||||
<Button type="submit" variant="contained" disabled={isLoading}>
|
|
||||||
{t("submit")}
|
{/* 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>
|
</Button>
|
||||||
|
|
||||||
|
{/* Alert Message */}
|
||||||
{msg && (
|
{msg && (
|
||||||
<Alert severity={msg.type}>
|
<Alert severity={msg.type} sx={{ mt: 2 }}>
|
||||||
{msg.headline}: {msg.text}
|
{msg.headline}: {msg.text}
|
||||||
</Alert>
|
</Alert>
|
||||||
)}
|
)}
|
||||||
</form>
|
</form>
|
||||||
</>
|
</Paper>
|
||||||
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ i18n
|
|||||||
.init({
|
.init({
|
||||||
resources,
|
resources,
|
||||||
fallbackLng: "en", // use en if detected lng is not available
|
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
|
// 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
|
// if you're using a language detector, do not define the lng option
|
||||||
|
|
||||||
|
|||||||
@@ -11,5 +11,12 @@
|
|||||||
"submit": "Kaufen",
|
"submit": "Kaufen",
|
||||||
"failed-to-load-users": "Das Laden der Benutzer ist fehlgeschlagen.",
|
"failed-to-load-users": "Das Laden der Benutzer ist fehlgeschlagen.",
|
||||||
"user": "Benutzer",
|
"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"
|
||||||
}
|
}
|
||||||
@@ -11,5 +11,12 @@
|
|||||||
"submit": "Buy",
|
"submit": "Buy",
|
||||||
"failed-to-load-users": "Failed to load users.",
|
"failed-to-load-users": "Failed to load users.",
|
||||||
"user": "User",
|
"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"
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user