Compare commits
2 Commits
dev_feat_mailer
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
| f8e29dca10 | |||
| e52fc13da4 |
@@ -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"
|
||||||
|
|||||||
+228
-184
@@ -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,185 +193,229 @@ const ItemTable: React.FC = () => {
|
|||||||
|
|
||||||
{/* make table fill available width, like UserTable */}
|
{/* make table fill available width, like UserTable */}
|
||||||
{!isLoading && (
|
{!isLoading && (
|
||||||
<Table.Root
|
<Table.ScrollArea flex="1" minH={0} rounded="md" mt={4}>
|
||||||
size="sm"
|
<Table.Root
|
||||||
striped
|
size="sm"
|
||||||
w="100%"
|
striped
|
||||||
style={{ tableLayout: "auto" }} // Spalten nach Content
|
stickyHeader
|
||||||
>
|
css={{
|
||||||
<Table.Header>
|
"& [data-sticky]": {
|
||||||
<Table.Row>
|
position: "sticky",
|
||||||
<Table.ColumnHeader>
|
zIndex: 1,
|
||||||
<strong>#</strong>
|
bg: "bg",
|
||||||
</Table.ColumnHeader>
|
|
||||||
<Table.ColumnHeader>
|
_after: {
|
||||||
<strong>Gegenstand</strong>
|
content: '""',
|
||||||
</Table.ColumnHeader>
|
position: "absolute",
|
||||||
<Table.ColumnHeader>
|
pointerEvents: "none",
|
||||||
<strong>Ausleih Berechtigung</strong>
|
top: "0",
|
||||||
</Table.ColumnHeader>
|
bottom: "-1px",
|
||||||
<Table.ColumnHeader>
|
width: "32px",
|
||||||
<strong>Im Schließfach</strong>
|
},
|
||||||
</Table.ColumnHeader>
|
},
|
||||||
<Table.ColumnHeader width="1%" whiteSpace="nowrap">
|
|
||||||
<strong>Schließfachnummer</strong>
|
"& [data-sticky=end]": {
|
||||||
</Table.ColumnHeader>
|
_after: {
|
||||||
<Table.ColumnHeader width="1%" whiteSpace="nowrap">
|
insetInlineEnd: "0",
|
||||||
<strong>Schlüssel</strong>
|
translate: "100% 0",
|
||||||
</Table.ColumnHeader>
|
shadow: "inset 8px 0px 8px -8px rgba(0, 0, 0, 0.16)",
|
||||||
<Table.ColumnHeader>
|
},
|
||||||
<strong>Eintrag erstellt am</strong>
|
},
|
||||||
</Table.ColumnHeader>
|
|
||||||
<Table.ColumnHeader>
|
"& [data-sticky=start]": {
|
||||||
<strong>Eintrag aktualisiert am</strong>
|
_after: {
|
||||||
</Table.ColumnHeader>
|
insetInlineStart: "0",
|
||||||
<Table.ColumnHeader>
|
translate: "-100% 0",
|
||||||
<strong>LaP *</strong>
|
shadow: "inset -8px 0px 8px -8px rgba(0, 0, 0, 0.16)",
|
||||||
</Table.ColumnHeader>
|
},
|
||||||
<Table.ColumnHeader>
|
},
|
||||||
<strong>Dav **</strong>
|
|
||||||
</Table.ColumnHeader>
|
"& thead tr": {
|
||||||
<Table.ColumnHeader width="1%" whiteSpace="nowrap">
|
shadow: "0 1px 0 0 {colors.border}",
|
||||||
<strong>Aktionen</strong>
|
"&:has(th[data-sticky])": {
|
||||||
</Table.ColumnHeader>
|
zIndex: 2,
|
||||||
</Table.Row>
|
},
|
||||||
</Table.Header>
|
},
|
||||||
<Table.Body>
|
}}
|
||||||
{items.map((item) => (
|
>
|
||||||
<Table.Row key={item.id}>
|
<Table.Header>
|
||||||
<Table.Cell>{item.id}</Table.Cell>
|
<Table.Row>
|
||||||
<Table.Cell>
|
<Table.ColumnHeader>
|
||||||
<Input
|
<strong>#</strong>
|
||||||
size="sm"
|
</Table.ColumnHeader>
|
||||||
w="max-content"
|
<Table.ColumnHeader>
|
||||||
onChange={(e) =>
|
<strong>Gegenstand</strong>
|
||||||
handleItemNameChange(item.id, e.target.value)
|
</Table.ColumnHeader>
|
||||||
}
|
<Table.ColumnHeader>
|
||||||
value={item.item_name}
|
<strong>Ausleih Berechtigung</strong>
|
||||||
/>
|
</Table.ColumnHeader>
|
||||||
</Table.Cell>
|
<Table.ColumnHeader>
|
||||||
<Table.Cell>
|
<strong>Im Schließfach</strong>
|
||||||
<Input
|
</Table.ColumnHeader>
|
||||||
size="sm"
|
<Table.ColumnHeader width="1%" whiteSpace="nowrap">
|
||||||
w="max-content"
|
<strong>Schließfachnummer</strong>
|
||||||
onChange={(e) =>
|
</Table.ColumnHeader>
|
||||||
handleCanBorrowRoleChange(item.id, e.target.value)
|
<Table.ColumnHeader width="1%" whiteSpace="nowrap">
|
||||||
}
|
<strong>Schlüssel</strong>
|
||||||
value={item.can_borrow_role}
|
</Table.ColumnHeader>
|
||||||
/>
|
<Table.ColumnHeader>
|
||||||
</Table.Cell>
|
<strong>Eintrag erstellt am</strong>
|
||||||
<Table.Cell>
|
</Table.ColumnHeader>
|
||||||
<Button
|
<Table.ColumnHeader>
|
||||||
onClick={() =>
|
<strong>Eintrag aktualisiert am</strong>
|
||||||
changeSafeState(item.id).then(() => setReload(!reload))
|
</Table.ColumnHeader>
|
||||||
}
|
<Table.ColumnHeader>
|
||||||
size="xs"
|
<strong>LaP *</strong>
|
||||||
rounded="full"
|
</Table.ColumnHeader>
|
||||||
px={3}
|
<Table.ColumnHeader>
|
||||||
py={1}
|
<strong>Dav **</strong>
|
||||||
gap={2}
|
</Table.ColumnHeader>
|
||||||
variant="ghost"
|
<Table.ColumnHeader width="1%" whiteSpace="nowrap">
|
||||||
color={item.in_safe ? "green.600" : "red.600"}
|
<strong>Aktionen</strong>
|
||||||
borderWidth="1px"
|
</Table.ColumnHeader>
|
||||||
borderColor={item.in_safe ? "green.300" : "red.300"}
|
|
||||||
_hover={{
|
|
||||||
bg: item.in_safe ? "green.50" : "red.50",
|
|
||||||
borderColor: item.in_safe ? "green.400" : "red.400",
|
|
||||||
transform: "translateY(-1px)",
|
|
||||||
shadow: "sm",
|
|
||||||
}}
|
|
||||||
_active={{ transform: "translateY(0)" }}
|
|
||||||
aria-label={
|
|
||||||
item.in_safe ? "Mark as not in safe" : "Mark as in safe"
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Icon
|
|
||||||
as={item.in_safe ? CheckCircle2 : XCircle}
|
|
||||||
boxSize={3.5}
|
|
||||||
mr={2}
|
|
||||||
/>
|
|
||||||
<Text as="span" fontSize="xs" fontWeight="semibold">
|
|
||||||
{item.in_safe ? "Yes" : "No"}
|
|
||||||
</Text>
|
|
||||||
</Button>
|
|
||||||
</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>
|
|
||||||
<Input
|
|
||||||
size="sm"
|
|
||||||
w="max-content"
|
|
||||||
onChange={(e) =>
|
|
||||||
handleDoorKeyChange(item.id, e.target.value)
|
|
||||||
}
|
|
||||||
value={item.door_key}
|
|
||||||
/>
|
|
||||||
</Table.Cell>
|
|
||||||
<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.currently_borrowing}</Table.Cell>
|
|
||||||
<Table.Cell whiteSpace="nowrap">
|
|
||||||
<Button
|
|
||||||
onClick={() =>
|
|
||||||
handleEditItems(
|
|
||||||
item.id,
|
|
||||||
item.item_name,
|
|
||||||
item.safe_nr,
|
|
||||||
item.door_key,
|
|
||||||
item.can_borrow_role
|
|
||||||
).then((response) => {
|
|
||||||
if (response.success) {
|
|
||||||
setError(
|
|
||||||
"success",
|
|
||||||
"Gegenstand erfolgreich bearbeitet!",
|
|
||||||
"Gegenstand " +
|
|
||||||
'"' +
|
|
||||||
item.item_name +
|
|
||||||
'" mit ID ' +
|
|
||||||
item.id +
|
|
||||||
" bearbeitet."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
colorPalette="teal"
|
|
||||||
size="sm"
|
|
||||||
>
|
|
||||||
<Save />
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
onClick={() =>
|
|
||||||
deleteItem(item.id).then((response) => {
|
|
||||||
if (response.success) {
|
|
||||||
setItems(items.filter((i) => i.id !== item.id));
|
|
||||||
setError(
|
|
||||||
"success",
|
|
||||||
"Gegenstand gelöscht",
|
|
||||||
"Der Gegenstand wurde erfolgreich gelöscht."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
colorPalette="red"
|
|
||||||
size="sm"
|
|
||||||
ml={2}
|
|
||||||
>
|
|
||||||
<Trash2 />
|
|
||||||
</Button>
|
|
||||||
</Table.Cell>
|
|
||||||
</Table.Row>
|
</Table.Row>
|
||||||
))}
|
</Table.Header>
|
||||||
</Table.Body>
|
<Table.Body>
|
||||||
</Table.Root>
|
{items.map((item) => (
|
||||||
|
<Table.Row key={item.id}>
|
||||||
|
<Table.Cell>{item.id}</Table.Cell>
|
||||||
|
<Table.Cell>
|
||||||
|
<Input
|
||||||
|
size="sm"
|
||||||
|
w="max-content"
|
||||||
|
onChange={(e) =>
|
||||||
|
handleItemNameChange(item.id, e.target.value)
|
||||||
|
}
|
||||||
|
value={item.item_name}
|
||||||
|
/>
|
||||||
|
</Table.Cell>
|
||||||
|
<Table.Cell>
|
||||||
|
<Input
|
||||||
|
size="sm"
|
||||||
|
w="max-content"
|
||||||
|
onChange={(e) =>
|
||||||
|
handleCanBorrowRoleChange(item.id, e.target.value)
|
||||||
|
}
|
||||||
|
value={item.can_borrow_role}
|
||||||
|
/>
|
||||||
|
</Table.Cell>
|
||||||
|
<Table.Cell>
|
||||||
|
<Button
|
||||||
|
onClick={() =>
|
||||||
|
changeSafeState(item.id).then(() => setReload(!reload))
|
||||||
|
}
|
||||||
|
size="xs"
|
||||||
|
rounded="full"
|
||||||
|
px={3}
|
||||||
|
py={1}
|
||||||
|
gap={2}
|
||||||
|
variant="ghost"
|
||||||
|
color={item.in_safe ? "green.600" : "red.600"}
|
||||||
|
borderWidth="1px"
|
||||||
|
borderColor={item.in_safe ? "green.300" : "red.300"}
|
||||||
|
_hover={{
|
||||||
|
bg: item.in_safe ? "green.50" : "red.50",
|
||||||
|
borderColor: item.in_safe ? "green.400" : "red.400",
|
||||||
|
transform: "translateY(-1px)",
|
||||||
|
shadow: "sm",
|
||||||
|
}}
|
||||||
|
_active={{ transform: "translateY(0)" }}
|
||||||
|
aria-label={
|
||||||
|
item.in_safe ? "Mark as not in safe" : "Mark as in safe"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
as={item.in_safe ? CheckCircle2 : XCircle}
|
||||||
|
boxSize={3.5}
|
||||||
|
mr={2}
|
||||||
|
/>
|
||||||
|
<Text as="span" fontSize="xs" fontWeight="semibold">
|
||||||
|
{item.in_safe ? "Yes" : "No"}
|
||||||
|
</Text>
|
||||||
|
</Button>
|
||||||
|
</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>
|
||||||
|
<Input
|
||||||
|
size="sm"
|
||||||
|
w="max-content"
|
||||||
|
onChange={(e) =>
|
||||||
|
handleDoorKeyChange(item.id, e.target.value)
|
||||||
|
}
|
||||||
|
value={item.door_key}
|
||||||
|
/>
|
||||||
|
</Table.Cell>
|
||||||
|
<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.currently_borrowing}</Table.Cell>
|
||||||
|
<Table.Cell whiteSpace="nowrap">
|
||||||
|
<Button
|
||||||
|
onClick={() =>
|
||||||
|
handleEditItems(
|
||||||
|
item.id,
|
||||||
|
item.item_name,
|
||||||
|
item.safe_nr,
|
||||||
|
item.door_key,
|
||||||
|
item.can_borrow_role,
|
||||||
|
).then((response) => {
|
||||||
|
if (response.success) {
|
||||||
|
setError(
|
||||||
|
"success",
|
||||||
|
"Gegenstand erfolgreich bearbeitet!",
|
||||||
|
"Gegenstand " +
|
||||||
|
'"' +
|
||||||
|
item.item_name +
|
||||||
|
'" mit ID ' +
|
||||||
|
item.id +
|
||||||
|
" bearbeitet.",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
colorPalette="teal"
|
||||||
|
size="sm"
|
||||||
|
>
|
||||||
|
<Save />
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
onClick={() =>
|
||||||
|
deleteItem(item.id).then((response) => {
|
||||||
|
if (response.success) {
|
||||||
|
setItems(items.filter((i) => i.id !== item.id));
|
||||||
|
setError(
|
||||||
|
"success",
|
||||||
|
"Gegenstand gelöscht",
|
||||||
|
"Der Gegenstand wurde erfolgreich gelöscht.",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
colorPalette="red"
|
||||||
|
size="sm"
|
||||||
|
ml={2}
|
||||||
|
>
|
||||||
|
<Trash2 />
|
||||||
|
</Button>
|
||||||
|
</Table.Cell>
|
||||||
|
</Table.Row>
|
||||||
|
))}
|
||||||
|
</Table.Body>
|
||||||
|
</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>
|
||||||
|
|||||||
@@ -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,86 +132,131 @@ const LoanTable: React.FC = () => {
|
|||||||
</VStack>
|
</VStack>
|
||||||
)}
|
)}
|
||||||
{!isLoading && (
|
{!isLoading && (
|
||||||
<Table.Root size="sm" striped>
|
<Table.ScrollArea flex="1" minH={0} rounded="md" mt={4}>
|
||||||
<Table.Header>
|
<Table.Root
|
||||||
<Table.Row>
|
size="sm"
|
||||||
<Table.ColumnHeader>
|
striped
|
||||||
<strong>#</strong>
|
stickyHeader
|
||||||
</Table.ColumnHeader>
|
css={{
|
||||||
<Table.ColumnHeader>
|
"& [data-sticky]": {
|
||||||
<strong>Besitzer</strong>
|
position: "sticky",
|
||||||
</Table.ColumnHeader>
|
zIndex: 1,
|
||||||
<Table.ColumnHeader>
|
bg: "bg",
|
||||||
<strong>Ausleih code</strong>
|
|
||||||
</Table.ColumnHeader>
|
_after: {
|
||||||
<Table.ColumnHeader>
|
content: '""',
|
||||||
<strong>Startdatum</strong>
|
position: "absolute",
|
||||||
</Table.ColumnHeader>
|
pointerEvents: "none",
|
||||||
<Table.ColumnHeader>
|
top: "0",
|
||||||
<strong>Enddatum</strong>
|
bottom: "-1px",
|
||||||
</Table.ColumnHeader>
|
width: "32px",
|
||||||
<Table.ColumnHeader>
|
},
|
||||||
<strong>Ausleihdatum</strong>
|
},
|
||||||
</Table.ColumnHeader>
|
|
||||||
<Table.ColumnHeader>
|
"& [data-sticky=end]": {
|
||||||
<strong>Rückgabedatum</strong>
|
_after: {
|
||||||
</Table.ColumnHeader>
|
insetInlineEnd: "0",
|
||||||
<Table.ColumnHeader>
|
translate: "100% 0",
|
||||||
<strong>Erstellt am</strong>
|
shadow: "inset 8px 0px 8px -8px rgba(0, 0, 0, 0.16)",
|
||||||
</Table.ColumnHeader>
|
},
|
||||||
<Table.ColumnHeader>
|
},
|
||||||
<strong>Ausgeliehene Artikel</strong>
|
|
||||||
</Table.ColumnHeader>
|
"& [data-sticky=start]": {
|
||||||
<Table.ColumnHeader>
|
_after: {
|
||||||
<strong>Notiz</strong>
|
insetInlineStart: "0",
|
||||||
</Table.ColumnHeader>
|
translate: "-100% 0",
|
||||||
<Table.ColumnHeader>
|
shadow: "inset -8px 0px 8px -8px rgba(0, 0, 0, 0.16)",
|
||||||
<strong>Aktionen</strong>
|
},
|
||||||
</Table.ColumnHeader>
|
},
|
||||||
</Table.Row>
|
|
||||||
</Table.Header>
|
"& thead tr": {
|
||||||
<Table.Body>
|
shadow: "0 1px 0 0 {colors.border}",
|
||||||
{items.map((item) => (
|
"&:has(th[data-sticky])": {
|
||||||
<Table.Row color={item.deleted ? "red" : "white"} key={item.id}>
|
zIndex: 2,
|
||||||
<Table.Cell>{item.id}</Table.Cell>
|
},
|
||||||
<Table.Cell>{item.username}</Table.Cell>
|
},
|
||||||
<Table.Cell>
|
}}
|
||||||
<Code>{item.loan_code}</Code>
|
>
|
||||||
</Table.Cell>
|
<Table.Header>
|
||||||
<Table.Cell>{formatDateTime(item.start_date)}</Table.Cell>
|
<Table.Row>
|
||||||
<Table.Cell>{formatDateTime(item.end_date)}</Table.Cell>
|
<Table.ColumnHeader>
|
||||||
<Table.Cell>{formatDateTime(item.take_date)}</Table.Cell>
|
<strong>#</strong>
|
||||||
<Table.Cell>{formatDateTime(item.returned_date)}</Table.Cell>
|
</Table.ColumnHeader>
|
||||||
<Table.Cell>{formatDateTime(item.created_at)}</Table.Cell>
|
<Table.ColumnHeader>
|
||||||
<Table.Cell>{item.loaned_items_name.join(", ")}</Table.Cell>
|
<strong>Besitzer</strong>
|
||||||
<Table.Cell>{item.note}</Table.Cell>
|
</Table.ColumnHeader>
|
||||||
<Table.Cell>
|
<Table.ColumnHeader>
|
||||||
<Button
|
<strong>Ausleihcode</strong>
|
||||||
onClick={() =>
|
</Table.ColumnHeader>
|
||||||
deleteLoan(item.id).then((response) => {
|
<Table.ColumnHeader>
|
||||||
if (response.success) {
|
<strong>Startdatum</strong>
|
||||||
setItems(items.filter((i) => i.id !== item.id));
|
</Table.ColumnHeader>
|
||||||
setError(
|
<Table.ColumnHeader>
|
||||||
"success",
|
<strong>Enddatum</strong>
|
||||||
"Loan deleted",
|
</Table.ColumnHeader>
|
||||||
"The loan has been successfully deleted."
|
<Table.ColumnHeader>
|
||||||
);
|
<strong>Ausleihdatum</strong>
|
||||||
}
|
</Table.ColumnHeader>
|
||||||
})
|
<Table.ColumnHeader>
|
||||||
}
|
<strong>Rückgabedatum</strong>
|
||||||
colorPalette="red"
|
</Table.ColumnHeader>
|
||||||
size="sm"
|
<Table.ColumnHeader>
|
||||||
ml={2}
|
<strong>Erstellt am</strong>
|
||||||
>
|
</Table.ColumnHeader>
|
||||||
<Trash2 />
|
<Table.ColumnHeader>
|
||||||
</Button>
|
<strong>Ausgeliehene Artikel</strong>
|
||||||
</Table.Cell>
|
</Table.ColumnHeader>
|
||||||
|
<Table.ColumnHeader>
|
||||||
|
<strong>Notiz</strong>
|
||||||
|
</Table.ColumnHeader>
|
||||||
|
<Table.ColumnHeader>
|
||||||
|
<strong>Aktionen</strong>
|
||||||
|
</Table.ColumnHeader>
|
||||||
</Table.Row>
|
</Table.Row>
|
||||||
))}
|
</Table.Header>
|
||||||
</Table.Body>
|
<Table.Body>
|
||||||
</Table.Root>
|
{items.map((item) => (
|
||||||
|
<Table.Row color={item.deleted ? "red" : "white"} key={item.id}>
|
||||||
|
<Table.Cell>{item.id}</Table.Cell>
|
||||||
|
<Table.Cell>{item.username}</Table.Cell>
|
||||||
|
<Table.Cell>
|
||||||
|
<Code>{item.loan_code}</Code>
|
||||||
|
</Table.Cell>
|
||||||
|
<Table.Cell>{formatDateTime(item.start_date)}</Table.Cell>
|
||||||
|
<Table.Cell>{formatDateTime(item.end_date)}</Table.Cell>
|
||||||
|
<Table.Cell>{formatDateTime(item.take_date)}</Table.Cell>
|
||||||
|
<Table.Cell>{formatDateTime(item.returned_date)}</Table.Cell>
|
||||||
|
<Table.Cell>{formatDateTime(item.created_at)}</Table.Cell>
|
||||||
|
<Table.Cell>{item.loaned_items_name.join(", ")}</Table.Cell>
|
||||||
|
<Table.Cell>{item.note}</Table.Cell>
|
||||||
|
<Table.Cell>
|
||||||
|
<Button
|
||||||
|
onClick={() =>
|
||||||
|
deleteLoan(item.id).then((response) => {
|
||||||
|
if (response.success) {
|
||||||
|
setItems(items.filter((i) => i.id !== item.id));
|
||||||
|
setError(
|
||||||
|
"success",
|
||||||
|
"Loan deleted",
|
||||||
|
"The loan has been successfully deleted.",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
colorPalette="red"
|
||||||
|
size="sm"
|
||||||
|
ml={2}
|
||||||
|
>
|
||||||
|
<Trash2 />
|
||||||
|
</Button>
|
||||||
|
</Table.Cell>
|
||||||
|
</Table.Row>
|
||||||
|
))}
|
||||||
|
</Table.Body>
|
||||||
|
</Table.Root>
|
||||||
|
</Table.ScrollArea>
|
||||||
)}
|
)}
|
||||||
</>
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ This update provides some new features for the design. It also contains some imp
|
|||||||
- Improved error logging
|
- Improved error logging
|
||||||
- If you try to delete a loan that has not been returned yet, you will get an 507 error code.
|
- If you try to delete a loan that has not been returned yet, you will get an 507 error code.
|
||||||
- When the admin deletes a loan, the loan will be still visible in the database, but it will be marked as deleted. This is to prevent data loss and to keep track of deleted loans.
|
- When the admin deletes a loan, the loan will be still visible in the database, but it will be marked as deleted. This is to prevent data loss and to keep track of deleted loans.
|
||||||
|
- Mailer improvements: The mailer is now more clearly organised. Two large code files are now split into five smaller code files which are easier to maintain. Also the design of the mails has improved.
|
||||||
|
|
||||||
## Fixed bugs
|
## Fixed bugs
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user