@ticketboothapp/booking 1.2.164 → 1.2.166
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -924,7 +924,7 @@ export function AdminChangeBookingFlow({
|
|
|
924
924
|
checkoutModalData,
|
|
925
925
|
showAdminPaymentChoice,
|
|
926
926
|
adminChoiceData,
|
|
927
|
-
|
|
927
|
+
handleCheckoutClose,
|
|
928
928
|
handleCheckout,
|
|
929
929
|
handleConfirmWithoutPayment,
|
|
930
930
|
handlePayNow,
|
|
@@ -1022,7 +1022,7 @@ export function AdminChangeBookingFlow({
|
|
|
1022
1022
|
...{ pickupLocationId, pickupLocationSkipped, firstName, lastName, email, getSuccessUrl, t },
|
|
1023
1023
|
onPayNow: handlePayNow,
|
|
1024
1024
|
onConfirmWithoutPayment: handleConfirmWithoutPayment, onAdminPaymentChoiceCancel: handleAdminPaymentChoiceCancel,
|
|
1025
|
-
onCheckoutClose:
|
|
1025
|
+
onCheckoutClose: handleCheckoutClose, onPaymentSubmitStart: handlePaymentSubmitStart,
|
|
1026
1026
|
onPaymentSubmitError: handlePaymentSubmitError, onPaymentConfirmed: handlePaymentConfirmed,
|
|
1027
1027
|
isPartialLaunch,
|
|
1028
1028
|
checkoutVisible: selectedAvailability != null,
|
|
@@ -126,6 +126,18 @@ export function buildAdminChangePayNowCheckoutModalData(
|
|
|
126
126
|
};
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
+
export function shouldRestoreAdminChangePaymentChoiceAfterCheckoutClose(
|
|
130
|
+
isProviderDashboardChange: boolean,
|
|
131
|
+
isChangeBookingContext: boolean,
|
|
132
|
+
adminChoiceData: Pick<AdminChangePaymentChoiceData, 'pricingQuoteId'> | null,
|
|
133
|
+
): boolean {
|
|
134
|
+
return Boolean(
|
|
135
|
+
isProviderDashboardChange &&
|
|
136
|
+
isChangeBookingContext &&
|
|
137
|
+
adminChoiceData?.pricingQuoteId?.trim(),
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
129
141
|
export interface ConfirmAdminChangeBookingWithoutPaymentParams {
|
|
130
142
|
adminChoiceData: AdminChangePaymentChoiceData;
|
|
131
143
|
bookingSourceAttribution: Partial<BookingSourceMetadata>;
|
|
@@ -59,6 +59,7 @@ import {
|
|
|
59
59
|
buildAdminChangePaymentChoiceData,
|
|
60
60
|
buildAdminChangePayNowCheckoutModalData,
|
|
61
61
|
confirmAdminChangeBookingWithoutPayment,
|
|
62
|
+
shouldRestoreAdminChangePaymentChoiceAfterCheckoutClose,
|
|
62
63
|
type AdminChangeCheckoutModalData,
|
|
63
64
|
type AdminChangePaymentChoiceData,
|
|
64
65
|
} from './admin-change-payment-choice-runner';
|
|
@@ -292,6 +293,27 @@ export function useAdminChangeCheckoutController({
|
|
|
292
293
|
setCheckoutClientSecret('');
|
|
293
294
|
}, []);
|
|
294
295
|
|
|
296
|
+
const handleCheckoutClose = useCallback(() => {
|
|
297
|
+
if (paymentSubmitInFlightRef.current) return;
|
|
298
|
+
cancelPendingReservation();
|
|
299
|
+
setError('');
|
|
300
|
+
// An existing-booking Pay now attempt owns an immutable quote/payment-choice snapshot.
|
|
301
|
+
// Closing Stripe must return to that choice instead of making the user create a new quote.
|
|
302
|
+
if (shouldRestoreAdminChangePaymentChoiceAfterCheckoutClose(
|
|
303
|
+
isProviderDashboardChange,
|
|
304
|
+
isChangeBookingContext,
|
|
305
|
+
adminChoiceData,
|
|
306
|
+
)) {
|
|
307
|
+
setShowAdminPaymentChoice(true);
|
|
308
|
+
}
|
|
309
|
+
}, [
|
|
310
|
+
adminChoiceData?.pricingQuoteId,
|
|
311
|
+
cancelPendingReservation,
|
|
312
|
+
isChangeBookingContext,
|
|
313
|
+
isProviderDashboardChange,
|
|
314
|
+
setError,
|
|
315
|
+
]);
|
|
316
|
+
|
|
295
317
|
const cancelPendingReservationBestEffort = useCallback(() => {
|
|
296
318
|
if (paymentSubmitInFlightRef.current) return;
|
|
297
319
|
const pending = pendingReservationRef.current;
|
|
@@ -323,6 +345,7 @@ export function useAdminChangeCheckoutController({
|
|
|
323
345
|
const buildProviderChangePayload = (
|
|
324
346
|
availabilityProductOptionId: string,
|
|
325
347
|
bookingItems: AdminChangeBookingItem[],
|
|
348
|
+
authoritativeQuote: AdminChangeLatestQuote | null = latestChangeQuote,
|
|
326
349
|
): ProviderDashboardChangeBookingPayload | null => {
|
|
327
350
|
return buildAdminChangeProviderPayload({
|
|
328
351
|
selectedAvailability,
|
|
@@ -340,8 +363,8 @@ export function useAdminChangeCheckoutController({
|
|
|
340
363
|
mergedProviderAdditionalAdjustments,
|
|
341
364
|
adminStructuredAdjustments,
|
|
342
365
|
refundDispositionsByOperationId,
|
|
343
|
-
pricingV2QuoteId:
|
|
344
|
-
pricingV2QuotedTotal:
|
|
366
|
+
pricingV2QuoteId: authoritativeQuote?.quoteId ?? null,
|
|
367
|
+
pricingV2QuotedTotal: authoritativeQuote?.quotedTotal ?? authoritativeQuote?.serverDisplay?.total ?? null,
|
|
345
368
|
providerApplyAuthoritativeReceipt,
|
|
346
369
|
previousPassengerCount: changeFlowInitialTicketCount,
|
|
347
370
|
previousAvailabilityId: initialValues?.availabilityId ?? null,
|
|
@@ -436,6 +459,7 @@ export function useAdminChangeCheckoutController({
|
|
|
436
459
|
let changeIntentIdForCheckout: string | undefined;
|
|
437
460
|
let changeBookingReferenceForPaidFlow: string | undefined;
|
|
438
461
|
let confirmedChangeAmountDueForCheckout: number | null = null;
|
|
462
|
+
let authoritativeChangeQuoteForCheckout = latestChangeQuote;
|
|
439
463
|
|
|
440
464
|
if (isCustomerSelfServeChange) {
|
|
441
465
|
const quoteResult = await quoteAdminCustomerChangeForCheckout({
|
|
@@ -464,11 +488,18 @@ export function useAdminChangeCheckoutController({
|
|
|
464
488
|
});
|
|
465
489
|
changeBookingReferenceForPaidFlow = quoteResult.bookingReference;
|
|
466
490
|
setLatestChangeQuote(quoteResult.mergedQuote);
|
|
491
|
+
// React state is not updated synchronously. Everything in this checkout attempt must
|
|
492
|
+
// use the quote returned above, not the stale latestChangeQuote render closure.
|
|
493
|
+
authoritativeChangeQuoteForCheckout = quoteResult.mergedQuote;
|
|
467
494
|
confirmedChangeAmountDueForCheckout = quoteResult.decision.amountDueForCheckout;
|
|
468
495
|
|
|
469
496
|
if (quoteResult.decision.kind === 'free') {
|
|
470
497
|
if (onChangeBooking) {
|
|
471
|
-
const providerPayload = buildProviderChangePayload(
|
|
498
|
+
const providerPayload = buildProviderChangePayload(
|
|
499
|
+
availabilityProductOptionId,
|
|
500
|
+
bookingItems,
|
|
501
|
+
authoritativeChangeQuoteForCheckout,
|
|
502
|
+
);
|
|
472
503
|
if (!providerPayload) {
|
|
473
504
|
setError('No availability selected');
|
|
474
505
|
setLoading(false);
|
|
@@ -501,7 +532,7 @@ export function useAdminChangeCheckoutController({
|
|
|
501
532
|
const itineraryDisplay = computeItineraryDisplayForStorage() ?? computeItineraryDisplay();
|
|
502
533
|
const taxForBreakdown = effectivePromoDiscountAmount > 0 ? effectiveTax : tax;
|
|
503
534
|
const amountDueForCheckout = isProviderDashboardChange && isChangeBookingContext
|
|
504
|
-
? Math.max(0,
|
|
535
|
+
? Math.max(0, authoritativeChangeQuoteForCheckout?.priceDiff ?? 0)
|
|
505
536
|
: isCustomerSelfServeChange
|
|
506
537
|
? confirmedChangeAmountDueForCheckout ??
|
|
507
538
|
Math.max(
|
|
@@ -546,14 +577,21 @@ export function useAdminChangeCheckoutController({
|
|
|
546
577
|
// quote-bound Stripe authorization and applies only after that authorization succeeds.
|
|
547
578
|
if (isProviderDashboardChange && isChangeBookingContext) {
|
|
548
579
|
const bookingReference = initialValues?.bookingReference?.trim();
|
|
549
|
-
const quoteId =
|
|
580
|
+
const quoteId = authoritativeChangeQuoteForCheckout?.quoteId?.trim();
|
|
550
581
|
if (!bookingReference) throw new Error('Missing booking reference.');
|
|
551
|
-
if (!quoteId ||
|
|
552
|
-
throw new Error(
|
|
582
|
+
if (!quoteId || authoritativeChangeQuoteForCheckout?.canProceed === false) {
|
|
583
|
+
throw new Error(
|
|
584
|
+
authoritativeChangeQuoteForCheckout?.reasonIfBlocked ||
|
|
585
|
+
'The authoritative change quote is not ready.',
|
|
586
|
+
);
|
|
553
587
|
}
|
|
554
588
|
if (amountDueForCheckout <= 0) {
|
|
555
589
|
if (!onChangeBooking) throw new Error('Provider change handler is unavailable.');
|
|
556
|
-
const providerPayload = buildProviderChangePayload(
|
|
590
|
+
const providerPayload = buildProviderChangePayload(
|
|
591
|
+
availabilityProductOptionId,
|
|
592
|
+
bookingItems,
|
|
593
|
+
authoritativeChangeQuoteForCheckout,
|
|
594
|
+
);
|
|
557
595
|
if (!providerPayload) throw new Error('No availability selected');
|
|
558
596
|
await onChangeBooking(providerPayload);
|
|
559
597
|
onSuccess?.({ reservationReference: bookingReference });
|
|
@@ -590,7 +628,9 @@ export function useAdminChangeCheckoutController({
|
|
|
590
628
|
'Pay later to apply the change and add the amount to the booking balance, or collect a new card payment before applying it.',
|
|
591
629
|
confirmWithoutPaymentLabel: 'Pay later',
|
|
592
630
|
previousTotal: originalReceipt?.total,
|
|
593
|
-
newTotal:
|
|
631
|
+
newTotal:
|
|
632
|
+
authoritativeChangeQuoteForCheckout?.serverDisplay?.total ??
|
|
633
|
+
authoritativeChangeQuoteForCheckout?.quotedTotal,
|
|
594
634
|
finalizeExistingChangeInline: true,
|
|
595
635
|
preferConfirmWithoutPayment: true,
|
|
596
636
|
}));
|
|
@@ -940,6 +980,7 @@ export function useAdminChangeCheckoutController({
|
|
|
940
980
|
showAdminPaymentChoice,
|
|
941
981
|
adminChoiceData,
|
|
942
982
|
cancelPendingReservation,
|
|
983
|
+
handleCheckoutClose,
|
|
943
984
|
handleCheckout,
|
|
944
985
|
handleConfirmWithoutPayment,
|
|
945
986
|
handlePayNow,
|
|
@@ -37,6 +37,7 @@ import { buildPublicChangeAmountDueSummary } from '../src/components/booking/cha
|
|
|
37
37
|
import {
|
|
38
38
|
buildAdminChangePaymentChoiceData,
|
|
39
39
|
buildAdminChangePayNowCheckoutModalData,
|
|
40
|
+
shouldRestoreAdminChangePaymentChoiceAfterCheckoutClose,
|
|
40
41
|
} from '../src/components/booking/admin-change-payment-choice-runner';
|
|
41
42
|
|
|
42
43
|
function quote(overrides: Partial<ChangeBookingQuoteResponse>): ChangeBookingQuoteResponse {
|
|
@@ -117,6 +118,16 @@ test('admin existing-booking pay-now review keeps previous, updated, and exact d
|
|
|
117
118
|
assert.equal(checkout.finalizeExistingChangeInline, true);
|
|
118
119
|
assert.equal(choice.confirmWithoutPaymentLabel, 'Pay later');
|
|
119
120
|
assert.equal(choice.preferConfirmWithoutPayment, true);
|
|
121
|
+
assert.equal(
|
|
122
|
+
shouldRestoreAdminChangePaymentChoiceAfterCheckoutClose(true, true, choice),
|
|
123
|
+
true,
|
|
124
|
+
);
|
|
125
|
+
assert.equal(
|
|
126
|
+
shouldRestoreAdminChangePaymentChoiceAfterCheckoutClose(true, true, {
|
|
127
|
+
pricingQuoteId: ' ',
|
|
128
|
+
}),
|
|
129
|
+
false,
|
|
130
|
+
);
|
|
120
131
|
assert.equal(
|
|
121
132
|
buildAdminChangePayNowCheckoutModalData(
|
|
122
133
|
{ ...choice, finalizeExistingChangeInline: undefined },
|