@ticketboothapp/booking 1.2.142 → 1.2.144

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.142",
3
+ "version": "1.2.144",
4
4
  "private": false,
5
5
  "sideEffects": [
6
6
  "**/*.css",
@@ -158,6 +158,7 @@ const checkoutPanelPropKeys = [
158
158
  'serverAmendmentLines',
159
159
  'serverAmountDue',
160
160
  'serverUpdatedTotal',
161
+ 'serverQuoteError',
161
162
  'isTaxIncludedInPrice',
162
163
  'taxRate',
163
164
  'currency',
@@ -983,6 +983,7 @@ export function AdminChangeBookingFlow({
983
983
  latestChangeQuote?.pricingVersion === 'booking-amendment-v1'
984
984
  ? latestChangeQuote.serverPreview?.totalNewBooking ?? null
985
985
  : null,
986
+ serverQuoteError: changeQuoteFetchError,
986
987
  ...{ priceSummaryLinesIncludeTaxRow, isTaxIncludedInPrice, showProviderPricingInlineEditor },
987
988
  taxRate: pricingConfig?.taxRate,
988
989
  ...{ providerPricingUi, providerQuotedLines },
@@ -33,6 +33,7 @@ export interface AdminChangeCheckoutPanelProps {
33
33
  serverAmendmentLines: PriceSummaryLine[] | null;
34
34
  serverAmountDue: number | null;
35
35
  serverUpdatedTotal: number | null;
36
+ serverQuoteError?: string | null;
36
37
  isTaxIncludedInPrice: boolean;
37
38
  taxRate?: number;
38
39
  currency: Currency;
@@ -105,6 +106,7 @@ export function AdminChangeCheckoutPanel({
105
106
  serverAmendmentLines,
106
107
  serverAmountDue,
107
108
  serverUpdatedTotal,
109
+ serverQuoteError,
108
110
  isTaxIncludedInPrice,
109
111
  taxRate,
110
112
  currency,
@@ -190,6 +192,8 @@ export function AdminChangeCheckoutPanel({
190
192
  amendmentLines={serverAmendmentLines}
191
193
  amountDue={serverAmountDue}
192
194
  updatedTotal={serverUpdatedTotal}
195
+ selectionChanged={hasEffectiveChangeSelection}
196
+ quoteError={serverQuoteError}
193
197
  amountDueLabel={totalSummaryLabel}
194
198
  currency={currency}
195
199
  locale={locale}
@@ -17,6 +17,8 @@ export interface AdminChangeReceiptComparisonProps {
17
17
  amountDue: number | null;
18
18
  /** Full resulting booking total returned by the same server quote. */
19
19
  updatedTotal: number | null;
20
+ selectionChanged: boolean;
21
+ quoteError?: string | null;
20
22
  amountDueLabel: string;
21
23
  currency: Currency;
22
24
  locale: string;
@@ -46,6 +48,8 @@ export function AdminChangeReceiptComparison({
46
48
  amendmentLines,
47
49
  amountDue,
48
50
  updatedTotal,
51
+ selectionChanged,
52
+ quoteError,
49
53
  amountDueLabel,
50
54
  currency,
51
55
  locale,
@@ -97,7 +101,16 @@ export function AdminChangeReceiptComparison({
97
101
  {amountDue == null ? '—' : formatCurrencyAmount(amountDue, currency, displayLocale)}
98
102
  </span>
99
103
  </div>
100
- {!quoteReady ? (
104
+ {!selectionChanged ? (
105
+ <div className="rounded-md border border-dashed border-stone-300 bg-white/70 px-3 py-4 text-center">
106
+ <p className="text-sm font-medium text-stone-700">No changes selected</p>
107
+ <p className="mt-1 text-xs text-stone-500">Change tickets or another booking option to request a price.</p>
108
+ </div>
109
+ ) : quoteError ? (
110
+ <div className="rounded-md border border-red-200 bg-red-50 px-3 py-4 text-center" role="alert">
111
+ <p className="text-sm font-medium text-red-800">{quoteError}</p>
112
+ </div>
113
+ ) : !quoteReady ? (
101
114
  <div className="rounded-md border border-dashed border-stone-300 bg-white/70 px-3 py-4 text-center">
102
115
  <p className="text-sm font-medium text-stone-700">Waiting for server price…</p>
103
116
  </div>
@@ -140,7 +153,7 @@ export function AdminChangeReceiptComparison({
140
153
  <div className="flex flex-wrap items-center justify-between gap-2 rounded-lg border border-stone-200 bg-stone-50 px-3 py-2">
141
154
  <span className="text-sm font-semibold text-stone-900">{amountDueLabel}</span>
142
155
  <span className={`text-lg font-semibold tabular-nums ${amountDueClass}`}>
143
- {amountDue == null ? '—' : formatCurrencyAmount(amountDue, currency, displayLocale)}
156
+ {!selectionChanged || amountDue == null ? '—' : formatCurrencyAmount(amountDue, currency, displayLocale)}
144
157
  </span>
145
158
  </div>
146
159
  </div>
@@ -1631,9 +1631,30 @@ export async function quoteAdminChangeBookingV2(
1631
1631
  throw new Error(message);
1632
1632
  }
1633
1633
  const response = await parseJsonSafely(res);
1634
- const outer = (response as { data?: unknown } | null)?.data;
1635
- const data = ((outer as { data?: AdminChangeBookingQuoteV2Data } | null)?.data ??
1636
- outer) as AdminChangeBookingQuoteV2Data;
1634
+ let candidate: unknown = response;
1635
+ for (let depth = 0; depth < 4; depth += 1) {
1636
+ if (
1637
+ candidate != null &&
1638
+ typeof candidate === 'object' &&
1639
+ 'oldReceipt' in candidate &&
1640
+ 'canApply' in candidate
1641
+ ) {
1642
+ break;
1643
+ }
1644
+ candidate =
1645
+ candidate != null && typeof candidate === 'object' && 'data' in candidate
1646
+ ? (candidate as { data?: unknown }).data
1647
+ : undefined;
1648
+ }
1649
+ if (
1650
+ candidate == null ||
1651
+ typeof candidate !== 'object' ||
1652
+ !('oldReceipt' in candidate) ||
1653
+ !('canApply' in candidate)
1654
+ ) {
1655
+ throw new Error('Invalid admin Pricing V2 quote response');
1656
+ }
1657
+ const data = candidate as AdminChangeBookingQuoteV2Data;
1637
1658
  const oldReceipt = data.oldReceipt;
1638
1659
  const newQuote = data.newQuote ?? null;
1639
1660
  const currency = newQuote?.currency ?? oldReceipt.currency ?? undefined;