feat: Integrate Girocode functionality for wire payments in OrdersTab and LoginComponent, enhance user experience with pending payment notifications, and update translations across multiple locales
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import React, { useState, useEffect, useCallback } from "react";
|
||||
import React, { useState, useEffect, useCallback, Fragment } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { withI18n } from "../../i18n/withTranslation.js";
|
||||
import {
|
||||
@@ -24,6 +24,12 @@ import {
|
||||
import SearchIcon from "@mui/icons-material/Search";
|
||||
import CancelIcon from "@mui/icons-material/Cancel";
|
||||
import OrderDetailsDialog from "./OrderDetailsDialog.js";
|
||||
import WireOrderGirocode from "./WireOrderGirocode.js";
|
||||
import {
|
||||
isWireGirocodeEligible,
|
||||
hasPendingWirePaymentOrder,
|
||||
WIRE_PAYMENT_PENDING_EVENT,
|
||||
} from "../../utils/wireGirocodeEligibility.js";
|
||||
|
||||
// Constants
|
||||
const getStatusTranslation = (status, t) => {
|
||||
@@ -100,8 +106,20 @@ const OrdersTab = ({ orderIdFromHash, t }) => {
|
||||
window.socketManager.emit("getOrders", (response) => {
|
||||
if (response.success) {
|
||||
setOrders(response.orders);
|
||||
window.dispatchEvent(
|
||||
new CustomEvent(WIRE_PAYMENT_PENDING_EVENT, {
|
||||
detail: {
|
||||
pending: hasPendingWirePaymentOrder(response.orders),
|
||||
},
|
||||
})
|
||||
);
|
||||
} else {
|
||||
setError(response.error || "Failed to fetch orders.");
|
||||
window.dispatchEvent(
|
||||
new CustomEvent(WIRE_PAYMENT_PENDING_EVENT, {
|
||||
detail: { pending: false },
|
||||
})
|
||||
);
|
||||
}
|
||||
setLoading(false);
|
||||
});
|
||||
@@ -216,89 +234,107 @@ const OrdersTab = ({ orderIdFromHash, t }) => {
|
||||
0
|
||||
);
|
||||
return (
|
||||
<TableRow key={order.orderId} hover>
|
||||
<TableCell>{order.orderId}</TableCell>
|
||||
<TableCell>
|
||||
{new Date(order.created_at).toLocaleDateString()}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: "8px",
|
||||
color: getStatusColor(order.status),
|
||||
}}
|
||||
>
|
||||
<span style={{ fontSize: "1.2rem" }}>
|
||||
{getStatusEmoji(order.status)}
|
||||
</span>
|
||||
<Typography
|
||||
variant="body2"
|
||||
component="span"
|
||||
sx={{ fontWeight: "medium" }}
|
||||
<Fragment key={order.orderId}>
|
||||
<TableRow hover>
|
||||
<TableCell>{order.orderId}</TableCell>
|
||||
<TableCell>
|
||||
{new Date(order.created_at).toLocaleDateString()}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: "8px",
|
||||
color: getStatusColor(order.status),
|
||||
}}
|
||||
>
|
||||
{displayStatus}
|
||||
</Typography>
|
||||
</Box>
|
||||
{order.delivery_method === 'DHL' && order.trackingCode && (
|
||||
<Box sx={{ mt: 0.5 }}>
|
||||
<a
|
||||
href={`https://www.dhl.de/de/privatkunden/dhl-sendungsverfolgung.html?piececode=${order.trackingCode}`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
style={{ fontSize: '0.85rem', color: '#d40511' }}
|
||||
<span style={{ fontSize: "1.2rem" }}>
|
||||
{getStatusEmoji(order.status)}
|
||||
</span>
|
||||
<Typography
|
||||
variant="body2"
|
||||
component="span"
|
||||
sx={{ fontWeight: "medium" }}
|
||||
>
|
||||
📦 {t ? t('orders.trackShipment') : 'Sendung verfolgen'}
|
||||
</a>
|
||||
{displayStatus}
|
||||
</Typography>
|
||||
</Box>
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{order.items
|
||||
.filter(item => {
|
||||
// Exclude delivery items - backend uses deliveryMethod ID as item name
|
||||
const itemName = item.name || '';
|
||||
return itemName !== 'DHL' &&
|
||||
itemName !== 'DPD' &&
|
||||
itemName !== 'Sperrgut' &&
|
||||
itemName !== 'Abholung';
|
||||
})
|
||||
.reduce(
|
||||
(acc, item) => acc + item.quantity_ordered,
|
||||
0
|
||||
{order.delivery_method === 'DHL' && order.trackingCode && (
|
||||
<Box sx={{ mt: 0.5 }}>
|
||||
<a
|
||||
href={`https://www.dhl.de/de/privatkunden/dhl-sendungsverfolgung.html?piececode=${order.trackingCode}`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
style={{ fontSize: '0.85rem', color: '#d40511' }}
|
||||
>
|
||||
📦 {t ? t('orders.trackShipment') : 'Sendung verfolgen'}
|
||||
</a>
|
||||
</Box>
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell align="right">
|
||||
{currencyFormatter.format(total)}
|
||||
</TableCell>
|
||||
<TableCell align="center">
|
||||
<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)}
|
||||
aria-label={t ? t('orders.tooltips.viewDetails') : 'Details anzeigen'}
|
||||
>
|
||||
<SearchIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
{isOrderCancelable(order) && (
|
||||
<Tooltip title={t ? t('orders.tooltips.cancelOrder') : 'Bestellung stornieren'}>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{order.items
|
||||
.filter(item => {
|
||||
// Exclude delivery items - backend uses deliveryMethod ID as item name
|
||||
const itemName = item.name || '';
|
||||
return itemName !== 'DHL' &&
|
||||
itemName !== 'DPD' &&
|
||||
itemName !== 'Sperrgut' &&
|
||||
itemName !== 'Abholung';
|
||||
})
|
||||
.reduce(
|
||||
(acc, item) => acc + item.quantity_ordered,
|
||||
0
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell align="right">
|
||||
{currencyFormatter.format(total)}
|
||||
</TableCell>
|
||||
<TableCell align="center">
|
||||
<Box sx={{ display: 'flex', gap: 1, justifyContent: 'center' }}>
|
||||
<Tooltip title={t ? t('orders.tooltips.viewDetails') : 'Details anzeigen'}>
|
||||
<IconButton
|
||||
size="small"
|
||||
color="error"
|
||||
onClick={() => handleCancelClick(order)}
|
||||
aria-label={t ? t('orders.tooltips.cancelOrder') : 'Bestellung stornieren'}
|
||||
color="primary"
|
||||
onClick={() => handleViewDetails(order.orderId)}
|
||||
aria-label={t ? t('orders.tooltips.viewDetails') : 'Details anzeigen'}
|
||||
>
|
||||
<CancelIcon />
|
||||
<SearchIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
</Box>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
{isOrderCancelable(order) && (
|
||||
<Tooltip title={t ? t('orders.tooltips.cancelOrder') : 'Bestellung stornieren'}>
|
||||
<IconButton
|
||||
size="small"
|
||||
color="error"
|
||||
onClick={() => handleCancelClick(order)}
|
||||
aria-label={t ? t('orders.tooltips.cancelOrder') : 'Bestellung stornieren'}
|
||||
>
|
||||
<CancelIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
</Box>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
{isWireGirocodeEligible(order) && (
|
||||
<TableRow>
|
||||
<TableCell
|
||||
colSpan={6}
|
||||
sx={{
|
||||
py: 2,
|
||||
px: { xs: 1, sm: 2 },
|
||||
verticalAlign: "top",
|
||||
bgcolor: "action.hover",
|
||||
borderTop: (theme) => `1px solid ${theme.palette.divider}`,
|
||||
}}
|
||||
>
|
||||
<WireOrderGirocode order={order} t={t} />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
</Fragment>
|
||||
);
|
||||
})}
|
||||
</TableBody>
|
||||
|
||||
Reference in New Issue
Block a user