From 3832aca12cc76a1c795ce9d54b776bcbbd498588 Mon Sep 17 00:00:00 2001 From: Theis Date: Mon, 18 May 2026 18:05:05 +0200 Subject: [PATCH] implemented tanstack query --- backend/routes/default/frontend.data.js | 10 ++- frontend/package-lock.json | 51 ++++++++---- frontend/package.json | 2 + frontend/src/main.tsx | 7 +- frontend/src/pages/MainForm.tsx | 93 +++++++++++----------- frontend/src/utils/api/users.ts | 21 +++++ frontend/src/utils/i18n/locales/de/de.json | 4 +- frontend/src/utils/i18n/locales/en/en.json | 4 +- frontend/tests/test.local.js | 15 ++++ frontend/tests/test.server.js | 15 ++++ 10 files changed, 151 insertions(+), 71 deletions(-) create mode 100644 frontend/src/utils/api/users.ts create mode 100644 frontend/tests/test.local.js create mode 100644 frontend/tests/test.server.js diff --git a/backend/routes/default/frontend.data.js b/backend/routes/default/frontend.data.js index 7e3eb62..57e06c1 100644 --- a/backend/routes/default/frontend.data.js +++ b/backend/routes/default/frontend.data.js @@ -28,6 +28,10 @@ export const confirmUser = async (username) => { ]); if (rows.length > 0) { + console.log(rows); + const { first_name, last_name } = rows[0]; + const fullname = first_name + " " + last_name; + // creating userTicketTable const d = new Date(); @@ -37,8 +41,6 @@ export const confirmUser = async (username) => { const date = `${day}_${month}_${year}`; const tableName = `${username}_${date}`; - console.log(tableName); - const [createTable] = await pool.query( `CREATE TABLE IF NOT EXISTS ?? ( id INT AUTO_INCREMENT PRIMARY KEY, @@ -70,9 +72,9 @@ export const confirmUser = async (username) => { nextID = rows.length > 0 ? rows[0].id + 1 : 1; }; await getNextID(); - return { success: true, nextID, tableName }; + return { success: true, nextID, tableName, fullname }; } else { - return { success: false, message: "Table creation failed" }; + return { success: false, message: "Table creation failed", fullname }; } } else { return null; diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 95e7dff..e676de0 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -16,8 +16,10 @@ "@mui/joy": "^5.0.0-beta.52", "@mui/material": "^9.0.1", "@tailwindcss/vite": "^4.3.0", + "@tanstack/react-query": "^5.100.10", "i18next": "^26.0.10", "js-cookie": "^3.0.5", + "k6": "^0.0.0", "lucide-react": "^1.14.0", "react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0", @@ -1766,6 +1768,32 @@ "vite": "^5.2.0 || ^6 || ^7 || ^8" } }, + "node_modules/@tanstack/query-core": { + "version": "5.100.10", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.100.10.tgz", + "integrity": "sha512-8UR0yJR+GiQ40m3lPhUr0xbfAupe6GSQiksSBSa9SM2NjezFyxXCIA69/lz8cSoNKZLrw1/PktIyQBJcVeMi3w==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-query": { + "version": "5.100.10", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.100.10.tgz", + "integrity": "sha512-FLaZf2RCrA/Zgp4aiu5tG3TyasTRO7aZ99skxQpr3Hg/zXOhu6yq5FZCYQ/tRaJtM9ylnoK8tFK7PolXQadv6Q==", + "license": "MIT", + "dependencies": { + "@tanstack/query-core": "5.100.10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^18 || ^19" + } + }, "node_modules/@tybys/wasm-util": { "version": "0.10.2", "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", @@ -3042,6 +3070,12 @@ "node": ">=6" } }, + "node_modules/k6": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/k6/-/k6-0.0.0.tgz", + "integrity": "sha512-GAQSWayS2+LjbH5bkRi+pMPYyP1JSp7o+4j58ANZ762N/RH/SdlAT3CHHztnn8s/xgg8kYNM24Gd2IPo9b5W+g==", + "license": "AGPL-3.0" + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -4178,23 +4212,6 @@ "dev": true, "license": "ISC" }, - "node_modules/yaml": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.4.tgz", - "integrity": "sha512-ml/JPOj9fOQK8RNnWojA67GbZ0ApXAUlN2UQclwv2eVgTgn7O9gg9o7paZWKMp4g0H3nTLtS9LVzhkpOFIKzog==", - "license": "ISC", - "optional": true, - "peer": true, - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14.6" - }, - "funding": { - "url": "https://github.com/sponsors/eemeli" - } - }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index ed61e3e..8e872d4 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -18,8 +18,10 @@ "@mui/joy": "^5.0.0-beta.52", "@mui/material": "^9.0.1", "@tailwindcss/vite": "^4.3.0", + "@tanstack/react-query": "^5.100.10", "i18next": "^26.0.10", "js-cookie": "^3.0.5", + "k6": "^0.0.0", "lucide-react": "^1.14.0", "react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0", diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx index 63fd9f8..2146915 100644 --- a/frontend/src/main.tsx +++ b/frontend/src/main.tsx @@ -3,9 +3,14 @@ import { createRoot } from "react-dom/client"; import "./utils/i18n/index.ts"; import "./index.css"; import App from "./App.tsx"; +import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; + +const queryClient = new QueryClient(); createRoot(document.getElementById("root")!).render( - + + + , ); diff --git a/frontend/src/pages/MainForm.tsx b/frontend/src/pages/MainForm.tsx index 2205bd9..0eee534 100644 --- a/frontend/src/pages/MainForm.tsx +++ b/frontend/src/pages/MainForm.tsx @@ -20,12 +20,13 @@ import { ModalClose, } from "@mui/joy"; import { submitFormData } from "../utils/sender"; -import { API_BASE } from "../config/api.config"; 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 qrCode from "../assets/PayPal-QR-Code.png"; +import { useQuery } from "@tanstack/react-query"; +import { confirmUser, fetchUsers } from "../utils/api/users"; const PAYMENT_METHODS = ["bar", "paypal", "andere"] as const; const PAYMENT_LABELS: Record = { @@ -85,10 +86,8 @@ export const MainForm = () => { const [invoice, setInvoice] = useState(false); const [msg, setMsg] = useState(null); - const [isLoading, setIsLoading] = useState(false); const [nextID, setNextID] = useState(null); - const [users, setUsers] = useState([]); - const [selectedUser, setSelectedUser] = useState(null); + const [selectedUser, setSelectedUser] = useState(""); const [formData, setFormData] = useState(DEFAULT_FORM); const [showSelectUser, setShowSelectUser] = useState(false); const [QRmodal, setQRmodal] = useState(false); @@ -97,23 +96,37 @@ export const MainForm = () => { setFormData({ ...formData, [e.target.name]: e.target.value }); }; - const confirmUser = async (username: string) => { - try { - const res = await fetch( - `${API_BASE}/default/confirm-user?username=${username}`, - ); - const data = await res.json(); - setNextID(data.nextID); - } catch (error) { - console.error("Error confirming user:", error); + useEffect(() => { + const savedUser = Cookies.get("selectedUser"); + if (savedUser) { + setSelectedUser(savedUser); } - }; + }, []); + + const { data: usernameData, isLoading: usernameDataIsLoading } = useQuery({ + queryKey: ["users"], + queryFn: fetchUsers, + }); + + const { data: userData, isSuccess: userDataIsSuccess } = useQuery({ + queryKey: ["user", selectedUser], + enabled: !!selectedUser, + queryFn: () => confirmUser(selectedUser), + }); + + // Setting the nextID after a user is selected + useEffect(() => { + if (!userData) return; + setNextID(userData.nextID); + }, [userDataIsSuccess]); const handleUserSelection = (username: string | null) => { - if (!username) return; + if (username == null || username == "") { + console.log("Username must be set!"); + return; + } + setSelectedUser(username); - confirmUser(username); - Cookies.set("selectedUser", username); }; const changeTranslation = () => { @@ -140,30 +153,7 @@ export const MainForm = () => { } }, [formData.paymentMethod]); - useEffect(() => { - (async () => { - try { - const res = await fetch(`${API_BASE}/default/users`); - const data = await res.json(); - setUsers(data.users); - } catch { - setMsg({ - type: "danger", - headline: t("error"), - text: t("failed-to-load-users"), - }); - } - })(); - - const cookieUser = Cookies.get("selectedUser"); - if (cookieUser) { - setSelectedUser(cookieUser); - confirmUser(cookieUser); - } - }, []); - const handleSubmit = async () => { - setIsLoading(true); try { const result = await submitFormData(formData, selectedUser || ""); if (result.success) { @@ -175,8 +165,8 @@ export const MainForm = () => { text: result.error || t("form-submission-failed"), }); } - } finally { - setIsLoading(false); + } catch (err) { + console.log("remove"); } }; @@ -191,15 +181,14 @@ export const MainForm = () => { {t("user")} {/* User selection */} handleUserSelection(value)} placeholder={t("user")} variant="soft" sx={{ borderRadius: "10px" }} - onKeyDown={(e) => { - if (e.key === "Enter") e.preventDefault(); - }} /> @@ -250,6 +239,17 @@ export const MainForm = () => { + + {`${t("greeting")} ${userData?.fullname ?? t("loading")}`} +
{ {/* Submit button */}