@gomusdev/web-components 3.7.0 → 3.8.1

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.
@@ -12000,8 +12000,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
12000
12000
  ticketId
12001
12001
  }).map((x) => x.totalCapacity)) ?? 0;
12002
12002
  },
12003
- timeslotsOn(date) {
12004
- const bySlot = group(this.timeslots().filter((x) => x.timeSlot.startsWith(date.toString())), (r) => r.timeSlot);
12003
+ timeslotsOn(date, ticketIds) {
12004
+ let rows = this.timeslots().filter((x) => x.timeSlot.startsWith(date.toString()));
12005
+ if (ticketIds) rows = rows.filter((x) => x.tickets.some((t) => ticketIds.includes(t)));
12006
+ const bySlot = group(rows, (r) => r.timeSlot);
12005
12007
  return Object.values(bySlot).map((slotRows) => {
12006
12008
  return max$2(unique(slotRows.flatMap((r) => r.tickets)).map((t) => min$2(slotRows.filter((r) => r.tickets.includes(t)), (r) => r.capacity)).filter((r) => r !== null), (r) => r.capacity) ?? slotRows[0];
12007
12009
  }).sort((a, b) => a.timeSlot.localeCompare(b.timeSlot));
@@ -12203,7 +12205,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
12203
12205
  if (lsItems.length === 0) cart.clearItems();
12204
12206
  else cart.items = lsItems.map(generateCartItem).filter(defined);
12205
12207
  cart.clearCoupons();
12206
- lsCoupons.forEach((coupon) => cart.addCoupon(coupon));
12208
+ lsCoupons.forEach((coupon) => cart.addCoupon(typeof coupon === "string" ? {
12209
+ code: coupon,
12210
+ kind: "actionToken"
12211
+ } : coupon));
12207
12212
  return cart.items;
12208
12213
  } catch (e) {
12209
12214
  console.error(e);
@@ -12263,6 +12268,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
12263
12268
  get totalQuantity() {
12264
12269
  return sum(this.items, (item) => item.quantity);
12265
12270
  },
12271
+ get valueVoucherCents() {
12272
+ return sum(this.coupons.filter((c) => c.kind === "valueVoucher"), (c) => c.valueCents ?? 0);
12273
+ },
12274
+ get amountToPayCents() {
12275
+ return Math.max(0, this.totalPriceCents - this.valueVoucherCents);
12276
+ },
12266
12277
  /**
12267
12278
  * Generates a formatted string representation of the current object.
12268
12279
  */
@@ -12279,10 +12290,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
12279
12290
  comment: null,
12280
12291
  reference: null,
12281
12292
  payment_mode_id: this.paymentModeId ?? shop.settings?.defaultPaymentModeId,
12282
- coupons: this.coupons,
12293
+ coupons: this.coupons.map((c) => c.code),
12283
12294
  donations: [],
12284
12295
  affiliate: {},
12285
- total: this.totalPriceCents
12296
+ total: this.amountToPayCents
12286
12297
  };
12287
12298
  },
12288
12299
  get totalFormatted() {
@@ -12301,11 +12312,16 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
12301
12312
  addItems(items) {
12302
12313
  items.forEach((item) => this.addItem(item));
12303
12314
  },
12304
- addCoupon(token) {
12305
- if (!this.coupons.includes(token)) this.coupons.push(token);
12315
+ addCoupon(item) {
12316
+ const coupon = {
12317
+ ...item,
12318
+ code: item.code.toUpperCase()
12319
+ };
12320
+ if (!this.coupons.some((c) => c.code === coupon.code)) this.coupons.push(coupon);
12306
12321
  },
12307
- removeCoupon(token) {
12308
- const index = this.coupons.indexOf(token);
12322
+ removeCoupon(code) {
12323
+ const upper = code.toUpperCase();
12324
+ const index = this.coupons.findIndex((c) => c.code === upper);
12309
12325
  if (index > -1) this.coupons.splice(index, 1);
12310
12326
  },
12311
12327
  clearCoupons() {
@@ -14924,8 +14940,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
14924
14940
  }
14925
14941
  function createDisplayCart(baseCart, apiItems) {
14926
14942
  const displayCart = createCart();
14927
- const appliedCoupons = /* @__PURE__ */ new Set();
14928
- baseCart.coupons.forEach((coupon) => displayCart.addCoupon(coupon));
14943
+ const echoed = new Set(apiItems.map((i) => i.attributes.coupon).filter(Boolean).map((c) => c.toUpperCase()));
14944
+ baseCart.coupons.forEach((coupon) => displayCart.addCoupon({
14945
+ ...coupon,
14946
+ applied: coupon.kind !== "actionToken" || echoed.has(coupon.code)
14947
+ }));
14929
14948
  apiItems.forEach((apiItem) => {
14930
14949
  const attrs = apiItem.attributes;
14931
14950
  const scalePriceId = getScalePriceId(attrs);
@@ -14937,16 +14956,9 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
14937
14956
  });
14938
14957
  return;
14939
14958
  }
14940
- if (attrs.coupon) {
14941
- displayCart.addCoupon(attrs.coupon);
14942
- appliedCoupons.add(attrs.coupon);
14943
- }
14944
14959
  displayCart.addItem(createDisplayCartItem(itemInBaseCart, attrs));
14945
14960
  });
14946
- return {
14947
- cart: displayCart,
14948
- appliedCoupons
14949
- };
14961
+ return displayCart;
14950
14962
  }
14951
14963
  function createDisplayCartItem(cartItem, attrs) {
14952
14964
  const quantity = resolveApiQuantity(attrs);
@@ -14976,13 +14988,6 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
14976
14988
  set displayCart(value) {
14977
14989
  set(this.#displayCart, value, true);
14978
14990
  }
14979
- #appliedCoupons = /* @__PURE__ */ state(proxy(/* @__PURE__ */ new Set()));
14980
- get appliedCoupons() {
14981
- return get$2(this.#appliedCoupons);
14982
- }
14983
- set appliedCoupons(value) {
14984
- set(this.#appliedCoupons, value, true);
14985
- }
14986
14991
  #preview = /* @__PURE__ */ state(false);
14987
14992
  get preview() {
14988
14993
  return get$2(this.#preview);
@@ -14991,7 +14996,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
14991
14996
  set(this.#preview, value, true);
14992
14997
  }
14993
14998
  get totalPriceCents() {
14994
- return this.displayCart?.totalPriceCents ?? 0;
14999
+ return this.displayCart?.amountToPayCents ?? 0;
14995
15000
  }
14996
15001
  get subtotalPriceCents() {
14997
15002
  return shop.cart?.totalPriceCents ?? 0;
@@ -15011,14 +15016,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15011
15016
  items,
15012
15017
  coupons
15013
15018
  });
15014
- if (!response || "error" in response) {
15015
- if (response && "error" in response) console.error("(go-cart) Unable to fetch discounted cart data", response.error);
15016
- this.displayCart = mc;
15019
+ if (response?.data) {
15020
+ this.displayCart = createDisplayCart(mc, response.data.items ?? []);
15017
15021
  return;
15018
15022
  }
15019
- const result = createDisplayCart(mc, response.data.items ?? []);
15020
- this.displayCart = result.cart;
15021
- this.appliedCoupons = result.appliedCoupons;
15023
+ console.error("(go-cart) Unable to fetch discounted cart data", response?.error);
15024
+ this.displayCart = mc;
15022
15025
  } catch (error) {
15023
15026
  console.error("(go-cart) Unable to fetch discounted cart data", error);
15024
15027
  this.displayCart = mc;
@@ -15448,7 +15451,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15448
15451
  var node = first_child(fragment);
15449
15452
  var consequent_1 = ($$anchor) => {
15450
15453
  var ol = root_2$8();
15451
- each(ol, 20, () => get$2(details).displayCart.coupons, (coupon) => coupon, ($$anchor, coupon) => {
15454
+ each(ol, 21, () => get$2(details).displayCart.coupons, (coupon) => coupon.code, ($$anchor, coupon) => {
15452
15455
  var li = root_1$12();
15453
15456
  let classes;
15454
15457
  var article = child(li);
@@ -15462,7 +15465,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15462
15465
  var button = child(li_2);
15463
15466
  reset(li_2);
15464
15467
  template_effect(($0) => set_attribute(button, "aria-label", $0), [() => shop.t("cart.coupons.remove")]);
15465
- delegated("click", button, () => shop.cart?.removeCoupon(coupon));
15468
+ delegated("click", button, () => shop.cart?.removeCoupon(get$2(coupon).code));
15466
15469
  append($$anchor, li_2);
15467
15470
  };
15468
15471
  if_block(node_1, ($$render) => {
@@ -15471,10 +15474,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15471
15474
  reset(ul);
15472
15475
  reset(article);
15473
15476
  reset(li);
15474
- template_effect(($0) => {
15475
- classes = set_class(li, 1, "go-cart-coupon", null, classes, $0);
15476
- set_text(text, coupon);
15477
- }, [() => ({ "go-cart-coupon-inactive": !get$2(details).appliedCoupons.has(coupon) })]);
15477
+ template_effect(() => {
15478
+ classes = set_class(li, 1, "go-cart-coupon", null, classes, { "go-cart-coupon-inactive": !get$2(coupon).applied });
15479
+ set_text(text, get$2(coupon).code);
15480
+ });
15478
15481
  append($$anchor, li);
15479
15482
  });
15480
15483
  reset(ol);
@@ -15524,7 +15527,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15524
15527
  user_effect(() => {
15525
15528
  if (!shop.cart) return;
15526
15529
  shop.cart.items.map((i) => i.uuid + ":" + i.quantity + ":" + i.time);
15527
- shop.cart.coupons.join("|");
15530
+ shop.cart.coupons.map((c) => c.code).join("|");
15528
15531
  untrack(() => details.calculateDisplayCart());
15529
15532
  });
15530
15533
  async function flushCoupons() {
@@ -15542,6 +15545,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15542
15545
  const innerForm = submit.closest("go-form");
15543
15546
  if (innerForm && $$props.$$host.contains(innerForm)) return;
15544
15547
  const ok = await flushCoupons();
15548
+ if (!ok) return;
15545
15549
  $$props.$$host.dispatchEvent(new CustomEvent("go-submit", {
15546
15550
  detail: { ok },
15547
15551
  bubbles: true,
@@ -15705,13 +15709,27 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15705
15709
  var APPLY_ORDER_DISCOUNT = "TokenActions::ApplyOrderDiscount";
15706
15710
  async function redeem(token) {
15707
15711
  if (!shop.cart) throw new Error("(go-coupon-redemption): cart not found");
15712
+ const cart = shop.cart;
15708
15713
  const couponSale = await shop.asyncFetch(() => shop.getCouponSaleByBarcode(token));
15709
15714
  if (!couponSale?.is_valid) return fail([shop.t("cart.coupon.form.errors.notValid")]);
15710
15715
  if (couponSale.value_action === APPLY_ORDER_DISCOUNT) {
15711
- shop.cart.addCoupon(token);
15716
+ cart.addCoupon({
15717
+ code: token,
15718
+ kind: "actionToken"
15719
+ });
15712
15720
  return { success: true };
15713
- } else if (couponSale.is_voucher_for) return applyVoucher(token, couponSale);
15714
- else return fail([shop.t("cart.coupon.form.errors.notValid")]);
15721
+ }
15722
+ if (couponSale.is_voucher_for) return applyVoucher(token, couponSale);
15723
+ if (couponSale.value_cents && couponSale.value_cents > 0) return applyValueCoupon(token, couponSale.value_cents);
15724
+ return fail([shop.t("cart.coupon.form.errors.notValid")]);
15725
+ }
15726
+ function applyValueCoupon(token, valueCents) {
15727
+ shop.cart.addCoupon({
15728
+ code: token,
15729
+ kind: "valueVoucher",
15730
+ valueCents
15731
+ });
15732
+ return { success: true };
15715
15733
  }
15716
15734
  async function applyVoucher(token, couponSale) {
15717
15735
  const ticket = (await shop.asyncFetch(() => shop.tickets({ "by_ticket_ids[]": [couponSale.is_voucher_for] }))).find((t) => t.id === couponSale.is_voucher_for);
@@ -15721,7 +15739,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15721
15739
  price_cents: 0
15722
15740
  };
15723
15741
  shop.cart.addItem(createCartItem(createUITicket(voucherTicket), { quantity: 1 }));
15724
- shop.cart.addCoupon(token);
15742
+ shop.cart.addCoupon({
15743
+ code: token,
15744
+ kind: "serviceVoucher"
15745
+ });
15725
15746
  return { success: true };
15726
15747
  }
15727
15748
  function fail(errors) {
@@ -32405,262 +32426,19 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
32405
32426
  "coupon"
32406
32427
  ];
32407
32428
  //#endregion
32408
- //#region src/components/ticketSelection/filters/ticket/timeslot.ts
32409
- var filter$11 = {
32410
- name: "ticket:timeslot",
32411
- calendarEndpoint: "tickets",
32412
- apiToken: "time_slot",
32413
- requires: [{
32414
- kind: "tsd",
32415
- field: "selectedDate"
32416
- }, {
32417
- kind: "tsd",
32418
- field: "selectedTimeslot"
32419
- }],
32420
- isCalendarVisible: () => true,
32421
- isTimeslotsVisible: (tsd) => Boolean(tsd.selectedDate),
32422
- isTicketsVisible: (tsd) => Boolean(tsd.selectedDate && tsd.selectedTimeslot),
32423
- async loadTimeslots(tsd) {
32424
- if (!tsd?.selectedDate) return;
32425
- const { quotas } = await shop.asyncFetch(() => shop.ticketsAndQuotas({
32426
- by_bookable: true,
32427
- valid_at: tsd.selectedDate.toString(),
32428
- by_ticket_type: "time_slot",
32429
- "by_museum_ids[]": tsd.museumIds,
32430
- "by_exhibition_ids[]": tsd.exhibitionIds,
32431
- "by_ticket_ids[]": tsd.ticketIds,
32432
- "by_ticket_group_ids[]": tsd.ticketGroupIds
32433
- }));
32434
- shop.capacityManager.addQuotas(quotas);
32435
- },
32436
- async loadProducts(segment) {
32437
- const tsd = segment.ticketSelectionDetails;
32438
- if (!tsd?.selectedDate || !tsd.selectedTimeslot) return;
32439
- const { tickets, quotas } = await shop.asyncFetch(() => shop.ticketsAndQuotas({
32440
- by_bookable: true,
32441
- valid_at: tsd.selectedDate.toString(),
32442
- by_ticket_type: "time_slot",
32443
- "by_museum_ids[]": segment.museumIds ?? tsd.museumIds,
32444
- "by_exhibition_ids[]": tsd.exhibitionIds,
32445
- "by_ticket_ids[]": tsd.ticketIds,
32446
- "by_ticket_group_ids[]": segment.ticketGroupIds ?? tsd.ticketGroupIds
32447
- }));
32448
- shop.capacityManager.addQuotas(quotas);
32449
- const uiTickets = initUITimeslotTickets(filterAvailabletickets(tickets, tsd.selectedTime), tsd.selectedTime);
32450
- for (const ticket of uiTickets) segment.preCart.addItem(createCartItem(ticket, { time: tsd.selectedTime }));
32451
- }
32452
- };
32453
- //#endregion
32454
- //#region src/components/ticketSelection/filters/ticket/day.ts
32455
- var filter$10 = {
32456
- name: "ticket:day",
32457
- calendarEndpoint: "tickets",
32458
- apiToken: "normal",
32459
- requires: [{
32460
- kind: "tsd",
32461
- field: "selectedDate"
32462
- }],
32463
- isCalendarVisible: () => true,
32464
- isTimeslotsVisible: () => false,
32465
- isTicketsVisible: (tsd) => Boolean(tsd.selectedDate),
32466
- async loadTimeslots() {},
32467
- async loadProducts(segment) {
32468
- const tsd = segment.ticketSelectionDetails;
32469
- if (!tsd?.selectedDate) return;
32470
- const { tickets, quotas } = await shop.asyncFetch(() => shop.ticketsAndQuotas({
32471
- by_bookable: true,
32472
- valid_at: tsd.selectedDate.toString(),
32473
- "by_ticket_types[]": ["normal"],
32474
- "by_museum_ids[]": segment.museumIds ?? tsd.museumIds,
32475
- "by_exhibition_ids[]": tsd.exhibitionIds,
32476
- "by_ticket_ids[]": tsd.ticketIds,
32477
- "by_ticket_group_ids[]": segment.ticketGroupIds ?? tsd.ticketGroupIds
32478
- }));
32479
- shop.capacityManager.addQuotas(quotas);
32480
- const firstQuota = Object.values(quotas)[0];
32481
- const timeslot = firstQuota ? Object.keys(firstQuota.capacities)[0] : void 0;
32482
- const uiTickets = initUITimeslotTickets(filterAvailabletickets(tickets, timeslot), timeslot);
32483
- for (const ticket of uiTickets) segment.preCart.addItem(createCartItem(ticket, { time: timeslot }));
32484
- }
32485
- };
32486
- //#endregion
32487
- //#region src/components/ticketSelection/filters/ticket/annual.ts
32488
- var filter$9 = {
32489
- name: "ticket:annual",
32490
- calendarEndpoint: null,
32491
- apiToken: "annual",
32492
- requires: [],
32493
- isCalendarVisible: () => false,
32494
- isTimeslotsVisible: () => false,
32495
- isTicketsVisible: () => true,
32496
- async loadTimeslots() {},
32497
- async loadProducts(segment) {
32498
- const tsd = segment.ticketSelectionDetails;
32499
- if (!tsd) return;
32500
- const tickets = await shop.asyncFetch(() => shop.tickets({
32501
- by_bookable: true,
32502
- "by_ticket_types[]": ["annual"],
32503
- "by_ticket_ids[]": tsd.ticketIds,
32504
- "by_ticket_group_ids[]": segment.ticketGroupIds ?? tsd.ticketGroupIds
32505
- }));
32506
- for (const t of Object.values(tickets)) segment.preCart.addItem(createCartItem(createUITicket(t)));
32507
- }
32508
- };
32509
- //#endregion
32510
- //#region src/components/ticketSelection/filters/event/admission.ts
32511
- var filter$8 = {
32512
- name: "event:admission",
32513
- calendarEndpoint: "events",
32514
- requires: [{
32515
- kind: "tsd",
32516
- field: "eventIds"
32517
- }, {
32518
- kind: "tsd",
32519
- field: "selectedDate"
32520
- }],
32521
- isCalendarVisible: () => true,
32522
- isTimeslotsVisible: (tsd) => Boolean(tsd.selectedDate),
32523
- isTicketsVisible: (tsd) => Boolean(tsd.selectedDate && tsd.selectedTimeslot),
32524
- async loadTimeslots(tsd) {
32525
- if (!tsd?.eventIds?.length || !tsd.selectedDate) return;
32526
- const event = await shop.asyncFetch(() => shop.getEvent(tsd.eventIds[0]));
32527
- if (!event.tickets?.length) return;
32528
- const { quotas } = await shop.asyncFetch(() => shop.ticketsAndQuotas({
32529
- "by_ticket_ids[]": event.tickets,
32530
- by_bookable: true,
32531
- valid_at: tsd.selectedDate.toString()
32532
- }));
32533
- shop.capacityManager.addQuotas(quotas);
32534
- },
32535
- async loadProducts(segment) {
32536
- const tsd = segment.ticketSelectionDetails;
32537
- if (!tsd?.eventIds?.length || !tsd.selectedDate) return;
32538
- if (!(await shop.asyncFetch(() => shop.getEvent(tsd.eventIds[0]))).tickets?.length) return;
32539
- const { tickets, quotas } = await shop.asyncFetch(() => shop.ticketsAndQuotas({
32540
- by_bookable: true,
32541
- valid_at: tsd.selectedDate.toString(),
32542
- date_id: segment.dateId
32543
- }));
32544
- shop.capacityManager.addQuotas(quotas);
32545
- const uiTickets = initUITimeslotTickets(filterAvailabletickets(tickets, tsd.selectedTime), tsd.selectedTime);
32546
- for (const ticket of uiTickets) segment.preCart.addItem(createCartItem(ticket, { time: tsd.selectedTime }));
32547
- }
32548
- };
32549
- //#endregion
32550
- //#region src/components/ticketSelection/filters/event/admission-day.ts
32551
- var filter$7 = {
32552
- name: "event:admission:day",
32553
- calendarEndpoint: "events",
32554
- requires: [{
32555
- kind: "tsd",
32556
- field: "eventIds"
32557
- }, {
32558
- kind: "tsd",
32559
- field: "selectedDate"
32560
- }],
32561
- isCalendarVisible: () => true,
32562
- isTimeslotsVisible: () => false,
32563
- isTicketsVisible: (tsd) => Boolean(tsd.selectedDate),
32564
- async loadTimeslots() {},
32565
- async loadProducts(segment) {
32566
- const tsd = segment.ticketSelectionDetails;
32567
- if (!tsd?.eventIds?.length || !tsd.selectedDate) return;
32568
- const event = await shop.asyncFetch(() => shop.getEvent(tsd.eventIds[0]));
32569
- if (!event.tickets?.length) return;
32570
- const { tickets, quotas } = await shop.asyncFetch(() => shop.ticketsAndQuotas({
32571
- "by_ticket_ids[]": event.tickets,
32572
- "by_ticket_types[]": ["normal"],
32573
- by_bookable: true,
32574
- valid_at: tsd.selectedDate.toString()
32575
- }));
32576
- shop.capacityManager.addQuotas(quotas);
32577
- const firstQuota = Object.values(quotas)[0];
32578
- const time = firstQuota ? Object.keys(firstQuota.capacities)[0] : void 0;
32579
- const uiTickets = initUITimeslotTickets(filterAvailabletickets(tickets, time), time);
32580
- for (const t of uiTickets) segment.preCart.addItem(createCartItem(t, { time }));
32581
- }
32582
- };
32583
- //#endregion
32584
- //#region src/components/ticketSelection/filters/event/admission-timeslot.ts
32585
- var filter$6 = {
32586
- name: "event:admission:timeslot",
32587
- calendarEndpoint: "events",
32588
- requires: [
32589
- {
32590
- kind: "tsd",
32591
- field: "eventIds"
32592
- },
32593
- {
32594
- kind: "tsd",
32595
- field: "selectedDate"
32596
- },
32597
- {
32598
- kind: "tsd",
32599
- field: "selectedTimeslot"
32600
- }
32601
- ],
32602
- isCalendarVisible: () => true,
32603
- isTimeslotsVisible: (tsd) => Boolean(tsd.selectedDate),
32604
- isTicketsVisible: (tsd) => Boolean(tsd.selectedDate && tsd.selectedTimeslot),
32605
- async loadTimeslots(tsd) {
32606
- if (!tsd?.eventIds?.length || !tsd.selectedDate) return;
32607
- const event = await shop.asyncFetch(() => shop.getEvent(tsd.eventIds[0]));
32608
- if (!event.tickets?.length) return;
32609
- const { quotas } = await shop.asyncFetch(() => shop.ticketsAndQuotas({
32610
- "by_ticket_ids[]": event.tickets,
32611
- by_ticket_type: "time_slot",
32612
- by_bookable: true,
32613
- valid_at: tsd.selectedDate.toString()
32614
- }));
32615
- shop.capacityManager.addQuotas(quotas);
32616
- },
32617
- async loadProducts(segment) {
32618
- const tsd = segment.ticketSelectionDetails;
32619
- if (!tsd?.eventIds?.length || !tsd.selectedDate || !tsd.selectedTimeslot) return;
32620
- const event = await shop.asyncFetch(() => shop.getEvent(tsd.eventIds[0]));
32621
- if (!event.tickets?.length) return;
32622
- const { tickets, quotas } = await shop.asyncFetch(() => shop.ticketsAndQuotas({
32623
- "by_ticket_ids[]": event.tickets,
32624
- by_ticket_type: "time_slot",
32625
- by_bookable: true,
32626
- valid_at: tsd.selectedDate.toString()
32627
- }));
32628
- shop.capacityManager.addQuotas(quotas);
32629
- const uiTickets = initUITimeslotTickets(filterAvailabletickets(tickets, tsd.selectedTime), tsd.selectedTime);
32630
- for (const t of uiTickets) segment.preCart.addItem(createCartItem(t, { time: tsd.selectedTime }));
32631
- }
32632
- };
32633
- //#endregion
32634
- //#region src/components/ticketSelection/filters/event/price.ts
32635
- var filter$5 = {
32636
- name: "event:price",
32637
- calendarEndpoint: "events",
32638
- requires: [{
32639
- kind: "tsd",
32640
- field: "eventIds"
32641
- }, {
32642
- kind: "segment",
32643
- field: "dateId"
32644
- }],
32645
- isCalendarVisible: () => false,
32646
- isTimeslotsVisible: () => false,
32647
- isTicketsVisible: (tsd) => Boolean(tsd.eventIds?.length),
32648
- loadTimeslots: async () => {},
32649
- async loadProducts(segment) {
32650
- const tsd = segment.ticketSelectionDetails;
32651
- if (!tsd?.eventIds?.length || segment.dateId === void 0) return;
32652
- const date = await shop.asyncFetch(() => shop.getEventDetailsOnDate(tsd.eventIds[0], segment.dateId));
32653
- if (!date.prices?.length) return;
32654
- for (const price of date.prices) {
32655
- const ticket = createUIEventTicket(price, date.id, { event_title: date.event_title });
32656
- segment.preCart.addItem(createCartItem(ticket, { time: date.start_time }));
32657
- }
32658
- if (date.seats) shop.capacityManager.addSeats(date.id, date.seats);
32659
- }
32660
- };
32661
- //#endregion
32662
32429
  //#region src/components/ticketSelection/filters/_helpers.ts
32663
32430
  var TWO_HOURS_MS = 7200 * 1e3;
32431
+ /**
32432
+ * Load quotas fetched by a filter's loadTimeslots into the shared quota store and
32433
+ * record which ticket ids this selection loaded for its picker. timeslotsOn() reads
32434
+ * tsd.timeslotTicketIds, so only these tickets' slots render — a foreign
32435
+ * segment/selection sharing the store can't leak in. Appends, so multiple active
32436
+ * filters accumulate within one render pass (<go-timeslots> resets the list first).
32437
+ */
32438
+ function loadPickerQuotas(tsd, quotas) {
32439
+ shop.capacityManager.addQuotas(quotas);
32440
+ tsd.timeslotTicketIds = [...tsd.timeslotTicketIds, ...Object.values(quotas).flatMap((q) => q.ticket_ids)];
32441
+ }
32664
32442
  function filterDatesInWindow(dates, selectedDate, selectedTime) {
32665
32443
  const selectedMs = Date.parse(selectedTime);
32666
32444
  return dates.filter((d) => {
@@ -32680,18 +32458,251 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
32680
32458
  "by_ticket_ids[]": tsd.ticketIds,
32681
32459
  "by_ticket_group_ids[]": tsd.ticketGroupIds
32682
32460
  }));
32683
- shop.capacityManager.addQuotas(quotas);
32461
+ loadPickerQuotas(tsd, quotas);
32684
32462
  }
32685
32463
  //#endregion
32686
32464
  //#region src/components/ticketSelection/filters/registry.ts
32687
32465
  var REGISTRY = {
32688
- "ticket:timeslot": filter$11,
32689
- "ticket:day": filter$10,
32690
- "ticket:annual": filter$9,
32691
- "event:admission": filter$8,
32692
- "event:admission:day": filter$7,
32693
- "event:admission:timeslot": filter$6,
32694
- "event:price": filter$5,
32466
+ "ticket:timeslot": {
32467
+ name: "ticket:timeslot",
32468
+ calendarEndpoint: "tickets",
32469
+ apiToken: "time_slot",
32470
+ requires: [{
32471
+ kind: "tsd",
32472
+ field: "selectedDate"
32473
+ }, {
32474
+ kind: "tsd",
32475
+ field: "selectedTimeslot"
32476
+ }],
32477
+ isCalendarVisible: () => true,
32478
+ isTimeslotsVisible: (tsd) => Boolean(tsd.selectedDate),
32479
+ isTicketsVisible: (tsd) => Boolean(tsd.selectedDate && tsd.selectedTimeslot),
32480
+ async loadTimeslots(tsd) {
32481
+ if (!tsd?.selectedDate) return;
32482
+ const { quotas } = await shop.asyncFetch(() => shop.ticketsAndQuotas({
32483
+ by_bookable: true,
32484
+ valid_at: tsd.selectedDate.toString(),
32485
+ by_ticket_type: "time_slot",
32486
+ "by_museum_ids[]": tsd.museumIds,
32487
+ "by_exhibition_ids[]": tsd.exhibitionIds,
32488
+ "by_ticket_ids[]": tsd.ticketIds,
32489
+ "by_ticket_group_ids[]": tsd.ticketGroupIds
32490
+ }));
32491
+ loadPickerQuotas(tsd, quotas);
32492
+ },
32493
+ async loadProducts(segment) {
32494
+ const tsd = segment.ticketSelectionDetails;
32495
+ if (!tsd?.selectedDate || !tsd.selectedTimeslot) return;
32496
+ const { tickets, quotas } = await shop.asyncFetch(() => shop.ticketsAndQuotas({
32497
+ by_bookable: true,
32498
+ valid_at: tsd.selectedDate.toString(),
32499
+ by_ticket_type: "time_slot",
32500
+ "by_museum_ids[]": segment.museumIds ?? tsd.museumIds,
32501
+ "by_exhibition_ids[]": tsd.exhibitionIds,
32502
+ "by_ticket_ids[]": tsd.ticketIds,
32503
+ "by_ticket_group_ids[]": segment.ticketGroupIds ?? tsd.ticketGroupIds
32504
+ }));
32505
+ shop.capacityManager.addQuotas(quotas);
32506
+ const uiTickets = initUITimeslotTickets(filterAvailabletickets(tickets, tsd.selectedTime), tsd.selectedTime);
32507
+ for (const ticket of uiTickets) segment.preCart.addItem(createCartItem(ticket, { time: tsd.selectedTime }));
32508
+ }
32509
+ },
32510
+ "ticket:day": {
32511
+ name: "ticket:day",
32512
+ calendarEndpoint: "tickets",
32513
+ apiToken: "normal",
32514
+ requires: [{
32515
+ kind: "tsd",
32516
+ field: "selectedDate"
32517
+ }],
32518
+ isCalendarVisible: () => true,
32519
+ isTimeslotsVisible: () => false,
32520
+ isTicketsVisible: (tsd) => Boolean(tsd.selectedDate),
32521
+ async loadTimeslots() {},
32522
+ async loadProducts(segment) {
32523
+ const tsd = segment.ticketSelectionDetails;
32524
+ if (!tsd?.selectedDate) return;
32525
+ const { tickets, quotas } = await shop.asyncFetch(() => shop.ticketsAndQuotas({
32526
+ by_bookable: true,
32527
+ valid_at: tsd.selectedDate.toString(),
32528
+ "by_ticket_types[]": ["normal"],
32529
+ "by_museum_ids[]": segment.museumIds ?? tsd.museumIds,
32530
+ "by_exhibition_ids[]": tsd.exhibitionIds,
32531
+ "by_ticket_ids[]": tsd.ticketIds,
32532
+ "by_ticket_group_ids[]": segment.ticketGroupIds ?? tsd.ticketGroupIds
32533
+ }));
32534
+ shop.capacityManager.addQuotas(quotas);
32535
+ const firstQuota = Object.values(quotas)[0];
32536
+ const timeslot = firstQuota ? Object.keys(firstQuota.capacities)[0] : void 0;
32537
+ const uiTickets = initUITimeslotTickets(filterAvailabletickets(tickets, timeslot), timeslot);
32538
+ for (const ticket of uiTickets) segment.preCart.addItem(createCartItem(ticket, { time: timeslot }));
32539
+ }
32540
+ },
32541
+ "ticket:annual": {
32542
+ name: "ticket:annual",
32543
+ calendarEndpoint: null,
32544
+ apiToken: "annual",
32545
+ requires: [],
32546
+ isCalendarVisible: () => false,
32547
+ isTimeslotsVisible: () => false,
32548
+ isTicketsVisible: () => true,
32549
+ async loadTimeslots() {},
32550
+ async loadProducts(segment) {
32551
+ const tsd = segment.ticketSelectionDetails;
32552
+ if (!tsd) return;
32553
+ const tickets = await shop.asyncFetch(() => shop.tickets({
32554
+ by_bookable: true,
32555
+ "by_ticket_types[]": ["annual"],
32556
+ "by_ticket_ids[]": tsd.ticketIds,
32557
+ "by_ticket_group_ids[]": segment.ticketGroupIds ?? tsd.ticketGroupIds
32558
+ }));
32559
+ for (const t of Object.values(tickets)) segment.preCart.addItem(createCartItem(createUITicket(t)));
32560
+ }
32561
+ },
32562
+ "event:admission": {
32563
+ name: "event:admission",
32564
+ calendarEndpoint: "events",
32565
+ requires: [{
32566
+ kind: "tsd",
32567
+ field: "eventIds"
32568
+ }, {
32569
+ kind: "tsd",
32570
+ field: "selectedDate"
32571
+ }],
32572
+ isCalendarVisible: () => true,
32573
+ isTimeslotsVisible: (tsd) => Boolean(tsd.selectedDate),
32574
+ isTicketsVisible: (tsd) => Boolean(tsd.selectedDate && tsd.selectedTimeslot),
32575
+ async loadTimeslots(tsd) {
32576
+ if (!tsd?.eventIds?.length || !tsd.selectedDate) return;
32577
+ const event = await shop.asyncFetch(() => shop.getEvent(tsd.eventIds[0]));
32578
+ if (!event.tickets?.length) return;
32579
+ const { quotas } = await shop.asyncFetch(() => shop.ticketsAndQuotas({
32580
+ "by_ticket_ids[]": event.tickets,
32581
+ by_bookable: true,
32582
+ valid_at: tsd.selectedDate.toString()
32583
+ }));
32584
+ loadPickerQuotas(tsd, quotas);
32585
+ },
32586
+ async loadProducts(segment) {
32587
+ const tsd = segment.ticketSelectionDetails;
32588
+ if (!tsd?.eventIds?.length || !tsd.selectedDate) return;
32589
+ if (!(await shop.asyncFetch(() => shop.getEvent(tsd.eventIds[0]))).tickets?.length) return;
32590
+ const { tickets, quotas } = await shop.asyncFetch(() => shop.ticketsAndQuotas({
32591
+ by_bookable: true,
32592
+ valid_at: tsd.selectedDate.toString(),
32593
+ date_id: segment.dateId
32594
+ }));
32595
+ shop.capacityManager.addQuotas(quotas);
32596
+ const uiTickets = initUITimeslotTickets(filterAvailabletickets(tickets, tsd.selectedTime), tsd.selectedTime);
32597
+ for (const ticket of uiTickets) segment.preCart.addItem(createCartItem(ticket, { time: tsd.selectedTime }));
32598
+ }
32599
+ },
32600
+ "event:admission:day": {
32601
+ name: "event:admission:day",
32602
+ calendarEndpoint: "events",
32603
+ requires: [{
32604
+ kind: "tsd",
32605
+ field: "eventIds"
32606
+ }, {
32607
+ kind: "tsd",
32608
+ field: "selectedDate"
32609
+ }],
32610
+ isCalendarVisible: () => true,
32611
+ isTimeslotsVisible: () => false,
32612
+ isTicketsVisible: (tsd) => Boolean(tsd.selectedDate),
32613
+ async loadTimeslots() {},
32614
+ async loadProducts(segment) {
32615
+ const tsd = segment.ticketSelectionDetails;
32616
+ if (!tsd?.eventIds?.length || !tsd.selectedDate) return;
32617
+ const event = await shop.asyncFetch(() => shop.getEvent(tsd.eventIds[0]));
32618
+ if (!event.tickets?.length) return;
32619
+ const { tickets, quotas } = await shop.asyncFetch(() => shop.ticketsAndQuotas({
32620
+ "by_ticket_ids[]": event.tickets,
32621
+ "by_ticket_types[]": ["normal"],
32622
+ by_bookable: true,
32623
+ valid_at: tsd.selectedDate.toString()
32624
+ }));
32625
+ shop.capacityManager.addQuotas(quotas);
32626
+ const firstQuota = Object.values(quotas)[0];
32627
+ const time = firstQuota ? Object.keys(firstQuota.capacities)[0] : void 0;
32628
+ const uiTickets = initUITimeslotTickets(filterAvailabletickets(tickets, time), time);
32629
+ for (const t of uiTickets) segment.preCart.addItem(createCartItem(t, { time }));
32630
+ }
32631
+ },
32632
+ "event:admission:timeslot": {
32633
+ name: "event:admission:timeslot",
32634
+ calendarEndpoint: "events",
32635
+ requires: [
32636
+ {
32637
+ kind: "tsd",
32638
+ field: "eventIds"
32639
+ },
32640
+ {
32641
+ kind: "tsd",
32642
+ field: "selectedDate"
32643
+ },
32644
+ {
32645
+ kind: "tsd",
32646
+ field: "selectedTimeslot"
32647
+ }
32648
+ ],
32649
+ isCalendarVisible: () => true,
32650
+ isTimeslotsVisible: (tsd) => Boolean(tsd.selectedDate),
32651
+ isTicketsVisible: (tsd) => Boolean(tsd.selectedDate && tsd.selectedTimeslot),
32652
+ async loadTimeslots(tsd) {
32653
+ if (!tsd?.eventIds?.length || !tsd.selectedDate) return;
32654
+ const event = await shop.asyncFetch(() => shop.getEvent(tsd.eventIds[0]));
32655
+ if (!event.tickets?.length) return;
32656
+ const { quotas } = await shop.asyncFetch(() => shop.ticketsAndQuotas({
32657
+ "by_ticket_ids[]": event.tickets,
32658
+ by_ticket_type: "time_slot",
32659
+ by_bookable: true,
32660
+ valid_at: tsd.selectedDate.toString()
32661
+ }));
32662
+ loadPickerQuotas(tsd, quotas);
32663
+ },
32664
+ async loadProducts(segment) {
32665
+ const tsd = segment.ticketSelectionDetails;
32666
+ if (!tsd?.eventIds?.length || !tsd.selectedDate || !tsd.selectedTimeslot) return;
32667
+ const event = await shop.asyncFetch(() => shop.getEvent(tsd.eventIds[0]));
32668
+ if (!event.tickets?.length) return;
32669
+ const { tickets, quotas } = await shop.asyncFetch(() => shop.ticketsAndQuotas({
32670
+ "by_ticket_ids[]": event.tickets,
32671
+ by_ticket_type: "time_slot",
32672
+ by_bookable: true,
32673
+ valid_at: tsd.selectedDate.toString()
32674
+ }));
32675
+ shop.capacityManager.addQuotas(quotas);
32676
+ const uiTickets = initUITimeslotTickets(filterAvailabletickets(tickets, tsd.selectedTime), tsd.selectedTime);
32677
+ for (const t of uiTickets) segment.preCart.addItem(createCartItem(t, { time: tsd.selectedTime }));
32678
+ }
32679
+ },
32680
+ "event:price": {
32681
+ name: "event:price",
32682
+ calendarEndpoint: "events",
32683
+ requires: [{
32684
+ kind: "tsd",
32685
+ field: "eventIds"
32686
+ }, {
32687
+ kind: "segment",
32688
+ field: "dateId"
32689
+ }],
32690
+ isCalendarVisible: () => false,
32691
+ isTimeslotsVisible: () => false,
32692
+ isTicketsVisible: (tsd) => Boolean(tsd.eventIds?.length),
32693
+ loadTimeslots: async () => {},
32694
+ async loadProducts(segment) {
32695
+ const tsd = segment.ticketSelectionDetails;
32696
+ if (!tsd?.eventIds?.length || segment.dateId === void 0) return;
32697
+ const date = await shop.asyncFetch(() => shop.getEventDetailsOnDate(tsd.eventIds[0], segment.dateId));
32698
+ if (!date.prices?.length) return;
32699
+ for (const price of date.prices) {
32700
+ const ticket = createUIEventTicket(price, date.id, { event_title: date.event_title });
32701
+ segment.preCart.addItem(createCartItem(ticket, { time: date.start_time }));
32702
+ }
32703
+ if (date.seats) shop.capacityManager.addSeats(date.id, date.seats);
32704
+ }
32705
+ },
32695
32706
  "events:admission": {
32696
32707
  name: "events:admission",
32697
32708
  calendarEndpoint: "events",
@@ -32942,6 +32953,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
32942
32953
  set selectedTimeslot(value) {
32943
32954
  set(this.#selectedTimeslot, value, true);
32944
32955
  }
32956
+ timeslotTicketIds = [];
32945
32957
  #selectedTime = /* @__PURE__ */ user_derived(() => this.selectedTimeslot);
32946
32958
  get selectedTime() {
32947
32959
  return get$2(this.#selectedTime);
@@ -36322,7 +36334,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
36322
36334
  this.timeslots = [];
36323
36335
  return;
36324
36336
  }
36325
- this.timeslots = shop.capacityManager.quotaManager.timeslotsOn(date).map((x) => ({
36337
+ this.timeslots = shop.capacityManager.quotaManager.timeslotsOn(date, this.tsd?.timeslotTicketIds).map((x) => ({
36326
36338
  ...x,
36327
36339
  startAt: x.timeSlot,
36328
36340
  timeFormatted: x.timeSlot.substring(11, 16),
@@ -36344,6 +36356,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
36344
36356
  const filters = tsd.filters;
36345
36357
  const date = tsd.selectedDate;
36346
36358
  untrack(async () => {
36359
+ tsd.timeslotTicketIds = [];
36347
36360
  if (filters?.length && date) await Promise.all(filters.map((f) => getFilter(f).loadTimeslots(tsd)));
36348
36361
  details.recalculateCapacities();
36349
36362
  });