tf-checkout-react-native 2.0.0-beta.19 → 2.0.0-beta.22

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/dist/index.js CHANGED
@@ -244,7 +244,7 @@ __export(index_exports, {
244
244
  clearCheckoutGuestSession: () => clearCheckoutGuestSession,
245
245
  clearSession: () => clearSession,
246
246
  computeRadialTreeLayout: () => computeRadialTreeLayout,
247
- configure: () => configure,
247
+ configure: () => configureCheckout,
248
248
  configureCheckout: () => configureCheckout,
249
249
  confirmBundlePaymentWith: () => confirmBundlePaymentWith,
250
250
  confirmInstallmentsHasNextAction: () => confirmInstallmentsHasNextAction,
@@ -262,7 +262,6 @@ __export(index_exports, {
262
262
  createInstallmentChoices: () => createInstallmentChoices,
263
263
  createLiveScope: () => createLiveScope,
264
264
  createMemoryStorage: () => createMemoryStorage,
265
- createMmkvStorage: () => createMmkvStorage,
266
265
  createOwnedElements: () => createOwnedElements,
267
266
  createPaymentMarks: () => createPaymentMarks,
268
267
  createProviderPages: () => createProviderPages,
@@ -349,7 +348,6 @@ __export(index_exports, {
349
348
  mirroredHolderDraft: () => mirroredHolderDraft,
350
349
  missingCheckoutDetails: () => missingCheckoutDetails,
351
350
  missingRequiredAddOns: () => missingRequiredAddOns,
352
- mmkvStorageAdapter: () => mmkvStorageAdapter,
353
351
  mountKeyedField: () => mountKeyedField,
354
352
  nativeStripeErrorOutcome: () => nativeStripeErrorOutcome,
355
353
  newBundleIdempotencyKey: () => newBundleIdempotencyKey,
@@ -500,6 +498,7 @@ __export(index_exports, {
500
498
  ticketConfirmerKey: () => ticketConfirmerKey,
501
499
  ticketFieldsFor: () => ticketFieldsFor,
502
500
  ticketPaymentKeys: () => ticketPaymentKeys,
501
+ ticketPriceContext: () => ticketPriceContext,
503
502
  ticketQuantityRange: () => ticketQuantityRange,
504
503
  ticketRefundConsequences: () => ticketRefundConsequences,
505
504
  ticketTypesForTier: () => ticketTypesForTier,
@@ -6307,7 +6306,7 @@ var tripStatus = (status, locale) => {
6307
6306
  };
6308
6307
  var isEventTrip = (data) => "event" in data;
6309
6308
  var brandingLines = (identities = []) => identities.map(
6310
- (identity) => [...new Set([identity.brand_name, identity.platform_name].filter(Boolean))].join(
6309
+ (identity2) => [...new Set([identity2.brand_name, identity2.platform_name].filter(Boolean))].join(
6311
6310
  " \xB7 "
6312
6311
  )
6313
6312
  ).filter(Boolean);
@@ -7344,16 +7343,20 @@ var mapOption = (o) => {
7344
7343
  requiresSignIn: o.requiresSignIn === true || o.requires_sign_in === true
7345
7344
  };
7346
7345
  };
7346
+ var waitlistId = (value6) => typeof value6 === "string" && /^[1-9]\d*$/.test(value6) ? value6 : typeof value6 === "number" && Number.isSafeInteger(value6) && value6 > 0 ? String(value6) : null;
7347
7347
  var mapWaitlist = (w) => {
7348
- var _a2, _b, _c, _d;
7348
+ const ticketTypeId = waitlistId(w.ticketTypeId);
7349
+ if (!ticketTypeId || typeof w.name !== "string" || !w.name.trim()) return null;
7350
+ if (w.entry === null) return { ticketTypeId, name: w.name, entry: null };
7351
+ if (!w.entry || typeof w.entry !== "object" || Array.isArray(w.entry)) return null;
7352
+ const id2 = waitlistId(w.entry.id);
7353
+ const { status, offerExpiresAt } = w.entry;
7354
+ if (!id2 || !["waiting", "offered"].includes(status) || offerExpiresAt !== void 0 && offerExpiresAt !== null && typeof offerExpiresAt !== "string")
7355
+ return null;
7349
7356
  return {
7350
- ticketTypeId: String((_a2 = w.ticketTypeId) != null ? _a2 : ""),
7351
- name: String((_b = w.name) != null ? _b : ""),
7352
- entry: w.entry && typeof w.entry === "object" ? {
7353
- id: String((_c = w.entry.id) != null ? _c : ""),
7354
- status: String((_d = w.entry.status) != null ? _d : ""),
7355
- offerExpiresAt: text3(w.entry.offerExpiresAt)
7356
- } : null
7357
+ ticketTypeId,
7358
+ name: w.name,
7359
+ entry: { id: id2, status, offerExpiresAt: text3(offerExpiresAt) }
7357
7360
  };
7358
7361
  };
7359
7362
  var list = (value6) => Array.isArray(value6) ? value6.filter((v) => v && typeof v === "object") : [];
@@ -7373,7 +7376,7 @@ var ticketChangeOptionsFromResponse = (body3) => {
7373
7376
  closesAt: text3((_d = a.cutoff) == null ? void 0 : _d.closesAt)
7374
7377
  },
7375
7378
  options,
7376
- waitlistOptions: list(a.waitlistOptions).map(mapWaitlist),
7379
+ waitlistOptions: list(a.waitlistOptions).map(mapWaitlist).filter((option) => option !== null),
7377
7380
  sellInstead: {
7378
7381
  available: Boolean((_e = a.sellInstead) == null ? void 0 : _e.available) && Boolean((_f = a.sellInstead) == null ? void 0 : _f.url),
7379
7382
  url: text3((_g = a.sellInstead) == null ? void 0 : _g.url)
@@ -9045,21 +9048,43 @@ var waitingListEntryFrom = (definition, draft) => {
9045
9048
  quantity
9046
9049
  };
9047
9050
  };
9051
+ var identity = (ticket) => {
9052
+ var _a2;
9053
+ return (_a2 = ticket.selectionKey) != null ? _a2 : ticket.id;
9054
+ };
9055
+ var ticketPriceContext = (scope, ticket) => {
9056
+ var _a2, _b;
9057
+ return JSON.stringify([
9058
+ scope,
9059
+ ticket.currency,
9060
+ (_a2 = ticket.timeSlot) == null ? void 0 : _a2.date,
9061
+ (_b = ticket.timeSlot) == null ? void 0 : _b.time,
9062
+ identity(ticket)
9063
+ ]);
9064
+ };
9048
9065
  var calendarTicketRows = (base, dated) => {
9049
- const ids = new Set(dated.map((ticket) => ticket.id));
9066
+ const ids = new Set(dated.map(identity));
9050
9067
  return [
9051
9068
  ...dated,
9052
- ...base.filter((ticket) => ticket.isRegularTicket === true && !ids.has(ticket.id))
9069
+ ...base.filter(
9070
+ (ticket) => ticket.isRegularTicket === true && !ids.has(identity(ticket))
9071
+ )
9053
9072
  ];
9054
9073
  };
9055
9074
  var catalogDate = (selected, dates) => {
9056
9075
  var _a2;
9057
9076
  return dates.includes(selected) ? selected : (_a2 = dates[0]) != null ? _a2 : "";
9058
9077
  };
9059
- var catalogQuantities = (previous, tickets) => {
9078
+ var catalogQuantities = (previous, tickets, previousTickets = tickets, dateChanged = false) => {
9079
+ var _a2;
9080
+ const retained = /* @__PURE__ */ new Map();
9081
+ for (const ticket of previousTickets) {
9082
+ if (dateChanged && ticket.timeSlot) continue;
9083
+ if (previous[ticket.id] > 0) retained.set(identity(ticket), previous[ticket.id]);
9084
+ }
9060
9085
  const next = {};
9061
9086
  for (const ticket of tickets) {
9062
- const quantity = previous[ticket.id];
9087
+ const quantity = (_a2 = retained.get(identity(ticket))) != null ? _a2 : 0;
9063
9088
  const range = ticketQuantityRange(ticket);
9064
9089
  if (quantity > 0 && !ticket.soldOut && ticket.salesStarted && !ticket.salesEnded && quantity >= range.min && quantity <= range.max && quantity % range.step === 0)
9065
9090
  next[ticket.id] = quantity;
@@ -10026,10 +10051,23 @@ var getVerificationInfo = async () => get(ENDPOINTS.auth.verificationInfo);
10026
10051
  var updateVerificationStatus = async () => patch(ENDPOINTS.auth.verify, {
10027
10052
  data: { attributes: { verification: { verificationStatus: "PENDING" } } }
10028
10053
  });
10029
- var logout = async () => {
10054
+ var logout = async (options = {}) => {
10055
+ const device = options.pushDevice;
10056
+ if (device !== void 0 && (device === null || typeof device !== "object" || Array.isArray(device) || typeof device.appId !== "string" || !/^[a-z][a-z0-9_-]{0,63}$/.test(device.appId) || typeof device.token !== "string" || !device.token || device.token.length > 4096 || /[^\x21-\x7e]/.test(device.token) || device.registration !== void 0 && (typeof device.registration !== "string" || !/^[1-9][0-9]{0,19}:[0-9]{1,20}$/.test(device.registration))))
10057
+ throw new TtfError(
10058
+ "This device could not be removed securely.",
10059
+ 0,
10060
+ "VALIDATION_ERROR"
10061
+ );
10062
+ const headers = device ? {
10063
+ "X-TF-Push-App": device.appId,
10064
+ "X-TF-Push-Token": device.token,
10065
+ ...device.registration ? { "X-TF-Push-Registration": device.registration } : {}
10066
+ } : void 0;
10030
10067
  const epoch = advanceSessionEpoch();
10031
10068
  try {
10032
- await del(ENDPOINTS.auth.session);
10069
+ if (headers) await del(ENDPOINTS.auth.session, { headers });
10070
+ else await del(ENDPOINTS.auth.session);
10033
10071
  } finally {
10034
10072
  if (epoch === getSessionEpoch()) clearSession();
10035
10073
  }
@@ -10499,10 +10537,21 @@ var badgeOf = (raw) => {
10499
10537
  const text6 = typeof raw === "string" ? raw.trim() : "";
10500
10538
  return text6 || null;
10501
10539
  };
10502
- var mapTicket = (t) => {
10540
+ var eventCurrency = (raw) => {
10541
+ if (typeof raw === "string") return { currency: raw };
10542
+ if (!raw || typeof raw !== "object") return {};
10543
+ const value6 = raw;
10544
+ return {
10545
+ ...typeof value6.currency === "string" ? { currency: value6.currency } : {},
10546
+ ...typeof value6.symbol === "string" ? { priceSymbol: value6.symbol } : {}
10547
+ };
10548
+ };
10549
+ var selectionKey = (raw, eventId) => typeof raw === "string" && raw.trim() === raw && /^event:[1-9]\d*:ticket:[1-9]\d*$/.test(raw) && raw.startsWith(`event:${eventId}:ticket:`) ? raw : void 0;
10550
+ var mapTicket = (t, eventId) => {
10503
10551
  var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
10504
10552
  return {
10505
10553
  id: String(t.id),
10554
+ ...selectionKey(t.selectionKey, eventId) ? { selectionKey: selectionKey(t.selectionKey, eventId) } : {},
10506
10555
  isRegularTicket: typeof t.isRegularTicket === "boolean" ? t.isRegularTicket : void 0,
10507
10556
  name: (_a2 = t.displayName) != null ? _a2 : "",
10508
10557
  groupName: (_c = (_b = t.groupName) != null ? _b : t.group_name) != null ? _c : null,
@@ -10562,7 +10611,7 @@ var getEventDetails = async (eventId, language = "en") => {
10562
10611
  endDate: hideDate ? null : text6(a.endDate),
10563
10612
  formattedDate: hideDate ? "Date TBC" : String((_q = a.formattedDate) != null ? _q : ""),
10564
10613
  timezone: text6(a.timezone),
10565
- currency: String((_r = a.currency) != null ? _r : ""),
10614
+ currency: (_r = eventCurrency(a.currency).currency) != null ? _r : "",
10566
10615
  salesStart: text6(a.salesStart),
10567
10616
  salesEnd: text6(a.salesEnd),
10568
10617
  salesStarted: Boolean(a.salesStarted),
@@ -10587,7 +10636,7 @@ var getEventTickets = async (eventId) => {
10587
10636
  tfCatalogContext: true
10588
10637
  });
10589
10638
  const ticketsObj = (_c = (_b = (_a2 = body3 == null ? void 0 : body3.data) == null ? void 0 : _a2.attributes) == null ? void 0 : _b.tickets) != null ? _c : {};
10590
- return Object.values(ticketsObj).map(mapTicket);
10639
+ return Object.values(ticketsObj).map((ticket) => mapTicket(ticket, eventId));
10591
10640
  };
10592
10641
  var getEventInfo = async (eventId, pk) => {
10593
10642
  var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q;
@@ -10603,6 +10652,7 @@ var getEventInfo = async (eventId, pk) => {
10603
10652
  const rawCountry = a.country;
10604
10653
  const countryCode = (_j = (_i = (_h = typeof rawCountry === "string" ? rawCountry : rawCountry == null ? void 0 : rawCountry.code) != null ? _h : a.countryCode) != null ? _i : a.country_code) != null ? _j : null;
10605
10654
  return {
10655
+ ...eventCurrency(a.currency),
10606
10656
  isSeatedEvent: isSeatedEvent(attributes6),
10607
10657
  tableMapEnabled: Boolean((_k = a.tableMapEnabled) != null ? _k : a.table_map_enabled),
10608
10658
  isTimeSlotEvent: Boolean(
@@ -10636,7 +10686,7 @@ var getEventConditions = async (eventId) => {
10636
10686
  }).filter((c) => c.content || c.name);
10637
10687
  };
10638
10688
  var getEventTimeSlotTickets = async (eventId, date, options) => {
10639
- var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u;
10689
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z;
10640
10690
  await sdkSeatSessionHeaders(eventId);
10641
10691
  const body3 = await get(ENDPOINTS.events.timeSlotByDate(eventId), {
10642
10692
  tfCatalogContext: true,
@@ -10657,25 +10707,28 @@ var getEventTimeSlotTickets = async (eventId, date, options) => {
10657
10707
  const stock = Number((_h = (_g = s9.in_stock) != null ? _g : s9.real_stock) != null ? _h : 0);
10658
10708
  out.push({
10659
10709
  id: String(s9.matrix_record_id),
10710
+ ...selectionKey(s9.selectionKey, eventId) ? { selectionKey: selectionKey(s9.selectionKey, eventId) } : {},
10660
10711
  name: s9.display_name || s9.option_value || "Ticket",
10661
10712
  groupName: (_j = (_i = s9.group_name) != null ? _i : s9.groupName) != null ? _j : null,
10662
- optionName: String((_k = s9.option_key) != null ? _k : ""),
10663
- price: Number((_l = s9.base_price) != null ? _l : 0),
10664
- priceWithFees: Number((_n = (_m = s9.price_with_fees) != null ? _m : s9.base_price) != null ? _n : 0),
10665
- priceSymbol: (_p = (_o = s9.price_symbol) != null ? _o : s9.priceSymbol) != null ? _p : "",
10666
- currency: "",
10667
- feeIncluded: false,
10713
+ optionName: String((_l = (_k = s9.product_option_key) != null ? _k : s9.option_key) != null ? _l : ""),
10714
+ price: Number((_n = (_m = s9.display_price) != null ? _m : s9.base_price) != null ? _n : 0),
10715
+ priceWithFees: Number((_p = (_o = s9.price_with_fees) != null ? _o : s9.base_price) != null ? _p : 0),
10716
+ priceSymbol: (_r = (_q = s9.price_symbol) != null ? _q : s9.priceSymbol) != null ? _r : "",
10717
+ currency: (_s = s9.price_currency) != null ? _s : "",
10718
+ feeIncluded: s9.fee_included === true,
10668
10719
  depositPercent: s9.deposit_percent != null ? Number(s9.deposit_percent) : null,
10669
10720
  soldOut: Boolean(s9.sold_out) || stock <= 0,
10670
10721
  salesStarted: s9.sales_started != null ? Boolean(s9.sales_started) : true,
10671
10722
  salesEnded: Boolean(s9.sales_ended),
10672
- minQuantity: Number((_q = s9.min_quantity) != null ? _q : 1) || 1,
10673
- maxQuantity: Number((_r = s9.max_quantity) != null ? _r : 10) || 10,
10674
- multiplier: Number((_s = s9.multiplier) != null ? _s : 1) || 1,
10675
- isTable: Boolean(s9.is_table),
10676
- allowDirectPurchase: true,
10677
- descriptionRich: (_t = s9.description) != null ? _t : null,
10678
- badgeText: badgeOf((_u = s9.badge_text) != null ? _u : s9.badgeText),
10723
+ minQuantity: Number((_t = s9.min_quantity) != null ? _t : 1) || 1,
10724
+ maxQuantity: Number((_u = s9.max_quantity) != null ? _u : 10),
10725
+ multiplier: Number((_v = s9.multiplier) != null ? _v : 1) || 1,
10726
+ isTable: s9.x_is_table !== void 0 && s9.x_is_table !== null ? Number(s9.x_is_table) === 1 : Boolean(s9.is_table),
10727
+ minGuests: s9.min_guests === void 0 || s9.min_guests === null ? void 0 : Number(s9.min_guests),
10728
+ maxGuests: s9.max_guests === void 0 || s9.max_guests === null ? void 0 : Number(s9.max_guests),
10729
+ allowDirectPurchase: Number((_w = s9.allow_direct_purchase_for_seat_map) != null ? _w : 1) === 1,
10730
+ descriptionRich: (_y = (_x = s9.x_description_rich) != null ? _x : s9.description) != null ? _y : null,
10731
+ badgeText: badgeOf((_z = s9.badge_text) != null ? _z : s9.badgeText),
10679
10732
  timeSlot: { date: slotDate, time: timeKey }
10680
10733
  });
10681
10734
  }
@@ -10812,7 +10865,7 @@ var getEventTicketsWithMeta = async (eventId) => {
10812
10865
  const attrs = (_b = (_a2 = body3 == null ? void 0 : body3.data) == null ? void 0 : _a2.attributes) != null ? _b : {};
10813
10866
  const ticketsObj = (_c = attrs.tickets) != null ? _c : {};
10814
10867
  return {
10815
- tickets: Object.values(ticketsObj).map(mapTicket),
10868
+ tickets: Object.values(ticketsObj).map((ticket) => mapTicket(ticket, eventId)),
10816
10869
  promo: {
10817
10870
  isPromotionsEnabled: attrs.isPromotionsEnabled === true,
10818
10871
  isAccessCodeEnabled: attrs.is_access_code === true,
@@ -20596,15 +20649,15 @@ var useCheckoutImageField = ({
20596
20649
  value: value6,
20597
20650
  onChange,
20598
20651
  pick: pick3,
20599
- identity,
20652
+ identity: identity2,
20600
20653
  disabled = false
20601
20654
  }) => {
20602
20655
  const assertOwner = useSessionAction();
20603
20656
  const [busy, setBusy] = (0, import_react35.useState)(false);
20604
20657
  const [error, setError] = (0, import_react35.useState)(null);
20605
- const owner = (0, import_react35.useRef)({ identity, value: value6, disabled });
20606
- if (owner.current.identity !== identity || owner.current.value !== value6 || owner.current.disabled !== disabled)
20607
- owner.current = { identity, value: value6, disabled };
20658
+ const owner = (0, import_react35.useRef)({ identity: identity2, value: value6, disabled });
20659
+ if (owner.current.identity !== identity2 || owner.current.value !== value6 || owner.current.disabled !== disabled)
20660
+ owner.current = { identity: identity2, value: value6, disabled };
20608
20661
  const renderOwner = owner.current;
20609
20662
  const operation = (0, import_react35.useRef)(0);
20610
20663
  const inFlight = (0, import_react35.useRef)(false);
@@ -20622,7 +20675,7 @@ var useCheckoutImageField = ({
20622
20675
  inFlight.current = false;
20623
20676
  setBusy(false);
20624
20677
  setError(null);
20625
- }, [identity, value6, disabled]);
20678
+ }, [identity2, value6, disabled]);
20626
20679
  const select = async (picker = pick3) => {
20627
20680
  if (!mounted.current || owner.current !== renderOwner || !picker || disabled || inFlight.current)
20628
20681
  return;
@@ -21997,7 +22050,7 @@ var useTicketCatalog = (eventId, explicitDates) => {
21997
22050
  }
21998
22051
  };
21999
22052
  };
22000
- const [qty, updateQty] = useScopedState(subject, {});
22053
+ const [selection, updateSelection] = useScopedState(subject, { rows: EMPTY_TICKETS, date: "", quantities: {} });
22001
22054
  const [slotDate, updateDate] = useScopedState(subject, "");
22002
22055
  const [refreshing, setRefreshing] = useScopedState(subject, false);
22003
22056
  const eventQuery = useEvent(eventId);
@@ -22017,25 +22070,76 @@ var useTicketCatalog = (eventId, explicitDates) => {
22017
22070
  const base = (_b2 = (_a3 = ticketsQuery.data) == null ? void 0 : _a3.tickets) != null ? _b2 : EMPTY_TICKETS;
22018
22071
  if (!isTimeSlot)
22019
22072
  return { tickets: base, datedTickets: EMPTY_TICKETS, regularTickets: EMPTY_TICKETS };
22020
- const dated = (_c2 = slotQuery.data) != null ? _c2 : EMPTY_TICKETS;
22073
+ const currencies = [...new Set(base.map((ticket) => ticket.currency).filter(Boolean))];
22074
+ const currency = (eventInfo == null ? void 0 : eventInfo.currency) || (currencies.length === 1 ? currencies[0] : "");
22075
+ const symbols = [
22076
+ ...new Set(
22077
+ base.filter((ticket) => ticket.currency === currency).map((ticket) => ticket.priceSymbol).filter(Boolean)
22078
+ )
22079
+ ];
22080
+ const symbol = (eventInfo == null ? void 0 : eventInfo.priceSymbol) || (symbols.length === 1 ? symbols[0] : "");
22081
+ const dated = (slotQuery.isPlaceholderData ? EMPTY_TICKETS : (_c2 = slotQuery.data) != null ? _c2 : EMPTY_TICKETS).map((ticket) => ({
22082
+ ...ticket,
22083
+ currency: ticket.currency || currency,
22084
+ priceSymbol: ticket.priceSymbol || symbol
22085
+ }));
22021
22086
  const rows2 = calendarTicketRows(base, dated);
22022
22087
  return {
22023
22088
  tickets: rows2,
22024
22089
  datedTickets: dated,
22025
22090
  regularTickets: rows2.slice(dated.length)
22026
22091
  };
22027
- }, [eventInfo, explicitDates, isTimeSlot, (_b = ticketsQuery.data) == null ? void 0 : _b.tickets, slotQuery.data]);
22092
+ }, [
22093
+ eventInfo,
22094
+ explicitDates,
22095
+ isTimeSlot,
22096
+ (_b = ticketsQuery.data) == null ? void 0 : _b.tickets,
22097
+ slotQuery.data,
22098
+ slotQuery.isPlaceholderData
22099
+ ]);
22100
+ const liveCatalog = (0, import_react42.useRef)({ tickets, date: slotDate });
22101
+ (0, import_react42.useLayoutEffect)(() => {
22102
+ liveCatalog.current = { tickets, date: slotDate };
22103
+ }, [tickets, slotDate]);
22104
+ const qty = (0, import_react42.useMemo)(
22105
+ () => catalogQuantities(
22106
+ selection.quantities,
22107
+ tickets,
22108
+ selection.rows,
22109
+ selection.date !== slotDate
22110
+ ),
22111
+ [selection, tickets, slotDate]
22112
+ );
22028
22113
  (0, import_react42.useEffect)(() => {
22029
22114
  if (!current5()) return;
22030
22115
  const next = isTimeSlot ? catalogDate(slotDate, dates) : "";
22031
22116
  if (next !== slotDate) updateDate(next);
22032
- updateQty((previous) => catalogQuantities(previous, tickets));
22033
- }, [current5, isTimeSlot, slotDate, dates, tickets, updateDate, updateQty]);
22117
+ updateSelection((previous) => {
22118
+ const quantities = catalogQuantities(
22119
+ previous.quantities,
22120
+ tickets,
22121
+ previous.rows,
22122
+ previous.date !== slotDate
22123
+ );
22124
+ return previous.rows === tickets && previous.date === slotDate && quantities === previous.quantities ? previous : { rows: tickets, date: slotDate, quantities };
22125
+ });
22126
+ }, [current5, isTimeSlot, slotDate, dates, tickets, updateDate, updateSelection]);
22034
22127
  const setQty = (0, import_react42.useCallback)(
22035
22128
  (update) => {
22036
- if (current5()) updateQty(update);
22129
+ if (current5())
22130
+ updateSelection((previous) => {
22131
+ const { tickets: rows2, date } = liveCatalog.current;
22132
+ const quantities = catalogQuantities(
22133
+ previous.quantities,
22134
+ rows2,
22135
+ previous.rows,
22136
+ previous.date !== date
22137
+ );
22138
+ const requested = typeof update === "function" ? update(quantities) : update;
22139
+ return { rows: rows2, date, quantities: catalogQuantities(requested, rows2) };
22140
+ });
22037
22141
  },
22038
- [current5, updateQty]
22142
+ [current5, updateSelection]
22039
22143
  );
22040
22144
  const setSlotDate = (0, import_react42.useCallback)(
22041
22145
  (date) => {
@@ -25727,39 +25831,42 @@ var useCheckout2 = (opts = {}) => {
25727
25831
  };
25728
25832
  };
25729
25833
 
25730
- // src/storage.ts
25731
- var import_react_native_mmkv = require("react-native-mmkv");
25732
- var createMmkvStorage = (id2 = "tf-checkout") => {
25733
- const mmkv = new import_react_native_mmkv.MMKV({ id: id2 });
25734
- return {
25735
- getItem: (key5) => {
25736
- var _a2;
25737
- return (_a2 = mmkv.getString(key5)) != null ? _a2 : null;
25738
- },
25739
- setItem: (key5, value6) => mmkv.set(key5, value6),
25740
- removeItem: (key5) => mmkv.delete(key5)
25741
- };
25742
- };
25743
-
25744
25834
  // src/configure.ts
25745
- var mmkvStorageAdapter = createMmkvStorage();
25746
- var configureCheckout = (config) => configure({
25747
- storage: mmkvStorageAdapter,
25748
- cookieAuth: true,
25749
- ...config,
25750
- // NSURLSession/RCTNetworking would otherwise accept Set-Cookie outside
25751
- // the SDK epoch guard. Only the SDK's header-backed jar owns native auth.
25752
- withCredentials: false,
25753
- // Native owns no browser cookie jar. Ask the canonical session owner to
25754
- // return its guest carrier and resume that exact carrier on later requests.
25755
- auth: () => {
25756
- var _a2;
25757
- return {
25758
- ...(_a2 = config.auth) == null ? void 0 : _a2.call(config),
25759
- "X-TF-Session-Mode": "header-only"
25760
- };
25835
+ var requireStorage = (storage) => {
25836
+ if (!storage || typeof storage !== "object" || Array.isArray(storage) || ["getItem", "setItem", "removeItem"].some(
25837
+ (method) => typeof storage[method] !== "function" || Object.prototype.toString.call(storage[method]) === "[object AsyncFunction]"
25838
+ ) || storage.flush !== void 0 && typeof storage.flush !== "function") {
25839
+ throw new Error(
25840
+ "Ticket Fairy native checkout requires a synchronous storage adapter. Pass storage backed by iOS Keychain or Android Keystore; hydrate an async-backed mirror before configuration and await flush() after credential changes."
25841
+ );
25761
25842
  }
25762
- });
25843
+ };
25844
+ var configureCheckout = (config) => {
25845
+ requireStorage(config == null ? void 0 : config.storage);
25846
+ configure({
25847
+ cookieAuth: true,
25848
+ ...config,
25849
+ // NSURLSession/RCTNetworking would otherwise accept Set-Cookie outside
25850
+ // the SDK epoch guard. Only the SDK's header-backed jar owns native auth.
25851
+ withCredentials: false,
25852
+ // Native owns no browser cookie jar. Ask the canonical session owner to
25853
+ // return its guest carrier and resume that exact carrier on later requests.
25854
+ auth: () => {
25855
+ var _a2, _b;
25856
+ return {
25857
+ ...Object.fromEntries(
25858
+ Object.entries((_b = (_a2 = config.auth) == null ? void 0 : _a2.call(config)) != null ? _b : {}).filter(
25859
+ ([name]) => name.toLowerCase() !== "cache-control"
25860
+ )
25861
+ ),
25862
+ "X-TF-Session-Mode": "header-only",
25863
+ // Account/ticket responses must not be saved by the native HTTP cache.
25864
+ // Revalidate any older cached response as well as forbidding a new store.
25865
+ "Cache-Control": "no-store, no-cache"
25866
+ };
25867
+ }
25868
+ });
25869
+ };
25763
25870
 
25764
25871
  // src/ui/Field.tsx
25765
25872
  var import_react50 = require("react");
@@ -26763,8 +26870,9 @@ var Tickets = ({
26763
26870
  const originals = (0, import_react57.useRef)({});
26764
26871
  (0, import_react57.useEffect)(() => {
26765
26872
  for (const t of tickets)
26766
- if (originals.current[t.id] == null) originals.current[t.id] = t.price;
26767
- }, [tickets]);
26873
+ if (originals.current[ticketPriceContext(catalog.scope, t)] == null)
26874
+ originals.current[ticketPriceContext(catalog.scope, t)] = t.price;
26875
+ }, [tickets, catalog.scope]);
26768
26876
  const selected = tickets.filter((t) => {
26769
26877
  var _a3;
26770
26878
  return ((_a3 = qty[t.id]) != null ? _a3 : 0) > 0;
@@ -26826,7 +26934,7 @@ var Tickets = ({
26826
26934
  var _a3, _b2;
26827
26935
  const notStarted = !t.salesStarted;
26828
26936
  const unavailable = t.soldOut || t.salesEnded || notStarted;
26829
- const original = originals.current[t.id];
26937
+ const original = originals.current[ticketPriceContext(catalog.scope, t)];
26830
26938
  const discounted = original != null && original > t.price;
26831
26939
  const isFree = Number(t.price) === 0;
26832
26940
  const sym = t.priceSymbol || t.currency;
@@ -28266,35 +28374,35 @@ var PhoneIdentity = ({
28266
28374
  ...options
28267
28375
  }) => {
28268
28376
  var _a2;
28269
- const identity = hooks_exports.useCheckoutPhoneIdentity(options);
28377
+ const identity2 = hooks_exports.useCheckoutPhoneIdentity(options);
28270
28378
  const [code, setCode] = (0, import_react63.useState)("");
28271
28379
  const [emailInstead, setEmailInstead] = (0, import_react63.useState)(false);
28272
28380
  if (emailInstead) return null;
28273
- if (identity.challenge)
28381
+ if (identity2.challenge)
28274
28382
  return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
28275
28383
  TwoFactorForm,
28276
28384
  {
28277
- loading: identity.busy,
28278
- error: identity.error,
28385
+ loading: identity2.busy,
28386
+ error: identity2.error,
28279
28387
  successMessage: "",
28280
- smsAvailable: identity.challenge.smsAvailable,
28281
- smsRetryAfter: identity.retryAfter,
28282
- onSubmit: identity.verifyTwoFactor,
28283
- onSendSms: identity.sendTwoFactorSms,
28284
- onCancel: identity.cancel
28388
+ smsAvailable: identity2.challenge.smsAvailable,
28389
+ smsRetryAfter: identity2.retryAfter,
28390
+ onSubmit: identity2.verifyTwoFactor,
28391
+ onSendSms: identity2.sendTwoFactorSms,
28392
+ onCancel: identity2.cancel
28285
28393
  }
28286
28394
  );
28287
28395
  return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_react_native22.View, { style: { gap: 12, paddingVertical: 12 }, children: [
28288
28396
  /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_native22.Text, { children: "Verify your phone to complete your details faster" }),
28289
- identity.error ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ErrorText, { children: identity.error }) : null,
28290
- identity.verified ? /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
28397
+ identity2.error ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ErrorText, { children: identity2.error }) : null,
28398
+ identity2.verified ? /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
28291
28399
  /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(MutedText, { children: "Your phone is verified." }),
28292
- ((_a2 = identity.result) == null ? void 0 : _a2.prefill.has_known_email) === true && typeof identity.result.prefill.email_masked === "string" ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
28400
+ ((_a2 = identity2.result) == null ? void 0 : _a2.prefill.has_known_email) === true && typeof identity2.result.prefill.email_masked === "string" ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
28293
28401
  Checkbox,
28294
28402
  {
28295
28403
  checked: Boolean(knownEmailSelected),
28296
28404
  onChange: onUseKnownEmail,
28297
- label: `Send my tickets to ${identity.result.prefill.email_masked}`
28405
+ label: `Send my tickets to ${identity2.result.prefill.email_masked}`
28298
28406
  }
28299
28407
  ) : null
28300
28408
  ] }) : /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
@@ -28302,14 +28410,14 @@ var PhoneIdentity = ({
28302
28410
  Input,
28303
28411
  {
28304
28412
  accessibilityLabel: "Mobile number",
28305
- value: identity.phone,
28306
- onChangeText: identity.setPhone,
28413
+ value: identity2.phone,
28414
+ onChangeText: identity2.setPhone,
28307
28415
  keyboardType: "phone-pad",
28308
28416
  autoComplete: "tel",
28309
- editable: !identity.busy && !identity.sent
28417
+ editable: !identity2.busy && !identity2.sent
28310
28418
  }
28311
28419
  ) }),
28312
- identity.sent ? /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
28420
+ identity2.sent ? /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
28313
28421
  /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Field, { label: "Verification code", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
28314
28422
  Input,
28315
28423
  {
@@ -28320,15 +28428,15 @@ var PhoneIdentity = ({
28320
28428
  autoComplete: "one-time-code",
28321
28429
  maxLength: 6,
28322
28430
  accessibilityLabel: "Verification code",
28323
- editable: !identity.busy
28431
+ editable: !identity2.busy
28324
28432
  }
28325
28433
  ) }),
28326
28434
  /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
28327
28435
  Button,
28328
28436
  {
28329
- loading: identity.busy,
28437
+ loading: identity2.busy,
28330
28438
  disabled: !/^\d{6}$/.test(code),
28331
- onPress: () => void identity.verify(code),
28439
+ onPress: () => void identity2.verify(code),
28332
28440
  children: "Verify phone"
28333
28441
  }
28334
28442
  )
@@ -28336,30 +28444,30 @@ var PhoneIdentity = ({
28336
28444
  /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
28337
28445
  Button,
28338
28446
  {
28339
- disabled: identity.busy || identity.retryAfter > 0 || !identity.phone.trim(),
28340
- onPress: () => void identity.request("sms"),
28341
- children: identity.retryAfter > 0 ? `Send another code in ${identity.retryAfter}s` : "Send code by SMS"
28447
+ disabled: identity2.busy || identity2.retryAfter > 0 || !identity2.phone.trim(),
28448
+ onPress: () => void identity2.request("sms"),
28449
+ children: identity2.retryAfter > 0 ? `Send another code in ${identity2.retryAfter}s` : "Send code by SMS"
28342
28450
  }
28343
28451
  ),
28344
28452
  options.whatsappAvailable ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
28345
28453
  Button,
28346
28454
  {
28347
28455
  variant: "ghost",
28348
- disabled: identity.busy || identity.retryAfter > 0 || !identity.phone.trim(),
28349
- onPress: () => void identity.request("whatsapp"),
28456
+ disabled: identity2.busy || identity2.retryAfter > 0 || !identity2.phone.trim(),
28457
+ onPress: () => void identity2.request("whatsapp"),
28350
28458
  children: "Send code by WhatsApp"
28351
28459
  }
28352
28460
  ) : null
28353
28461
  ] }),
28354
- (identity.sent || identity.verified) && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
28462
+ (identity2.sent || identity2.verified) && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
28355
28463
  Button,
28356
28464
  {
28357
28465
  variant: "ghost",
28358
- disabled: identity.busy,
28466
+ disabled: identity2.busy,
28359
28467
  onPress: () => {
28360
28468
  setCode("");
28361
28469
  onReset();
28362
- void identity.cancel();
28470
+ void identity2.cancel();
28363
28471
  },
28364
28472
  children: "Change phone number"
28365
28473
  }
@@ -28368,9 +28476,9 @@ var PhoneIdentity = ({
28368
28476
  Button,
28369
28477
  {
28370
28478
  variant: "ghost",
28371
- disabled: identity.busy,
28479
+ disabled: identity2.busy,
28372
28480
  onPress: () => {
28373
- void identity.cancel().then(() => setEmailInstead(true));
28481
+ void identity2.cancel().then(() => setEmailInstead(true));
28374
28482
  },
28375
28483
  children: "Use email instead"
28376
28484
  }