import { Spinner } from '@woocommerce/components'; import { Card, CardBody, Flex, Modal, Notice } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; import { lazy, Suspense, useCallback, useMemo, useState } from 'react'; import { BookingModalFooter, CheckoutErrorNotice, OrderCompleteView, OrderProgress, PaymentModal, PrepayTopUp, } from '../../shared/components'; import type { Order, OrderItemDimensions } from '../../types/order'; import type { PluginSettings } from '../../types/settings'; import type { CheckoutApiError, GenericPaymentResponse, PrepayAPI, PrePayBalance, } from '../../types'; import { useBulkShipFlow } from './hooks/useBulkShipFlow'; import { PrepayProcessing } from './PrepayProcessing'; const LazyBulkShipOverview = lazy(() => import('./bulk-ship-overview')); const LazyBulkShipBreakdown = lazy(() => import('./bulk-ship-breakdown')); interface BulkShipProps { selectedOrders: Order[]; onComplete: () => void; settings: PluginSettings; prepayBalance: PrePayBalance; isBalanceLoading: boolean; prepayError: string | null; fetchBalance: () => void; makePrepayPayment: ( orderId: string, hash: string ) => Promise; createTopUp: PrepayAPI['createTopUp']; isLinked: boolean; } export default function BulkShip({ selectedOrders, onComplete, settings, prepayBalance, isBalanceLoading, prepayError, fetchBalance, makePrepayPayment, createTopUp, isLinked, }: BulkShipProps) { const flow = useBulkShipFlow(selectedOrders, settings, onComplete); const orderIds = useMemo( () => [...new Set((selectedOrders ?? []).map((o) => o.id))], [selectedOrders] ); const defaultPackage = useMemo( () => settings?.packages?.find( (p) => p.id === settings.defaultPackageId ) as OrderItemDimensions | undefined, [settings] ); const amount = (flow.validationResult?.price?.gross ?? 0) / 100; const balance = prepayBalance?.balance; const handlePayByCard = useCallback(async () => { await flow.handlePayment('card', makePrepayPayment); }, [flow, makePrepayPayment]); const handlePayByPrepay = useCallback(async () => { await flow.handlePayment('prepay', makePrepayPayment); }, [flow, makePrepayPayment]); const modalTitle = useMemo(() => { const isSuccessStep = flow.step === 'success'; if (flow.isValidating || !flow.validationResult) return __('Validating orders...', 'parcel2go-shipping'); if (flow.isCreatingOrder) return __('Creating order...', 'parcel2go-shipping'); if (flow.inProgress) return __('Order in progress...', 'parcel2go-shipping'); if (isSuccessStep || flow.isFulfilled) return __('Order fulfilled', 'parcel2go-shipping'); return `${__('Bulk ship', 'parcel2go-shipping')} ${orderIds.length} ${__('orders', 'parcel2go-shipping')}`; }, [ flow.step, flow.isValidating, flow.validationResult, flow.isCreatingOrder, flow.inProgress, flow.isFulfilled, orderIds.length, ]); return ( <> {orderIds.length > 0 && ( }> o.cheapestQuote) .map((o) => o.cheapestQuote!)} settings={settings} /> )} {(flow.step === 'confirming' || flow.step === 'success') && ( {flow.step === 'confirming' && (
flow.setStep('prepay-topup')} onComplete={onComplete} />
)}
)} {flow.step === 'prepay-processing' && ( )} {flow.step === 'payment' && flow.pendingPayment && ( flow.onPaymentSuccess(response, flow.pendingPayment!) } /> )} {flow.step === 'prepay-topup' && ( { void fetchBalance(); flow.setStep('confirming'); }} Wrapper={({ children }) => ( flow.setStep('confirming')} > {children} )} /> )} ); } // ── Modal content — isolated so it doesn't re-render the whole modal ── function ModalContent({ flow, selectedOrders, defaultPackage, settings, isBalanceLoading, }) { if (flow.isValidating || !flow.validationResult || flow.isCreatingOrder) { return ( ); } if (flow.inProgress) { return ( }> 1 ? `(${flow.poller.totalOrders} ${__('orders', 'parcel2go-shipping')})` : flow.orderReference?.reference } orderLineCount={flow.progress.orderLineCount} bookedOrderLineCount={flow.progress.bookedOrderLineCount} /> ); } if (flow.isFulfilled) { const baseOrder = selectedOrders[0]; const completeOrder = { ...baseOrder, p2g: { ...(baseOrder?.p2g ?? {}), orderId: flow.p2gOrderId || baseOrder?.p2g?.orderId || '', orderLineIds: flow.p2gOrderLineIds.length > 0 ? flow.p2gOrderLineIds : (baseOrder?.p2g?.orderLineIds ?? []), }, }; return ( }> ); } return ( <> {!isBalanceLoading && flow.validationResult && !flow.validationResult.error && ( }> )} {flow.error && ( flow.setError(null)} > {flow.error} )} {flow.validationResult?.error && ( )} ); }