diff --git a/src/components/profile/OrderDetailsDialog.js b/src/components/profile/OrderDetailsDialog.js index 414ef1f..ee2f2dd 100644 --- a/src/components/profile/OrderDetailsDialog.js +++ b/src/components/profile/OrderDetailsDialog.js @@ -26,14 +26,25 @@ const OrderDetailsDialog = ({ open, onClose, order }) => { const currencyFormatter = new Intl.NumberFormat("de-DE", { style: "currency", currency: "EUR" }); + // Helper function to translate payment methods + const getPaymentMethodDisplay = (paymentMethod) => { + if (!paymentMethod) return t('orders.details.notSpecified'); + + switch (paymentMethod.toLowerCase()) { + case 'wire': + return t('payment.methods.bankTransfer'); + default: + return paymentMethod; + } + }; + const handleCancelOrder = () => { // Implement order cancellation logic here console.log(`Cancel order: ${order.orderId}`); onClose(); // Close the dialog after action }; - const subtotal = order.items.reduce((acc, item) => acc + item.price * item.quantity_ordered, 0); - const total = subtotal + order.delivery_cost; + const total = order.items.reduce((acc, item) => acc + item.price * item.quantity_ordered, 0); // Calculate VAT breakdown similar to CartDropdown const vatCalculations = order.items.reduce((acc, item) => { @@ -83,7 +94,7 @@ const OrderDetailsDialog = ({ open, onClose, order }) => { {t('orders.details.paymentMethod')} - {order.paymentMethod || order.payment_method || t('orders.details.notSpecified')} + {getPaymentMethodDisplay(order.paymentMethod || order.payment_method)} @@ -96,6 +107,7 @@ const OrderDetailsDialog = ({ open, onClose, order }) => { {t('orders.details.item')} {t('orders.details.quantity')} {t('orders.details.price')} + {t('product.vatShort')} {t('orders.details.total')} @@ -105,12 +117,12 @@ const OrderDetailsDialog = ({ open, onClose, order }) => { {item.name} {item.quantity_ordered} {currencyFormatter.format(item.price)} + {item.vat}% {currencyFormatter.format(item.price * item.quantity_ordered)} ))} - - + {t ? t('tax.totalNet') : 'Gesamtnettopreis'} @@ -119,35 +131,18 @@ const OrderDetailsDialog = ({ open, onClose, order }) => { {vatCalculations.vat7 > 0 && ( - - {t ? t('tax.vat7') : '7% Mehrwertsteuer'} + {t ? t('tax.vat7') : '7% Mehrwertsteuer'} {currencyFormatter.format(vatCalculations.vat7)} )} {vatCalculations.vat19 > 0 && ( - - {t ? t('tax.vat19') : '19% Mehrwertsteuer'} + {t ? t('tax.vat19') : '19% Mehrwertsteuer'} {currencyFormatter.format(vatCalculations.vat19)} )} - - - {t ? t('tax.subtotal') : 'Zwischensumme'} - - - {currencyFormatter.format(subtotal)} - - - - - {t ? t('cart.summary.shippingCosts') : 'Lieferkosten'} - {currencyFormatter.format(order.delivery_cost)} - - - - + {t ? t('cart.summary.total') : 'Gesamtsumme'} diff --git a/src/components/profile/OrdersTab.js b/src/components/profile/OrdersTab.js index 017d6a8..23a5809 100644 --- a/src/components/profile/OrdersTab.js +++ b/src/components/profile/OrdersTab.js @@ -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 ( @@ -181,11 +227,10 @@ const OrdersTab = ({ orderIdFromHash, t }) => { {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 ( {order.orderId} @@ -223,15 +268,28 @@ const OrdersTab = ({ orderIdFromHash, t }) => { {currencyFormatter.format(total)} - - handleViewDetails(order.orderId)} - > - - - + + + handleViewDetails(order.orderId)} + > + + + + {isOrderCancelable(order) && ( + + handleCancelClick(order)} + > + + + + )} + ); @@ -249,6 +307,47 @@ const OrdersTab = ({ orderIdFromHash, t }) => { onClose={handleCloseDetailsDialog} order={selectedOrder} /> + + {/* Cancel Confirmation Dialog */} + + + {t ? t('orders.cancelConfirm.title') : 'Bestellung stornieren'} + + + + {t ? t('orders.cancelConfirm.message') : 'Sind Sie sicher, dass Sie diese Bestellung stornieren möchten?'} + + {orderToCancel && ( + + {t ? t('orders.table.orderNumber') : 'Bestellnummer'}: {orderToCancel.orderId} + + )} + + + + + + ); }; diff --git a/src/i18n/locales/bg/orders.js b/src/i18n/locales/bg/orders.js index 3b67a94..25392fd 100644 --- a/src/i18n/locales/bg/orders.js +++ b/src/i18n/locales/bg/orders.js @@ -17,14 +17,14 @@ export default { "items": "Артикули", "total": "Общо", "actions": "Действия", - "viewDetails": "Виж подробности" + "viewDetails": "Виж детайли" }, "noOrders": "Все още не сте направили поръчки.", "details": { - "title": "Подробности за поръчка: {{orderId}}", + "title": "Детайли за поръчка: {{orderId}}", "deliveryAddress": "Адрес за доставка", "invoiceAddress": "Адрес за фактура", - "orderDetails": "Подробности за поръчката", + "orderDetails": "Детайли за поръчката", "deliveryMethod": "Начин на доставка:", "paymentMethod": "Начин на плащане:", "notSpecified": "Не е посочено", @@ -35,5 +35,11 @@ export default { "total": "Общо", "cancelOrder": "Отмени поръчката" }, + "cancelConfirm": { + "title": "Отмяна на поръчка", + "message": "Сигурни ли сте, че искате да отмените тази поръчка?", + "confirm": "Отмени поръчката", + "cancelling": "Отмяна..." + }, "processing": "Поръчката се обработва...", }; diff --git a/src/i18n/locales/cs/orders.js b/src/i18n/locales/cs/orders.js index 1d11444..a902f26 100644 --- a/src/i18n/locales/cs/orders.js +++ b/src/i18n/locales/cs/orders.js @@ -35,5 +35,11 @@ export default { "total": "Celkem", "cancelOrder": "Zrušit objednávku" }, - "processing": "Objednávka se dokončuje..." + "cancelConfirm": { + "title": "Zrušit objednávku", + "message": "Opravdu chcete tuto objednávku zrušit?", + "confirm": "Zrušit objednávku", + "cancelling": "Rušení..." + }, + "processing": "Objednávka se dokončuje...", }; diff --git a/src/i18n/locales/de/orders.js b/src/i18n/locales/de/orders.js index 0607749..c7e6a44 100644 --- a/src/i18n/locales/de/orders.js +++ b/src/i18n/locales/de/orders.js @@ -19,6 +19,10 @@ export default { "actions": "Aktionen", "viewDetails": "Details anzeigen" }, + "tooltips": { + "viewDetails": "Details anzeigen", + "cancelOrder": "Bestellung stornieren" + }, "noOrders": "Sie haben noch keine Bestellungen aufgegeben.", "details": { "title": "Bestelldetails: {{orderId}}", @@ -35,5 +39,11 @@ export default { "total": "Gesamt", "cancelOrder": "Bestellung stornieren" }, + "cancelConfirm": { + "title": "Bestellung stornieren", + "message": "Sind Sie sicher, dass Sie diese Bestellung stornieren möchten?", + "confirm": "Stornieren", + "cancelling": "Wird storniert..." + }, "processing": "Bestellung wird abgeschlossen..." }; \ No newline at end of file diff --git a/src/i18n/locales/en/orders.js b/src/i18n/locales/en/orders.js index 054ae79..f0839cc 100644 --- a/src/i18n/locales/en/orders.js +++ b/src/i18n/locales/en/orders.js @@ -19,6 +19,10 @@ export default { "actions": "Actions", // Aktionen "viewDetails": "View details" // Details anzeigen }, + "tooltips": { + "viewDetails": "View details", // Details anzeigen + "cancelOrder": "Cancel order" // Bestellung stornieren + }, "noOrders": "You have not placed any orders yet.", // Sie haben noch keine Bestellungen aufgegeben. "details": { "title": "Order details: {{orderId}}", // Bestelldetails: {{orderId}} @@ -32,8 +36,15 @@ export default { "item": "Item", // Artikel "quantity": "Quantity", // Menge "price": "Price", // Preis + "vat": "VAT", // MwSt. "total": "Total", // Gesamt "cancelOrder": "Cancel order" // Bestellung stornieren }, + "cancelConfirm": { + "title": "Cancel Order", + "message": "Are you sure you want to cancel this order?", + "confirm": "Cancel Order", + "cancelling": "Cancelling..." + }, "processing": "Order is being completed...", // Bestellung wird abgeschlossen... }; diff --git a/src/i18n/locales/es/orders.js b/src/i18n/locales/es/orders.js index c7b26cf..6ed4381 100644 --- a/src/i18n/locales/es/orders.js +++ b/src/i18n/locales/es/orders.js @@ -35,5 +35,11 @@ export default { "total": "Total", "cancelOrder": "Cancelar pedido" }, - "processing": "El pedido se está completando..." + "cancelConfirm": { + "title": "Cancelar pedido", + "message": "¿Estás seguro de que deseas cancelar este pedido?", + "confirm": "Cancelar pedido", + "cancelling": "Cancelando..." + }, + "processing": "El pedido se está completando...", }; diff --git a/src/i18n/locales/fr/orders.js b/src/i18n/locales/fr/orders.js index 21ca801..ebc7019 100644 --- a/src/i18n/locales/fr/orders.js +++ b/src/i18n/locales/fr/orders.js @@ -19,7 +19,7 @@ export default { "actions": "Actions", "viewDetails": "Voir les détails" }, - "noOrders": "Vous n'avez encore passé aucune commande.", + "noOrders": "Vous n'avez pas encore passé de commandes.", "details": { "title": "Détails de la commande : {{orderId}}", "deliveryAddress": "Adresse de livraison", @@ -35,5 +35,11 @@ export default { "total": "Total", "cancelOrder": "Annuler la commande" }, + "cancelConfirm": { + "title": "Annuler la commande", + "message": "Êtes-vous sûr de vouloir annuler cette commande ?", + "confirm": "Annuler la commande", + "cancelling": "Annulation en cours..." + }, "processing": "La commande est en cours de traitement...", }; diff --git a/src/pages/ProfilePage.js b/src/pages/ProfilePage.js index 3a8e51f..22aaf34 100644 --- a/src/pages/ProfilePage.js +++ b/src/pages/ProfilePage.js @@ -94,21 +94,17 @@ const ProfilePage = (props) => { useEffect(() => { const hash = location.hash; - console.log('ProfilePage: Processing hash:', hash); switch (hash) { case '#cart': - console.log('ProfilePage: Switching to cart tab'); setTabValue(0); setOrderIdFromHash(null); break; case '#orders': - console.log('ProfilePage: Switching to orders tab'); setTabValue(1); setOrderIdFromHash(null); break; case '#settings': - console.log('ProfilePage: Switching to settings tab'); setTabValue(2); setOrderIdFromHash(null); break; @@ -117,18 +113,15 @@ const ProfilePage = (props) => { // Check if it's a potential order ID (starts with # and has alphanumeric characters with dashes) const potentialOrderId = hash.substring(1); if (/^[A-Z0-9]+-[A-Z0-9]+$/i.test(potentialOrderId)) { - console.log('ProfilePage: Detected order ID from hash:', potentialOrderId); setOrderIdFromHash(potentialOrderId); setTabValue(1); // Switch to Orders tab } else { - console.log('ProfilePage: Hash does not match order ID pattern:', potentialOrderId); setOrderIdFromHash(null); } } else { setOrderIdFromHash(null); // If no hash is present, set default to cart tab if (!hash) { - console.log('ProfilePage: No hash present, redirecting to cart'); navigate('/profile#cart', { replace: true }); } }