From a66b150d97800cdfe577b8d3823ae21db6ffc590 Mon Sep 17 00:00:00 2001 From: Theis Date: Wed, 3 Jun 2026 16:29:45 +0200 Subject: [PATCH] added prize draw name to tables --- .gitignore | 1 + backend/routes/default/frontend.data.js | 18 +++++++----- backend/routes/default/frontend.route.js | 19 ++++++++---- backend/scheme.sql | 9 ++++++ docker-compose.yml | 2 +- .../src/components/modals/SelectUserModal.tsx | 21 +++++++++++--- frontend/src/pages/MainForm.tsx | 29 +++++++++++++++---- frontend/src/utils/api/form.ts | 9 +++++- frontend/src/utils/api/users.ts | 6 ++-- frontend/src/utils/i18n/locales/de/de.json | 3 +- frontend/src/utils/i18n/locales/en/en.json | 3 +- 11 files changed, 91 insertions(+), 29 deletions(-) diff --git a/.gitignore b/.gitignore index b98371a..eb51ab1 100644 --- a/.gitignore +++ b/.gitignore @@ -158,6 +158,7 @@ keys/ # Own files ToDo.txt PayPal-QR-Code.png +.docker/volumes # only in development branch next-env.d.ts \ No newline at end of file diff --git a/backend/routes/default/frontend.data.js b/backend/routes/default/frontend.data.js index 833f8e7..82ea938 100644 --- a/backend/routes/default/frontend.data.js +++ b/backend/routes/default/frontend.data.js @@ -11,14 +11,16 @@ const pool = mysql }) .promise(); -export const getUser = async () => { - const [rows] = await pool.query("SELECT username FROM users"); +export const getInfo = async () => { + const [rows] = await pool.query("SELECT username FROM users;"); + const [rows2] = await pool.query("SELECT name FROM prize_draws;"); - if (rows.length > 0) { + if (rows.length > 0 && rows2.length > 0) { const users = rows.map((r) => r.username); - return { users }; + const prize_draws = rows2.map((n) => n.name); + return { users, prize_draws }; } else { - return { users: [], message: "No data found" }; + return { message: "No data found" }; } }; @@ -43,6 +45,7 @@ export const confirmUser = async (username) => { const [createTable] = await pool.query( `CREATE TABLE IF NOT EXISTS ?? ( id INT AUTO_INCREMENT PRIMARY KEY, + Verlosung VARCHAR(100) NOT NULL, Vorname VARCHAR(100) NOT NULL, Nachname Varchar(100) NOT NULL, EMail Varchar(100) NOT NULL, @@ -80,7 +83,7 @@ export const confirmUser = async (username) => { } }; -export const newEntry = async (formData, username) => { +export const newEntry = async (formData, username, prizeDraw) => { const confirmation = await confirmUser(username); if (!confirmation || !confirmation.success) { @@ -90,9 +93,10 @@ export const newEntry = async (formData, username) => { const tableName = confirmation.tableName; const [result] = await pool.query( - `INSERT INTO ?? (Vorname, Nachname, EMail, Telefonnummer, Lose, Firmenname, Vorname_Geschaeftlich, Nachname_Geschaeftlich, EMail_Geschaeftlich, Telefonnummer_Geschaeftlich, Strasse_Hausnr, Plz_Ort, Zahlungsmethode) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, + `INSERT INTO ?? (Verlosung, Vorname, Nachname, EMail, Telefonnummer, Lose, Firmenname, Vorname_Geschaeftlich, Nachname_Geschaeftlich, EMail_Geschaeftlich, Telefonnummer_Geschaeftlich, Strasse_Hausnr, Plz_Ort, Zahlungsmethode) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [ tableName, + prizeDraw, formData.firstName, formData.lastName, formData.email, diff --git a/backend/routes/default/frontend.route.js b/backend/routes/default/frontend.route.js index e380a7d..d90a6e3 100644 --- a/backend/routes/default/frontend.route.js +++ b/backend/routes/default/frontend.route.js @@ -3,24 +3,33 @@ import dotenv from "dotenv"; const router = express.Router(); dotenv.config(); -import { getUser, newEntry, confirmUser } from "./frontend.data.js"; +import { getInfo, newEntry, confirmUser } from "./frontend.data.js"; router.post("/new-entry", async (req, res) => { const username = req.query.username; - const result = await newEntry(req.body, username); + const draw = req.query.draw; + + const result = await newEntry(req.body, username, draw); + if (!result.success) { return res.status(500).json({ message: "Form Data Invalid" }); } res.sendStatus(204); }); -router.get("/users", async (req, res) => { - const users = await getUser(); - res.json(users); +router.get("/info", async (req, res) => { + const info = await getInfo(); + + if (!info) { + return res.status(500).json({ message: "Server error" }); + } + + res.json(info); }); router.get("/confirm-user", async (req, res) => { const username = req.query.username; + if (!username) { return res.status(400).json({ message: "Username is required" }); } diff --git a/backend/scheme.sql b/backend/scheme.sql index 98f6c9b..300b7dd 100644 --- a/backend/scheme.sql +++ b/backend/scheme.sql @@ -1,3 +1,5 @@ +USE ca_lose; + CREATE TABLE users ( id INT AUTO_INCREMENT PRIMARY KEY, username VARCHAR(100) NOT NULL UNIQUE, @@ -6,9 +8,16 @@ CREATE TABLE users ( created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); +CREATE TABLE prize_draws ( + id INT AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(100) NOT NULL UNIQUE, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + /* This scheme does not have to be implemented manually. It always will be generated by the backend */ CREATE TABLE xx_DD_MM_YYYY ( id INT AUTO_INCREMENT PRIMARY KEY, + Verlosung VARCHAR(100) NOT NULL, Vorname VARCHAR(100) NOT NULL, Nachname Varchar(100) NOT NULL, EMail Varchar(100) NOT NULL, diff --git a/docker-compose.yml b/docker-compose.yml index 2f86d1f..49cc551 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -32,7 +32,7 @@ services: MYSQL_DATABASE: ca_lose TZ: Europe/Berlin volumes: - - ca-lose_mysql:/var/lib/mysql + - ./.docker/volumes/ca-lose_mysql:/var/lib/mysql - ./mysql-timezone.cnf:/etc/mysql/conf.d/timezone.cnf:ro volumes: diff --git a/frontend/src/components/modals/SelectUserModal.tsx b/frontend/src/components/modals/SelectUserModal.tsx index 6f6cd42..1a86328 100644 --- a/frontend/src/components/modals/SelectUserModal.tsx +++ b/frontend/src/components/modals/SelectUserModal.tsx @@ -10,10 +10,12 @@ import { useTranslation } from "react-i18next"; interface SelectUserModalProps { showSelectUser: boolean; setShowSelectUser: (value: boolean) => void; - usernameData: { users: string[] }; - usernameDataIsLoading: boolean; + info: { users: string[]; prize_draws: string[] }; + infoIsLoading: boolean; selectedUser: string | null; + selectedDraw: string | null; handleUserSelection: (value: string | null) => void; + handleDrawSelection: (value: string | null) => void; } export const SelectUserModal = (props: SelectUserModalProps) => { @@ -25,8 +27,8 @@ export const SelectUserModal = (props: SelectUserModalProps) => { {t("user")} {/* User selection */} props.handleUserSelection(value)} @@ -34,6 +36,17 @@ export const SelectUserModal = (props: SelectUserModalProps) => { variant="soft" sx={{ borderRadius: "10px" }} /> + {/* Prize selection */} + props.handleDrawSelection(value)} + placeholder={t("prize_draws")} + variant="soft" + sx={{ borderRadius: "10px" }} + /> ); diff --git a/frontend/src/pages/MainForm.tsx b/frontend/src/pages/MainForm.tsx index 04c274b..ab40baf 100644 --- a/frontend/src/pages/MainForm.tsx +++ b/frontend/src/pages/MainForm.tsx @@ -21,7 +21,7 @@ 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 { confirmUser, fetchInfo } from "../utils/api/users"; import { QRcodeModal } from "../components/modals/QR-CodeModal"; import { SelectUserModal } from "../components/modals/SelectUserModal"; import { useForm } from "@tanstack/react-form"; @@ -39,6 +39,7 @@ export const MainForm = () => { const [invoice, setInvoice] = useState(false); const [msg, setMsg] = useState(null); const [selectedUser, setSelectedUser] = useState(null); + const [selectedDraw, setSelectedDraw] = useState(null); const [showSelectUser, setShowSelectUser] = useState(false); const [QRmodal, setQRmodal] = useState(false); @@ -106,6 +107,11 @@ export const MainForm = () => { // useEffect that only executes on mount and is checking if there is a user selcted in the cookies useEffect(() => { const savedUser = Cookies.get("selectedUser"); + const savedDraw = Cookies.get("selectedDraw"); + if (savedDraw) { + setSelectedDraw(savedDraw); + } + if (savedUser) { setSelectedUser(savedUser); } else { @@ -118,9 +124,9 @@ export const MainForm = () => { }, []); // Fetch users tanstack query - const { data: usernameData, isLoading: usernameDataIsLoading } = useQuery({ - queryKey: ["users"], - queryFn: fetchUsers, + const { data: info, isLoading: infoIsLoading } = useQuery({ + queryKey: ["info"], + queryFn: fetchInfo, }); // Query for validating selcted user @@ -157,15 +163,26 @@ export const MainForm = () => { setSelectedUser(username); }; + // function for selecting draw + const handleDrawSelection = (draw: string | null) => { + if (draw == null || draw == "") { + return; + } + setSelectedDraw(draw); + Cookies.set("selectedDraw", draw); + }; + return ( <> diff --git a/frontend/src/utils/api/form.ts b/frontend/src/utils/api/form.ts index d74138c..26ed344 100644 --- a/frontend/src/utils/api/form.ts +++ b/frontend/src/utils/api/form.ts @@ -1,5 +1,6 @@ import { API_BASE } from "../../config/api.config"; import type { FormData } from "../../config/interfaces.config"; +import Cookies from "js-cookie"; export const submitFormData = async ( data: FormData, @@ -7,10 +8,16 @@ export const submitFormData = async ( ) => { console.warn("submitFormData is fetching!"); + const draw = Cookies.get("selectedDraw"); + + if (!draw) { + throw new Error("You need to set an prize draw!"); + } + // await new Promise((resolve) => setTimeout(resolve, 3000)); // Wait 3 seconds const response = await fetch( - `${API_BASE}/default/new-entry?username=${username}`, + `${API_BASE}/default/new-entry?username=${username}&draw=${draw}`, { method: "POST", headers: { diff --git a/frontend/src/utils/api/users.ts b/frontend/src/utils/api/users.ts index aac1c23..1902544 100644 --- a/frontend/src/utils/api/users.ts +++ b/frontend/src/utils/api/users.ts @@ -1,10 +1,10 @@ import { API_BASE } from "../../config/api.config"; import Cookies from "js-cookie"; -export const fetchUsers = async () => { - console.warn("fetchUsers is fetching!"); +export const fetchInfo = async () => { + console.warn("fetchInfo is fetching!"); - const response = await fetch(`${API_BASE}/default/users`); + const response = await fetch(`${API_BASE}/default/info`); const data = await response.json(); return data; diff --git a/frontend/src/utils/i18n/locales/de/de.json b/frontend/src/utils/i18n/locales/de/de.json index 605df4c..ceffc37 100644 --- a/frontend/src/utils/i18n/locales/de/de.json +++ b/frontend/src/utils/i18n/locales/de/de.json @@ -14,11 +14,12 @@ "user": "Benutzer", "next-id": "Nächste Eintragsnummer: ", "form-submitted-successfully": "Formular erfolgreich übermittelt!", - "form-submission-failed": "Formularübermittlung fehlgeschlagen.", + "form-submission-failed": "Formularübermittlung fehlgeschlagen. Haben Sie eine Verlosung ausgewählt?", "success": "Erfolg", "error": "Fehler", "cash": "Bar", "paypal": "PayPal", + "prize_draws": "Verlosungen", "transfer": "Andere (notieren)", "ticket-payment_one": "Sie haben erfolgreich {{count}} Los gekauft.", "ticket-payment_other": "Sie haben erfolgreich {{count}} Lose gekauft.", diff --git a/frontend/src/utils/i18n/locales/en/en.json b/frontend/src/utils/i18n/locales/en/en.json index 8c2e961..e2c55b3 100644 --- a/frontend/src/utils/i18n/locales/en/en.json +++ b/frontend/src/utils/i18n/locales/en/en.json @@ -13,7 +13,8 @@ "user": "User", "next-id": "Next Entry Number: ", "form-submitted-successfully": "Form submitted successfully!", - "orm-submission-failed": "Form submission failed.", + "form-submission-failed": "Form submission failed. Have you set an prize draw?", + "prize_draws": "Prize draws", "success": "Success", "error": "Error", "cash": "Cash",