semi working order info admin page

This commit is contained in:
Tim
2025-06-17 11:52:20 +02:00
parent 9895ccbcd4
commit a98fd3925e
13 changed files with 295 additions and 270 deletions

View File

@@ -41,6 +41,7 @@ public class ControllerPathConfig {
//OrderController //OrderController
public static final String ORDER_BASE = "/order"; public static final String ORDER_BASE = "/order";
public static final String ORDER_GET_ALL = ORDER_BASE + "/all"; public static final String ORDER_GET_ALL = ORDER_BASE + "/all";
public static final String ORDER_GET_ALL_ADMIN = ORDER_BASE + "/all/all";
//ReviewController //ReviewController
public static final String REVIEW_BASE = "/review"; public static final String REVIEW_BASE = "/review";

View File

@@ -16,8 +16,7 @@ import org.springframework.web.bind.annotation.*;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import static de.htwsaar.webshop.config.ControllerPathConfig.ORDER_BASE; import static de.htwsaar.webshop.config.ControllerPathConfig.*;
import static de.htwsaar.webshop.config.ControllerPathConfig.ORDER_GET_ALL;
import static de.htwsaar.webshop.config.ParameterConfig.*; import static de.htwsaar.webshop.config.ParameterConfig.*;
import static de.htwsaar.webshop.util.LoggerUtil.logRequest; import static de.htwsaar.webshop.util.LoggerUtil.logRequest;
@@ -47,7 +46,7 @@ public class OrderController {
return ResponseEntity.ok(orders.stream().map(Order::toModel).toList()); return ResponseEntity.ok(orders.stream().map(Order::toModel).toList());
} }
@RequestMapping(path = ORDER_GET_ALL, method = RequestMethod.TRACE, produces = "application/json") @RequestMapping(path = ORDER_GET_ALL_ADMIN, method = RequestMethod.GET, produces = "application/json")
public ResponseEntity<List<OrderModel>> getAll(HttpServletRequest request, public ResponseEntity<List<OrderModel>> getAll(HttpServletRequest request,
@RequestParam(value = PARAM_EMAIL) String email, @RequestParam(value = PARAM_EMAIL) String email,
@RequestParam(value = PARAM_SESSION) UUID token) { @RequestParam(value = PARAM_SESSION) UUID token) {
@@ -92,10 +91,16 @@ public class OrderController {
@RequestParam(value = PARAM_STATUS) OrderStatus status) { @RequestParam(value = PARAM_STATUS) OrderStatus status) {
logRequest(request); logRequest(request);
if (orderId == null) { if (orderId == null) {
log.info("[{}] failed to update, empty orderID", request.getRequestURI());
return ResponseEntity.badRequest().build();
}
if (status == null) {
log.info("[{}] failed to update, empty status, orderID {}", request.getRequestURI(), orderId);
return ResponseEntity.badRequest().build(); return ResponseEntity.badRequest().build();
} }
Order order = orderService.getOrderById(orderId); Order order = orderService.getOrderById(orderId);
if (order == null) { if (order == null) {
log.info("[{}] failed to update orderID {}", request.getRequestURI(), orderId);
return ResponseEntity.notFound().build(); return ResponseEntity.notFound().build();
} }
order.setStatus(status); order.setStatus(status);

View File

@@ -26,6 +26,8 @@
"react": "^19.0.0", "react": "^19.0.0",
"react-chartjs-2": "^5.3.0", "react-chartjs-2": "^5.3.0",
"react-cookie": "^8.0.1", "react-cookie": "^8.0.1",
"react-dnd": "^16.0.1",
"react-dnd-html5-backend": "^16.0.1",
"react-dom": "^19.1.0", "react-dom": "^19.1.0",
"react-i18next": "^15.5.1", "react-i18next": "^15.5.1",
"react-router-dom": "^7.5.3" "react-router-dom": "^7.5.3"
@@ -1693,6 +1695,24 @@
"url": "https://opencollective.com/popperjs" "url": "https://opencollective.com/popperjs"
} }
}, },
"node_modules/@react-dnd/asap": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/@react-dnd/asap/-/asap-5.0.2.tgz",
"integrity": "sha512-WLyfoHvxhs0V9U+GTsGilGgf2QsPl6ZZ44fnv0/b8T3nQyvzxidxsg/ZltbWssbsRDlYW8UKSQMTGotuTotZ6A==",
"license": "MIT"
},
"node_modules/@react-dnd/invariant": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/@react-dnd/invariant/-/invariant-4.0.2.tgz",
"integrity": "sha512-xKCTqAK/FFauOM9Ta2pswIyT3D8AQlfrYdOi/toTPEhqCuAs1v5tcJ3Y08Izh1cJ5Jchwy9SeAXmMg6zrKs2iw==",
"license": "MIT"
},
"node_modules/@react-dnd/shallowequal": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/@react-dnd/shallowequal/-/shallowequal-4.0.2.tgz",
"integrity": "sha512-/RVXdLvJxLg4QKvMoM5WlwNR9ViO9z8B/qPcc+C0Sa/teJY7QG7kJ441DwzOjMYEY7GmU4dj5EcGHIkKZiQZCA==",
"license": "MIT"
},
"node_modules/@rolldown/pluginutils": { "node_modules/@rolldown/pluginutils": {
"version": "1.0.0-beta.11", "version": "1.0.0-beta.11",
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.11.tgz", "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.11.tgz",
@@ -2933,6 +2953,17 @@
"robust-predicates": "^3.0.2" "robust-predicates": "^3.0.2"
} }
}, },
"node_modules/dnd-core": {
"version": "16.0.1",
"resolved": "https://registry.npmjs.org/dnd-core/-/dnd-core-16.0.1.tgz",
"integrity": "sha512-HK294sl7tbw6F6IeuK16YSBUoorvHpY8RHO+9yFfaJyCDVb6n7PRcezrOEOa2SBCqiYpemh5Jx20ZcjKdFAVng==",
"license": "MIT",
"dependencies": {
"@react-dnd/asap": "^5.0.1",
"@react-dnd/invariant": "^4.0.1",
"redux": "^4.2.0"
}
},
"node_modules/dom-helpers": { "node_modules/dom-helpers": {
"version": "5.2.1", "version": "5.2.1",
"resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
@@ -3204,7 +3235,6 @@
"version": "3.1.3", "version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/fast-glob": { "node_modules/fast-glob": {
@@ -4110,6 +4140,45 @@
"react": ">= 16.3.0" "react": ">= 16.3.0"
} }
}, },
"node_modules/react-dnd": {
"version": "16.0.1",
"resolved": "https://registry.npmjs.org/react-dnd/-/react-dnd-16.0.1.tgz",
"integrity": "sha512-QeoM/i73HHu2XF9aKksIUuamHPDvRglEwdHL4jsp784BgUuWcg6mzfxT0QDdQz8Wj0qyRKx2eMg8iZtWvU4E2Q==",
"license": "MIT",
"dependencies": {
"@react-dnd/invariant": "^4.0.1",
"@react-dnd/shallowequal": "^4.0.1",
"dnd-core": "^16.0.1",
"fast-deep-equal": "^3.1.3",
"hoist-non-react-statics": "^3.3.2"
},
"peerDependencies": {
"@types/hoist-non-react-statics": ">= 3.3.1",
"@types/node": ">= 12",
"@types/react": ">= 16",
"react": ">= 16.14"
},
"peerDependenciesMeta": {
"@types/hoist-non-react-statics": {
"optional": true
},
"@types/node": {
"optional": true
},
"@types/react": {
"optional": true
}
}
},
"node_modules/react-dnd-html5-backend": {
"version": "16.0.1",
"resolved": "https://registry.npmjs.org/react-dnd-html5-backend/-/react-dnd-html5-backend-16.0.1.tgz",
"integrity": "sha512-Wu3dw5aDJmOGw8WjH1I1/yTH+vlXEL4vmjk5p+MHxP8HuHJS1lAGeIdG/hze1AvNeXWo/JgULV87LyQOr+r5jw==",
"license": "MIT",
"dependencies": {
"dnd-core": "^16.0.1"
}
},
"node_modules/react-dom": { "node_modules/react-dom": {
"version": "19.1.0", "version": "19.1.0",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz",
@@ -4218,6 +4287,15 @@
"react-dom": ">=16.6.0" "react-dom": ">=16.6.0"
} }
}, },
"node_modules/redux": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz",
"integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.9.2"
}
},
"node_modules/reselect": { "node_modules/reselect": {
"version": "5.1.1", "version": "5.1.1",
"resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz", "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz",

View File

@@ -30,6 +30,8 @@
"react": "^19.0.0", "react": "^19.0.0",
"react-chartjs-2": "^5.3.0", "react-chartjs-2": "^5.3.0",
"react-cookie": "^8.0.1", "react-cookie": "^8.0.1",
"react-dnd": "^16.0.1",
"react-dnd-html5-backend": "^16.0.1",
"react-dom": "^19.1.0", "react-dom": "^19.1.0",
"react-i18next": "^15.5.1", "react-i18next": "^15.5.1",
"react-router-dom": "^7.5.3" "react-router-dom": "^7.5.3"

View File

@@ -135,5 +135,10 @@
"itemVolumeDistribution": "Verteilung der Artikelmenge", "itemVolumeDistribution": "Verteilung der Artikelmenge",
"itemRevenueDistribution": "Verteilung des Artikelumsatzes", "itemRevenueDistribution": "Verteilung des Artikelumsatzes",
"stockFulfillment": "Bestandserfüllung", "stockFulfillment": "Bestandserfüllung",
"orderStatus": "Bestellstatus" "orderStatus": "Bestellstatus",
"ORDERED": "Bestellt",
"IN_PROGRESS": "In Versand",
"ISSUES": "Probleme",
"DELIVERED": "Zugesendet",
"CANCELLED": "Storniert"
} }

View File

@@ -135,5 +135,10 @@
"itemVolumeDistribution": "Item Volume Distribution", "itemVolumeDistribution": "Item Volume Distribution",
"itemRevenueDistribution": "Item Revenue Distribution", "itemRevenueDistribution": "Item Revenue Distribution",
"stockFulfillment": "Stock fulfillment", "stockFulfillment": "Stock fulfillment",
"orderStatus": "Order Status" "orderStatus": "Order Status",
"ORDERED": "Ordered",
"IN_PROGRESS": "In Progress",
"ISSUES": "Issues",
"DELIVERED": "Delivered",
"CANCELLED": "Cancelled"
} }

View File

@@ -1,9 +1,9 @@
export enum OrderStatusEnum { export enum OrderStatusEnum {
CANCELLED = 'CANCELLED',
ISSUES = 'ISSUES',
DELIVERED = 'DELIVERED',
ORDERED = 'ORDERED', ORDERED = 'ORDERED',
IN_PROGRESS = 'IN_PROGRESS', IN_PROGRESS = 'IN_PROGRESS',
ISSUES = 'ISSUES',
DELIVERED = 'DELIVERED',
CANCELLED = 'CANCELLED',
}; };
type OrderType = { type OrderType = {

View File

@@ -1,31 +0,0 @@
import { useDroppable } from "@dnd-kit/core";
import { Box, useTheme } from "@mui/material";
import { ReactNode } from "react";
import { OrderStatusEnum } from "../../components/Order";
type DroppableContainerProps = {
id: OrderStatusEnum;
children: ReactNode;
};
export function DroppableContainer({ id, children }: DroppableContainerProps) {
const { setNodeRef } = useDroppable({ id });
const theme = useTheme();
return (
<Box
ref={setNodeRef}
sx={{
flex: 1,
minHeight: 400,
backgroundColor: theme.palette.background.default,
border: `1px solid ${theme.palette.divider}`,
borderRadius: 2,
p: 2,
transition: "background-color 0.3s, border-color 0.3s",
}}
>
{children}
</Box>
);
}

View File

@@ -1,65 +1,27 @@
import { closestCenter, DndContext } from "@dnd-kit/core";
import { restrictToParentElement } from "@dnd-kit/modifiers";
import { import {
Box, Box,
Button, Button,
Dialog, Dialog,
DialogContent, DialogContent,
DialogTitle, DialogTitle,
DialogActions,
List, ListItemText,
Typography, Typography,
useTheme useTheme,
Card, CardContent,
Stack,
Divider,
Snackbar
} from "@mui/material"; } from "@mui/material";
import { useState } from "react"; import React, { useState, useEffect, PropsWithChildren } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { DroppableContainer } from "./DroppableContainer";
import SortableItem from "./SortableItem";
import OrderType, { OrderStatusEnum } from "../../components/Order"; import OrderType, { OrderStatusEnum } from "../../components/Order";
import { useDrag, useDrop, DndProvider } from 'react-dnd';
const mockOrders: OrderType[] = [ import { HTML5Backend } from 'react-dnd-html5-backend';
{ import { useQuery } from "@tanstack/react-query";
id: "1001", import { fetchOrdersAdmin, orderPatch } from "../query/Queries";
date: "2025-05-20", import { useAccount } from "../AccountProvider";
status: OrderStatusEnum.CANCELLED, import { useQueryClient } from "@tanstack/react-query";
items: [
{ name: "Tomatensamen", quantity: 2, price: 3.99 },
{ name: "Blumenerde", quantity: 1, price: 7.49 }
],
total: 15.47,
address: "Musterstraße 1, 12345 Musterstadt"
},
{
id: "1000",
date: "2025-05-10",
status: OrderStatusEnum.ISSUES,
items: [{ name: "Gießkanne", quantity: 1, price: 12.99 }],
total: 12.99,
address: "Musterstraße 1, 12345 Musterstadt"
},
{
id: "1002",
date: "2025-05-15",
status: OrderStatusEnum.DELIVERED,
items: [{ name: "Pflanzendünger", quantity: 1, price: 8.99 }],
total: 8.99,
address: "Musterstraße 1, 12345 Musterstadt"
},
{
id: "1003",
date: "2025-05-18",
status: OrderStatusEnum.ORDERED,
items: [{ name: "Blumentopf", quantity: 2, price: 5.99 }],
total: 11.98,
address: "Musterstraße 1, 12345 Musterstadt"
},
{
id: "1004",
date: "2025-05-18",
status: OrderStatusEnum.IN_PROGRESS,
items: [{ name: "TimWall", quantity: 2, price: 5.99 }],
total: 12.99,
address: "Musterstraße 1, 12345 Musterstadt"
}
];
// The order in which the statuses are displayed // The order in which the statuses are displayed
const statusOrder: OrderStatusEnum[] = [ const statusOrder: OrderStatusEnum[] = [
@@ -70,130 +32,175 @@ const statusOrder: OrderStatusEnum[] = [
OrderStatusEnum.DELIVERED OrderStatusEnum.DELIVERED
]; ];
// Main component for managing orders
export default function OrdersInfo() { const OrderCard: React.FC<{ order: OrderType; onClick: () => void }> = ({ order, onClick }) => {
const { t } = useTranslation(); const { t } = useTranslation();
const theme = useTheme(); const theme = useTheme();
const [orders, setOrders] = useState<OrderType[]>(mockOrders);
const [selectedOrder, setSelectedOrder] = useState<OrderType | null>(null);
// eslint-disable-next-line @typescript-eslint/no-explicit-any const [{ isDragging }, drag] = useDrag(() => ({
const handleDragEnd = (event: any) => { type: 'order',
const { active, over } = event; item: { id: order.id },
if (!over || active.id === over.id) return; collect: (monitor) => ({
isDragging: !!monitor.isDragging(),
const newStatus = over.id; }),
setOrders((prev) => }));
prev.map((order) =>
order.id === active.id ? { ...order, status: newStatus } : order
)
);
};
const handleNextStatus = (order: OrderType) => {
const currentIndex = statusOrder.indexOf(order.status);
if (currentIndex < statusOrder.length - 1) {
setOrders((prev) =>
prev.map((o) =>
o.id === order.id
? { ...o, status: statusOrder[currentIndex + 1] as OrderType["status"] }
: o
)
);
}
};
const renderOrders = (status: OrderStatusEnum) => {
const filtered = orders.filter((o) => o.status === status);
return ( return (
<Box <div ref={drag} style={{ opacity: isDragging ? 0.5 : 1, marginBottom: 8 }}>
sx={{ <Card elevation={4}>
minHeight: 300, <CardContent onClick={onClick}>
p: 2, <Typography gutterBottom variant="h5" component="div">
bgcolor: theme.palette.background.paper, Order: {order.id}
border: `1px solid ${theme.palette.divider}`,
borderRadius: 2
}}>
<Typography
variant="h6"
align="center"
gutterBottom
sx={{ color: theme.palette.text.primary }}>
{t(status.toString())}
</Typography> </Typography>
{filtered.map((order) => ( <Typography>
<SortableItem {t('date') + ": " + new Date(order.time).toUTCString()}
key={order.id} </Typography>
id={order.id} <Typography>
order={order} {t('total') + ": " + order.total}
onClick={() => setSelectedOrder(order)} </Typography>
</CardContent>
</Card>
</div>
);
};
const Column: React.FC<PropsWithChildren<{ status: OrderStatusEnum; onDrop: (id: number, status: OrderStatusEnum) => void }>> = ({ status, onDrop, children }) => {
const { t } = useTranslation();
const theme = useTheme();
const [{ isOver }, drop] = useDrop(() => ({
accept: 'order',
drop: (item: { id: number }) => onDrop(item.id, status),
collect: (monitor) => ({
isOver: !!monitor.isOver(),
}),
}));
return (
<div ref={drop} style={{ flex: 1, backgroundColor: isOver ? theme.palette.background.paper : 'transparent', padding: 3, minHeight: 200 }}>
<Card>
<CardContent>
<Typography variant="h6">{t(status)}</Typography>
{children}
</CardContent>
</Card>
</div>
);
};
const EditOrder: React.FC<{ open: boolean; order: OrderType | null; onClose: () => void}> = ({ open, order, onClose }) => {
const { t } = useTranslation();
const theme = useTheme();
if(order === null)
return "";
return (
<Dialog open={open} onClose={onClose} maxWidth="sm" fullWidth>
<DialogTitle>
{`${t(order.status)} #${order?.id}`}
</DialogTitle>
<DialogContent dividers>
{order && (
<Stack spacing={2}>
<Typography variant="subtitle1">{`${t('orderDate')}: ${new Date(order.time).toDateString()}`}</Typography>
<Divider />
<Typography variant="subtitle2">{t('orderedItems')}:</Typography>
<List dense>
{order.orderItems.map((item, idx) => (
<ListItemText
key={idx}
primary={`${item.article} x${item.amount}`}
/> />
))} ))}
</Box> </List>
<Divider />
<Typography variant="h6">{`${t('sum')}: ${(order.total/100).toFixed(2)}`}</Typography>
</Stack>
)}
</DialogContent>
<DialogActions>
<Button onClick={onClose}>{t('close')}</Button>
</DialogActions>
</Dialog>
); );
}; };
return ( // Main component for managing orders
<Box> export default function OrdersInfo() {
<Typography variant="h4" align="center" gutterBottom> const [orders, setOrders] = useState<OrderType[]>([]);
{t("Orders Management")} {/* Bestellverwaltung */} const [editOrder, setEditOrder] = useState<OrderType | null>(null);
</Typography> const [openSnackbar, setOpenSnackbar] = useState(false);
<DndContext const {user: loginData} = useAccount();
collisionDetection={closestCenter} const queryClient = useQueryClient()
onDragEnd={handleDragEnd}
modifiers={[restrictToParentElement]}
>
<Box sx={{ display: "flex", gap: 2 }}>
{statusOrder.map((status) => (
<DroppableContainer key={status} id={status}>
{renderOrders(status)}
</DroppableContainer>
))}
</Box>
</DndContext>
<Dialog open={!!selectedOrder} onClose={() => setSelectedOrder(null)}> const { data, refetch } = useQuery({
<DialogTitle>{t("orderDetails")}</DialogTitle> {/* Bestelldetails */} queryKey: ["fetchOrdersAdmin", loginData],
<DialogContent sx={{ bgcolor: theme.palette.background.paper }}> queryFn: () => fetchOrdersAdmin(loginData? loginData : {email: "", password: "", session: "", customerId: -1, isAdmin: false}),
{selectedOrder && ( retry: 3,
<Box sx={{ color: theme.palette.text.primary }}> retryDelay: 1000,
<Typography variant="body1"> });
<strong>{t("orderId")}:</strong> {selectedOrder.id}
</Typography> useEffect(() => {
<Typography variant="body1"> console.log("data", data);
<strong>{t("date")}:</strong> {selectedOrder.date} if (data) {
</Typography> setOrders(data);
<Typography variant="body1"> }
<strong>{t("address")}:</strong> {selectedOrder.address} }, [data]);
</Typography>
<Typography variant="body1" sx={{ mt: 2 }}>
<strong>{t("items")}:</strong> const handleDrop = async (id: number, status: OrderStatusEnum) => {
</Typography> if(orders.length < 1) {
{selectedOrder.items.map((item, idx) => ( const resp = await refetch();
<Typography key={idx} variant="body2"> setOrders(resp.data); // i dont know
{item.quantity}x {item.name} {item.price.toFixed(2)} }
</Typography> const obj = orders.find((o) => {
))} return o.id === id
<Typography variant="body1" sx={{ mt: 2 }}> })
<strong>{t("total")}:</strong> {selectedOrder.total.toFixed(2)} if(!obj) {
</Typography> setOpenSnackbar(true);
<Button return;
variant="contained" }
color="primary" obj.status = status
sx={{ mt: 2 }} const resp = await queryClient.fetchQuery({
onClick={() => { queryKey: ["orderPatch", {id: obj.id, status: obj.status}],
handleNextStatus(selectedOrder); queryFn: () => orderPatch({id: obj.id, status: obj.status}),
setSelectedOrder(null); retry: 0,
}}> retryDelay: 1000,
{t("moveToNextStatus")} {/* Zum nächsten Status bewegen */} })
</Button> refetch();
</Box> setOrders(orders.map((o) => (o.id === id ? obj : o )));
)} };
const handleEdit = (order: OrderType) => setEditOrder(order);
return (
<DndProvider backend={HTML5Backend}>
<div style={{ display: 'flex', gap: 16 }}>
{statusOrder.map((status) => (
<Column key={status} status={status} onDrop={handleDrop}>
{orders
.filter((o) => o.status === status)
.map((o) => (
<OrderCard key={o.id} order={o} onClick={() => handleEdit(o)} />
))}
</Column>
))}
</div>
<EditOrder
open={!!editOrder}
order={editOrder}
onClose={() => setEditOrder(null)}
/>
<Snackbar
open={openSnackbar}
autoHideDuration={4000}
onClose={() => setOpenSnackbar(false)}
message="Failed changing Orderstatus"
/>
</DndProvider>
);
</DialogContent>
</Dialog>
</Box>
);
} }

View File

@@ -1,55 +0,0 @@
import { useSortable } from "@dnd-kit/sortable";
import { CSS } from "@dnd-kit/utilities";
import { Paper, Typography, useTheme } from "@mui/material";
import { useTranslation } from "react-i18next";
type SortableItemProps = {
id: string;
order: {
id: string;
total: number;
};
onClick: () => void;
};
export default function SortableItem({ id, order, onClick }: SortableItemProps) {
const { attributes, listeners, setNodeRef, transform, transition } = useSortable({ id });
const theme = useTheme();
const { t } = useTranslation();
const style = {
transform: CSS.Transform.toString(transform),
transition,
cursor: "grab",
};
return (
<Paper
ref={setNodeRef}
style={style}
{...attributes}
{...listeners}
onClick={onClick}
sx={{
p: 2,
mb: 2,
backgroundColor: theme.palette.background.paper,
color: theme.palette.text.primary,
"&:hover": {
backgroundColor:
theme.palette.mode === "dark"
? "rgba(255, 255, 255, 0.05)"
: "rgba(0, 0, 0, 0.04)",
},
}}
>
<Typography variant="body1">
{t("orderId")}: {order.id}
</Typography>
<Typography variant="body2">
{t("total")}: {order.total.toFixed(2)}
</Typography>
</Paper>
);
}

View File

@@ -136,7 +136,6 @@ export default function StatisticsInfo() {
useEffect(() => { useEffect(() => {
if(dataStockPercent) { if(dataStockPercent) {
console.log(dataStockPercent);
const stockPercent = [] const stockPercent = []
let i = 0 let i = 0
for(let x = 0; x < 10; x++) { for(let x = 0; x < 10; x++) {

View File

@@ -232,3 +232,12 @@ export const fetchStockPercent = async (loginData: User) => {
} }
return response.json(); return response.json();
}; };
export const fetchOrdersAdmin = async (loginData: User) => {
const response = await fetch("http://localhost:8085/order/all/all?email=" + loginData.email + "&session=" + loginData.session);
if (!response.ok) {
throw new Error("fetching admin orders failed");
}
return response.json();
};

View File

@@ -83,7 +83,7 @@ export default function Orders() {
<ListItemButton key={order.id} onClick={() => setSelectedOrder(order)}> <ListItemButton key={order.id} onClick={() => setSelectedOrder(order)}>
<ListItemText <ListItemText
primary={`${t('order')} #${order.id}${order.status}${order.time}`} primary={`${t('order')} #${order.id}${order.status}${order.time}`}
secondary={`${t('sum')}: ${order.total.toFixed(2)} € • ${order.orderItems.length} ${t('items')}`} secondary={`${t('sum')}: ${(order.total/100).toFixed(2)} € • ${order.orderItems.length} ${t('items')}`}
/> />
</ListItemButton> </ListItemButton>
))} ))}