@ticketboothapp/booking 1.2.92 → 1.2.94

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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ticketboothapp/booking",
3
- "version": "1.2.92",
3
+ "version": "1.2.94",
4
4
  "private": false,
5
5
  "sideEffects": [
6
6
  "**/*.css",
@@ -5047,6 +5047,48 @@ export function AdminChangeBookingFlow({
5047
5047
  if (!quote.changeIntentId) {
5048
5048
  throw new Error('Missing change intent for booking change confirmation.');
5049
5049
  }
5050
+ if (onChangeBooking) {
5051
+ const pickupForChange = pickupLocationId
5052
+ ? product.pickupLocations?.find((loc) => loc.id === pickupLocationId)
5053
+ : null;
5054
+ await onChangeBooking({
5055
+ productId: availabilityProductOptionId,
5056
+ dateTime: selectedAvailability.dateTime,
5057
+ bookingItems,
5058
+ returnAvailabilityId: selectedReturnOption?.returnAvailabilityId ?? null,
5059
+ pickupLocationId: pickupLocationId ?? null,
5060
+ travelerHotel: pickupForChange?.name ?? null,
5061
+ startTime: selectedAvailability.dateTime ?? null,
5062
+ passengerCount: null,
5063
+ childSafetySeatsCount: null,
5064
+ foodRestrictions: null,
5065
+ addOnSelections: addOnSelections.length > 0 ? addOnSelections : null,
5066
+ cancellationPolicyId: cancellationPolicyId ?? initialValues?.cancellationPolicyId ?? null,
5067
+ promoCode: appliedPromoCode ?? null,
5068
+ newTotalAmount: displayChangeFlowProposedTotalWithEditableLines,
5069
+ additionalHoursCount: null,
5070
+ pricingAdjustment:
5071
+ providerPricingOverrides.length > 0 || mergedProviderAdditionalAdjustments.length > 0
5072
+ ? {
5073
+ mode: 'MANUAL_LINES',
5074
+ ...(providerPricingOverrides.length > 0 ? { lineOverrides: providerPricingOverrides } : {}),
5075
+ ...(mergedProviderAdditionalAdjustments.length > 0
5076
+ ? { additionalAdjustments: mergedProviderAdditionalAdjustments }
5077
+ : {}),
5078
+ }
5079
+ : undefined,
5080
+ capacitySeatCredit: {
5081
+ enabled: true,
5082
+ previousPassengerCount: changeFlowInitialTicketCount,
5083
+ previousAvailabilityId: initialValues?.availabilityId ?? null,
5084
+ previousReturnAvailabilityId: initialValues?.returnAvailabilityId ?? null,
5085
+ },
5086
+ deferPaymentToBalance: true,
5087
+ });
5088
+ onSuccess?.({ reservationReference: changeBookingReference });
5089
+ setLoading(false);
5090
+ return;
5091
+ }
5050
5092
  const freeConfirm = await confirmFreeChangeBooking(quote.changeIntentId);
5051
5093
  if (freeConfirm.status && freeConfirm.status !== 'APPLIED') {
5052
5094
  throw new Error('We could not apply this booking change yet. Please try again.');
@@ -44,6 +44,7 @@ import { CheckoutModal, type CheckoutModalLineItem } from './CheckoutModal';
44
44
  import { CancellationPolicySelector } from './CancellationPolicySelector';
45
45
  import { PriceSummary } from './PriceSummary';
46
46
  import { TermsAcceptance } from './TermsAcceptance';
47
+ import { PromoCodeInput } from './PromoCodeInput';
47
48
  import { ItineraryBuilder } from './ItineraryBuilder';
48
49
  import { MealDrinkAddOnSelector, canUseMealDrinkSelector } from './MealDrinkAddOnSelector';
49
50
  import { AdminPaymentChoiceModal } from './AdminPaymentChoiceModal';
@@ -261,6 +262,7 @@ export function PrivateShuttleBookingFlow({
261
262
  const [promoDiscountAmount, setPromoDiscountAmount] = useState(0);
262
263
  const [isGiftCard, setIsGiftCard] = useState(false);
263
264
  const [isVoucher, setIsVoucher] = useState(false);
265
+ const activePromoCode = isAdmin ? appliedPromoCode : null;
264
266
  const [additionalHoursCount, setAdditionalHoursCount] = useState(
265
267
  () => initialBooking?.additionalHoursCount ?? initialValues?.additionalHoursCount ?? 0
266
268
  );
@@ -369,7 +371,7 @@ export function PrivateShuttleBookingFlow({
369
371
  const endDate = format(endOfDay(clampedEnd), 'yyyy-MM-dd');
370
372
  const result = await getAvailabilities(product.productId, startDate, endDate, {
371
373
  allOptions: true,
372
- promoCode: appliedPromoCode || undefined,
374
+ promoCode: activePromoCode || undefined,
373
375
  ...(pricingProfileIdForAvailabilities
374
376
  ? { pricingProfileId: pricingProfileIdForAvailabilities }
375
377
  : {}),
@@ -417,7 +419,7 @@ export function PrivateShuttleBookingFlow({
417
419
  ? buildAvailabilitiesCacheKey(
418
420
  product.productId,
419
421
  activeOptionIdsKey,
420
- appliedPromoCode,
422
+ activePromoCode,
421
423
  pricingProfileIdForAvailabilities,
422
424
  )
423
425
  : null;
@@ -438,7 +440,7 @@ export function PrivateShuttleBookingFlow({
438
440
  product.productId,
439
441
  selectedDate,
440
442
  companyTimezone,
441
- appliedPromoCode,
443
+ activePromoCode,
442
444
  pricingProfileIdForAvailabilities,
443
445
  cancellationPolicyProfileIdForAvailabilities,
444
446
  activeOptionIdsKey,
@@ -477,7 +479,7 @@ export function PrivateShuttleBookingFlow({
477
479
  useEffect(() => {
478
480
  fetchedRangesRef.current = [];
479
481
  }, [
480
- appliedPromoCode,
482
+ activePromoCode,
481
483
  pricingProfileIdForAvailabilities,
482
484
  cancellationPolicyProfileIdForAvailabilities,
483
485
  ]);
@@ -527,7 +529,7 @@ export function PrivateShuttleBookingFlow({
527
529
  ? buildAvailabilitiesCacheKey(
528
530
  product.productId,
529
531
  activeOptionIdsKey,
530
- appliedPromoCode,
532
+ activePromoCode,
531
533
  pricingProfileIdForAvailabilities,
532
534
  )
533
535
  : null;
@@ -583,7 +585,7 @@ export function PrivateShuttleBookingFlow({
583
585
  const endDate = format(endOfDay(clampedEnd), 'yyyy-MM-dd');
584
586
  const result = await getAvailabilities(product.productId, startDate, endDate, {
585
587
  allOptions: true,
586
- promoCode: appliedPromoCode || undefined,
588
+ promoCode: activePromoCode || undefined,
587
589
  ...(pricingProfileIdForAvailabilities
588
590
  ? { pricingProfileId: pricingProfileIdForAvailabilities }
589
591
  : {}),
@@ -657,7 +659,7 @@ export function PrivateShuttleBookingFlow({
657
659
  activeOptionIdsKey,
658
660
  selectedDate,
659
661
  product.productId,
660
- appliedPromoCode,
662
+ activePromoCode,
661
663
  pricingProfileIdForAvailabilities,
662
664
  cancellationPolicyProfileIdForAvailabilities,
663
665
  needsFetch,
@@ -864,7 +866,7 @@ export function PrivateShuttleBookingFlow({
864
866
 
865
867
  useEffect(() => {
866
868
  if (
867
- !appliedPromoCode ||
869
+ !activePromoCode ||
868
870
  !selectedOption ||
869
871
  !selectedDate ||
870
872
  !selectedStartTime ||
@@ -879,7 +881,7 @@ export function PrivateShuttleBookingFlow({
879
881
  if (!companyId) return;
880
882
  let cancelled = false;
881
883
  getPromoDiscount(
882
- appliedPromoCode,
884
+ activePromoCode,
883
885
  companyId,
884
886
  product.productId,
885
887
  selectedOption,
@@ -906,7 +908,7 @@ export function PrivateShuttleBookingFlow({
906
908
  cancelled = true;
907
909
  };
908
910
  }, [
909
- appliedPromoCode,
911
+ activePromoCode,
910
912
  selectedOption,
911
913
  selectedDate,
912
914
  selectedStartTime,
@@ -1086,6 +1088,7 @@ export function PrivateShuttleBookingFlow({
1086
1088
 
1087
1089
  const handleApplyPromo = useCallback(async () => {
1088
1090
  const code = promoCodeInput.trim().toUpperCase();
1091
+ if (!isAdmin) return;
1089
1092
  if (!code || appliedPromoCode === code) return;
1090
1093
  if (!product.companyId) return;
1091
1094
  lastValidatedInputRef.current = code;
@@ -1116,6 +1119,7 @@ export function PrivateShuttleBookingFlow({
1116
1119
  }, [
1117
1120
  promoCodeInput,
1118
1121
  appliedPromoCode,
1122
+ isAdmin,
1119
1123
  product.companyId,
1120
1124
  product.productId,
1121
1125
  hasOngoingDiscount,
@@ -1125,6 +1129,29 @@ export function PrivateShuttleBookingFlow({
1125
1129
  const handleApplyPromoRef = useRef(handleApplyPromo);
1126
1130
  handleApplyPromoRef.current = handleApplyPromo;
1127
1131
 
1132
+ useEffect(() => {
1133
+ if (!isAdmin) return;
1134
+ const trimmed = promoCodeInput.trim().toUpperCase();
1135
+ if (!trimmed) return;
1136
+ if (!selectedOption || !selectedStartTime || resourceCount === 0) return;
1137
+ if (appliedPromoCode === trimmed) return;
1138
+ if (lastValidatedInputRef.current === trimmed && promoCodeError) return;
1139
+
1140
+ const timer = setTimeout(() => {
1141
+ handleApplyPromoRef.current();
1142
+ }, 600);
1143
+
1144
+ return () => clearTimeout(timer);
1145
+ }, [
1146
+ isAdmin,
1147
+ promoCodeInput,
1148
+ appliedPromoCode,
1149
+ promoCodeError,
1150
+ selectedOption,
1151
+ selectedStartTime,
1152
+ resourceCount,
1153
+ ]);
1154
+
1128
1155
  const itineraryDisplayItems = useMemo(() => {
1129
1156
  if (!selectedOption || !selectedStartTime) return [];
1130
1157
  const items: Array<{
@@ -1276,7 +1303,7 @@ export function PrivateShuttleBookingFlow({
1276
1303
  foodRestrictions: foodRestrictions.trim() || null,
1277
1304
  addOnSelections: addOnSelections.length > 0 ? addOnSelections : null,
1278
1305
  cancellationPolicyId: cancellationPolicyId ?? initialBooking?.cancellationPolicyId ?? null,
1279
- promoCode: appliedPromoCode ?? null,
1306
+ promoCode: activePromoCode ?? null,
1280
1307
  newTotalAmount: totalPrice,
1281
1308
  additionalHoursCount: isAdmin ? additionalHoursCount : null,
1282
1309
  });
@@ -1310,7 +1337,7 @@ export function PrivateShuttleBookingFlow({
1310
1337
  requestedPassengerCount: isSpecialRequest ? passengerCount : undefined,
1311
1338
  pickupLocationId: pickupLocationId || undefined,
1312
1339
  cancellationPolicyId: cancellationPolicyId || undefined,
1313
- promoCode: (isAdmin ? appliedPromoCode : null) || undefined,
1340
+ promoCode: activePromoCode || undefined,
1314
1341
  travelerHotel: selectedPickupLocation?.name || customPickupAddress || undefined,
1315
1342
  draftItinerary:
1316
1343
  draftItineraryDestinations.length > 0 || planningNotes
@@ -1427,8 +1454,8 @@ export function PrivateShuttleBookingFlow({
1427
1454
  ? [
1428
1455
  {
1429
1456
  label:
1430
- appliedPromoCode
1431
- ? `Promo: ${appliedPromoCode}`
1457
+ activePromoCode
1458
+ ? `Promo: ${activePromoCode}`
1432
1459
  : (t('booking.discount') || 'Discount'),
1433
1460
  amount: -effectivePromoDiscountAmount,
1434
1461
  type: isGiftCard ? 'GIFT_CARD' : 'PROMO_CODE',
@@ -1502,7 +1529,7 @@ export function PrivateShuttleBookingFlow({
1502
1529
  itineraryDisplay: itineraryDisplayForStorage,
1503
1530
  termsAcceptedAt: termsAcceptedAt ?? undefined,
1504
1531
  cancellationPolicyId: cancellationPolicyId || undefined,
1505
- promoCode: (isAdmin ? appliedPromoCode : null) || undefined,
1532
+ promoCode: activePromoCode || undefined,
1506
1533
  checkoutBreakdown,
1507
1534
  paymentPlanType: 'DEPOSIT',
1508
1535
  depositAmount: depositInfo.depositAmount,
@@ -1559,7 +1586,7 @@ export function PrivateShuttleBookingFlow({
1559
1586
  isTaxIncludedInPrice,
1560
1587
  taxRate,
1561
1588
  promoDiscountAmount: effectivePromoDiscountAmount > 0 ? effectivePromoDiscountAmount : 0,
1562
- discountLabel: appliedPromoCode ? `Promo: ${appliedPromoCode}` : undefined,
1589
+ discountLabel: activePromoCode ? `Promo: ${activePromoCode}` : undefined,
1563
1590
  });
1564
1591
  setShowAdminPaymentChoice(true);
1565
1592
  setLoading(false);
@@ -1582,7 +1609,7 @@ export function PrivateShuttleBookingFlow({
1582
1609
  itineraryDisplay: itineraryDisplayForStorage,
1583
1610
  termsAcceptedAt: termsAcceptedAt ?? undefined,
1584
1611
  cancellationPolicyId: cancellationPolicyId || undefined,
1585
- promoCode: (isAdmin ? appliedPromoCode : null) || undefined,
1612
+ promoCode: activePromoCode || undefined,
1586
1613
  checkoutBreakdown,
1587
1614
  ...(depositInfo && {
1588
1615
  paymentPlanType: 'DEPOSIT' as const,
@@ -1674,7 +1701,7 @@ export function PrivateShuttleBookingFlow({
1674
1701
  cancellationPolicyFee,
1675
1702
  cancellationPolicyLabel: selectedCancellationPolicy?.label,
1676
1703
  promoDiscountAmount: effectivePromoDiscountAmount > 0 ? effectivePromoDiscountAmount : 0,
1677
- discountLabel: appliedPromoCode ? `Promo: ${appliedPromoCode}` : undefined,
1704
+ discountLabel: activePromoCode ? `Promo: ${activePromoCode}` : undefined,
1678
1705
  isDepositPayment: !!depositInfo,
1679
1706
  balanceChargeDaysBefore: depositInfo ? (privateShuttleConfig?.balanceChargeDaysBefore ?? 7) : undefined,
1680
1707
  });
@@ -2528,8 +2555,39 @@ export function PrivateShuttleBookingFlow({
2528
2555
  total={depositInfo ? depositInfo.depositAmount : totalPrice}
2529
2556
  currency={currency}
2530
2557
  locale={locale as 'en' | 'fr'}
2531
- taxAmount={taxAmount}
2558
+ taxAmount={effectiveTaxAmount}
2532
2559
  taxRate={taxRate}
2560
+ discountAmount={effectivePromoDiscountAmount}
2561
+ discountLabel={activePromoCode ? `Promo: ${activePromoCode}` : undefined}
2562
+ extraBetweenTaxAndTotal={
2563
+ isAdmin ? (
2564
+ <PromoCodeInput
2565
+ promoCodeInput={promoCodeInput}
2566
+ appliedPromoCode={appliedPromoCode}
2567
+ promoCodeError={promoCodeError}
2568
+ promoCodeValidating={promoCodeValidating}
2569
+ promoDiscountAmount={promoDiscountAmount}
2570
+ currency={currency}
2571
+ locale={locale}
2572
+ t={t}
2573
+ onInputChange={(value) => {
2574
+ setPromoCodeInput(value);
2575
+ setPromoCodeError('');
2576
+ }}
2577
+ onApply={handleApplyPromo}
2578
+ onRemove={() => {
2579
+ lastValidatedInputRef.current = null;
2580
+ setAppliedPromoCode(null);
2581
+ setPromoCodeInput('');
2582
+ setPromoCodeError('');
2583
+ setPromoDiscountAmount(0);
2584
+ setIsGiftCard(false);
2585
+ setIsVoucher(false);
2586
+ fetchedRangesRef.current = [];
2587
+ }}
2588
+ />
2589
+ ) : null
2590
+ }
2533
2591
  size="sm"
2534
2592
  t={t}
2535
2593
  depositMode={