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:
sebseb7
2026-03-24 00:48:22 +01:00
parent f47fbc5c39
commit a9bf1aee5f
31 changed files with 969 additions and 93 deletions

View File

@@ -23,6 +23,10 @@ import CartSyncDialog from './CartSyncDialog.js';
import { localAndArchiveServer, mergeCarts } from '../utils/cartUtils.js';
import config from '../config.js';
import { withI18n } from '../i18n/withTranslation.js';
import {
hasPendingWirePaymentOrder,
WIRE_PAYMENT_PENDING_EVENT,
} from '../utils/wireGirocodeEligibility.js';
import GoogleIcon from '@mui/icons-material/Google';
// Lazy load GoogleAuthProvider
@@ -117,10 +121,28 @@ export class LoginComponent extends Component {
localCartSync: [],
serverCartSync: [],
pendingNavigate: null,
privacyConfirmed: sessionStorage.getItem('privacyConfirmed') === 'true'
privacyConfirmed: sessionStorage.getItem('privacyConfirmed') === 'true',
pendingWirePaymentOrders: false
};
}
refreshPendingWireOrders = () => {
if (typeof window === 'undefined' || !window.socketManager) return;
window.socketManager.emit('getOrders', (response) => {
if (response.success && Array.isArray(response.orders)) {
this.setState({
pendingWirePaymentOrders: hasPendingWirePaymentOrder(response.orders),
});
}
});
};
handleWirePaymentPendingEvent = (e) => {
if (e.detail && typeof e.detail.pending === 'boolean') {
this.setState({ pendingWirePaymentOrders: e.detail.pending });
}
};
componentDidMount() {
// Make the open function available globally
window.openLoginDrawer = this.handleOpen;
@@ -128,17 +150,26 @@ export class LoginComponent extends Component {
if (this.props.open) {
this.setState({ open: true });
}
if (this.state.isLoggedIn) {
this.refreshPendingWireOrders();
}
window.addEventListener(WIRE_PAYMENT_PENDING_EVENT, this.handleWirePaymentPendingEvent);
}
componentDidUpdate(prevProps) {
componentDidUpdate(prevProps, prevState) {
if (this.props.open !== prevProps.open) {
this.setState({ open: this.props.open });
}
if (this.state.isLoggedIn && !prevState.isLoggedIn) {
this.refreshPendingWireOrders();
}
}
componentWillUnmount() {
// Cleanup function to remove global reference when component unmounts
window.openLoginDrawer = undefined;
window.removeEventListener(WIRE_PAYMENT_PENDING_EVENT, this.handleWirePaymentPendingEvent);
}
resetForm = () => {
@@ -308,6 +339,7 @@ export class LoginComponent extends Component {
handleUserMenuClick = (event) => {
this.setState({ anchorEl: event.currentTarget });
this.refreshPendingWireOrders();
};
handleUserMenuClose = () => {
@@ -326,6 +358,7 @@ export class LoginComponent extends Component {
isLoggedIn: false,
isAdmin: false,
anchorEl: null,
pendingWirePaymentOrders: false,
});
}
});
@@ -480,7 +513,8 @@ export class LoginComponent extends Component {
cartSyncOpen,
localCartSync,
serverCartSync,
privacyConfirmed
privacyConfirmed,
pendingWirePaymentOrders
} = this.state;
const { open: openProp, handleClose: handleCloseProp } = this.props;
@@ -520,8 +554,13 @@ export class LoginComponent extends Component {
<MenuItem component={Link} to="/profile#cart" onClick={this.handleUserMenuClose} sx={{ pl: 4 }}>
{this.props.t ? this.props.t('auth.menu.checkout') : 'Bestellabschluss'}
</MenuItem>
<MenuItem component={Link} to="/profile#orders" onClick={this.handleUserMenuClose} sx={{ pl: 4 }}>
{this.props.t ? this.props.t('auth.menu.orders') : 'Bestellungen'}
<MenuItem component={Link} to="/profile#orders" onClick={this.handleUserMenuClose} sx={{ pl: 4, display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 1 }}>
<span>{this.props.t ? this.props.t('auth.menu.orders') : 'Bestellungen'}</span>
{pendingWirePaymentOrders ? (
<Typography component="span" sx={{ color: 'error.main', fontWeight: 700, fontSize: '0.875rem', flexShrink: 0 }} aria-label="!">
[!]
</Typography>
) : null}
</MenuItem>
<MenuItem component={Link} to="/profile#settings" onClick={this.handleUserMenuClose} sx={{ pl: 4 }}>
{this.props.t ? this.props.t('auth.menu.settings') : 'Einstellungen'}