@gomusdev/web-components 4.13.0 → 4.14.0

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.
@@ -11112,9 +11112,6 @@ function $d07e34cce18680fd$export$b21e0b124e224484(date, time) {
11112
11112
  if (time) ({hour: hour, minute: minute, second: second, millisecond: millisecond} = time);
11113
11113
  return new $2aaf608024c21ca1$export$ca871e8dbb80966f(date.calendar, date.era, date.year, date.month, date.day, hour, minute, second, millisecond);
11114
11114
  }
11115
- function $d07e34cce18680fd$export$d33f79e3ffc3dc83(dateTime) {
11116
- return new $2aaf608024c21ca1$export$680ea196effce5f(dateTime.hour, dateTime.minute, dateTime.second, dateTime.millisecond);
11117
- }
11118
11115
  function $d07e34cce18680fd$export$b4a036af3fc0b032(date, calendar) {
11119
11116
  if ($ad063034c8620db8$export$dbc69fd56b53d5e(date.calendar, calendar)) return date;
11120
11117
  let calendarDate = calendar.fromJulianDay(date.calendar.toJulianDay(date));
@@ -11272,14 +11269,6 @@ function $435a2ceaa8778ed8$var$addTimeFields(time, duration) {
11272
11269
  time.millisecond += duration.milliseconds || 0;
11273
11270
  return $435a2ceaa8778ed8$var$balanceTime(time);
11274
11271
  }
11275
- function $435a2ceaa8778ed8$export$7ed87b6bc2506470(time, duration) {
11276
- let res = time.copy();
11277
- $435a2ceaa8778ed8$var$addTimeFields(res, duration);
11278
- return res;
11279
- }
11280
- function $435a2ceaa8778ed8$export$fe34d3a381cd7501(time, duration) {
11281
- return $435a2ceaa8778ed8$export$7ed87b6bc2506470(time, $435a2ceaa8778ed8$export$3e2544e88a25bff8(duration));
11282
- }
11283
11272
  function $435a2ceaa8778ed8$export$d52ced6badfb9a4c(value, field, amount, options) {
11284
11273
  let mutable = value.copy();
11285
11274
  switch (field) {
@@ -11561,46 +11550,6 @@ var $2aaf608024c21ca1$export$99faa760c7908e4f = class $2aaf608024c21ca1$export$9
11561
11550
  return $ad063034c8620db8$export$68781ddf31c0090f(this, b);
11562
11551
  }
11563
11552
  };
11564
- var $2aaf608024c21ca1$export$680ea196effce5f = class $2aaf608024c21ca1$export$680ea196effce5f {
11565
- #type;
11566
- constructor(hour = 0, minute = 0, second = 0, millisecond = 0) {
11567
- this.hour = hour;
11568
- this.minute = minute;
11569
- this.second = second;
11570
- this.millisecond = millisecond;
11571
- $435a2ceaa8778ed8$export$7555de1e070510cb(this);
11572
- }
11573
- /** Returns a copy of this time. */ copy() {
11574
- return new $2aaf608024c21ca1$export$680ea196effce5f(this.hour, this.minute, this.second, this.millisecond);
11575
- }
11576
- /** Returns a new `Time` with the given duration added to it. */ add(duration) {
11577
- return $435a2ceaa8778ed8$export$7ed87b6bc2506470(this, duration);
11578
- }
11579
- /** Returns a new `Time` with the given duration subtracted from it. */ subtract(duration) {
11580
- return $435a2ceaa8778ed8$export$fe34d3a381cd7501(this, duration);
11581
- }
11582
- /**
11583
- * Returns a new `Time` with the given fields set to the provided values. Other fields will be
11584
- * constrained accordingly.
11585
- */ set(fields) {
11586
- return $435a2ceaa8778ed8$export$e5d5e1c1822b6e56(this, fields);
11587
- }
11588
- /**
11589
- * Returns a new `Time` with the given field adjusted by a specified amount.
11590
- * When the resulting value reaches the limits of the field, it wraps around.
11591
- */ cycle(field, amount, options) {
11592
- return $435a2ceaa8778ed8$export$dd02b3e0007dfe28(this, field, amount, options);
11593
- }
11594
- /** Converts the time to an ISO 8601 formatted string. */ toString() {
11595
- return $58246871e4652552$export$f59dee82248f5ad4(this);
11596
- }
11597
- /**
11598
- * Compares this time with another. A negative result indicates that this time is before the given
11599
- * one, and a positive time indicates that it is after.
11600
- */ compare(b) {
11601
- return $ad063034c8620db8$export$c19a80a9721b80f6(this, b);
11602
- }
11603
- };
11604
11553
  var $2aaf608024c21ca1$export$ca871e8dbb80966f = class $2aaf608024c21ca1$export$ca871e8dbb80966f {
11605
11554
  #type;
11606
11555
  constructor(...args) {
@@ -11825,19 +11774,31 @@ function $12a3c853105e5a70$var$getResolvedHourCycle(locale, options) {
11825
11774
  }
11826
11775
  //#endregion
11827
11776
  //#region ../../packages/gomus-types/lib/helpers/utils.ts
11828
- function formatTime(value) {
11829
- return $d07e34cce18680fd$export$d33f79e3ffc3dc83($58246871e4652552$export$5adfdab05168c219(value, "Europe/Berlin")).toString().slice(0, -3);
11777
+ /** Named date presets — the single place defining what each rendering means (WI 151). */
11778
+ var DATE_FORMAT_PRESETS = {
11779
+ dayMonth: {
11780
+ month: "numeric",
11781
+ day: "numeric"
11782
+ },
11783
+ short: {
11784
+ year: "numeric",
11785
+ month: "numeric",
11786
+ day: "numeric"
11787
+ }
11788
+ };
11789
+ function formatTime(value, locale) {
11790
+ const zoned = $58246871e4652552$export$5adfdab05168c219(value, "Europe/Berlin");
11791
+ return new $12a3c853105e5a70$export$ad991b66133851cf(locale, {
11792
+ timeZone: zoned.timeZone,
11793
+ hour: "numeric",
11794
+ minute: "numeric"
11795
+ }).format(zoned.toDate());
11830
11796
  }
11831
- function formatDate(isoDateString, options = {
11832
- weekday: "long",
11833
- year: "numeric",
11834
- month: "long",
11835
- day: "numeric"
11836
- }, locale = "de") {
11797
+ function formatDate(isoDateString, preset, locale) {
11837
11798
  const zoned = $58246871e4652552$export$5adfdab05168c219(isoDateString instanceof Date ? isoDateString.toISOString() : isoDateString, "Europe/Berlin");
11838
11799
  return new $12a3c853105e5a70$export$ad991b66133851cf(locale, {
11839
11800
  timeZone: zoned.timeZone,
11840
- ...options
11801
+ ...DATE_FORMAT_PRESETS[preset]
11841
11802
  }).format(zoned.toDate());
11842
11803
  }
11843
11804
  //#endregion
@@ -13829,7 +13790,13 @@ var Shop = class {
13829
13790
  return "https://" + this.shopDomain;
13830
13791
  }
13831
13792
  get locale() {
13832
- return get$2(this.#data).locale;
13793
+ return get$2(this.#data).locale ?? "de";
13794
+ }
13795
+ formatTime(value) {
13796
+ return formatTime(value, this.locale);
13797
+ }
13798
+ formatDate(value, preset) {
13799
+ return formatDate(value, preset, this.locale);
13833
13800
  }
13834
13801
  get shop() {
13835
13802
  return this.fetchAndCache("/api/v4/shop", "shop", "shop");
@@ -15565,10 +15532,7 @@ function Event$2($$anchor, $$props) {
15565
15532
  template_effect(($0, $1) => {
15566
15533
  set_text(text_2, $0);
15567
15534
  set_text(text_3, $1);
15568
- }, [() => formatDate(cartItem().time, {
15569
- month: "numeric",
15570
- day: "numeric"
15571
- }, shop.locale), () => formatTime(cartItem().time)]);
15535
+ }, [() => shop.formatDate(cartItem().time, "dayMonth"), () => shop.formatTime(cartItem().time)]);
15572
15536
  append($$anchor, fragment_1);
15573
15537
  };
15574
15538
  if_block(node, ($$render) => {
@@ -15627,16 +15591,13 @@ function Ticket($$anchor, $$props) {
15627
15591
  var span_3 = root_1$19();
15628
15592
  var text_3 = child(span_3, true);
15629
15593
  reset(span_3);
15630
- template_effect(($0) => set_text(text_3, $0), [() => formatTime(cartItem().time)]);
15594
+ template_effect(($0) => set_text(text_3, $0), [() => shop.formatTime(cartItem().time)]);
15631
15595
  append($$anchor, span_3);
15632
15596
  };
15633
15597
  if_block(node_2, ($$render) => {
15634
15598
  if (cartItem().product.type === "Ticket" && cartItem().product.subtype === "timeslot") $$render(consequent_1);
15635
15599
  });
15636
- template_effect(($0) => set_text(text_2, $0), [() => formatDate(cartItem().time, {
15637
- month: "numeric",
15638
- day: "numeric"
15639
- }, shop.locale)]);
15600
+ template_effect(($0) => set_text(text_2, $0), [() => shop.formatDate(cartItem().time, "dayMonth")]);
15640
15601
  append($$anchor, fragment_1);
15641
15602
  };
15642
15603
  if_block(node_1, ($$render) => {
@@ -15661,12 +15622,8 @@ function Tour$1($$anchor, $$props) {
15661
15622
  if (!cartItem().time) return null;
15662
15623
  try {
15663
15624
  return {
15664
- date: formatDate(cartItem().time, {
15665
- year: "numeric",
15666
- month: "numeric",
15667
- day: "numeric"
15668
- }, shop.locale),
15669
- time: formatTime(cartItem().time)
15625
+ date: shop.formatDate(cartItem().time, "short"),
15626
+ time: shop.formatTime(cartItem().time)
15670
15627
  };
15671
15628
  } catch {
15672
15629
  return {
@@ -18142,12 +18099,14 @@ create_custom_element(SubRow, {
18142
18099
  * the visible row title: event rows compose it from event_title + time because a
18143
18100
  * flat-price event's price row carries no title (the row IS the event) — naming
18144
18101
  * the control from product.title alone left it unnamed (WI #141).
18102
+ *
18103
+ * Locale comes in as a parameter — shared/ components stay store-agnostic (WI #151).
18145
18104
  */
18146
- function quantityLabel(item) {
18105
+ function quantityLabel(item, locale) {
18147
18106
  const { product } = item;
18148
18107
  return isEventTicket(product) ? [
18149
18108
  product.event_title,
18150
- item.time && formatTime(item.time),
18109
+ item.time && formatTime(item.time, locale),
18151
18110
  product.title
18152
18111
  ].filter(Boolean).join(" - ") : product.title;
18153
18112
  }
@@ -18312,7 +18271,7 @@ function Item$1($$anchor, $$props) {
18312
18271
  var alternate_1 = ($$anchor) => {
18313
18272
  {
18314
18273
  let $0 = /* @__PURE__ */ user_derived(() => displayItem().quantity ?? 0);
18315
- let $1 = /* @__PURE__ */ user_derived(() => quantityLabel(displayItem()));
18274
+ let $1 = /* @__PURE__ */ user_derived(() => quantityLabel(displayItem(), shop.locale));
18316
18275
  QuantityControl($$anchor, {
18317
18276
  get value() {
18318
18277
  return get$2($0);
@@ -35531,12 +35490,32 @@ var FILTER_NAMES = [
35531
35490
  "events:admission:day",
35532
35491
  "events:admission:timeslot",
35533
35492
  "events:price",
35534
- "coupon"
35493
+ "coupon",
35494
+ "tour"
35535
35495
  ];
35536
35496
  //#endregion
35537
35497
  //#region src/components/ticketSelection/filters/_helpers.ts
35538
35498
  var TWO_HOURS_MS = 7200 * 1e3;
35539
35499
  /**
35500
+ * The common tail of every ticket filter's `addToCart`: given the ticket
35501
+ * its loader resolved, build the cart line, reject if the ticket is unavailable
35502
+ * (sold out / unknown → the loader yielded nothing) or the quantity exceeds the
35503
+ * remaining capacity, add the line, and return its uuid. Subtype-agnostic — the
35504
+ * per-filter loader is the only thing that differs.
35505
+ */
35506
+ function addResolvedTicketToCart(ticket, { id, quantity, time }) {
35507
+ if (!(quantity > 0)) throw new Error(`(go.cart.addItem) 'quantity' must be a positive number`);
35508
+ if (!ticket) throw new Error(`(go.cart.addItem) ticket ${id} not available (sold out or unknown)`);
35509
+ const item = createCartItem(ticket, {
35510
+ quantity,
35511
+ time: time ?? ticket.selectedTime
35512
+ });
35513
+ const { max } = shop.capacityManager.capacity(shop.cart, item, createCart());
35514
+ if (quantity > max) throw new Error(`(go.cart.addItem) only ${max} left for ticket ${id}`);
35515
+ shop.cart.addItem(item);
35516
+ return item.uuid;
35517
+ }
35518
+ /**
35540
35519
  * When a segment opts into content attributes (with-content), batch-fetch
35541
35520
  * tickets/content for the given tickets and merge each entry's `content` onto
35542
35521
  * the matching ticket by id (mirrors the legacy `ticket.content = item.content`).
@@ -35596,433 +35575,566 @@ async function loadEventsTimeslots(tsd) {
35596
35575
  loadPickerQuotas(tsd, quotas);
35597
35576
  }
35598
35577
  //#endregion
35599
- //#region src/components/ticketSelection/filters/registry.ts
35600
- var REGISTRY = {
35601
- "ticket:timeslot": {
35602
- name: "ticket:timeslot",
35603
- calendarEndpoint: "tickets",
35604
- apiToken: "time_slot",
35605
- requires: [{
35606
- kind: "tsd",
35607
- field: "selectedDate"
35608
- }, {
35609
- kind: "tsd",
35610
- field: "selectedTimeslot"
35611
- }],
35612
- isCalendarVisible: () => true,
35613
- isTimeslotsVisible: (tsd) => Boolean(tsd.selectedDate),
35614
- isTicketsVisible: (tsd) => Boolean(tsd.selectedDate && tsd.selectedTimeslot),
35615
- async loadTimeslots(tsd) {
35616
- if (!tsd?.selectedDate) return;
35617
- const { quotas } = await shop.asyncFetch(() => shop.ticketsAndQuotas({
35618
- by_bookable: true,
35619
- valid_at: tsd.selectedDate.toString(),
35620
- by_ticket_type: "time_slot",
35621
- "by_museum_ids[]": tsd.museumIds,
35622
- "by_exhibition_ids[]": tsd.exhibitionIds,
35623
- "by_ticket_ids[]": tsd.ticketIds,
35624
- "by_ticket_group_ids[]": tsd.ticketGroupIds
35625
- }));
35626
- loadPickerQuotas(tsd, quotas);
35627
- },
35628
- async loadProducts(segment) {
35629
- const tsd = segment.ticketSelectionDetails;
35630
- if (!tsd?.selectedDate || !tsd.selectedTimeslot) return;
35631
- const { tickets, quotas } = await shop.asyncFetch(() => shop.ticketsAndQuotas({
35632
- by_bookable: true,
35633
- valid_at: tsd.selectedDate.toString(),
35634
- by_ticket_type: "time_slot",
35635
- "by_museum_ids[]": segment.museumIds ?? tsd.museumIds,
35636
- "by_exhibition_ids[]": tsd.exhibitionIds,
35637
- "by_ticket_ids[]": tsd.ticketIds,
35638
- "by_ticket_group_ids[]": segment.ticketGroupIds ?? tsd.ticketGroupIds
35639
- }));
35640
- shop.capacityManager.addQuotas(quotas);
35641
- const uiTickets = initUITimeslotTickets(filterAvailabletickets(tickets, tsd.selectedTime), tsd.selectedTime);
35642
- await enrichTicketsWithContent(segment, uiTickets);
35643
- for (const ticket of uiTickets) segment.preCart.addItem(createCartItem(ticket, { time: tsd.selectedTime }));
35644
- }
35578
+ //#region src/components/ticketSelection/filters/ticket/timeslot.ts
35579
+ async function loadTimeslotTickets(filters, selectedTime) {
35580
+ const { tickets, quotas } = await shop.asyncFetch(() => shop.ticketsAndQuotas({
35581
+ by_bookable: true,
35582
+ by_ticket_type: "time_slot",
35583
+ ...filters
35584
+ }));
35585
+ shop.capacityManager.addQuotas(quotas);
35586
+ return initUITimeslotTickets(filterAvailabletickets(tickets, selectedTime), selectedTime);
35587
+ }
35588
+ var filter$12 = {
35589
+ name: "ticket:timeslot",
35590
+ calendarEndpoint: "tickets",
35591
+ apiToken: "time_slot",
35592
+ requires: [{
35593
+ kind: "tsd",
35594
+ field: "selectedDate"
35595
+ }, {
35596
+ kind: "tsd",
35597
+ field: "selectedTimeslot"
35598
+ }],
35599
+ isCalendarVisible: () => true,
35600
+ isTimeslotsVisible: (tsd) => Boolean(tsd.selectedDate),
35601
+ isTicketsVisible: (tsd) => Boolean(tsd.selectedDate && tsd.selectedTimeslot),
35602
+ async addToCart(options) {
35603
+ const { id, quantity, time } = options;
35604
+ if (!time) throw new Error(`(go.cart.addItem) ticket:timeslot requires a 'time'`);
35605
+ const ticket = (await loadTimeslotTickets({
35606
+ valid_at: time.slice(0, 10),
35607
+ "by_ticket_ids[]": [id]
35608
+ }, time))[0];
35609
+ return addResolvedTicketToCart(ticket, {
35610
+ id,
35611
+ quantity,
35612
+ time
35613
+ });
35645
35614
  },
35646
- "ticket:day": {
35647
- name: "ticket:day",
35648
- calendarEndpoint: "tickets",
35649
- apiToken: "normal",
35650
- requires: [{
35651
- kind: "tsd",
35652
- field: "selectedDate"
35653
- }],
35654
- isCalendarVisible: () => true,
35655
- isTimeslotsVisible: () => false,
35656
- isTicketsVisible: (tsd) => Boolean(tsd.selectedDate),
35657
- async loadTimeslots() {},
35658
- async loadProducts(segment) {
35659
- const tsd = segment.ticketSelectionDetails;
35660
- if (!tsd?.selectedDate) return;
35661
- const { tickets, quotas } = await shop.asyncFetch(() => shop.ticketsAndQuotas({
35662
- by_bookable: true,
35663
- valid_at: tsd.selectedDate.toString(),
35664
- "by_ticket_types[]": ["normal"],
35665
- "by_museum_ids[]": segment.museumIds ?? tsd.museumIds,
35666
- "by_exhibition_ids[]": tsd.exhibitionIds,
35667
- "by_ticket_ids[]": tsd.ticketIds,
35668
- "by_ticket_group_ids[]": segment.ticketGroupIds ?? tsd.ticketGroupIds
35669
- }));
35670
- shop.capacityManager.addQuotas(quotas);
35671
- const uiTickets = initUIDayTickets(tickets);
35672
- await enrichTicketsWithContent(segment, uiTickets);
35673
- for (const ticket of uiTickets) segment.preCart.addItem(createCartItem(ticket, { time: ticket.selectedTime }));
35674
- }
35615
+ async loadTimeslots(tsd) {
35616
+ if (!tsd?.selectedDate) return;
35617
+ const { quotas } = await shop.asyncFetch(() => shop.ticketsAndQuotas({
35618
+ by_bookable: true,
35619
+ valid_at: tsd.selectedDate.toString(),
35620
+ by_ticket_type: "time_slot",
35621
+ "by_museum_ids[]": tsd.museumIds,
35622
+ "by_exhibition_ids[]": tsd.exhibitionIds,
35623
+ "by_ticket_ids[]": tsd.ticketIds,
35624
+ "by_ticket_group_ids[]": tsd.ticketGroupIds
35625
+ }));
35626
+ loadPickerQuotas(tsd, quotas);
35675
35627
  },
35676
- "ticket:annual": {
35677
- name: "ticket:annual",
35678
- calendarEndpoint: null,
35679
- apiToken: "annual",
35680
- requires: [],
35681
- isCalendarVisible: () => false,
35682
- isTimeslotsVisible: () => false,
35683
- isTicketsVisible: () => true,
35684
- async loadTimeslots() {},
35685
- async loadProducts(segment) {
35686
- const tsd = segment.ticketSelectionDetails;
35687
- if (!tsd) return;
35688
- const tickets = await shop.asyncFetch(() => shop.tickets({
35689
- by_bookable: true,
35690
- "by_ticket_types[]": ["annual"],
35691
- "by_ticket_ids[]": tsd.ticketIds,
35692
- "by_ticket_group_ids[]": segment.ticketGroupIds ?? tsd.ticketGroupIds
35693
- }));
35694
- const uiTickets = Object.values(tickets).map((t) => createUITicket(t));
35695
- await enrichTicketsWithContent(segment, uiTickets);
35696
- for (const ticket of uiTickets) segment.preCart.addItem(createCartItem(ticket));
35697
- }
35628
+ async loadProducts(segment) {
35629
+ const tsd = segment.ticketSelectionDetails;
35630
+ if (!tsd?.selectedDate || !tsd.selectedTimeslot) return;
35631
+ const uiTickets = await loadTimeslotTickets({
35632
+ valid_at: tsd.selectedDate.toString(),
35633
+ "by_museum_ids[]": segment.museumIds ?? tsd.museumIds,
35634
+ "by_exhibition_ids[]": tsd.exhibitionIds,
35635
+ "by_ticket_ids[]": tsd.ticketIds,
35636
+ "by_ticket_group_ids[]": segment.ticketGroupIds ?? tsd.ticketGroupIds
35637
+ }, tsd.selectedTimeslot);
35638
+ await enrichTicketsWithContent(segment, uiTickets);
35639
+ for (const ticket of uiTickets) segment.preCart.addItem(createCartItem(ticket, { time: tsd.selectedTime }));
35640
+ }
35641
+ };
35642
+ //#endregion
35643
+ //#region src/components/ticketSelection/filters/ticket/day.ts
35644
+ async function loadDayTickets(filters) {
35645
+ const { tickets, quotas } = await shop.asyncFetch(() => shop.ticketsAndQuotas({
35646
+ by_bookable: true,
35647
+ "by_ticket_types[]": ["normal"],
35648
+ ...filters
35649
+ }));
35650
+ shop.capacityManager.addQuotas(quotas);
35651
+ return initUIDayTickets(tickets);
35652
+ }
35653
+ var filter$11 = {
35654
+ name: "ticket:day",
35655
+ calendarEndpoint: "tickets",
35656
+ apiToken: "normal",
35657
+ requires: [{
35658
+ kind: "tsd",
35659
+ field: "selectedDate"
35660
+ }],
35661
+ isCalendarVisible: () => true,
35662
+ isTimeslotsVisible: () => false,
35663
+ isTicketsVisible: (tsd) => Boolean(tsd.selectedDate),
35664
+ async loadTimeslots() {},
35665
+ async addToCart(options) {
35666
+ const { id, quantity, date } = options;
35667
+ if (!date) throw new Error(`(go.cart.addItem) ticket:day requires a 'date'`);
35668
+ const ticket = (await loadDayTickets({
35669
+ valid_at: date,
35670
+ "by_ticket_ids[]": [id]
35671
+ }))[0];
35672
+ return addResolvedTicketToCart(ticket, {
35673
+ id,
35674
+ quantity
35675
+ });
35676
+ },
35677
+ async loadProducts(segment) {
35678
+ const tsd = segment.ticketSelectionDetails;
35679
+ if (!tsd?.selectedDate) return;
35680
+ const uiTickets = await loadDayTickets({
35681
+ valid_at: tsd.selectedDate.toString(),
35682
+ "by_museum_ids[]": segment.museumIds ?? tsd.museumIds,
35683
+ "by_exhibition_ids[]": tsd.exhibitionIds,
35684
+ "by_ticket_ids[]": tsd.ticketIds,
35685
+ "by_ticket_group_ids[]": segment.ticketGroupIds ?? tsd.ticketGroupIds
35686
+ });
35687
+ await enrichTicketsWithContent(segment, uiTickets);
35688
+ for (const ticket of uiTickets) segment.preCart.addItem(createCartItem(ticket, { time: ticket.selectedTime }));
35689
+ }
35690
+ };
35691
+ //#endregion
35692
+ //#region src/components/ticketSelection/filters/ticket/annual.ts
35693
+ async function loadAnnualTickets(filters) {
35694
+ const tickets = await shop.asyncFetch(() => shop.tickets({
35695
+ by_bookable: true,
35696
+ "by_ticket_types[]": ["annual"],
35697
+ ...filters
35698
+ }));
35699
+ return Object.values(tickets).map((t) => createUITicket(t));
35700
+ }
35701
+ var filter$10 = {
35702
+ name: "ticket:annual",
35703
+ calendarEndpoint: null,
35704
+ apiToken: "annual",
35705
+ requires: [],
35706
+ isCalendarVisible: () => false,
35707
+ isTimeslotsVisible: () => false,
35708
+ isTicketsVisible: () => true,
35709
+ async loadTimeslots() {},
35710
+ async addToCart(options) {
35711
+ const { id, quantity } = options;
35712
+ const ticket = (await loadAnnualTickets({ "by_ticket_ids[]": [id] }))[0];
35713
+ return addResolvedTicketToCart(ticket, {
35714
+ id,
35715
+ quantity
35716
+ });
35717
+ },
35718
+ async loadProducts(segment) {
35719
+ const tsd = segment.ticketSelectionDetails;
35720
+ if (!tsd) return;
35721
+ const uiTickets = await loadAnnualTickets({
35722
+ "by_ticket_ids[]": tsd.ticketIds,
35723
+ "by_ticket_group_ids[]": segment.ticketGroupIds ?? tsd.ticketGroupIds
35724
+ });
35725
+ await enrichTicketsWithContent(segment, uiTickets);
35726
+ for (const ticket of uiTickets) segment.preCart.addItem(createCartItem(ticket));
35727
+ }
35728
+ };
35729
+ //#endregion
35730
+ //#region src/components/ticketSelection/filters/event/admission.ts
35731
+ var filter$9 = {
35732
+ name: "event:admission",
35733
+ calendarEndpoint: "events",
35734
+ requires: [{
35735
+ kind: "tsd",
35736
+ field: "eventIds"
35737
+ }, {
35738
+ kind: "tsd",
35739
+ field: "selectedDate"
35740
+ }],
35741
+ isCalendarVisible: () => true,
35742
+ isTimeslotsVisible: (tsd) => Boolean(tsd.selectedDate),
35743
+ isTicketsVisible: (tsd) => Boolean(tsd.selectedDate && tsd.selectedTimeslot),
35744
+ async loadTimeslots(tsd) {
35745
+ if (!tsd?.eventIds?.length || !tsd.selectedDate) return;
35746
+ const event = await shop.asyncFetch(() => shop.getEvent(tsd.eventIds[0]));
35747
+ if (!event.tickets?.length) return;
35748
+ const { quotas } = await shop.asyncFetch(() => shop.ticketsAndQuotas({
35749
+ "by_ticket_ids[]": event.tickets,
35750
+ by_bookable: true,
35751
+ valid_at: tsd.selectedDate.toString()
35752
+ }));
35753
+ loadPickerQuotas(tsd, quotas);
35698
35754
  },
35699
- "event:admission": {
35700
- name: "event:admission",
35701
- calendarEndpoint: "events",
35702
- requires: [{
35755
+ async loadProducts(segment) {
35756
+ const tsd = segment.ticketSelectionDetails;
35757
+ if (!tsd?.eventIds?.length || !tsd.selectedDate) return;
35758
+ const event = await shop.asyncFetch(() => shop.getEvent(tsd.eventIds[0]));
35759
+ if (!event.tickets?.length) return;
35760
+ const { tickets, quotas } = await shop.asyncFetch(() => shop.ticketsAndQuotas({
35761
+ "by_ticket_ids[]": event.tickets,
35762
+ by_bookable: true,
35763
+ valid_at: tsd.selectedDate.toString()
35764
+ }));
35765
+ shop.capacityManager.addQuotas(quotas);
35766
+ const uiTickets = initUITimeslotTickets(filterAvailabletickets(tickets, tsd.selectedTime), tsd.selectedTime);
35767
+ await enrichTicketsWithContent(segment, uiTickets);
35768
+ for (const ticket of uiTickets) segment.preCart.addItem(createCartItem(ticket, { time: tsd.selectedTime }));
35769
+ }
35770
+ };
35771
+ //#endregion
35772
+ //#region src/components/ticketSelection/filters/event/admission-day.ts
35773
+ var filter$8 = {
35774
+ name: "event:admission:day",
35775
+ calendarEndpoint: "events",
35776
+ requires: [{
35777
+ kind: "tsd",
35778
+ field: "eventIds"
35779
+ }, {
35780
+ kind: "tsd",
35781
+ field: "selectedDate"
35782
+ }],
35783
+ isCalendarVisible: () => true,
35784
+ isTimeslotsVisible: () => false,
35785
+ isTicketsVisible: (tsd) => Boolean(tsd.selectedDate),
35786
+ async loadTimeslots() {},
35787
+ async loadProducts(segment) {
35788
+ const tsd = segment.ticketSelectionDetails;
35789
+ if (!tsd?.eventIds?.length || !tsd.selectedDate) return;
35790
+ const event = await shop.asyncFetch(() => shop.getEvent(tsd.eventIds[0]));
35791
+ if (!event.tickets?.length) return;
35792
+ const { tickets, quotas } = await shop.asyncFetch(() => shop.ticketsAndQuotas({
35793
+ "by_ticket_ids[]": event.tickets,
35794
+ "by_ticket_types[]": ["normal"],
35795
+ by_bookable: true,
35796
+ valid_at: tsd.selectedDate.toString()
35797
+ }));
35798
+ shop.capacityManager.addQuotas(quotas);
35799
+ const uiTickets = initUIDayTickets(tickets);
35800
+ await enrichTicketsWithContent(segment, uiTickets);
35801
+ for (const t of uiTickets) segment.preCart.addItem(createCartItem(t, { time: t.selectedTime }));
35802
+ }
35803
+ };
35804
+ //#endregion
35805
+ //#region src/components/ticketSelection/filters/event/admission-timeslot.ts
35806
+ var filter$7 = {
35807
+ name: "event:admission:timeslot",
35808
+ calendarEndpoint: "events",
35809
+ requires: [
35810
+ {
35703
35811
  kind: "tsd",
35704
35812
  field: "eventIds"
35705
- }, {
35813
+ },
35814
+ {
35706
35815
  kind: "tsd",
35707
35816
  field: "selectedDate"
35708
- }],
35709
- isCalendarVisible: () => true,
35710
- isTimeslotsVisible: (tsd) => Boolean(tsd.selectedDate),
35711
- isTicketsVisible: (tsd) => Boolean(tsd.selectedDate && tsd.selectedTimeslot),
35712
- async loadTimeslots(tsd) {
35713
- if (!tsd?.eventIds?.length || !tsd.selectedDate) return;
35714
- const event = await shop.asyncFetch(() => shop.getEvent(tsd.eventIds[0]));
35715
- if (!event.tickets?.length) return;
35716
- const { quotas } = await shop.asyncFetch(() => shop.ticketsAndQuotas({
35717
- "by_ticket_ids[]": event.tickets,
35718
- by_bookable: true,
35719
- valid_at: tsd.selectedDate.toString()
35720
- }));
35721
- loadPickerQuotas(tsd, quotas);
35722
35817
  },
35723
- async loadProducts(segment) {
35724
- const tsd = segment.ticketSelectionDetails;
35725
- if (!tsd?.eventIds?.length || !tsd.selectedDate) return;
35726
- const event = await shop.asyncFetch(() => shop.getEvent(tsd.eventIds[0]));
35727
- if (!event.tickets?.length) return;
35818
+ {
35819
+ kind: "tsd",
35820
+ field: "selectedTimeslot"
35821
+ }
35822
+ ],
35823
+ isCalendarVisible: () => true,
35824
+ isTimeslotsVisible: (tsd) => Boolean(tsd.selectedDate),
35825
+ isTicketsVisible: (tsd) => Boolean(tsd.selectedDate && tsd.selectedTimeslot),
35826
+ async loadTimeslots(tsd) {
35827
+ if (!tsd?.eventIds?.length || !tsd.selectedDate) return;
35828
+ const event = await shop.asyncFetch(() => shop.getEvent(tsd.eventIds[0]));
35829
+ if (!event.tickets?.length) return;
35830
+ const { quotas } = await shop.asyncFetch(() => shop.ticketsAndQuotas({
35831
+ "by_ticket_ids[]": event.tickets,
35832
+ by_ticket_type: "time_slot",
35833
+ by_bookable: true,
35834
+ valid_at: tsd.selectedDate.toString()
35835
+ }));
35836
+ loadPickerQuotas(tsd, quotas);
35837
+ },
35838
+ async loadProducts(segment) {
35839
+ const tsd = segment.ticketSelectionDetails;
35840
+ if (!tsd?.eventIds?.length || !tsd.selectedDate || !tsd.selectedTimeslot) return;
35841
+ const event = await shop.asyncFetch(() => shop.getEvent(tsd.eventIds[0]));
35842
+ if (!event.tickets?.length) return;
35843
+ const { tickets, quotas } = await shop.asyncFetch(() => shop.ticketsAndQuotas({
35844
+ "by_ticket_ids[]": event.tickets,
35845
+ by_ticket_type: "time_slot",
35846
+ by_bookable: true,
35847
+ valid_at: tsd.selectedDate.toString()
35848
+ }));
35849
+ shop.capacityManager.addQuotas(quotas);
35850
+ const uiTickets = initUITimeslotTickets(filterAvailabletickets(tickets, tsd.selectedTime), tsd.selectedTime);
35851
+ await enrichTicketsWithContent(segment, uiTickets);
35852
+ for (const t of uiTickets) segment.preCart.addItem(createCartItem(t, { time: tsd.selectedTime }));
35853
+ }
35854
+ };
35855
+ //#endregion
35856
+ //#region src/components/ticketSelection/filters/event/price.ts
35857
+ var filter$6 = {
35858
+ name: "event:price",
35859
+ calendarEndpoint: "events",
35860
+ requires: [{
35861
+ kind: "tsd",
35862
+ field: "eventIds"
35863
+ }, {
35864
+ kind: "segment",
35865
+ field: "dateId"
35866
+ }],
35867
+ isCalendarVisible: () => false,
35868
+ isTimeslotsVisible: () => false,
35869
+ isTicketsVisible: (tsd) => Boolean(tsd.eventIds?.length),
35870
+ loadTimeslots: async () => {},
35871
+ async loadProducts(segment) {
35872
+ const tsd = segment.ticketSelectionDetails;
35873
+ if (!tsd?.eventIds?.length || segment.dateId === void 0) return;
35874
+ const date = await shop.asyncFetch(() => shop.getEventDetailsOnDate(tsd.eventIds[0], segment.dateId));
35875
+ if (!date.prices?.length) return;
35876
+ for (const price of date.prices) {
35877
+ const ticket = createUIEventTicket(price, date.id, { event_title: date.event_title });
35878
+ segment.preCart.addItem(createCartItem(ticket, { time: date.start_time }));
35879
+ }
35880
+ if (date.seats) shop.capacityManager.addSeats(date.id, date.seats);
35881
+ }
35882
+ };
35883
+ //#endregion
35884
+ //#region src/components/ticketSelection/filters/events/admission.ts
35885
+ var filter$5 = {
35886
+ name: "events:admission",
35887
+ calendarEndpoint: "events",
35888
+ requires: [{
35889
+ kind: "tsd",
35890
+ field: "selectedDate"
35891
+ }, {
35892
+ kind: "tsd",
35893
+ field: "selectedTimeslot"
35894
+ }],
35895
+ isCalendarVisible: () => true,
35896
+ isTimeslotsVisible: () => true,
35897
+ isTicketsVisible: () => true,
35898
+ loadTimeslots: (tsd) => loadEventsTimeslots(tsd),
35899
+ async loadProducts(segment) {
35900
+ const tsd = segment.ticketSelectionDetails;
35901
+ if (!tsd?.selectedDate || !tsd.selectedTime) return;
35902
+ const dates = filterDatesInWindow(await shop.asyncFetch(() => shop.getDates({
35903
+ by_bookable: true,
35904
+ "by_museum_ids[]": segment.museumIds ?? tsd.museumIds,
35905
+ "by_exhibition_ids[]": tsd.exhibitionIds,
35906
+ "by_event_ids[]": tsd.eventIds,
35907
+ "by_language_ids[]": segment.languageIds,
35908
+ "by_catch_word_ids[]": segment.catchWordIds,
35909
+ start_at: tsd.selectedDate.toString(),
35910
+ per_page: segment.limit || 30
35911
+ })), tsd.selectedDate.toString(), tsd.selectedTime);
35912
+ for (const date of dates) {
35913
+ if (!date.event_id || !date.start_time) continue;
35914
+ const event = await shop.asyncFetch(() => shop.getEvent(date.event_id));
35915
+ if (!event?.tickets?.length) continue;
35728
35916
  const { tickets, quotas } = await shop.asyncFetch(() => shop.ticketsAndQuotas({
35729
35917
  "by_ticket_ids[]": event.tickets,
35730
35918
  by_bookable: true,
35731
- valid_at: tsd.selectedDate.toString()
35919
+ valid_at: date.start_time.slice(0, 10)
35732
35920
  }));
35733
35921
  shop.capacityManager.addQuotas(quotas);
35734
- const uiTickets = initUITimeslotTickets(filterAvailabletickets(tickets, tsd.selectedTime), tsd.selectedTime);
35922
+ const uiTickets = initUITimeslotTickets(filterAvailabletickets(tickets, date.start_time), date.start_time);
35735
35923
  await enrichTicketsWithContent(segment, uiTickets);
35736
- for (const ticket of uiTickets) segment.preCart.addItem(createCartItem(ticket, { time: tsd.selectedTime }));
35924
+ for (const ticket of uiTickets) segment.preCart.addItem(createCartItem(ticket, { time: date.start_time }));
35737
35925
  }
35738
- },
35739
- "event:admission:day": {
35740
- name: "event:admission:day",
35741
- calendarEndpoint: "events",
35742
- requires: [{
35743
- kind: "tsd",
35744
- field: "eventIds"
35745
- }, {
35746
- kind: "tsd",
35747
- field: "selectedDate"
35748
- }],
35749
- isCalendarVisible: () => true,
35750
- isTimeslotsVisible: () => false,
35751
- isTicketsVisible: (tsd) => Boolean(tsd.selectedDate),
35752
- async loadTimeslots() {},
35753
- async loadProducts(segment) {
35754
- const tsd = segment.ticketSelectionDetails;
35755
- if (!tsd?.eventIds?.length || !tsd.selectedDate) return;
35756
- const event = await shop.asyncFetch(() => shop.getEvent(tsd.eventIds[0]));
35757
- if (!event.tickets?.length) return;
35926
+ }
35927
+ };
35928
+ //#endregion
35929
+ //#region src/components/ticketSelection/filters/events/admission-day.ts
35930
+ var filter$4 = {
35931
+ name: "events:admission:day",
35932
+ calendarEndpoint: "events",
35933
+ requires: [{
35934
+ kind: "tsd",
35935
+ field: "selectedDate"
35936
+ }, {
35937
+ kind: "tsd",
35938
+ field: "selectedTimeslot"
35939
+ }],
35940
+ isCalendarVisible: () => true,
35941
+ isTimeslotsVisible: () => true,
35942
+ isTicketsVisible: () => true,
35943
+ loadTimeslots: (tsd) => loadEventsTimeslots(tsd),
35944
+ async loadProducts(segment) {
35945
+ const tsd = segment.ticketSelectionDetails;
35946
+ if (!tsd?.selectedDate || !tsd.selectedTime) return;
35947
+ const dates = filterDatesInWindow(await shop.asyncFetch(() => shop.getDates({
35948
+ by_bookable: true,
35949
+ "by_museum_ids[]": segment.museumIds ?? tsd.museumIds,
35950
+ "by_exhibition_ids[]": tsd.exhibitionIds,
35951
+ "by_event_ids[]": tsd.eventIds,
35952
+ "by_language_ids[]": segment.languageIds,
35953
+ "by_catch_word_ids[]": segment.catchWordIds,
35954
+ start_at: tsd.selectedDate.toString(),
35955
+ per_page: segment.limit || 30
35956
+ })), tsd.selectedDate.toString(), tsd.selectedTime);
35957
+ for (const date of dates) {
35958
+ if (!date.event_id || !date.start_time) continue;
35959
+ const event = await shop.asyncFetch(() => shop.getEvent(date.event_id));
35960
+ if (!event?.tickets?.length) continue;
35758
35961
  const { tickets, quotas } = await shop.asyncFetch(() => shop.ticketsAndQuotas({
35759
35962
  "by_ticket_ids[]": event.tickets,
35760
35963
  "by_ticket_types[]": ["normal"],
35761
35964
  by_bookable: true,
35762
- valid_at: tsd.selectedDate.toString()
35965
+ valid_at: date.start_time.slice(0, 10)
35763
35966
  }));
35764
35967
  shop.capacityManager.addQuotas(quotas);
35765
- const uiTickets = initUIDayTickets(tickets);
35968
+ const uiTickets = initUIDayTickets(tickets, date.start_time);
35766
35969
  await enrichTicketsWithContent(segment, uiTickets);
35767
35970
  for (const t of uiTickets) segment.preCart.addItem(createCartItem(t, { time: t.selectedTime }));
35768
35971
  }
35769
- },
35770
- "event:admission:timeslot": {
35771
- name: "event:admission:timeslot",
35772
- calendarEndpoint: "events",
35773
- requires: [
35774
- {
35775
- kind: "tsd",
35776
- field: "eventIds"
35777
- },
35778
- {
35779
- kind: "tsd",
35780
- field: "selectedDate"
35781
- },
35782
- {
35783
- kind: "tsd",
35784
- field: "selectedTimeslot"
35785
- }
35786
- ],
35787
- isCalendarVisible: () => true,
35788
- isTimeslotsVisible: (tsd) => Boolean(tsd.selectedDate),
35789
- isTicketsVisible: (tsd) => Boolean(tsd.selectedDate && tsd.selectedTimeslot),
35790
- async loadTimeslots(tsd) {
35791
- if (!tsd?.eventIds?.length || !tsd.selectedDate) return;
35792
- const event = await shop.asyncFetch(() => shop.getEvent(tsd.eventIds[0]));
35793
- if (!event.tickets?.length) return;
35794
- const { quotas } = await shop.asyncFetch(() => shop.ticketsAndQuotas({
35795
- "by_ticket_ids[]": event.tickets,
35796
- by_ticket_type: "time_slot",
35797
- by_bookable: true,
35798
- valid_at: tsd.selectedDate.toString()
35799
- }));
35800
- loadPickerQuotas(tsd, quotas);
35801
- },
35802
- async loadProducts(segment) {
35803
- const tsd = segment.ticketSelectionDetails;
35804
- if (!tsd?.eventIds?.length || !tsd.selectedDate || !tsd.selectedTimeslot) return;
35805
- const event = await shop.asyncFetch(() => shop.getEvent(tsd.eventIds[0]));
35806
- if (!event.tickets?.length) return;
35972
+ }
35973
+ };
35974
+ //#endregion
35975
+ //#region src/components/ticketSelection/filters/events/admission-timeslot.ts
35976
+ var filter$3 = {
35977
+ name: "events:admission:timeslot",
35978
+ calendarEndpoint: "events",
35979
+ requires: [{
35980
+ kind: "tsd",
35981
+ field: "selectedDate"
35982
+ }, {
35983
+ kind: "tsd",
35984
+ field: "selectedTimeslot"
35985
+ }],
35986
+ isCalendarVisible: () => true,
35987
+ isTimeslotsVisible: () => true,
35988
+ isTicketsVisible: () => true,
35989
+ loadTimeslots: (tsd) => loadEventsTimeslots(tsd),
35990
+ async loadProducts(segment) {
35991
+ const tsd = segment.ticketSelectionDetails;
35992
+ if (!tsd?.selectedDate || !tsd.selectedTime) return;
35993
+ const dates = filterDatesInWindow(await shop.asyncFetch(() => shop.getDates({
35994
+ by_bookable: true,
35995
+ "by_museum_ids[]": segment.museumIds ?? tsd.museumIds,
35996
+ "by_exhibition_ids[]": tsd.exhibitionIds,
35997
+ "by_event_ids[]": tsd.eventIds,
35998
+ "by_language_ids[]": segment.languageIds,
35999
+ "by_catch_word_ids[]": segment.catchWordIds,
36000
+ start_at: tsd.selectedDate.toString(),
36001
+ per_page: segment.limit || 30
36002
+ })), tsd.selectedDate.toString(), tsd.selectedTime);
36003
+ for (const date of dates) {
36004
+ if (!date.event_id || !date.start_time) continue;
36005
+ const event = await shop.asyncFetch(() => shop.getEvent(date.event_id));
36006
+ if (!event?.tickets?.length) continue;
35807
36007
  const { tickets, quotas } = await shop.asyncFetch(() => shop.ticketsAndQuotas({
35808
36008
  "by_ticket_ids[]": event.tickets,
35809
36009
  by_ticket_type: "time_slot",
35810
36010
  by_bookable: true,
35811
- valid_at: tsd.selectedDate.toString()
36011
+ valid_at: date.start_time.slice(0, 10)
35812
36012
  }));
35813
36013
  shop.capacityManager.addQuotas(quotas);
35814
- const uiTickets = initUITimeslotTickets(filterAvailabletickets(tickets, tsd.selectedTime), tsd.selectedTime);
36014
+ const uiTickets = initUITimeslotTickets(filterAvailabletickets(tickets, date.start_time), date.start_time);
35815
36015
  await enrichTicketsWithContent(segment, uiTickets);
35816
- for (const t of uiTickets) segment.preCart.addItem(createCartItem(t, { time: tsd.selectedTime }));
36016
+ for (const t of uiTickets) segment.preCart.addItem(createCartItem(t, { time: date.start_time }));
35817
36017
  }
35818
- },
35819
- "event:price": {
35820
- name: "event:price",
35821
- calendarEndpoint: "events",
35822
- requires: [{
35823
- kind: "tsd",
35824
- field: "eventIds"
35825
- }, {
35826
- kind: "segment",
35827
- field: "dateId"
35828
- }],
35829
- isCalendarVisible: () => false,
35830
- isTimeslotsVisible: () => false,
35831
- isTicketsVisible: (tsd) => Boolean(tsd.eventIds?.length),
35832
- loadTimeslots: async () => {},
35833
- async loadProducts(segment) {
35834
- const tsd = segment.ticketSelectionDetails;
35835
- if (!tsd?.eventIds?.length || segment.dateId === void 0) return;
35836
- const date = await shop.asyncFetch(() => shop.getEventDetailsOnDate(tsd.eventIds[0], segment.dateId));
35837
- if (!date.prices?.length) return;
35838
- for (const price of date.prices) {
36018
+ }
36019
+ };
36020
+ //#endregion
36021
+ //#region src/components/ticketSelection/filters/events/price.ts
36022
+ var filter$2 = {
36023
+ name: "events:price",
36024
+ calendarEndpoint: "events",
36025
+ requires: [{
36026
+ kind: "tsd",
36027
+ field: "selectedDate"
36028
+ }, {
36029
+ kind: "tsd",
36030
+ field: "selectedTimeslot"
36031
+ }],
36032
+ isCalendarVisible: () => true,
36033
+ isTimeslotsVisible: () => true,
36034
+ isTicketsVisible: () => true,
36035
+ loadTimeslots: (tsd) => loadEventsTimeslots(tsd),
36036
+ async loadProducts(segment) {
36037
+ const tsd = segment.ticketSelectionDetails;
36038
+ if (!tsd?.selectedDate || !tsd.selectedTime) return;
36039
+ const dates = filterDatesInWindow(await shop.asyncFetch(() => shop.getDates({
36040
+ by_bookable: true,
36041
+ "by_museum_ids[]": segment.museumIds ?? tsd.museumIds,
36042
+ "by_exhibition_ids[]": tsd.exhibitionIds,
36043
+ "by_event_ids[]": tsd.eventIds,
36044
+ "by_language_ids[]": segment.languageIds,
36045
+ "by_catch_word_ids[]": segment.catchWordIds,
36046
+ start_at: tsd.selectedDate.toString(),
36047
+ per_page: segment.limit || 30
36048
+ })), tsd.selectedDate.toString(), tsd.selectedTime);
36049
+ const query = segment.query;
36050
+ for (const date of dates) {
36051
+ if (!date.prices?.length) continue;
36052
+ const prices = query ? date.prices.filter((p) => p.title?.includes(query)) : date.prices;
36053
+ for (const price of prices) {
35839
36054
  const ticket = createUIEventTicket(price, date.id, { event_title: date.event_title });
35840
36055
  segment.preCart.addItem(createCartItem(ticket, { time: date.start_time }));
35841
36056
  }
35842
36057
  if (date.seats) shop.capacityManager.addSeats(date.id, date.seats);
35843
36058
  }
35844
- },
35845
- "events:admission": {
35846
- name: "events:admission",
35847
- calendarEndpoint: "events",
35848
- requires: [{
35849
- kind: "tsd",
35850
- field: "selectedDate"
35851
- }, {
35852
- kind: "tsd",
35853
- field: "selectedTimeslot"
35854
- }],
35855
- isCalendarVisible: () => true,
35856
- isTimeslotsVisible: () => true,
35857
- isTicketsVisible: () => true,
35858
- loadTimeslots: (tsd) => loadEventsTimeslots(tsd),
35859
- async loadProducts(segment) {
35860
- const tsd = segment.ticketSelectionDetails;
35861
- if (!tsd?.selectedDate || !tsd.selectedTime) return;
35862
- const dates = filterDatesInWindow(await shop.asyncFetch(() => shop.getDates({
35863
- by_bookable: true,
35864
- "by_museum_ids[]": segment.museumIds ?? tsd.museumIds,
35865
- "by_exhibition_ids[]": tsd.exhibitionIds,
35866
- "by_event_ids[]": tsd.eventIds,
35867
- "by_language_ids[]": segment.languageIds,
35868
- "by_catch_word_ids[]": segment.catchWordIds,
35869
- start_at: tsd.selectedDate.toString(),
35870
- per_page: segment.limit || 30
35871
- })), tsd.selectedDate.toString(), tsd.selectedTime);
35872
- for (const date of dates) {
35873
- if (!date.event_id || !date.start_time) continue;
35874
- const event = await shop.asyncFetch(() => shop.getEvent(date.event_id));
35875
- if (!event?.tickets?.length) continue;
35876
- const { tickets, quotas } = await shop.asyncFetch(() => shop.ticketsAndQuotas({
35877
- "by_ticket_ids[]": event.tickets,
35878
- by_bookable: true,
35879
- valid_at: date.start_time.slice(0, 10)
35880
- }));
35881
- shop.capacityManager.addQuotas(quotas);
35882
- const uiTickets = initUITimeslotTickets(filterAvailabletickets(tickets, date.start_time), date.start_time);
35883
- await enrichTicketsWithContent(segment, uiTickets);
35884
- for (const ticket of uiTickets) segment.preCart.addItem(createCartItem(ticket, { time: date.start_time }));
35885
- }
35886
- }
35887
- },
35888
- "events:admission:day": {
35889
- name: "events:admission:day",
35890
- calendarEndpoint: "events",
35891
- requires: [{
35892
- kind: "tsd",
35893
- field: "selectedDate"
35894
- }, {
35895
- kind: "tsd",
35896
- field: "selectedTimeslot"
35897
- }],
35898
- isCalendarVisible: () => true,
35899
- isTimeslotsVisible: () => true,
35900
- isTicketsVisible: () => true,
35901
- loadTimeslots: (tsd) => loadEventsTimeslots(tsd),
35902
- async loadProducts(segment) {
35903
- const tsd = segment.ticketSelectionDetails;
35904
- if (!tsd?.selectedDate || !tsd.selectedTime) return;
35905
- const dates = filterDatesInWindow(await shop.asyncFetch(() => shop.getDates({
35906
- by_bookable: true,
35907
- "by_museum_ids[]": segment.museumIds ?? tsd.museumIds,
35908
- "by_exhibition_ids[]": tsd.exhibitionIds,
35909
- "by_event_ids[]": tsd.eventIds,
35910
- "by_language_ids[]": segment.languageIds,
35911
- "by_catch_word_ids[]": segment.catchWordIds,
35912
- start_at: tsd.selectedDate.toString(),
35913
- per_page: segment.limit || 30
35914
- })), tsd.selectedDate.toString(), tsd.selectedTime);
35915
- for (const date of dates) {
35916
- if (!date.event_id || !date.start_time) continue;
35917
- const event = await shop.asyncFetch(() => shop.getEvent(date.event_id));
35918
- if (!event?.tickets?.length) continue;
35919
- const { tickets, quotas } = await shop.asyncFetch(() => shop.ticketsAndQuotas({
35920
- "by_ticket_ids[]": event.tickets,
35921
- "by_ticket_types[]": ["normal"],
35922
- by_bookable: true,
35923
- valid_at: date.start_time.slice(0, 10)
35924
- }));
35925
- shop.capacityManager.addQuotas(quotas);
35926
- const uiTickets = initUIDayTickets(tickets, date.start_time);
35927
- await enrichTicketsWithContent(segment, uiTickets);
35928
- for (const t of uiTickets) segment.preCart.addItem(createCartItem(t, { time: t.selectedTime }));
35929
- }
35930
- }
35931
- },
35932
- "events:admission:timeslot": {
35933
- name: "events:admission:timeslot",
35934
- calendarEndpoint: "events",
35935
- requires: [{
35936
- kind: "tsd",
35937
- field: "selectedDate"
35938
- }, {
35939
- kind: "tsd",
35940
- field: "selectedTimeslot"
35941
- }],
35942
- isCalendarVisible: () => true,
35943
- isTimeslotsVisible: () => true,
35944
- isTicketsVisible: () => true,
35945
- loadTimeslots: (tsd) => loadEventsTimeslots(tsd),
35946
- async loadProducts(segment) {
35947
- const tsd = segment.ticketSelectionDetails;
35948
- if (!tsd?.selectedDate || !tsd.selectedTime) return;
35949
- const dates = filterDatesInWindow(await shop.asyncFetch(() => shop.getDates({
35950
- by_bookable: true,
35951
- "by_museum_ids[]": segment.museumIds ?? tsd.museumIds,
35952
- "by_exhibition_ids[]": tsd.exhibitionIds,
35953
- "by_event_ids[]": tsd.eventIds,
35954
- "by_language_ids[]": segment.languageIds,
35955
- "by_catch_word_ids[]": segment.catchWordIds,
35956
- start_at: tsd.selectedDate.toString(),
35957
- per_page: segment.limit || 30
35958
- })), tsd.selectedDate.toString(), tsd.selectedTime);
35959
- for (const date of dates) {
35960
- if (!date.event_id || !date.start_time) continue;
35961
- const event = await shop.asyncFetch(() => shop.getEvent(date.event_id));
35962
- if (!event?.tickets?.length) continue;
35963
- const { tickets, quotas } = await shop.asyncFetch(() => shop.ticketsAndQuotas({
35964
- "by_ticket_ids[]": event.tickets,
35965
- by_ticket_type: "time_slot",
35966
- by_bookable: true,
35967
- valid_at: date.start_time.slice(0, 10)
35968
- }));
35969
- shop.capacityManager.addQuotas(quotas);
35970
- const uiTickets = initUITimeslotTickets(filterAvailabletickets(tickets, date.start_time), date.start_time);
35971
- await enrichTicketsWithContent(segment, uiTickets);
35972
- for (const t of uiTickets) segment.preCart.addItem(createCartItem(t, { time: date.start_time }));
35973
- }
35974
- }
35975
- },
35976
- "events:price": {
35977
- name: "events:price",
35978
- calendarEndpoint: "events",
35979
- requires: [{
35980
- kind: "tsd",
35981
- field: "selectedDate"
35982
- }, {
35983
- kind: "tsd",
35984
- field: "selectedTimeslot"
35985
- }],
35986
- isCalendarVisible: () => true,
35987
- isTimeslotsVisible: () => true,
35988
- isTicketsVisible: () => true,
35989
- loadTimeslots: (tsd) => loadEventsTimeslots(tsd),
35990
- async loadProducts(segment) {
35991
- const tsd = segment.ticketSelectionDetails;
35992
- if (!tsd?.selectedDate || !tsd.selectedTime) return;
35993
- const dates = filterDatesInWindow(await shop.asyncFetch(() => shop.getDates({
35994
- by_bookable: true,
35995
- "by_museum_ids[]": segment.museumIds ?? tsd.museumIds,
35996
- "by_exhibition_ids[]": tsd.exhibitionIds,
35997
- "by_event_ids[]": tsd.eventIds,
35998
- "by_language_ids[]": segment.languageIds,
35999
- "by_catch_word_ids[]": segment.catchWordIds,
36000
- start_at: tsd.selectedDate.toString(),
36001
- per_page: segment.limit || 30
36002
- })), tsd.selectedDate.toString(), tsd.selectedTime);
36003
- const query = segment.query;
36004
- for (const date of dates) {
36005
- if (!date.prices?.length) continue;
36006
- const prices = query ? date.prices.filter((p) => p.title?.includes(query)) : date.prices;
36007
- for (const price of prices) {
36008
- const ticket = createUIEventTicket(price, date.id, { event_title: date.event_title });
36009
- segment.preCart.addItem(createCartItem(ticket, { time: date.start_time }));
36010
- }
36011
- if (date.seats) shop.capacityManager.addSeats(date.id, date.seats);
36012
- }
36013
- }
36014
- },
36015
- coupon: {
36016
- name: "coupon",
36059
+ }
36060
+ };
36061
+ //#endregion
36062
+ //#region src/components/ticketSelection/filters/coupon.ts
36063
+ /**
36064
+ * `coupon` — sells the shop's purchasable coupons (German "Wertgutschein" /
36065
+ * gift card). Coupons are fixed-value, standalone products:
36066
+ * no calendar, no timeslots, no capacity. They are always listed, like a
36067
+ * shelf of products.
36068
+ */
36069
+ var filter$1 = {
36070
+ name: "coupon",
36071
+ calendarEndpoint: null,
36072
+ requires: [],
36073
+ isCalendarVisible: () => false,
36074
+ isTimeslotsVisible: () => false,
36075
+ isTicketsVisible: () => true,
36076
+ loadTimeslots: async () => {},
36077
+ async loadProducts(segment) {
36078
+ const coupons = await shop.asyncFetch(() => shop.getCoupons());
36079
+ for (const coupon of coupons ?? []) segment.preCart.addItem(createCartItem(createUICoupon(coupon)));
36080
+ }
36081
+ };
36082
+ //#endregion
36083
+ //#region src/components/ticketSelection/filters/tour.ts
36084
+ var REQUIRED = [
36085
+ "id",
36086
+ "time",
36087
+ "participants",
36088
+ "languageId",
36089
+ "totalPriceCents",
36090
+ "title"
36091
+ ];
36092
+ //#endregion
36093
+ //#region src/components/ticketSelection/filters/registry.ts
36094
+ var REGISTRY = {
36095
+ "ticket:timeslot": filter$12,
36096
+ "ticket:day": filter$11,
36097
+ "ticket:annual": filter$10,
36098
+ "event:admission": filter$9,
36099
+ "event:admission:day": filter$8,
36100
+ "event:admission:timeslot": filter$7,
36101
+ "event:price": filter$6,
36102
+ "events:admission": filter$5,
36103
+ "events:admission:day": filter$4,
36104
+ "events:admission:timeslot": filter$3,
36105
+ "events:price": filter$2,
36106
+ coupon: filter$1,
36107
+ tour: {
36108
+ name: "tour",
36017
36109
  calendarEndpoint: null,
36018
36110
  requires: [],
36019
36111
  isCalendarVisible: () => false,
36020
36112
  isTimeslotsVisible: () => false,
36021
36113
  isTicketsVisible: () => true,
36022
- loadTimeslots: async () => {},
36023
- async loadProducts(segment) {
36024
- const coupons = await shop.asyncFetch(() => shop.getCoupons());
36025
- for (const coupon of coupons ?? []) segment.preCart.addItem(createCartItem(createUICoupon(coupon)));
36114
+ async loadTimeslots() {},
36115
+ async loadProducts() {},
36116
+ /**
36117
+ * Adds a group-tour booking and returns the cart line's uuid. Every call
36118
+ * appends a NEW line — identical bookings coexist; use the uuid to dedupe or
36119
+ * remove. Tours are not priced by the shop API: `totalPriceCents` is the
36120
+ * integrator-supplied total (incl. mandatory surcharges), verified by the
36121
+ * backend only at checkout.
36122
+ */
36123
+ async addToCart(options) {
36124
+ const o = options;
36125
+ for (const key of REQUIRED) if (o[key] == null || o[key] === "") throw new Error(`(go.cart.addItem) tour '${key}' is required`);
36126
+ if (!(o.participants > 0)) throw new Error(`(go.cart.addItem) tour 'participants' must be a positive number`);
36127
+ if (o.quantities) {
36128
+ const quantitiesSum = sum(Object.values(o.quantities));
36129
+ if (quantitiesSum !== o.participants) throw new Error(`(go.cart.addItem) tour 'quantities' must sum to 'participants' (${quantitiesSum} !== ${o.participants})`);
36130
+ }
36131
+ const { time, ...attributes } = o;
36132
+ const item = createCartItem(createUITour(attributes), {
36133
+ quantity: 1,
36134
+ time
36135
+ });
36136
+ shop.cart.addItem(item);
36137
+ return item.uuid;
36026
36138
  }
36027
36139
  }
36028
36140
  };
@@ -36507,10 +36619,7 @@ function Event$1($$anchor, $$props) {
36507
36619
  template_effect(($0, $1) => {
36508
36620
  set_text(text_1, $0);
36509
36621
  set_text(text_2, $1);
36510
- }, [() => formatDate(item().attributes.start_time, {
36511
- month: "numeric",
36512
- day: "numeric"
36513
- }, shop.locale), () => formatTime(item().attributes.start_time)]);
36622
+ }, [() => shop.formatDate(item().attributes.start_time, "dayMonth"), () => shop.formatTime(item().attributes.start_time)]);
36514
36623
  append($$anchor, fragment);
36515
36624
  };
36516
36625
  if_block(node, ($$render) => {
@@ -36653,20 +36762,14 @@ function TicketSale($$anchor, $$props) {
36653
36762
  template_effect(($0, $1) => {
36654
36763
  set_text(text_3, $0);
36655
36764
  set_text(text_4, $1);
36656
- }, [() => formatDate(item().attributes.start_time, {
36657
- month: "numeric",
36658
- day: "numeric"
36659
- }, shop.locale), () => formatTime(item().attributes.start_time)]);
36765
+ }, [() => shop.formatDate(item().attributes.start_time, "dayMonth"), () => shop.formatTime(item().attributes.start_time)]);
36660
36766
  append($$anchor, fragment_4);
36661
36767
  };
36662
36768
  var consequent_2 = ($$anchor) => {
36663
36769
  var span_5 = root_3$3();
36664
36770
  var text_5 = child(span_5, true);
36665
36771
  reset(span_5);
36666
- template_effect(($0) => set_text(text_5, $0), [() => formatDate(item().attributes.start_time, {
36667
- month: "numeric",
36668
- day: "numeric"
36669
- }, shop.locale)]);
36772
+ template_effect(($0) => set_text(text_5, $0), [() => shop.formatDate(item().attributes.start_time, "dayMonth")]);
36670
36773
  append($$anchor, span_5);
36671
36774
  };
36672
36775
  if_block(node_5, ($$render) => {
@@ -36858,10 +36961,7 @@ function Tour($$anchor, $$props) {
36858
36961
  template_effect(($0, $1) => {
36859
36962
  set_text(text_2, $0);
36860
36963
  set_text(text_3, $1);
36861
- }, [() => formatDate(item().attributes.start_time, {
36862
- month: "numeric",
36863
- day: "numeric"
36864
- }, shop.locale), () => formatTime(item().attributes.start_time)]);
36964
+ }, [() => shop.formatDate(item().attributes.start_time, "dayMonth"), () => shop.formatTime(item().attributes.start_time)]);
36865
36965
  append($$anchor, fragment);
36866
36966
  };
36867
36967
  if_block(node, ($$render) => {
@@ -37635,7 +37735,7 @@ function Item($$anchor, $$props) {
37635
37735
  template_effect(($0) => {
37636
37736
  set_text(text, `${item().product.event_title ?? ""} - ${$0 ?? ""}`);
37637
37737
  set_text(text_1, item().product.title);
37638
- }, [() => formatTime(item().time)]);
37738
+ }, [() => shop.formatTime(item().time)]);
37639
37739
  append($$anchor, fragment);
37640
37740
  };
37641
37741
  const default_title = ($$anchor) => {
@@ -37744,7 +37844,7 @@ function Item($$anchor, $$props) {
37744
37844
  var li_6 = sibling(li_5, 2);
37745
37845
  var node_5 = child(li_6);
37746
37846
  {
37747
- let $0 = /* @__PURE__ */ user_derived(() => quantityLabel(item()));
37847
+ let $0 = /* @__PURE__ */ user_derived(() => quantityLabel(item(), shop.locale));
37748
37848
  QuantityControl(node_5, {
37749
37849
  get value() {
37750
37850
  return item().quantity;
@@ -37922,7 +38022,7 @@ var Details$1 = class {
37922
38022
  this.timeslots = quotaManager.timeslotsOn(date, this.tsd?.timeslotTicketIds).map((x) => ({
37923
38023
  ...x,
37924
38024
  startAt: x.timeSlot,
37925
- timeFormatted: x.timeSlot.substring(11, 16),
38025
+ timeFormatted: shop.formatTime(x.timeSlot),
37926
38026
  available: x.capacity > 0
37927
38027
  }));
37928
38028
  }
@@ -38557,41 +38657,13 @@ customElements.define("go-withdrawal-form", create_custom_element(Withdrawal, {
38557
38657
  } }, [], []));
38558
38658
  //#endregion
38559
38659
  //#region src/go/cart.ts
38560
- var REQUIRED = [
38561
- "id",
38562
- "time",
38563
- "participants",
38564
- "languageId",
38565
- "totalPriceCents",
38566
- "title"
38567
- ];
38568
- function validate(options) {
38569
- for (const key of REQUIRED) if (options[key] == null || options[key] === "") throw new Error(`(go.cart.addTour) '${key}' is required`);
38570
- if (!(options.participants > 0)) throw new Error(`(go.cart.addTour) 'participants' must be a positive number`);
38571
- if (options.quantities) {
38572
- const quantitiesSum = sum(Object.values(options.quantities));
38573
- if (quantitiesSum !== options.participants) throw new Error(`(go.cart.addTour) 'quantities' must sum to 'participants' (${quantitiesSum} !== ${options.participants})`);
38574
- }
38575
- }
38576
- /**
38577
- * Adds a group-tour booking to the cart and resolves with the cart line's
38578
- * uuid. Every call appends a NEW line — identical bookings coexist; use the
38579
- * returned uuid to deduplicate or remove.
38580
- *
38581
- * Tours are not priced by the shop API: `totalPriceCents` is the
38582
- * integrator-supplied booking total (incl. mandatory surcharges) and is
38583
- * verified by the backend only at checkout.
38584
- */
38585
- async function addTour(options) {
38586
- validate(options);
38587
- if (!shop.cart) throw new Error("(go.cart.addTour) shop not initialized — call go.init first");
38588
- const { time, ...attributes } = options;
38589
- const item = createCartItem(createUITour(attributes), {
38590
- quantity: 1,
38591
- time
38592
- });
38593
- shop.cart.addItem(item);
38594
- return item.uuid;
38660
+ /** Resolves with the new cart line's uuid. Throws if the filter can't add to
38661
+ * the cart, or on the filter's own validation / availability errors. */
38662
+ async function addItem({ filter, ...options }) {
38663
+ if (!shop.cart) throw new Error("(go.cart.addItem) shop not initialized — call go.init first");
38664
+ const module = getFilter(filter);
38665
+ if (!module?.addToCart) throw new Error(`(go.cart.addItem) filter '${filter}' cannot add to the cart`);
38666
+ return module.addToCart(options);
38595
38667
  }
38596
38668
  //#endregion
38597
38669
  //#region src/go/go.ts
@@ -38650,9 +38722,9 @@ var go = {
38650
38722
  return shop.asyncFetch(() => shop.getCustomerMemberships());
38651
38723
  }
38652
38724
  },
38653
- cart: { addTour: async (options) => {
38725
+ cart: { addItem: async (options) => {
38654
38726
  await ensureShopReady();
38655
- return addTour(options);
38727
+ return addItem(options);
38656
38728
  } }
38657
38729
  };
38658
38730
  (async () => {