@gomusdev/web-components 4.8.0 → 4.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # Changelog
2
2
 
3
+ ## 4.8.2 (2026-07-16)
4
+
5
+ ### Bug Fixes
6
+
7
+ * **mr2:** expand spec detection to include sibling `spec/` subdirectory
8
+ * **ticket-selection:** derive day-ticket time per ticket, not from first quota (TC-04), closes [#136](https://gitlab.giantmonkey.de/gomus/frontend/issues/136)
9
+
10
+ ## 4.8.1 (2026-07-16)
11
+
12
+ ### Bug Fixes
13
+
14
+ * **couponRedemption:** clear stale error when flush() succeeds
15
+ * **forms:** clear form-level api errors on valid submit, closes [#apiErrors](https://gitlab.giantmonkey.de/gomus/frontend/issues/apiErrors) [#147](https://gitlab.giantmonkey.de/gomus/frontend/issues/147)
16
+ * **forms:** reset stale success message on valid submit
17
+
3
18
  ## 4.8.0 (2026-07-15)
4
19
 
5
20
  ### Features
@@ -11860,6 +11860,17 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
11860
11860
  function initUITimeslotTickets(tickets, selectedTime = "") {
11861
11861
  return sort(Object.values(tickets).map((ticket) => createUITicket(ticket, { selectedTime })), (f) => f.shop_order);
11862
11862
  }
11863
+ /**
11864
+ * Day tickets (TC-04): each day quota keys its capacity at its OWN first-entry time, so
11865
+ * capacity keys differ across quotas. The day 'time' must be derived per ticket — the
11866
+ * first positive key of the ticket's own total_capacities — never from one global quota
11867
+ * key. A ticket with capacity keys that are all zero is sold out and dropped; a ticket
11868
+ * with no keys at all (no quota) is kept and gets `fallbackTime`.
11869
+ */
11870
+ function initUIDayTickets(tickets, fallbackTime) {
11871
+ const ownDayTime = (t) => Object.keys(t.total_capacities ?? {}).find((key) => (t.total_capacities?.[key] ?? 0) > 0);
11872
+ return sort(Object.values(tickets).filter((t) => ownDayTime(t) || Object.keys(t.total_capacities ?? {}).length === 0).map((t) => createUITicket(t, { selectedTime: ownDayTime(t) ?? fallbackTime })), (f) => f.shop_order);
11873
+ }
11863
11874
  function filterAvailabletickets(tickets, selectedTime = "") {
11864
11875
  let available = Object.entries(tickets);
11865
11876
  if (selectedTime !== "") available = available.filter(([, t]) => t.total_capacities?.[selectedTime] && t.total_capacities[selectedTime] > 0);
@@ -14872,6 +14883,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
14872
14883
  * @param {string[] | Record<string, string[]>} errors - Errors passed as an array or an object where keys are API field keys and values are arrays of error messages. If an array is provided, it assigns the errors directly. If an object is provided, it maps the errors to the respective fields based on their API keys.
14873
14884
  */
14874
14885
  set apiErrors(errors) {
14886
+ set(this.#apiErrors, [], true);
14875
14887
  this.fields.forEach((f) => f.apiErrors = []);
14876
14888
  if (isArray(errors)) {
14877
14889
  set(this.#apiErrors, errors, true);
@@ -14912,7 +14924,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
14912
14924
  */
14913
14925
  get fields() {
14914
14926
  const parent = this.form.closest("go-form");
14915
- return Array.from(this.form.querySelectorAll("go-field")).filter((fe) => fe.closest("go-form") === parent).map((fe) => fe.getField?.()).filter((f) => f);
14927
+ return Array.from(this.form.querySelectorAll("go-field")).filter((fe) => fe.closest("go-form") === parent).map((fe) => fe.getField?.()).filter((f) => !!f);
14916
14928
  }
14917
14929
  toString() {
14918
14930
  return `Form: ${this.formId}, Fields: [${this.fields.map((f) => f.key).join(", ")}], Data: ${JSON.stringify(this.formData)}`;
@@ -14980,6 +14992,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
14980
14992
  details?.form?.dispatchEvent(new Event("go-after-validation", event));
14981
14993
  if (details.isValid) {
14982
14994
  details.apiErrors = {};
14995
+ details.successMessage = void 0;
14983
14996
  details?.form?.dispatchEvent(new Event("go-submit", event));
14984
14997
  $$props.$$host.dispatchEvent(new Event("submit", {
14985
14998
  bubbles: true,
@@ -18599,6 +18612,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
18599
18612
  form.details.apiErrors = result.errors;
18600
18613
  return result;
18601
18614
  }
18615
+ form.details.apiErrors = [];
18602
18616
  if (field) field.value = "";
18603
18617
  form.dispatchEvent(new Event("go-success", {
18604
18618
  bubbles: true,
@@ -35400,11 +35414,9 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
35400
35414
  "by_ticket_group_ids[]": segment.ticketGroupIds ?? tsd.ticketGroupIds
35401
35415
  }));
35402
35416
  shop.capacityManager.addQuotas(quotas);
35403
- const firstQuota = Object.values(quotas)[0];
35404
- const timeslot = firstQuota ? Object.keys(firstQuota.capacities)[0] : void 0;
35405
- const uiTickets = initUITimeslotTickets(filterAvailabletickets(tickets, timeslot), timeslot);
35417
+ const uiTickets = initUIDayTickets(tickets);
35406
35418
  await enrichTicketsWithContent(segment, uiTickets);
35407
- for (const ticket of uiTickets) segment.preCart.addItem(createCartItem(ticket, { time: timeslot }));
35419
+ for (const ticket of uiTickets) segment.preCart.addItem(createCartItem(ticket, { time: ticket.selectedTime }));
35408
35420
  }
35409
35421
  },
35410
35422
  "ticket:annual": {
@@ -35496,11 +35508,9 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
35496
35508
  valid_at: tsd.selectedDate.toString()
35497
35509
  }));
35498
35510
  shop.capacityManager.addQuotas(quotas);
35499
- const firstQuota = Object.values(quotas)[0];
35500
- const time = firstQuota ? Object.keys(firstQuota.capacities)[0] : void 0;
35501
- const uiTickets = initUITimeslotTickets(filterAvailabletickets(tickets, time), time);
35511
+ const uiTickets = initUIDayTickets(tickets);
35502
35512
  await enrichTicketsWithContent(segment, uiTickets);
35503
- for (const t of uiTickets) segment.preCart.addItem(createCartItem(t, { time }));
35513
+ for (const t of uiTickets) segment.preCart.addItem(createCartItem(t, { time: t.selectedTime }));
35504
35514
  }
35505
35515
  },
35506
35516
  "event:admission:timeslot": {
@@ -35659,11 +35669,9 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
35659
35669
  valid_at: date.start_time.slice(0, 10)
35660
35670
  }));
35661
35671
  shop.capacityManager.addQuotas(quotas);
35662
- const firstQuota = Object.values(quotas)[0];
35663
- const time = firstQuota ? Object.keys(firstQuota.capacities)[0] : date.start_time;
35664
- const uiTickets = initUITimeslotTickets(filterAvailabletickets(tickets, time), time);
35672
+ const uiTickets = initUIDayTickets(tickets, date.start_time);
35665
35673
  await enrichTicketsWithContent(segment, uiTickets);
35666
- for (const t of uiTickets) segment.preCart.addItem(createCartItem(t, { time }));
35674
+ for (const t of uiTickets) segment.preCart.addItem(createCartItem(t, { time: t.selectedTime }));
35667
35675
  }
35668
35676
  }
35669
35677
  },
@@ -11859,6 +11859,17 @@ function createUITicket(apiTicket, options) {
11859
11859
  function initUITimeslotTickets(tickets, selectedTime = "") {
11860
11860
  return sort(Object.values(tickets).map((ticket) => createUITicket(ticket, { selectedTime })), (f) => f.shop_order);
11861
11861
  }
11862
+ /**
11863
+ * Day tickets (TC-04): each day quota keys its capacity at its OWN first-entry time, so
11864
+ * capacity keys differ across quotas. The day 'time' must be derived per ticket — the
11865
+ * first positive key of the ticket's own total_capacities — never from one global quota
11866
+ * key. A ticket with capacity keys that are all zero is sold out and dropped; a ticket
11867
+ * with no keys at all (no quota) is kept and gets `fallbackTime`.
11868
+ */
11869
+ function initUIDayTickets(tickets, fallbackTime) {
11870
+ const ownDayTime = (t) => Object.keys(t.total_capacities ?? {}).find((key) => (t.total_capacities?.[key] ?? 0) > 0);
11871
+ return sort(Object.values(tickets).filter((t) => ownDayTime(t) || Object.keys(t.total_capacities ?? {}).length === 0).map((t) => createUITicket(t, { selectedTime: ownDayTime(t) ?? fallbackTime })), (f) => f.shop_order);
11872
+ }
11862
11873
  function filterAvailabletickets(tickets, selectedTime = "") {
11863
11874
  let available = Object.entries(tickets);
11864
11875
  if (selectedTime !== "") available = available.filter(([, t]) => t.total_capacities?.[selectedTime] && t.total_capacities[selectedTime] > 0);
@@ -14871,6 +14882,7 @@ var FormDetails = class {
14871
14882
  * @param {string[] | Record<string, string[]>} errors - Errors passed as an array or an object where keys are API field keys and values are arrays of error messages. If an array is provided, it assigns the errors directly. If an object is provided, it maps the errors to the respective fields based on their API keys.
14872
14883
  */
14873
14884
  set apiErrors(errors) {
14885
+ set(this.#apiErrors, [], true);
14874
14886
  this.fields.forEach((f) => f.apiErrors = []);
14875
14887
  if (isArray(errors)) {
14876
14888
  set(this.#apiErrors, errors, true);
@@ -14911,7 +14923,7 @@ var FormDetails = class {
14911
14923
  */
14912
14924
  get fields() {
14913
14925
  const parent = this.form.closest("go-form");
14914
- return Array.from(this.form.querySelectorAll("go-field")).filter((fe) => fe.closest("go-form") === parent).map((fe) => fe.getField?.()).filter((f) => f);
14926
+ return Array.from(this.form.querySelectorAll("go-field")).filter((fe) => fe.closest("go-form") === parent).map((fe) => fe.getField?.()).filter((f) => !!f);
14915
14927
  }
14916
14928
  toString() {
14917
14929
  return `Form: ${this.formId}, Fields: [${this.fields.map((f) => f.key).join(", ")}], Data: ${JSON.stringify(this.formData)}`;
@@ -14979,6 +14991,7 @@ function Form($$anchor, $$props) {
14979
14991
  details?.form?.dispatchEvent(new Event("go-after-validation", event));
14980
14992
  if (details.isValid) {
14981
14993
  details.apiErrors = {};
14994
+ details.successMessage = void 0;
14982
14995
  details?.form?.dispatchEvent(new Event("go-submit", event));
14983
14996
  $$props.$$host.dispatchEvent(new Event("submit", {
14984
14997
  bubbles: true,
@@ -18598,6 +18611,7 @@ function CouponRedemption($$anchor, $$props) {
18598
18611
  form.details.apiErrors = result.errors;
18599
18612
  return result;
18600
18613
  }
18614
+ form.details.apiErrors = [];
18601
18615
  if (field) field.value = "";
18602
18616
  form.dispatchEvent(new Event("go-success", {
18603
18617
  bubbles: true,
@@ -35399,11 +35413,9 @@ var REGISTRY = {
35399
35413
  "by_ticket_group_ids[]": segment.ticketGroupIds ?? tsd.ticketGroupIds
35400
35414
  }));
35401
35415
  shop.capacityManager.addQuotas(quotas);
35402
- const firstQuota = Object.values(quotas)[0];
35403
- const timeslot = firstQuota ? Object.keys(firstQuota.capacities)[0] : void 0;
35404
- const uiTickets = initUITimeslotTickets(filterAvailabletickets(tickets, timeslot), timeslot);
35416
+ const uiTickets = initUIDayTickets(tickets);
35405
35417
  await enrichTicketsWithContent(segment, uiTickets);
35406
- for (const ticket of uiTickets) segment.preCart.addItem(createCartItem(ticket, { time: timeslot }));
35418
+ for (const ticket of uiTickets) segment.preCart.addItem(createCartItem(ticket, { time: ticket.selectedTime }));
35407
35419
  }
35408
35420
  },
35409
35421
  "ticket:annual": {
@@ -35495,11 +35507,9 @@ var REGISTRY = {
35495
35507
  valid_at: tsd.selectedDate.toString()
35496
35508
  }));
35497
35509
  shop.capacityManager.addQuotas(quotas);
35498
- const firstQuota = Object.values(quotas)[0];
35499
- const time = firstQuota ? Object.keys(firstQuota.capacities)[0] : void 0;
35500
- const uiTickets = initUITimeslotTickets(filterAvailabletickets(tickets, time), time);
35510
+ const uiTickets = initUIDayTickets(tickets);
35501
35511
  await enrichTicketsWithContent(segment, uiTickets);
35502
- for (const t of uiTickets) segment.preCart.addItem(createCartItem(t, { time }));
35512
+ for (const t of uiTickets) segment.preCart.addItem(createCartItem(t, { time: t.selectedTime }));
35503
35513
  }
35504
35514
  },
35505
35515
  "event:admission:timeslot": {
@@ -35658,11 +35668,9 @@ var REGISTRY = {
35658
35668
  valid_at: date.start_time.slice(0, 10)
35659
35669
  }));
35660
35670
  shop.capacityManager.addQuotas(quotas);
35661
- const firstQuota = Object.values(quotas)[0];
35662
- const time = firstQuota ? Object.keys(firstQuota.capacities)[0] : date.start_time;
35663
- const uiTickets = initUITimeslotTickets(filterAvailabletickets(tickets, time), time);
35671
+ const uiTickets = initUIDayTickets(tickets, date.start_time);
35664
35672
  await enrichTicketsWithContent(segment, uiTickets);
35665
- for (const t of uiTickets) segment.preCart.addItem(createCartItem(t, { time }));
35673
+ for (const t of uiTickets) segment.preCart.addItem(createCartItem(t, { time: t.selectedTime }));
35666
35674
  }
35667
35675
  }
35668
35676
  },