From 80cb393768de7270c04e7df155df1fff1f7faeba Mon Sep 17 00:00:00 2001 From: Theis Gaedigk Date: Fri, 21 Nov 2025 16:55:18 +0100 Subject: [PATCH] Enhance item management: update API key display, add locker number input, and modify database schema for unique locker numbers --- admin/src/components/APIKeyTable.tsx | 4 +-- admin/src/components/AddItemForm.tsx | 17 +++++++++--- admin/src/components/ItemTable.tsx | 27 +++++++++++++++++-- admin/src/utils/userActions.ts | 10 ++++--- .../admin/database/itemDataMgmt.database.js | 6 ++--- backendV2/routes/admin/itemDataMgmt.route.js | 4 +-- backendV2/schemeV2.sql | 2 +- 7 files changed, 54 insertions(+), 16 deletions(-) diff --git a/admin/src/components/APIKeyTable.tsx b/admin/src/components/APIKeyTable.tsx index 076882e..eb0cd33 100644 --- a/admin/src/components/APIKeyTable.tsx +++ b/admin/src/components/APIKeyTable.tsx @@ -124,8 +124,8 @@ const APIKeyTable: React.FC = () => { {/* End action toolbar */} - - Gegenstände + + API Keys {isError && ( = ({ onClose, alert }) => { - Gegenstandsname + Gegenstandsname (muss einzigartig sein) + + Schließfachnummer (immer zwei Zahlen) + + Ausleih-Berechtigung (Rolle) @@ -53,10 +57,17 @@ const AddItemForm: React.FC = ({ onClose, alert }) => { (document.getElementById("can_borrow_role") as HTMLInputElement) ?.value ); + const lockerValue = ( + document.getElementById("lockerNumber") as HTMLInputElement + )?.value.trim(); + + const lockerNumber = + lockerValue === "" ? null : Number(lockerValue); if (!name || Number.isNaN(role)) return; + if (lockerNumber !== null && Number.isNaN(lockerNumber)) return; - const res = await createItem(name, role); + const res = await createItem(name, role, lockerNumber); if (res.success) { alert( "success", diff --git a/admin/src/components/ItemTable.tsx b/admin/src/components/ItemTable.tsx index 756143f..97b9f12 100644 --- a/admin/src/components/ItemTable.tsx +++ b/admin/src/components/ItemTable.tsx @@ -38,6 +38,7 @@ type Items = { item_name: string; can_borrow_role: string; in_safe: boolean; + safe_nr: string; entry_created_at: string; entry_updated_at: string; last_borrowed_person: string | null; @@ -66,6 +67,12 @@ const ItemTable: React.FC = () => { ); }; + const handleLockerNumberChange = (id: number, value: string) => { + setItems((prev) => + prev.map((it) => (it.id === id ? { ...it, lockerNumber: value } : it)) + ); + }; + const setError = ( status: "error" | "success", message: string, @@ -201,6 +208,9 @@ const ItemTable: React.FC = () => { Im Schließfach + + Schließfachnummer + Eintrag erstellt am @@ -208,10 +218,10 @@ const ItemTable: React.FC = () => { Eintrag aktualisiert am - Letzte ausleihende Person + LaP * - Derzeit ausgeliehen von + Dav ** Aktionen @@ -277,6 +287,16 @@ const ItemTable: React.FC = () => { + + + handleLockerNumberChange(item.id, e.target.value) + } + value={item.safe_nr} + /> + {formatDateTime(item.entry_created_at)} {formatDateTime(item.entry_updated_at)} {item.last_borrowed_person} @@ -287,6 +307,7 @@ const ItemTable: React.FC = () => { handleEditItems( item.id, item.item_name, + item.safe_nr, item.can_borrow_role ).then((response) => { if (response.success) { @@ -333,6 +354,8 @@ const ItemTable: React.FC = () => { + * LaP = Letzte ausleihende Person + ** Dav = Derzeit ausgeliehen von ); }; diff --git a/admin/src/utils/userActions.ts b/admin/src/utils/userActions.ts index 0e81320..76eea03 100644 --- a/admin/src/utils/userActions.ts +++ b/admin/src/utils/userActions.ts @@ -164,8 +164,10 @@ export const deleteItem = async (itemId: number) => { export const createItem = async ( item_name: string, - can_borrow_role: number + can_borrow_role: number, + lockerNumber: number | null ) => { + console.log(JSON.stringify({ item_name, can_borrow_role, lockerNumber })); try { const response = await fetch( `${API_BASE}/api/admin/item-data/create-item`, @@ -175,7 +177,7 @@ export const createItem = async ( "Content-Type": "application/json", Authorization: `Bearer ${Cookies.get("token")}`, }, - body: JSON.stringify({ item_name, can_borrow_role }), + body: JSON.stringify({ item_name, can_borrow_role, lockerNumber }), } ); if (!response.ok) { @@ -195,8 +197,10 @@ export const createItem = async ( export const handleEditItems = async ( itemId: number, item_name: string, + safe_nr: string | null, can_borrow_role: string ) => { + const newSafeNr = Number(safe_nr || 0); try { const response = await fetch( `${API_BASE}/api/admin/item-data/edit-item/${itemId}`, @@ -206,7 +210,7 @@ export const handleEditItems = async ( "Content-Type": "application/json", Authorization: `Bearer ${Cookies.get("token")}`, }, - body: JSON.stringify({ item_name, can_borrow_role }), + body: JSON.stringify({ item_name, newSafeNr, can_borrow_role }), } ); if (!response.ok) { diff --git a/backendV2/routes/admin/database/itemDataMgmt.database.js b/backendV2/routes/admin/database/itemDataMgmt.database.js index cef4dc9..98bbc30 100644 --- a/backendV2/routes/admin/database/itemDataMgmt.database.js +++ b/backendV2/routes/admin/database/itemDataMgmt.database.js @@ -23,10 +23,10 @@ export const deleteItemById = async (itemId) => { return { success: false }; }; -export const createItem = async (item_name, can_borrow_role, in_safe) => { +export const createItem = async (item_name, can_borrow_role, lockerNumber) => { const [result] = await pool.query( - "INSERT INTO items (item_name, can_borrow_role, in_safe) VALUES (?, ?, ?)", - [item_name, can_borrow_role, true] + "INSERT INTO items (item_name, can_borrow_role, in_safe, safe_nr) VALUES (?, ?, ?, ?)", + [item_name, can_borrow_role, true, lockerNumber] ); if (result.affectedRows > 0) return { success: true }; return { success: false }; diff --git a/backendV2/routes/admin/itemDataMgmt.route.js b/backendV2/routes/admin/itemDataMgmt.route.js index 0470ff0..9ca8642 100644 --- a/backendV2/routes/admin/itemDataMgmt.route.js +++ b/backendV2/routes/admin/itemDataMgmt.route.js @@ -31,8 +31,8 @@ router.delete("/delete-item/:id", authenticateAdmin, async (req, res) => { }); router.post("/create-item", authenticateAdmin, async (req, res) => { - const { item_name, can_borrow_role } = req.body; - const result = await createItem(item_name, can_borrow_role); + const { item_name, can_borrow_role, lockerNumber } = req.body; + const result = await createItem(item_name, can_borrow_role, lockerNumber); if (result.success) { return res.status(201).json({ message: "Item created successfully" }); } diff --git a/backendV2/schemeV2.sql b/backendV2/schemeV2.sql index 4a774c6..cdd0a16 100644 --- a/backendV2/schemeV2.sql +++ b/backendV2/schemeV2.sql @@ -37,7 +37,7 @@ CREATE TABLE items ( item_name varchar(255) NOT NULL UNIQUE, can_borrow_role INT NOT NULL, in_safe bool NOT NULL DEFAULT true, - safe_nr CHAR(2) DEFAULT NULL, + safe_nr CHAR(2) DEFAULT NULL UNIQUE, entry_created_at timestamp NULL DEFAULT CURRENT_TIMESTAMP, entry_updated_at timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, last_borrowed_person varchar(255) DEFAULT NULL,