Enhance item management: update API key display, add locker number input, and modify database schema for unique locker numbers

This commit is contained in:
2025-11-21 16:55:18 +01:00
parent 79486fe1cb
commit 80cb393768
7 changed files with 54 additions and 16 deletions

View File

@@ -124,8 +124,8 @@ const APIKeyTable: React.FC = () => {
</HStack> </HStack>
{/* End action toolbar */} {/* End action toolbar */}
<Heading marginBottom={4} size="md"> <Heading marginBottom={4} size="2xl">
Gegenstände API Keys
</Heading> </Heading>
{isError && ( {isError && (
<MyAlert <MyAlert

View File

@@ -25,15 +25,19 @@ const AddItemForm: React.FC<AddItemFormProps> = ({ onClose, alert }) => {
<Card.Body> <Card.Body>
<Stack gap="4" w="full"> <Stack gap="4" w="full">
<Field.Root> <Field.Root>
<Field.Label>Gegenstandsname</Field.Label> <Field.Label>Gegenstandsname (muss einzigartig sein)</Field.Label>
<Input id="item_name" placeholder="z.B. Laptop" /> <Input id="item_name" placeholder="z.B. Laptop" />
</Field.Root> </Field.Root>
<Field.Root>
<Field.Label>Schließfachnummer (immer zwei Zahlen)</Field.Label>
<Input id="lockerNumber" placeholder="Nummer 01 - 06" />
</Field.Root>
<Field.Root> <Field.Root>
<Field.Label>Ausleih-Berechtigung (Rolle)</Field.Label> <Field.Label>Ausleih-Berechtigung (Rolle)</Field.Label>
<Input <Input
id="can_borrow_role" id="can_borrow_role"
type="number" type="number"
placeholder="Zahl (1 - 4)" placeholder="Zahl (1 - 6)"
/> />
</Field.Root> </Field.Root>
</Stack> </Stack>
@@ -53,10 +57,17 @@ const AddItemForm: React.FC<AddItemFormProps> = ({ onClose, alert }) => {
(document.getElementById("can_borrow_role") as HTMLInputElement) (document.getElementById("can_borrow_role") as HTMLInputElement)
?.value ?.value
); );
const lockerValue = (
document.getElementById("lockerNumber") as HTMLInputElement
)?.value.trim();
const lockerNumber =
lockerValue === "" ? null : Number(lockerValue);
if (!name || Number.isNaN(role)) return; 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) { if (res.success) {
alert( alert(
"success", "success",

View File

@@ -38,6 +38,7 @@ type Items = {
item_name: string; item_name: string;
can_borrow_role: string; can_borrow_role: string;
in_safe: boolean; in_safe: boolean;
safe_nr: string;
entry_created_at: string; entry_created_at: string;
entry_updated_at: string; entry_updated_at: string;
last_borrowed_person: string | null; 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 = ( const setError = (
status: "error" | "success", status: "error" | "success",
message: string, message: string,
@@ -201,6 +208,9 @@ const ItemTable: React.FC = () => {
<Table.ColumnHeader> <Table.ColumnHeader>
<strong>Im Schließfach</strong> <strong>Im Schließfach</strong>
</Table.ColumnHeader> </Table.ColumnHeader>
<Table.ColumnHeader>
<strong>Schließfachnummer</strong>
</Table.ColumnHeader>
<Table.ColumnHeader> <Table.ColumnHeader>
<strong>Eintrag erstellt am</strong> <strong>Eintrag erstellt am</strong>
</Table.ColumnHeader> </Table.ColumnHeader>
@@ -208,10 +218,10 @@ const ItemTable: React.FC = () => {
<strong>Eintrag aktualisiert am</strong> <strong>Eintrag aktualisiert am</strong>
</Table.ColumnHeader> </Table.ColumnHeader>
<Table.ColumnHeader> <Table.ColumnHeader>
<strong>Letzte ausleihende Person</strong> <strong>LaP *</strong>
</Table.ColumnHeader> </Table.ColumnHeader>
<Table.ColumnHeader> <Table.ColumnHeader>
<strong>Derzeit ausgeliehen von</strong> <strong>Dav **</strong>
</Table.ColumnHeader> </Table.ColumnHeader>
<Table.ColumnHeader> <Table.ColumnHeader>
<strong>Aktionen</strong> <strong>Aktionen</strong>
@@ -277,6 +287,16 @@ const ItemTable: React.FC = () => {
</Text> </Text>
</Button> </Button>
</Table.Cell> </Table.Cell>
<Table.Cell>
<Input
size="sm"
w="max-content"
onChange={(e) =>
handleLockerNumberChange(item.id, e.target.value)
}
value={item.safe_nr}
/>
</Table.Cell>
<Table.Cell>{formatDateTime(item.entry_created_at)}</Table.Cell> <Table.Cell>{formatDateTime(item.entry_created_at)}</Table.Cell>
<Table.Cell>{formatDateTime(item.entry_updated_at)}</Table.Cell> <Table.Cell>{formatDateTime(item.entry_updated_at)}</Table.Cell>
<Table.Cell>{item.last_borrowed_person}</Table.Cell> <Table.Cell>{item.last_borrowed_person}</Table.Cell>
@@ -287,6 +307,7 @@ const ItemTable: React.FC = () => {
handleEditItems( handleEditItems(
item.id, item.id,
item.item_name, item.item_name,
item.safe_nr,
item.can_borrow_role item.can_borrow_role
).then((response) => { ).then((response) => {
if (response.success) { if (response.success) {
@@ -333,6 +354,8 @@ const ItemTable: React.FC = () => {
</Table.Body> </Table.Body>
</Table.Root> </Table.Root>
</Box> </Box>
<Text>* LaP = Letzte ausleihende Person</Text>
<Text>** Dav = Derzeit ausgeliehen von</Text>
</> </>
); );
}; };

View File

@@ -164,8 +164,10 @@ export const deleteItem = async (itemId: number) => {
export const createItem = async ( export const createItem = async (
item_name: string, 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 { try {
const response = await fetch( const response = await fetch(
`${API_BASE}/api/admin/item-data/create-item`, `${API_BASE}/api/admin/item-data/create-item`,
@@ -175,7 +177,7 @@ export const createItem = async (
"Content-Type": "application/json", "Content-Type": "application/json",
Authorization: `Bearer ${Cookies.get("token")}`, 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) { if (!response.ok) {
@@ -195,8 +197,10 @@ export const createItem = async (
export const handleEditItems = async ( export const handleEditItems = async (
itemId: number, itemId: number,
item_name: string, item_name: string,
safe_nr: string | null,
can_borrow_role: string can_borrow_role: string
) => { ) => {
const newSafeNr = Number(safe_nr || 0);
try { try {
const response = await fetch( const response = await fetch(
`${API_BASE}/api/admin/item-data/edit-item/${itemId}`, `${API_BASE}/api/admin/item-data/edit-item/${itemId}`,
@@ -206,7 +210,7 @@ export const handleEditItems = async (
"Content-Type": "application/json", "Content-Type": "application/json",
Authorization: `Bearer ${Cookies.get("token")}`, 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) { if (!response.ok) {

View File

@@ -23,10 +23,10 @@ export const deleteItemById = async (itemId) => {
return { success: false }; 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( const [result] = await pool.query(
"INSERT INTO items (item_name, can_borrow_role, in_safe) VALUES (?, ?, ?)", "INSERT INTO items (item_name, can_borrow_role, in_safe, safe_nr) VALUES (?, ?, ?, ?)",
[item_name, can_borrow_role, true] [item_name, can_borrow_role, true, lockerNumber]
); );
if (result.affectedRows > 0) return { success: true }; if (result.affectedRows > 0) return { success: true };
return { success: false }; return { success: false };

View File

@@ -31,8 +31,8 @@ router.delete("/delete-item/:id", authenticateAdmin, async (req, res) => {
}); });
router.post("/create-item", authenticateAdmin, async (req, res) => { router.post("/create-item", authenticateAdmin, async (req, res) => {
const { item_name, can_borrow_role } = req.body; const { item_name, can_borrow_role, lockerNumber } = req.body;
const result = await createItem(item_name, can_borrow_role); const result = await createItem(item_name, can_borrow_role, lockerNumber);
if (result.success) { if (result.success) {
return res.status(201).json({ message: "Item created successfully" }); return res.status(201).json({ message: "Item created successfully" });
} }

View File

@@ -37,7 +37,7 @@ CREATE TABLE items (
item_name varchar(255) NOT NULL UNIQUE, item_name varchar(255) NOT NULL UNIQUE,
can_borrow_role INT NOT NULL, can_borrow_role INT NOT NULL,
in_safe bool NOT NULL DEFAULT true, 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_created_at timestamp NULL DEFAULT CURRENT_TIMESTAMP,
entry_updated_at timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, entry_updated_at timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
last_borrowed_person varchar(255) DEFAULT NULL, last_borrowed_person varchar(255) DEFAULT NULL,