From fd2ccaa74733020e0f74ebac489a82f39e03caca Mon Sep 17 00:00:00 2001 From: Theis Gaedigk Date: Mon, 24 Nov 2025 17:12:37 +0100 Subject: [PATCH] feat: add door_key field to items and update related logic in forms and database --- admin/src/components/AddItemForm.tsx | 5 ++--- admin/src/components/ItemTable.tsx | 21 +++++++++++++++++++ admin/src/utils/userActions.ts | 5 +++-- .../admin/database/itemDataMgmt.database.js | 7 ++++--- backendV2/routes/admin/itemDataMgmt.route.js | 5 +++-- backendV2/routes/api/api.database.js | 12 +++++++++-- backendV2/routes/api/api.route.js | 1 + backendV2/schemeV2.sql | 8 +------ 8 files changed, 45 insertions(+), 19 deletions(-) diff --git a/admin/src/components/AddItemForm.tsx b/admin/src/components/AddItemForm.tsx index e48247a..e88bbd0 100644 --- a/admin/src/components/AddItemForm.tsx +++ b/admin/src/components/AddItemForm.tsx @@ -29,8 +29,8 @@ const AddItemForm: React.FC = ({ onClose, alert }) => { - Schließfachnummer (immer zwei Zahlen) - + Schließfachnummer + Ausleih-Berechtigung (Rolle) @@ -64,7 +64,6 @@ const AddItemForm: React.FC = ({ onClose, alert }) => { const safeNr = safeNrValue === "" ? null : safeNrValue; if (!name || Number.isNaN(role)) return; - if (safeNr !== null && !/^\d{2}$/.test(safeNr)) return; const res = await createItem(name, role, safeNr); if (res.success) { diff --git a/admin/src/components/ItemTable.tsx b/admin/src/components/ItemTable.tsx index 16336e0..ccadef0 100644 --- a/admin/src/components/ItemTable.tsx +++ b/admin/src/components/ItemTable.tsx @@ -38,6 +38,7 @@ type Items = { can_borrow_role: string; in_safe: boolean; safe_nr: string; + door_key: string; entry_created_at: string; entry_updated_at: string; last_borrowed_person: string | null; @@ -72,6 +73,12 @@ const ItemTable: React.FC = () => { ); }; + const handleDoorKeyChange = (id: number, value: string) => { + setItems((prev) => + prev.map((it) => (it.id === id ? { ...it, door_key: value } : it)) + ); + }; + const setError = ( status: "error" | "success", message: string, @@ -204,6 +211,9 @@ const ItemTable: React.FC = () => { Schließfachnummer + + Schlüssel + Eintrag erstellt am @@ -290,6 +300,16 @@ const ItemTable: React.FC = () => { value={item.safe_nr} /> + + + handleDoorKeyChange(item.id, e.target.value) + } + value={item.door_key} + /> + {formatDateTime(item.entry_created_at)} {formatDateTime(item.entry_updated_at)} {item.last_borrowed_person} @@ -301,6 +321,7 @@ const ItemTable: React.FC = () => { item.id, item.item_name, item.safe_nr, + item.door_key, item.can_borrow_role ).then((response) => { if (response.success) { diff --git a/admin/src/utils/userActions.ts b/admin/src/utils/userActions.ts index 06974df..85ebc25 100644 --- a/admin/src/utils/userActions.ts +++ b/admin/src/utils/userActions.ts @@ -184,7 +184,7 @@ export const createItem = async ( return { success: false, message: - "Fehler beim Erstellen des Gegenstands. Der Name des Gegenstandes darf nicht mehrmals vergeben werden.", + "Fehler beim Erstellen des Gegenstands. Der Name des Gegenstandes und die Schließfachnummer dürfen nicht mehrmals vergeben werden.", }; } return { success: true }; @@ -198,6 +198,7 @@ export const handleEditItems = async ( itemId: number, item_name: string, safe_nr: string | null, + door_key: string | null, can_borrow_role: string ) => { try { @@ -209,7 +210,7 @@ export const handleEditItems = async ( "Content-Type": "application/json", Authorization: `Bearer ${Cookies.get("token")}`, }, - body: JSON.stringify({ item_name, safe_nr, can_borrow_role }), + body: JSON.stringify({ item_name, safe_nr, door_key, 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 2637f9c..0593bde 100644 --- a/backendV2/routes/admin/database/itemDataMgmt.database.js +++ b/backendV2/routes/admin/database/itemDataMgmt.database.js @@ -36,7 +36,8 @@ export const editItemById = async ( itemId, item_name, can_borrow_role, - safe_nr + safe_nr, + door_key ) => { let newSafeNr; if (safe_nr === null || safe_nr === "") { @@ -45,8 +46,8 @@ export const editItemById = async ( newSafeNr = safe_nr; } const [result] = await pool.query( - "UPDATE items SET item_name = ?, can_borrow_role = ?, safe_nr = ?, entry_updated_at = NOW() WHERE id = ?", - [item_name, can_borrow_role, newSafeNr, itemId] + "UPDATE items SET item_name = ?, can_borrow_role = ?, safe_nr = ?, door_key = ?, entry_updated_at = NOW() WHERE id = ?", + [item_name, can_borrow_role, newSafeNr, door_key, itemId] ); 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 77eb6ad..95c1ee5 100644 --- a/backendV2/routes/admin/itemDataMgmt.route.js +++ b/backendV2/routes/admin/itemDataMgmt.route.js @@ -41,13 +41,14 @@ router.post("/create-item", authenticateAdmin, async (req, res) => { router.post("/edit-item/:id", authenticateAdmin, async (req, res) => { const itemId = req.params.id; - const { item_name, can_borrow_role, safe_nr } = req.body; + const { item_name, can_borrow_role, safe_nr, door_key } = req.body; const result = await editItemById( itemId, item_name, can_borrow_role, - safe_nr + safe_nr, + door_key ); if (result.success) { return res.status(200).json({ message: "Item edited successfully" }); diff --git a/backendV2/routes/api/api.database.js b/backendV2/routes/api/api.database.js index 4478d00..d80365c 100644 --- a/backendV2/routes/api/api.database.js +++ b/backendV2/routes/api/api.database.js @@ -117,11 +117,19 @@ export const getAllLoansV2 = async () => { export const openDoor = async (doorKey) => { const [result] = await pool.query( - "SELECT lockers FROM doorKeys WHERE door_key = ?;", + "SELECT safe_nr, id FROM items WHERE door_key = ?;", [doorKey] ); if (result.length > 0) { - return { success: true, data: result[0] }; + const [changeItemSate] = await pool.query( + "UPDATE items SET in_safe = NOT in_safe WHERE id = ?", + [result[0].id] + ); + if (changeItemSate.affectedRows > 0) { + return { success: true, data: result[0] }; + } else { + return { success: false }; + } } return { success: false }; }; diff --git a/backendV2/routes/api/api.route.js b/backendV2/routes/api/api.route.js index 8edec6e..56a289d 100644 --- a/backendV2/routes/api/api.route.js +++ b/backendV2/routes/api/api.route.js @@ -80,6 +80,7 @@ router.post( } ); +// Route for API to open a door router.get("/open-door/:key/:doorKey", authenticate, async (req, res) => { const doorKey = req.params.doorKey; diff --git a/backendV2/schemeV2.sql b/backendV2/schemeV2.sql index 05c9b24..95ff6ed 100644 --- a/backendV2/schemeV2.sql +++ b/backendV2/schemeV2.sql @@ -38,6 +38,7 @@ CREATE TABLE items ( can_borrow_role INT NOT NULL, in_safe bool NOT NULL DEFAULT true, safe_nr INT DEFAULT NULL UNIQUE, + door_key INT 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, @@ -53,11 +54,4 @@ CREATE TABLE apiKeys ( entry_created_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), CHECK (api_key REGEXP '^[0-9]{8}$') -) ENGINE=InnoDB; - -CREATE TABLE doorKeys ( - id int NOT NULL AUTO_INCREMENT, - door_key INT NOT NULL, - lockers INT NOT NULL, - PRIMARY KEY (id) ) ENGINE=InnoDB; \ No newline at end of file