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