Implement order cancellation feature in OrdersTab: Added functionality to confirm and cancel orders, including a confirmation dialog. Enhanced payment method display in OrderDetailsDialog and updated VAT calculations. Improved localization for order-related messages across multiple languages.

This commit is contained in:
sebseb7
2025-07-17 21:35:00 +02:00
parent 64048e6d0b
commit cb8ce69903
9 changed files with 185 additions and 53 deletions

View File

@@ -15,8 +15,14 @@ import {
Tooltip,
CircularProgress,
Typography,
Dialog,
DialogTitle,
DialogContent,
DialogActions,
Button,
} from "@mui/material";
import SearchIcon from "@mui/icons-material/Search";
import CancelIcon from "@mui/icons-material/Cancel";
import SocketContext from "../../contexts/SocketContext.js";
import OrderDetailsDialog from "./OrderDetailsDialog.js";
@@ -71,6 +77,9 @@ const OrdersTab = ({ orderIdFromHash, t }) => {
const [error, setError] = useState(null);
const [selectedOrder, setSelectedOrder] = useState(null);
const [isDetailsDialogOpen, setIsDetailsDialogOpen] = useState(false);
const [cancelConfirmOpen, setCancelConfirmOpen] = useState(false);
const [orderToCancel, setOrderToCancel] = useState(null);
const [isCancelling, setIsCancelling] = useState(false);
const {socket} = useContext(SocketContext);
const navigate = useNavigate();
@@ -121,11 +130,7 @@ const OrdersTab = ({ orderIdFromHash, t }) => {
useEffect(() => {
if (orderIdFromHash && orders.length > 0) {
console.log('OrdersTab: Attempting to open order from hash:', orderIdFromHash);
console.log('OrdersTab: Available orders:', orders.map(o => o.orderId));
handleViewDetails(orderIdFromHash);
} else if (orderIdFromHash && orders.length === 0) {
console.log('OrdersTab: Order ID from hash but no orders loaded yet:', orderIdFromHash);
}
}, [orderIdFromHash, orders, handleViewDetails]);
@@ -147,6 +152,47 @@ const OrdersTab = ({ orderIdFromHash, t }) => {
navigate("/profile#orders", { replace: true });
};
// Check if order can be cancelled
const isOrderCancelable = (order) => {
const cancelableStatuses = ['new', 'pending', 'processing'];
return cancelableStatuses.includes(order.status);
};
// Handle cancel button click
const handleCancelClick = (order) => {
setOrderToCancel(order);
setCancelConfirmOpen(true);
};
// Handle cancel confirmation
const handleConfirmCancel = () => {
if (!orderToCancel || !socket) return;
setIsCancelling(true);
socket.emit('cancelOrder', { orderId: orderToCancel.orderId }, (response) => {
setIsCancelling(false);
setCancelConfirmOpen(false);
if (response.success) {
console.log('Order cancelled:', response.orderId);
// Refresh orders list
fetchOrders();
} else {
setError(response.error || 'Failed to cancel order');
}
setOrderToCancel(null);
});
};
// Handle cancel dialog close
const handleCancelDialogClose = () => {
if (!isCancelling) {
setCancelConfirmOpen(false);
setOrderToCancel(null);
}
};
if (loading) {
return (
<Box sx={{ p: { xs: 1, sm: 3 }, display: "flex", justifyContent: "center" }}>
@@ -181,11 +227,10 @@ const OrdersTab = ({ orderIdFromHash, t }) => {
<TableBody>
{orders.map((order) => {
const displayStatus = getStatusDisplay(order.status);
const subtotal = order.items.reduce(
const total = order.items.reduce(
(acc, item) => acc + item.price * item.quantity_ordered,
0
);
const total = subtotal + order.delivery_cost;
return (
<TableRow key={order.orderId} hover>
<TableCell>{order.orderId}</TableCell>
@@ -223,15 +268,28 @@ const OrdersTab = ({ orderIdFromHash, t }) => {
{currencyFormatter.format(total)}
</TableCell>
<TableCell align="center">
<Tooltip title="Details anzeigen">
<IconButton
size="small"
color="primary"
onClick={() => handleViewDetails(order.orderId)}
>
<SearchIcon />
</IconButton>
</Tooltip>
<Box sx={{ display: 'flex', gap: 1, justifyContent: 'center' }}>
<Tooltip title={t ? t('orders.tooltips.viewDetails') : 'Details anzeigen'}>
<IconButton
size="small"
color="primary"
onClick={() => handleViewDetails(order.orderId)}
>
<SearchIcon />
</IconButton>
</Tooltip>
{isOrderCancelable(order) && (
<Tooltip title={t ? t('orders.tooltips.cancelOrder') : 'Bestellung stornieren'}>
<IconButton
size="small"
color="error"
onClick={() => handleCancelClick(order)}
>
<CancelIcon />
</IconButton>
</Tooltip>
)}
</Box>
</TableCell>
</TableRow>
);
@@ -249,6 +307,47 @@ const OrdersTab = ({ orderIdFromHash, t }) => {
onClose={handleCloseDetailsDialog}
order={selectedOrder}
/>
{/* Cancel Confirmation Dialog */}
<Dialog
open={cancelConfirmOpen}
onClose={handleCancelDialogClose}
maxWidth="sm"
fullWidth
>
<DialogTitle>
{t ? t('orders.cancelConfirm.title') : 'Bestellung stornieren'}
</DialogTitle>
<DialogContent>
<Typography>
{t ? t('orders.cancelConfirm.message') : 'Sind Sie sicher, dass Sie diese Bestellung stornieren möchten?'}
</Typography>
{orderToCancel && (
<Typography variant="body2" sx={{ mt: 1, fontWeight: 'bold' }}>
{t ? t('orders.table.orderNumber') : 'Bestellnummer'}: {orderToCancel.orderId}
</Typography>
)}
</DialogContent>
<DialogActions>
<Button
onClick={handleCancelDialogClose}
disabled={isCancelling}
>
{t ? t('common.cancel') : 'Abbrechen'}
</Button>
<Button
onClick={handleConfirmCancel}
color="error"
variant="contained"
disabled={isCancelling}
>
{isCancelling
? (t ? t('orders.cancelConfirm.cancelling') : 'Wird storniert...')
: (t ? t('orders.cancelConfirm.confirm') : 'Stornieren')
}
</Button>
</DialogActions>
</Dialog>
</Box>
);
};