improved loan tabel on admin panel

This commit is contained in:
2026-04-26 22:21:00 +02:00
parent e52fc13da4
commit f8e29dca10
3 changed files with 357 additions and 267 deletions
+2 -2
View File
@@ -47,7 +47,7 @@ const Dashboard: React.FC<DashboardProps> = ({ onLogout }) => {
viewAPI={() => setActiveView("API")} viewAPI={() => setActiveView("API")}
viewConfig={() => setActiveView("Server Konfiguration")} viewConfig={() => setActiveView("Server Konfiguration")}
/> />
<Box flex="1" display="flex" flexDirection="column"> <Box flex="1" display="flex" flexDirection="column" minH={0}>
<Flex <Flex
as="header" as="header"
align="center" align="center"
@@ -68,7 +68,7 @@ const Dashboard: React.FC<DashboardProps> = ({ onLogout }) => {
</Button> </Button>
</Flex> </Flex>
</Flex> </Flex>
<Box as="main" flex="1" p={6}> <Box as="main" flex="1" p={6} minH={0} overflow="hidden">
{activeView === "" && ( {activeView === "" && (
<Flex <Flex
align="center" align="center"
+57 -13
View File
@@ -57,32 +57,32 @@ const ItemTable: React.FC = () => {
const handleItemNameChange = (id: number, value: string) => { const handleItemNameChange = (id: number, value: string) => {
setItems((prev) => setItems((prev) =>
prev.map((it) => (it.id === id ? { ...it, item_name: value } : it)) prev.map((it) => (it.id === id ? { ...it, item_name: value } : it)),
); );
}; };
const handleCanBorrowRoleChange = (id: number, value: string) => { const handleCanBorrowRoleChange = (id: number, value: string) => {
setItems((prev) => setItems((prev) =>
prev.map((it) => (it.id === id ? { ...it, can_borrow_role: value } : it)) prev.map((it) => (it.id === id ? { ...it, can_borrow_role: value } : it)),
); );
}; };
const handleLockerNumberChange = (id: number, value: string) => { const handleLockerNumberChange = (id: number, value: string) => {
setItems((prev) => setItems((prev) =>
prev.map((it) => (it.id === id ? { ...it, safe_nr: value } : it)) prev.map((it) => (it.id === id ? { ...it, safe_nr: value } : it)),
); );
}; };
const handleDoorKeyChange = (id: number, value: string) => { const handleDoorKeyChange = (id: number, value: string) => {
setItems((prev) => setItems((prev) =>
prev.map((it) => (it.id === id ? { ...it, door_key: value } : it)) prev.map((it) => (it.id === id ? { ...it, door_key: value } : it)),
); );
}; };
const setError = ( const setError = (
status: "error" | "success", status: "error" | "success",
message: string, message: string,
description: string description: string,
) => { ) => {
setIsError(false); setIsError(false);
setErrorStatus(status); setErrorStatus(status);
@@ -102,7 +102,7 @@ const ItemTable: React.FC = () => {
headers: { headers: {
Authorization: `Bearer ${Cookies.get("token")}`, Authorization: `Bearer ${Cookies.get("token")}`,
}, },
} },
); );
const data = await response.json(); const data = await response.json();
return data; return data;
@@ -193,11 +193,50 @@ const ItemTable: React.FC = () => {
{/* make table fill available width, like UserTable */} {/* make table fill available width, like UserTable */}
{!isLoading && ( {!isLoading && (
<Table.ScrollArea flex="1" minH={0} rounded="md" mt={4}>
<Table.Root <Table.Root
size="sm" size="sm"
striped striped
w="100%" stickyHeader
style={{ tableLayout: "auto" }} // Spalten nach Content css={{
"& [data-sticky]": {
position: "sticky",
zIndex: 1,
bg: "bg",
_after: {
content: '""',
position: "absolute",
pointerEvents: "none",
top: "0",
bottom: "-1px",
width: "32px",
},
},
"& [data-sticky=end]": {
_after: {
insetInlineEnd: "0",
translate: "100% 0",
shadow: "inset 8px 0px 8px -8px rgba(0, 0, 0, 0.16)",
},
},
"& [data-sticky=start]": {
_after: {
insetInlineStart: "0",
translate: "-100% 0",
shadow: "inset -8px 0px 8px -8px rgba(0, 0, 0, 0.16)",
},
},
"& thead tr": {
shadow: "0 1px 0 0 {colors.border}",
"&:has(th[data-sticky])": {
zIndex: 2,
},
},
}}
> >
<Table.Header> <Table.Header>
<Table.Row> <Table.Row>
@@ -315,8 +354,12 @@ const ItemTable: React.FC = () => {
value={item.door_key} value={item.door_key}
/> />
</Table.Cell> </Table.Cell>
<Table.Cell>{formatDateTime(item.entry_created_at)}</Table.Cell> <Table.Cell>
<Table.Cell>{formatDateTime(item.entry_updated_at)}</Table.Cell> {formatDateTime(item.entry_created_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>
<Table.Cell>{item.currently_borrowing}</Table.Cell> <Table.Cell>{item.currently_borrowing}</Table.Cell>
<Table.Cell whiteSpace="nowrap"> <Table.Cell whiteSpace="nowrap">
@@ -327,7 +370,7 @@ const ItemTable: React.FC = () => {
item.item_name, item.item_name,
item.safe_nr, item.safe_nr,
item.door_key, item.door_key,
item.can_borrow_role item.can_borrow_role,
).then((response) => { ).then((response) => {
if (response.success) { if (response.success) {
setError( setError(
@@ -338,7 +381,7 @@ const ItemTable: React.FC = () => {
item.item_name + item.item_name +
'" mit ID ' + '" mit ID ' +
item.id + item.id +
" bearbeitet." " bearbeitet.",
); );
} }
}) })
@@ -356,7 +399,7 @@ const ItemTable: React.FC = () => {
setError( setError(
"success", "success",
"Gegenstand gelöscht", "Gegenstand gelöscht",
"Der Gegenstand wurde erfolgreich gelöscht." "Der Gegenstand wurde erfolgreich gelöscht.",
); );
} }
}) })
@@ -372,6 +415,7 @@ const ItemTable: React.FC = () => {
))} ))}
</Table.Body> </Table.Body>
</Table.Root> </Table.Root>
</Table.ScrollArea>
)} )}
<Text>* LaP = Letzte ausleihende Person</Text> <Text>* LaP = Letzte ausleihende Person</Text>
<Text>** Dav = Derzeit ausgeliehen von</Text> <Text>** Dav = Derzeit ausgeliehen von</Text>
+52 -6
View File
@@ -1,5 +1,6 @@
import React from "react"; import React from "react";
import { import {
Box,
Table, Table,
Spinner, Spinner,
Text, Text,
@@ -31,7 +32,7 @@ const LoanTable: React.FC = () => {
const setError = ( const setError = (
status: "error" | "success", status: "error" | "success",
message: string, message: string,
description: string description: string,
) => { ) => {
setIsError(false); setIsError(false);
setErrorStatus(status); setErrorStatus(status);
@@ -65,7 +66,7 @@ const LoanTable: React.FC = () => {
headers: { headers: {
Authorization: `Bearer ${Cookies.get("token")}`, Authorization: `Bearer ${Cookies.get("token")}`,
}, },
} },
); );
const data = await response.json(); const data = await response.json();
return data; return data;
@@ -83,7 +84,7 @@ const LoanTable: React.FC = () => {
}, [reload]); }, [reload]);
return ( return (
<> <Box h="full" display="flex" flexDirection="column" minH={0}>
{/* Action toolbar */} {/* Action toolbar */}
<HStack <HStack
mb={4} mb={4}
@@ -131,7 +132,51 @@ const LoanTable: React.FC = () => {
</VStack> </VStack>
)} )}
{!isLoading && ( {!isLoading && (
<Table.Root size="sm" striped> <Table.ScrollArea flex="1" minH={0} rounded="md" mt={4}>
<Table.Root
size="sm"
striped
stickyHeader
css={{
"& [data-sticky]": {
position: "sticky",
zIndex: 1,
bg: "bg",
_after: {
content: '""',
position: "absolute",
pointerEvents: "none",
top: "0",
bottom: "-1px",
width: "32px",
},
},
"& [data-sticky=end]": {
_after: {
insetInlineEnd: "0",
translate: "100% 0",
shadow: "inset 8px 0px 8px -8px rgba(0, 0, 0, 0.16)",
},
},
"& [data-sticky=start]": {
_after: {
insetInlineStart: "0",
translate: "-100% 0",
shadow: "inset -8px 0px 8px -8px rgba(0, 0, 0, 0.16)",
},
},
"& thead tr": {
shadow: "0 1px 0 0 {colors.border}",
"&:has(th[data-sticky])": {
zIndex: 2,
},
},
}}
>
<Table.Header> <Table.Header>
<Table.Row> <Table.Row>
<Table.ColumnHeader> <Table.ColumnHeader>
@@ -193,7 +238,7 @@ const LoanTable: React.FC = () => {
setError( setError(
"success", "success",
"Loan deleted", "Loan deleted",
"The loan has been successfully deleted." "The loan has been successfully deleted.",
); );
} }
}) })
@@ -209,8 +254,9 @@ const LoanTable: React.FC = () => {
))} ))}
</Table.Body> </Table.Body>
</Table.Root> </Table.Root>
</Table.ScrollArea>
)} )}
</> </Box>
); );
}; };