@ticketboothapp/booking 1.2.172 → 1.2.174

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.172",
3
+ "version": "1.2.174",
4
4
  "private": false,
5
5
  "sideEffects": [
6
6
  "**/*.css",
@@ -833,12 +833,6 @@ export function AdminChangeBookingFlow({
833
833
  latestChangeQuote?.allowedRefundDispositionsByOperationId,
834
834
  latestChangeQuote?.removedValueByOperationId,
835
835
  ]);
836
- useEffect(() => {
837
- if (!isProviderDashboardChange || responseRefundDecisionOperations.length === 0) return;
838
- setRefundDispositionsByOperationId((current) =>
839
- defaultPendingRefundDispositions(responseRefundDecisionOperations, current),
840
- );
841
- }, [isProviderDashboardChange, responseRefundDecisionOperations]);
842
836
  const activeRefundDecisionContext = useMemo(() => mergeAdminRefundDecisionContext({
843
837
  current: refundDecisionContext,
844
838
  selectionKey: refundDecisionSelectionKey,
@@ -857,9 +851,19 @@ export function AdminChangeBookingFlow({
857
851
  ? responseReturnPriceTreatmentOperations
858
852
  : [];
859
853
  const activeRefundDispositionsByOperationId = useMemo(() => {
854
+ // Provider changes default discovered refund operations to pending at
855
+ // settlement time. Do not write those response-derived defaults into the
856
+ // explicit input state: doing so changes the request key after the first
857
+ // quote and immediately triggers an identical second quote.
858
+ const dispositionsWithPendingRefundDefaults = isProviderDashboardChange
859
+ ? defaultPendingRefundDispositions(
860
+ activeRefundDecisionContext?.operations ?? [],
861
+ refundDispositionsByOperationId,
862
+ )
863
+ : refundDispositionsByOperationId;
860
864
  const dispositionsWithReturnPriceDefaults = defaultKeepOriginalReturnPriceDispositions(
861
865
  activeReturnPriceTreatmentOperations,
862
- refundDispositionsByOperationId,
866
+ dispositionsWithPendingRefundDefaults,
863
867
  );
864
868
  return selectRefundDispositionsForOperations(
865
869
  activeRefundDecisionContext,
@@ -869,6 +873,7 @@ export function AdminChangeBookingFlow({
869
873
  }, [
870
874
  activeRefundDecisionContext?.operations,
871
875
  activeReturnPriceTreatmentOperations,
876
+ isProviderDashboardChange,
872
877
  refundDispositionsByOperationId,
873
878
  ]);
874
879
  const handleRefundDispositionChange = useCallback((
@@ -910,7 +915,9 @@ export function AdminChangeBookingFlow({
910
915
  adminReverseAdjustmentIds,
911
916
  needsAdjustmentDiscovery:
912
917
  isProviderDashboardChange && !hasHydratedExistingAdjustments,
913
- refundDispositionsByOperationId: activeRefundDispositionsByOperationId,
918
+ // Only explicit user inputs belong to quote identity. Automatic provider
919
+ // defaults are derived separately for settlement/submission below.
920
+ refundDispositionsByOperationId,
914
921
  useAdminFeAuthoritativeQuote,
915
922
  latestChangeQuote,
916
923
  setLatestChangeQuote,
@@ -190,37 +190,15 @@ export function useAdminChangeQuotePreview({
190
190
  const refundDecisionRequired = (latestChangeQuote?.refundDecisionOperations?.length ?? 0) > 0;
191
191
  const hasPublishedChangeQuoteRef = useRef(latestChangeQuote !== null);
192
192
  hasPublishedChangeQuoteRef.current = latestChangeQuote !== null;
193
- /**
194
- * Existing admin adjustments must be discoverable before the operator makes a change.
195
- * Initial selection hydration can briefly leave the live availability/return unset, so use
196
- * the persisted booking identities for this read-only discovery quote instead of waiting for
197
- * the editable target controls to become complete.
198
- */
199
- const quoteAvailability = useMemo<Availability | null>(() => {
200
- if (selectedAvailability) return selectedAvailability;
201
- if (!needsAdjustmentDiscovery || !initialValues?.dateTime?.trim()) return null;
202
- const optionId = initialValues.productOptionId?.trim() || initialValues.productId?.trim();
203
- if (!optionId) return null;
204
- return {
205
- dateTime: initialValues.dateTime.trim(),
206
- availabilityId: initialValues.availabilityId?.trim() || undefined,
207
- productOptionId: optionId,
208
- vacancies: Math.max(totalQuantity, 1),
209
- currency,
210
- };
211
- }, [
212
- selectedAvailability,
213
- needsAdjustmentDiscovery,
214
- initialValues?.dateTime,
215
- initialValues?.availabilityId,
216
- initialValues?.productOptionId,
217
- initialValues?.productId,
218
- totalQuantity,
219
- currency,
220
- ]);
193
+ // Quote only against a live availability. Existing-adjustment discovery is
194
+ // bundled into the first real change quote; it must not issue a quote merely
195
+ // because the modal is hydrating.
196
+ const quoteAvailability = selectedAvailability;
221
197
  const quoteReturnAvailabilityId =
222
198
  selectedReturnOption?.returnAvailabilityId ??
223
- (needsAdjustmentDiscovery ? initialValues?.returnAvailabilityId?.trim() || null : null);
199
+ (quoteAvailability && needsAdjustmentDiscovery
200
+ ? initialValues?.returnAvailabilityId?.trim() || null
201
+ : null);
224
202
  const changeQuoteInputsKey = useMemo(() => buildAdminChangeQuoteRequestKey({
225
203
  bookingReference: initialValues?.bookingReference,
226
204
  lastName,
@@ -258,11 +236,13 @@ export function useAdminChangeQuotePreview({
258
236
  ]);
259
237
  const destinationRequiresReturnSelection = Boolean(selectedAvailability?.returnOptions?.length);
260
238
  const missingRequiredReturnSelection = destinationRequiresReturnSelection && !selectedReturnOption;
261
- const quoteMissingRequiredReturnSelection =
262
- missingRequiredReturnSelection && !needsAdjustmentDiscovery;
239
+ const quoteMissingRequiredReturnSelection = missingRequiredReturnSelection;
263
240
  const canRequestChangeQuote = canRequestAdminChangeQuote({
264
241
  isCustomerSelfServeChange,
265
- hasEffectiveChangeSelection: hasEffectiveChangeSelection || needsAdjustmentDiscovery,
242
+ // Opening the change flow is not itself a change. Existing adjustment
243
+ // discovery can be included with the first real quote instead of issuing a
244
+ // quote during modal hydration.
245
+ hasEffectiveChangeSelection,
266
246
  hasSelectedAvailability: quoteAvailability != null,
267
247
  bookingReference: initialValues?.bookingReference,
268
248
  lastName,
@@ -612,7 +612,7 @@ test('admin quote dedupe refetches unchanged inputs after the published quote is
612
612
  assert.equal(canReuseCompletedAdminChangeQuote(inputKey, 'different-inputs', true), false);
613
613
  });
614
614
 
615
- test('admin quote gate allows adjustment-only changes', () => {
615
+ test('admin quote gate requires a real change while allowing adjustment-only changes', () => {
616
616
  assert.equal(canRequestAdminChangeQuote({
617
617
  isCustomerSelfServeChange: true,
618
618
  hasEffectiveChangeSelection: true,
@@ -624,6 +624,7 @@ test('admin quote gate allows adjustment-only changes', () => {
624
624
 
625
625
  assert.equal(canRequestAdminChangeQuote({
626
626
  isCustomerSelfServeChange: true,
627
+ // A fully hydrated modal is still not quoteable until something changes.
627
628
  hasEffectiveChangeSelection: false,
628
629
  hasSelectedAvailability: true,
629
630
  bookingReference: 'DIFG66OF',