@getmicdrop/venue-calendar 4.0.108 → 4.0.109

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.
Files changed (89) hide show
  1. package/README.md +740 -740
  2. package/dist/CartView-C3N5pw89.js +2381 -0
  3. package/dist/CartView-C3N5pw89.js.map +1 -0
  4. package/dist/{Checkout-C4zUFYYG.js → Checkout-CMEf_qnp.js} +156 -156
  5. package/dist/Checkout-CMEf_qnp.js.map +1 -0
  6. package/dist/{Checkout-CACB_Qvi.js → Checkout-Chki2df_.js} +130 -130
  7. package/dist/Checkout-Chki2df_.js.map +1 -0
  8. package/dist/{CheckoutTimer-D5llSBPs.js → CheckoutTimer-BAaY_60w.js} +5 -5
  9. package/dist/CheckoutTimer-BAaY_60w.js.map +1 -0
  10. package/dist/{ClockIcon-BJnxLZ4f.js → ClockIcon-Dbbj_qur.js} +2 -2
  11. package/dist/ClockIcon-Dbbj_qur.js.map +1 -0
  12. package/dist/{CollectionView-BLpwWRcN.js → CollectionView-RM30YPOJ.js} +24 -24
  13. package/dist/CollectionView-RM30YPOJ.js.map +1 -0
  14. package/dist/{Event-DXp4Ypv4.js → Event-kdxMa6OT.js} +1682 -1602
  15. package/dist/Event-kdxMa6OT.js.map +1 -0
  16. package/dist/EventPage-BRBByBHe.js +1001 -0
  17. package/dist/EventPage-BRBByBHe.js.map +1 -0
  18. package/dist/{Heading-C_Pc_j8f.js → Heading-CSDFD80h.js} +5 -5
  19. package/dist/Heading-CSDFD80h.js.map +1 -0
  20. package/dist/{ScarcityBadge-CSi-i0-w.js → ScarcityBadge-B0ca48su.js} +27 -27
  21. package/dist/ScarcityBadge-B0ca48su.js.map +1 -0
  22. package/dist/{SeriesPage-bPZlyzQ6.js → SeriesPage-CczfbUKO.js} +5 -5
  23. package/dist/SeriesPage-CczfbUKO.js.map +1 -0
  24. package/dist/{Spinner-BFIjCOTb.js → Spinner--TOwvv9A.js} +2 -2
  25. package/dist/Spinner--TOwvv9A.js.map +1 -0
  26. package/dist/{Success-Cv8d2syu.js → Success-DIWUGUPs.js} +29 -29
  27. package/dist/Success-DIWUGUPs.js.map +1 -0
  28. package/dist/{Text-tWGKQJab.js → Text-WLl_ELy9.js} +12 -12
  29. package/dist/Text-WLl_ELy9.js.map +1 -0
  30. package/dist/{VenueCalendar-Dhoi9hF5.js → VenueCalendar-CU5N9klc.js} +4238 -4270
  31. package/dist/VenueCalendar-CU5N9klc.js.map +1 -0
  32. package/dist/{ViewTicketsEmbed-BrXae6cK.js → ViewTicketsEmbed-BOukxQIF.js} +80 -80
  33. package/dist/ViewTicketsEmbed-BOukxQIF.js.map +1 -0
  34. package/dist/api/api/events.d.ts +28 -12
  35. package/dist/api/api/index.d.ts +1 -1
  36. package/dist/api/api/route-manifest.d.ts +179 -0
  37. package/dist/api/api.cjs +1 -1
  38. package/dist/api/api.cjs.map +1 -1
  39. package/dist/api/api.mjs +316 -316
  40. package/dist/api/api.mjs.map +1 -1
  41. package/dist/api/types.d.ts +483 -483
  42. package/dist/{labels-CGndTgO9.js → labels-DXGieQXs.js} +61 -61
  43. package/dist/labels-DXGieQXs.js.map +1 -0
  44. package/dist/{modalManager.svelte-BgW5Xd6y.js → modalManager.svelte-Dbd1xgTQ.js} +2 -2
  45. package/dist/modalManager.svelte-Dbd1xgTQ.js.map +1 -0
  46. package/dist/promo-oWi_MKmY.js +29 -0
  47. package/dist/promo-oWi_MKmY.js.map +1 -0
  48. package/dist/seo/helpers.d.ts +11 -0
  49. package/dist/seo/seo.cjs +1 -1
  50. package/dist/seo/seo.cjs.map +1 -1
  51. package/dist/seo/seo.mjs +170 -179
  52. package/dist/seo/seo.mjs.map +1 -1
  53. package/dist/{showcase-state-options-BxLP2R1L.js → showcase-state-options-DJJdjxvZ.js} +2 -2
  54. package/dist/showcase-state-options-DJJdjxvZ.js.map +1 -0
  55. package/dist/{transform-CVOgA-Ky.js → transform-Bgqwj9i-.js} +38 -38
  56. package/dist/transform-Bgqwj9i-.js.map +1 -0
  57. package/dist/types/index.d.ts +455 -455
  58. package/dist/venue-calendar.css +1 -1
  59. package/dist/venue-calendar.es.js +4 -4
  60. package/dist/venue-calendar.iife.js +50 -50
  61. package/dist/venue-calendar.iife.js.map +1 -1
  62. package/dist/venue-calendar.umd.js +44 -44
  63. package/dist/venue-calendar.umd.js.map +1 -1
  64. package/package.json +199 -195
  65. package/src/lib/theme.js +222 -222
  66. package/dist/CartView-eQNOdQSz.js +0 -2354
  67. package/dist/CartView-eQNOdQSz.js.map +0 -1
  68. package/dist/Checkout-C4zUFYYG.js.map +0 -1
  69. package/dist/Checkout-CACB_Qvi.js.map +0 -1
  70. package/dist/CheckoutTimer-D5llSBPs.js.map +0 -1
  71. package/dist/ClockIcon-BJnxLZ4f.js.map +0 -1
  72. package/dist/CollectionView-BLpwWRcN.js.map +0 -1
  73. package/dist/Event-DXp4Ypv4.js.map +0 -1
  74. package/dist/EventPage-Dfxyzfg2.js +0 -949
  75. package/dist/EventPage-Dfxyzfg2.js.map +0 -1
  76. package/dist/Heading-C_Pc_j8f.js.map +0 -1
  77. package/dist/ScarcityBadge-CSi-i0-w.js.map +0 -1
  78. package/dist/SeriesPage-bPZlyzQ6.js.map +0 -1
  79. package/dist/Spinner-BFIjCOTb.js.map +0 -1
  80. package/dist/Success-Cv8d2syu.js.map +0 -1
  81. package/dist/Text-tWGKQJab.js.map +0 -1
  82. package/dist/VenueCalendar-Dhoi9hF5.js.map +0 -1
  83. package/dist/ViewTicketsEmbed-BrXae6cK.js.map +0 -1
  84. package/dist/labels-CGndTgO9.js.map +0 -1
  85. package/dist/modalManager.svelte-BgW5Xd6y.js.map +0 -1
  86. package/dist/promo-WWbp2OWI.js +0 -12
  87. package/dist/promo-WWbp2OWI.js.map +0 -1
  88. package/dist/showcase-state-options-BxLP2R1L.js.map +0 -1
  89. package/dist/transform-CVOgA-Ky.js.map +0 -1
@@ -1,22 +1,22 @@
1
1
  import "svelte/internal/disclose-version";
2
2
  import * as e from "svelte/internal/client";
3
- import { u as Y, aX as I, aY as O, aZ as M, ag as V, O as F, A as $, aO as N } from "./VenueCalendar-Dhoi9hF5.js";
4
- import { T as p } from "./Text-tWGKQJab.js";
5
- var G = e.from_svg('<path d="M208,32H184V24a8,8,0,0,0-16,0v8H88V24a8,8,0,0,0-16,0v8H48A16,16,0,0,0,32,48V208a16,16,0,0,0,16,16H208a16,16,0,0,0,16-16V48A16,16,0,0,0,208,32ZM112,184a8,8,0,0,1-16,0V132.94l-4.42,2.22a8,8,0,0,1-7.16-14.32l16-8A8,8,0,0,1,112,120Zm56-8a8,8,0,0,1,0,16H136a8,8,0,0,1-6.4-12.8l28.78-38.37A8,8,0,1,0,145.07,132a8,8,0,1,1-13.85-8A24,24,0,0,1,176,136a23.76,23.76,0,0,1-4.84,14.45L152,176ZM48,80V48H72v8a8,8,0,0,0,16,0V48h80v8a8,8,0,0,0,16,0V48h24V80Z"></path>'), j = e.from_svg('<rect x="40" y="40" width="176" height="176" rx="8" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"></rect><line x1="176" y1="24" x2="176" y2="56" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"></line><line x1="80" y1="24" x2="80" y2="56" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"></line><line x1="40" y1="88" x2="216" y2="88" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"></line><polyline points="88 128 104 120 104 184" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"></polyline><path d="M138.14,128a16,16,0,1,1,26.64,17.63L136,184h32" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"></path>', 1), U = e.from_svg('<svg aria-hidden="true" viewBox="0 0 256 256" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><!></svg>');
6
- function re(r, t) {
3
+ import { u as I, b1 as M, b2 as O, am as Y, b3 as N, aj as V, Q as F, D as $, ai as G } from "./VenueCalendar-CU5N9klc.js";
4
+ import { T as p } from "./Text-WLl_ELy9.js";
5
+ var j = e.from_svg('<path d="M208,32H184V24a8,8,0,0,0-16,0v8H88V24a8,8,0,0,0-16,0v8H48A16,16,0,0,0,32,48V208a16,16,0,0,0,16,16H208a16,16,0,0,0,16-16V48A16,16,0,0,0,208,32ZM112,184a8,8,0,0,1-16,0V132.94l-4.42,2.22a8,8,0,0,1-7.16-14.32l16-8A8,8,0,0,1,112,120Zm56-8a8,8,0,0,1,0,16H136a8,8,0,0,1-6.4-12.8l28.78-38.37A8,8,0,1,0,145.07,132a8,8,0,1,1-13.85-8A24,24,0,0,1,176,136a23.76,23.76,0,0,1-4.84,14.45L152,176ZM48,80V48H72v8a8,8,0,0,0,16,0V48h80v8a8,8,0,0,0,16,0V48h24V80Z"></path>'), U = e.from_svg('<rect x="40" y="40" width="176" height="176" rx="8" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"></rect><line x1="176" y1="24" x2="176" y2="56" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"></line><line x1="80" y1="24" x2="80" y2="56" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"></line><line x1="40" y1="88" x2="216" y2="88" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"></line><polyline points="88 128 104 120 104 184" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"></polyline><path d="M138.14,128a16,16,0,1,1,26.64,17.63L136,184h32" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"></path>', 1), W = e.from_svg('<svg aria-hidden="true" viewBox="0 0 256 256" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><!></svg>');
6
+ function ae(r, t) {
7
7
  e.push(t, !0);
8
8
  let a = e.prop(t, "size", 3, "24"), f = e.prop(t, "color", 3, "currentColor"), m = e.prop(t, "class", 3, "");
9
- const T = Y();
9
+ const T = I();
10
10
  let _ = e.derived(() => t.weight ?? T?.weight ?? "regular");
11
- var i = U();
11
+ var i = W();
12
12
  let S;
13
13
  var g = e.child(i);
14
14
  {
15
15
  var P = (v) => {
16
- var u = G();
16
+ var u = j();
17
17
  e.append(v, u);
18
18
  }, E = (v) => {
19
- var u = j();
19
+ var u = U();
20
20
  e.next(5), e.append(v, u);
21
21
  };
22
22
  e.if(g, (v) => {
@@ -27,18 +27,18 @@ function re(r, t) {
27
27
  e.set_class(i, 0, e.clsx(m())), e.set_attribute(i, "width", a()), e.set_attribute(i, "height", a()), S = e.set_style(i, "", S, { color: f() });
28
28
  }), e.append(r, i), e.pop();
29
29
  }
30
- function W(r, t, a = {}) {
30
+ function B(r, t, a = {}) {
31
31
  const {
32
32
  cancelled: f = !1,
33
33
  isRegistration: m = !1,
34
34
  waitlistEnabled: T = !1
35
- } = a, _ = /* @__PURE__ */ new Date();
35
+ } = a, _ = Y();
36
36
  if (f)
37
37
  return { text: "Cancelled", disabled: !0, reason: "cancelled" };
38
38
  const i = r.endDateTime || r.startDateTime;
39
39
  if (i && new Date(i) < _)
40
40
  return { text: "Sales ended", disabled: !0, reason: "event_past" };
41
- const S = r?.hasPurchasableHiddenTickets === !0 || Array.isArray(t) && t.some(I), g = (t || []).filter(
41
+ const S = r?.hasPurchasableHiddenTickets === !0 || Array.isArray(t) && t.some(M), g = (t || []).filter(
42
42
  (o) => o.salesChannel !== 2 && !o.isHidden && !(typeof o.visibility == "number" && o.visibility >= 2)
43
43
  );
44
44
  if (g.length === 0)
@@ -53,9 +53,9 @@ function W(r, t, a = {}) {
53
53
  };
54
54
  let P = !1, E = !0, v = !0, u = null;
55
55
  for (const o of g) {
56
- const y = o.salesBegin || o.salesStart || o.saleBegin || o.onSaleStart, A = o.salesEnd || o.saleEnd || o.onSaleEnd, b = o.remainingCapacity ?? o.quantityRemaining ?? o.quantity, x = o.soldOut || b != null && b <= 0, h = y ? new Date(y) > _ : !1, D = A ? new Date(A) < _ : !1;
57
- if (!x && !h && !D && (P = !0), x || (E = !1), h || (v = !1), h && y && !x && !D) {
58
- const R = new Date(y);
56
+ const w = o.salesBegin || o.salesStart || o.saleBegin || o.onSaleStart, A = o.salesEnd || o.saleEnd || o.onSaleEnd, b = o.remainingCapacity ?? o.quantityRemaining ?? o.quantity, x = o.soldOut || b != null && b <= 0, h = w ? new Date(w) > _ : !1, D = A ? new Date(A) < _ : !1;
57
+ if (!x && !h && !D && (P = !0), x || (E = !1), h || (v = !1), h && w && !x && !D) {
58
+ const R = new Date(w);
59
59
  (!u || R < u) && (u = R);
60
60
  }
61
61
  }
@@ -72,13 +72,13 @@ function W(r, t, a = {}) {
72
72
  disabled: !1,
73
73
  reason: "hidden_only"
74
74
  };
75
- const o = u.getTime() - _.getTime(), y = o / (1e3 * 60 * 60), A = o / (1e3 * 60 * 60 * 24), b = (h) => O(
75
+ const o = u.getTime() - _.getTime(), w = o / (1e3 * 60 * 60), A = o / (1e3 * 60 * 60 * 24), b = (h) => O(
76
76
  h,
77
77
  { hour: "numeric", minute: "2-digit", hour12: !0 },
78
78
  "en-US"
79
79
  );
80
80
  let x;
81
- return y < 24 ? x = b(u) : A <= 7 ? x = O(
81
+ return w < 24 ? x = b(u) : A <= 7 ? x = O(
82
82
  u,
83
83
  { weekday: "short", hour: "numeric", minute: "2-digit", hour12: !0 },
84
84
  "en-US"
@@ -106,14 +106,14 @@ function W(r, t, a = {}) {
106
106
  reason: "hidden_only"
107
107
  } : { text: "Sales ended", disabled: !0, reason: "sales_ended" };
108
108
  }
109
- function ae(r, t) {
109
+ function ie(r, t) {
110
110
  const a = V(r, t);
111
111
  return a === "sold-out" ? "sold_out" : a === "plenty" ? "none" : a;
112
112
  }
113
- function ie(r, t, a, f) {
114
- return r === "none" ? null : r === "sold_out" ? "Sold out" : r === "urgent" && a !== "browse" && t <= M.MAX_EXACT_COUNT ? `Only ${t} left` : r === "low" || r === "urgent" ? "Selling fast" : null;
113
+ function oe(r, t, a, f) {
114
+ return r === "none" ? null : r === "sold_out" ? "Sold out" : r === "urgent" && a !== "browse" && t <= N.MAX_EXACT_COUNT ? `Only ${t} left` : r === "low" || r === "urgent" ? "Selling fast" : null;
115
115
  }
116
- function oe(r) {
116
+ function ne(r) {
117
117
  const t = r.tickets.map((f) => ({
118
118
  salesBegin: f.salesStartDate,
119
119
  salesEnd: f.salesEndDate,
@@ -136,7 +136,7 @@ function oe(r) {
136
136
  disabled: !0,
137
137
  reason: "This event has ended"
138
138
  };
139
- const a = W(
139
+ const a = B(
140
140
  { startDateTime: r.startDateTime, endDateTime: r.endDateTime },
141
141
  t,
142
142
  {
@@ -148,10 +148,10 @@ function oe(r) {
148
148
  return {
149
149
  text: a.text,
150
150
  disabled: a.disabled,
151
- reason: a.disabled ? B(a.reason) : void 0
151
+ reason: a.disabled ? K(a.reason) : void 0
152
152
  };
153
153
  }
154
- function B(r) {
154
+ function K(r) {
155
155
  if (r)
156
156
  switch (r) {
157
157
  case "cancelled":
@@ -175,7 +175,7 @@ function B(r) {
175
175
  return;
176
176
  }
177
177
  }
178
- function ne(r) {
178
+ function le(r) {
179
179
  const t = r.tickets.filter(
180
180
  (i) => i.status === "on_sale" && !i.isHidden
181
181
  );
@@ -190,13 +190,13 @@ function ne(r) {
190
190
  const _ = Math.min(...T.map((i) => i.price));
191
191
  return m ? "Free" : a ? `From $${_}` : T.length === 1 ? `$${_}` : `From $${_}`;
192
192
  }
193
- function le(r, t) {
193
+ function de(r, t) {
194
194
  return F(r * (t / 100));
195
195
  }
196
196
  const Z = {
197
197
  normal: 300
198
198
  };
199
- function de() {
199
+ function ce() {
200
200
  return {
201
201
  code: "",
202
202
  isApplied: !1,
@@ -210,8 +210,8 @@ function de() {
210
210
  revealTicketIds: []
211
211
  };
212
212
  }
213
- var q = e.from_html('<div class="flex justify-between"><!> <!></div>'), K = e.from_html('<div class="flex justify-between pt-1 border-t border-default"><!> <!></div>'), J = e.from_html('<!> <!> <!> <!> <!> <div class="flex justify-between pt-2 border-t border-default"><!> <!></div>', 1), X = e.from_html('<div class="space-y-2"><!> <!></div>');
214
- function ce(r, t) {
213
+ var q = e.from_html('<div class="flex justify-between"><!> <!></div>'), J = e.from_html('<div class="flex justify-between pt-1 border-t border-default"><!> <!></div>'), Q = e.from_html('<!> <!> <!> <!> <!> <div class="flex justify-between pt-2 border-t border-default"><!> <!></div>', 1), X = e.from_html('<div class="space-y-2"><!> <!></div>');
214
+ function ue(r, t) {
215
215
  e.push(t, !0);
216
216
  let a = e.prop(t, "labels", 19, () => ({})), f = e.prop(t, "mode", 3, "full");
217
217
  var m = X(), T = e.child(m);
@@ -219,8 +219,8 @@ function ce(r, t) {
219
219
  var _ = (g) => {
220
220
  var P = e.comment(), E = e.first_child(P);
221
221
  e.each(E, 17, () => t.orderTotals.lines, (v) => v.ticketId, (v, u) => {
222
- var o = q(), y = e.child(o);
223
- p(y, {
222
+ var o = q(), w = e.child(o);
223
+ p(w, {
224
224
  size: "sm",
225
225
  children: (b, x) => {
226
226
  e.next();
@@ -229,14 +229,14 @@ function ce(r, t) {
229
229
  },
230
230
  $$slots: { default: !0 }
231
231
  });
232
- var A = e.sibling(y, 2);
232
+ var A = e.sibling(w, 2);
233
233
  p(A, {
234
234
  size: "sm",
235
235
  children: (b, x) => {
236
236
  e.next();
237
237
  var h = e.text();
238
238
  e.template_effect((D) => e.set_text(h, D), [
239
- () => e.get(u).isDonation ? $(e.get(u).subtotal) : N(e.get(u).subtotal, a())
239
+ () => e.get(u).isDonation ? $(e.get(u).subtotal) : G(e.get(u).subtotal, a())
240
240
  ]), e.append(b, h);
241
241
  },
242
242
  $$slots: { default: !0 }
@@ -250,14 +250,14 @@ function ce(r, t) {
250
250
  var i = e.sibling(T, 2);
251
251
  {
252
252
  var S = (g) => {
253
- var P = J(), E = e.first_child(P);
253
+ var P = Q(), E = e.first_child(P);
254
254
  {
255
255
  var v = (n) => {
256
- var l = K(), d = e.child(l);
256
+ var l = J(), d = e.child(l);
257
257
  p(d, {
258
258
  size: "sm",
259
259
  color: "muted",
260
- children: (c, w) => {
260
+ children: (c, y) => {
261
261
  e.next();
262
262
  var s = e.text();
263
263
  e.template_effect(() => e.set_text(s, a().subtotal || "Subtotal")), e.append(c, s);
@@ -268,7 +268,7 @@ function ce(r, t) {
268
268
  p(k, {
269
269
  size: "sm",
270
270
  color: "muted",
271
- children: (c, w) => {
271
+ children: (c, y) => {
272
272
  e.next();
273
273
  var s = e.text();
274
274
  e.template_effect((C) => e.set_text(s, C), [() => $(t.orderTotals.subtotal)]), e.append(c, s);
@@ -280,7 +280,7 @@ function ce(r, t) {
280
280
  p(d, {
281
281
  size: "sm",
282
282
  color: "muted",
283
- children: (c, w) => {
283
+ children: (c, y) => {
284
284
  e.next();
285
285
  var s = e.text();
286
286
  e.template_effect(() => e.set_text(s, a().subtotal || "Subtotal")), e.append(c, s);
@@ -291,7 +291,7 @@ function ce(r, t) {
291
291
  p(k, {
292
292
  size: "sm",
293
293
  color: "muted",
294
- children: (c, w) => {
294
+ children: (c, y) => {
295
295
  e.next();
296
296
  var s = e.text();
297
297
  e.template_effect((C) => e.set_text(s, C), [() => $(t.orderTotals.subtotal)]), e.append(c, s);
@@ -305,12 +305,12 @@ function ce(r, t) {
305
305
  }
306
306
  var o = e.sibling(E, 2);
307
307
  {
308
- var y = (n) => {
308
+ var w = (n) => {
309
309
  var l = q(), d = e.child(l);
310
310
  p(d, {
311
311
  size: "sm",
312
312
  color: "muted",
313
- children: (c, w) => {
313
+ children: (c, y) => {
314
314
  e.next();
315
315
  var s = e.text();
316
316
  e.template_effect(() => e.set_text(s, a().serviceFees || "Service fees")), e.append(c, s);
@@ -321,7 +321,7 @@ function ce(r, t) {
321
321
  p(k, {
322
322
  size: "sm",
323
323
  color: "muted",
324
- children: (c, w) => {
324
+ children: (c, y) => {
325
325
  e.next();
326
326
  var s = e.text();
327
327
  e.template_effect((C) => e.set_text(s, C), [() => $(t.orderTotals.fees)]), e.append(c, s);
@@ -330,7 +330,7 @@ function ce(r, t) {
330
330
  }), e.reset(l), e.append(n, l);
331
331
  };
332
332
  e.if(o, (n) => {
333
- t.orderTotals.fees > 0 && n(y);
333
+ t.orderTotals.fees > 0 && n(w);
334
334
  });
335
335
  }
336
336
  var A = e.sibling(o, 2);
@@ -340,7 +340,7 @@ function ce(r, t) {
340
340
  p(d, {
341
341
  size: "sm",
342
342
  color: "muted",
343
- children: (c, w) => {
343
+ children: (c, y) => {
344
344
  e.next();
345
345
  var s = e.text();
346
346
  e.template_effect(() => e.set_text(s, a().taxes || "Taxes")), e.append(c, s);
@@ -351,7 +351,7 @@ function ce(r, t) {
351
351
  p(k, {
352
352
  size: "sm",
353
353
  color: "muted",
354
- children: (c, w) => {
354
+ children: (c, y) => {
355
355
  e.next();
356
356
  var s = e.text();
357
357
  e.template_effect((C) => e.set_text(s, C), [() => $(t.orderTotals.taxes)]), e.append(c, s);
@@ -370,7 +370,7 @@ function ce(r, t) {
370
370
  p(d, {
371
371
  size: "sm",
372
372
  color: "success",
373
- children: (c, w) => {
373
+ children: (c, y) => {
374
374
  e.next();
375
375
  var s = e.text();
376
376
  e.template_effect(() => e.set_text(s, a().promoDiscount || "Promo discount")), e.append(c, s);
@@ -381,7 +381,7 @@ function ce(r, t) {
381
381
  p(k, {
382
382
  size: "sm",
383
383
  color: "success",
384
- children: (c, w) => {
384
+ children: (c, y) => {
385
385
  e.next();
386
386
  var s = e.text();
387
387
  e.template_effect((C) => e.set_text(s, `-${C ?? ""}`), [() => $(t.orderTotals.promoDiscount)]), e.append(c, s);
@@ -400,7 +400,7 @@ function ce(r, t) {
400
400
  p(d, {
401
401
  size: "sm",
402
402
  color: "success",
403
- children: (c, w) => {
403
+ children: (c, y) => {
404
404
  e.next();
405
405
  var s = e.text();
406
406
  e.template_effect(() => e.set_text(s, a().giftCard || "Gift card")), e.append(c, s);
@@ -411,7 +411,7 @@ function ce(r, t) {
411
411
  p(k, {
412
412
  size: "sm",
413
413
  color: "success",
414
- children: (c, w) => {
414
+ children: (c, y) => {
415
415
  e.next();
416
416
  var s = e.text();
417
417
  e.template_effect((C) => e.set_text(s, `-${C ?? ""}`), [() => $(t.orderTotals.giftCardAmount)]), e.append(c, s);
@@ -452,7 +452,7 @@ function ce(r, t) {
452
452
  }
453
453
  e.reset(m), e.template_effect(() => e.set_style(m, `transition-duration: ${Z.normal}ms;`)), e.append(r, m), e.pop();
454
454
  }
455
- const Q = {
455
+ const ee = {
456
456
  // ── Ticket quantity controls ──────────────────────────────────────
457
457
  // Stepper aria-labels compose these into "Increase <name> quantity" etc.
458
458
  // `quantityNoun` is deliberately its OWN key (not the main i18n's `quantity`,
@@ -624,19 +624,19 @@ const Q = {
624
624
  waitlistLinkInventoryExhausted: "Those tickets were just claimed. You're still on the waitlist — we'll email you if more free up.",
625
625
  dismiss: "Dismiss"
626
626
  };
627
- function ue(r = {}) {
628
- return { ...Q, ...r };
627
+ function fe(r = {}) {
628
+ return { ...ee, ...r };
629
629
  }
630
630
  export {
631
- re as C,
631
+ ae as C,
632
632
  Z as D,
633
- ce as O,
634
- ie as a,
635
- oe as b,
636
- le as c,
637
- ne as d,
638
- de as e,
639
- ae as g,
640
- ue as m
633
+ ue as O,
634
+ oe as a,
635
+ ne as b,
636
+ de as c,
637
+ le as d,
638
+ ce as e,
639
+ ie as g,
640
+ fe as m
641
641
  };
642
- //# sourceMappingURL=labels-CGndTgO9.js.map
642
+ //# sourceMappingURL=labels-DXGieQXs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"labels-DXGieQXs.js","sources":["../node_modules/@getmicdrop/svelte-components/dist/primitives/Icons/phosphor/CalendarIcon.svelte","../src/lib/api/cta.ts","../src/lib/public-calendar-flow/defaults.ts","../src/lib/public-calendar-flow/OrderSummary.svelte","../src/lib/public-calendar-flow/i18n/labels.js"],"sourcesContent":["<script lang=\"ts\">\r\n /**\r\n * Calendar — Phosphor icon (canonical Micdrop icon family).\r\n * Outline by default; pass `weight=\"fill\"` for solid, or let a stateful parent\r\n * (NavItem / Tabs / BottomNav / status badge) drive it via icon-weight context.\r\n */\r\n import { useIconWeight, type IconWeight } from './iconWeight.js';\r\n\r\n interface Props {\r\n /** Pixel size (width + height). */\r\n size?: string;\r\n /** Icon color; defaults to `currentColor` (inherits text color). */\r\n color?: string;\r\n /** Extra classes. */\r\n class?: string;\r\n /** `regular` (outline) or `fill` (solid). Overrides ambient state weight. */\r\n weight?: IconWeight;\r\n }\r\n\r\n let { size = '24', color = 'currentColor', class: className = '', weight }: Props = $props();\r\n\r\n const ctx = useIconWeight();\r\n let resolved: IconWeight = $derived(weight ?? ctx?.weight ?? 'regular');\r\n</script>\r\n\r\n<svg\r\n class={className}\r\n aria-hidden=\"true\"\r\n width={size}\r\n height={size}\r\n viewBox=\"0 0 256 256\"\r\n fill=\"currentColor\"\r\n style:color={color}\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n>\r\n {#if resolved === 'fill'}<path d=\"M208,32H184V24a8,8,0,0,0-16,0v8H88V24a8,8,0,0,0-16,0v8H48A16,16,0,0,0,32,48V208a16,16,0,0,0,16,16H208a16,16,0,0,0,16-16V48A16,16,0,0,0,208,32ZM112,184a8,8,0,0,1-16,0V132.94l-4.42,2.22a8,8,0,0,1-7.16-14.32l16-8A8,8,0,0,1,112,120Zm56-8a8,8,0,0,1,0,16H136a8,8,0,0,1-6.4-12.8l28.78-38.37A8,8,0,1,0,145.07,132a8,8,0,1,1-13.85-8A24,24,0,0,1,176,136a23.76,23.76,0,0,1-4.84,14.45L152,176ZM48,80V48H72v8a8,8,0,0,0,16,0V48h80v8a8,8,0,0,0,16,0V48h24V80Z\"/>{:else}<rect x=\"40\" y=\"40\" width=\"176\" height=\"176\" rx=\"8\" fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"16\"/><line x1=\"176\" y1=\"24\" x2=\"176\" y2=\"56\" fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"16\"/><line x1=\"80\" y1=\"24\" x2=\"80\" y2=\"56\" fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"16\"/><line x1=\"40\" y1=\"88\" x2=\"216\" y2=\"88\" fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"16\"/><polyline points=\"88 128 104 120 104 184\" fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"16\"/><path d=\"M138.14,128a16,16,0,1,1,26.64,17.63L136,184h32\" fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"16\"/>{/if}\r\n</svg>\r\n","/**\r\n * CTA state computation.\r\n *\r\n * Pure function (no I/O) — derives the buy-button state from an event and\r\n * its ticket list. Lives in `api/` because it is the canonical, single\r\n * source of truth that replaces the duplicate implementations previously\r\n * scattered across utils/api.js, core/api-client.js, and a few components.\r\n */\r\n\r\n// Import from the specific subpath (not the bare entry) so the api/\r\n// bundle doesn't pull in the entire SC component graph (Accordion etc.)\r\n// and break `npm run build:api`. `formatLocal` is the sanctioned browser-local\r\n// (no-timezone) Intl label home — these \"On sale …\" countdown labels render in\r\n// the viewer's own clock, so no venue timezone applies. The datetime subpath is\r\n// leaf/component-free; only `formatLocal` (→ Intl) is pulled, no date-fns.\r\nimport { browserNow, formatLocal } from '@getmicdrop/svelte-components/datetime';\r\n// Hidden-ticket predicate from the `/transforms` leaf subpath (no component\r\n// graph, so `npm run build:api` stays clean). SC's copy was pinned FROM this\r\n// body (dedup #392) and additionally honours the backend-resolved\r\n// `effectiveSales*` window for relative-offset tickets (#388). Imported (not\r\n// just re-exported) so it stays in local scope for `computeCtaState` below.\r\nimport { isHiddenTicketPurchasable } from '@getmicdrop/svelte-components/transforms';\r\n\r\nexport interface CtaStateOptions {\r\n cancelled?: boolean;\r\n isRegistration?: boolean;\r\n waitlistEnabled?: boolean;\r\n}\r\n\r\nexport interface CtaState {\r\n text: string;\r\n disabled: boolean;\r\n reason:\r\n | 'cancelled'\r\n | 'event_past'\r\n | 'no_tickets'\r\n | 'available'\r\n | 'coming_soon'\r\n | 'sold_out_waitlist'\r\n | 'sold_out'\r\n | 'sales_ended'\r\n | 'hidden_only';\r\n}\r\n\r\ninterface CtaEvent {\r\n startDateTime?: string | null;\r\n endDateTime?: string | null;\r\n hasPurchasableHiddenTickets?: boolean;\r\n}\r\n\r\ninterface CtaTicket {\r\n salesChannel?: number;\r\n salesBegin?: string | null;\r\n salesStart?: string | null;\r\n saleBegin?: string | null;\r\n onSaleStart?: string | null;\r\n salesEnd?: string | null;\r\n saleEnd?: string | null;\r\n onSaleEnd?: string | null;\r\n remainingCapacity?: number | null;\r\n quantityRemaining?: number | null;\r\n quantity?: number | null;\r\n soldOut?: boolean;\r\n isHidden?: boolean;\r\n visibility?: number;\r\n}\r\n\r\n// A hidden ticket (visibility>=2 or isHidden) that's still on sale drives the\r\n// \"Sales ended\" / \"Sold out\" / \"No tickets\" → \"Get tickets\" override. The user\r\n// just needs the promo code to see it. Re-exported from the SC canonical so\r\n// existing consumers (cta.test.ts, computeCtaState) keep their import path while\r\n// the single-source body lives in SC (dedup #392).\r\nexport { isHiddenTicketPurchasable };\r\n\r\nexport function computeCtaState(\r\n event: CtaEvent,\r\n tickets: CtaTicket[] | undefined,\r\n options: CtaStateOptions = {}\r\n): CtaState {\r\n const {\r\n cancelled = false,\r\n isRegistration = false,\r\n waitlistEnabled = false,\r\n } = options;\r\n const now = browserNow();\r\n\r\n if (cancelled)\r\n return { text: 'Cancelled', disabled: true, reason: 'cancelled' };\r\n\r\n const eventEnd = event.endDateTime || event.startDateTime;\r\n // @datetime-escape: absolute-instant compare of a UTC-Z field vs now — tz-independent\r\n if (eventEnd && new Date(eventEnd) < now) {\r\n return { text: 'Sales ended', disabled: true, reason: 'event_past' };\r\n }\r\n\r\n const hiddenAvailable =\r\n event?.hasPurchasableHiddenTickets === true ||\r\n (Array.isArray(tickets) && tickets.some(isHiddenTicketPurchasable));\r\n\r\n const publicTickets = (tickets || []).filter(\r\n t =>\r\n t.salesChannel !== 2 &&\r\n !t.isHidden &&\r\n !(typeof t.visibility === 'number' && t.visibility >= 2)\r\n );\r\n if (publicTickets.length === 0) {\r\n if (hiddenAvailable) {\r\n return {\r\n text: isRegistration ? 'Reserve a spot' : 'Get tickets',\r\n disabled: false,\r\n reason: 'hidden_only',\r\n };\r\n }\r\n return {\r\n text: 'No tickets available',\r\n disabled: true,\r\n reason: 'no_tickets',\r\n };\r\n }\r\n\r\n let hasPurchasable = false;\r\n let allSoldOut = true;\r\n let allComingSoon = true;\r\n let earliestSalesStart: Date | null = null;\r\n\r\n for (const ticket of publicTickets) {\r\n const salesBegin =\r\n ticket.salesBegin ||\r\n ticket.salesStart ||\r\n ticket.saleBegin ||\r\n ticket.onSaleStart;\r\n const salesEnd = ticket.salesEnd || ticket.saleEnd || ticket.onSaleEnd;\r\n const remaining =\r\n ticket.remainingCapacity ?? ticket.quantityRemaining ?? ticket.quantity;\r\n const isSoldOut =\r\n ticket.soldOut ||\r\n (remaining !== null && remaining !== undefined && remaining <= 0);\r\n\r\n const isScheduled = salesBegin ? new Date(salesBegin) > now : false; // @datetime-escape: absolute-instant compare of a UTC-Z field vs now — tz-independent\r\n const hasSalesEnded = salesEnd ? new Date(salesEnd) < now : false; // @datetime-escape: absolute-instant compare of a UTC-Z field vs now — tz-independent\r\n const isPurchasable = !isSoldOut && !isScheduled && !hasSalesEnded;\r\n\r\n if (isPurchasable) hasPurchasable = true;\r\n if (!isSoldOut) allSoldOut = false;\r\n if (!isScheduled) allComingSoon = false;\r\n\r\n if (isScheduled && salesBegin && !isSoldOut && !hasSalesEnded) {\r\n const startDate = new Date(salesBegin); // @datetime-escape: absolute-instant compare of a UTC-Z field vs now — tz-independent\r\n if (!earliestSalesStart || startDate < earliestSalesStart) {\r\n earliestSalesStart = startDate;\r\n }\r\n }\r\n }\r\n\r\n if (hasPurchasable) {\r\n return {\r\n text: isRegistration ? 'Reserve a spot' : 'Get tickets',\r\n disabled: false,\r\n reason: 'available',\r\n };\r\n }\r\n\r\n if (allComingSoon && earliestSalesStart) {\r\n if (hiddenAvailable) {\r\n return {\r\n text: isRegistration ? 'Reserve a spot' : 'Get tickets',\r\n disabled: false,\r\n reason: 'hidden_only',\r\n };\r\n }\r\n const diffMs = earliestSalesStart.getTime() - now.getTime();\r\n const diffHours = diffMs / (1000 * 60 * 60);\r\n const diffDays = diffMs / (1000 * 60 * 60 * 24);\r\n // Viewer-local time label (\"8:00 PM\") — the shape shared by the <24h branch\r\n // and the >7d composite. Matches the deprecated `formatTime(d,{hour12:true})`\r\n // defaults-merge exactly.\r\n const timeLabel = (d: Date) =>\r\n formatLocal(\r\n d,\r\n { hour: 'numeric', minute: '2-digit', hour12: true },\r\n 'en-US'\r\n );\r\n let dateText: string;\r\n if (diffHours < 24) {\r\n dateText = timeLabel(earliestSalesStart);\r\n } else if (diffDays <= 7) {\r\n dateText = formatLocal(\r\n earliestSalesStart,\r\n { weekday: 'short', hour: 'numeric', minute: '2-digit', hour12: true },\r\n 'en-US'\r\n );\r\n } else {\r\n const d = formatLocal(\r\n earliestSalesStart,\r\n { month: 'short', day: 'numeric' },\r\n 'en-US'\r\n );\r\n dateText = `${d} ${timeLabel(earliestSalesStart)}`;\r\n }\r\n return {\r\n text: `On sale ${dateText}`,\r\n disabled: true,\r\n reason: 'coming_soon',\r\n };\r\n }\r\n\r\n if (allSoldOut) {\r\n if (hiddenAvailable) {\r\n return {\r\n text: isRegistration ? 'Reserve a spot' : 'Get tickets',\r\n disabled: false,\r\n reason: 'hidden_only',\r\n };\r\n }\r\n if (waitlistEnabled) {\r\n return {\r\n text: 'Join Waitlist',\r\n disabled: false,\r\n reason: 'sold_out_waitlist',\r\n };\r\n }\r\n return { text: 'Sold out', disabled: true, reason: 'sold_out' };\r\n }\r\n\r\n if (hiddenAvailable) {\r\n return {\r\n text: isRegistration ? 'Reserve a spot' : 'Get tickets',\r\n disabled: false,\r\n reason: 'hidden_only',\r\n };\r\n }\r\n\r\n return { text: 'Sales ended', disabled: true, reason: 'sales_ended' };\r\n}\r\n","// @currency-escape: feeCents / 100 in calculateServiceFee is arithmetic,\r\n// not display. Produces a dollar-magnitude number used in the fee formula\r\n// `price * (feePercentage / 100) + feeCents / 100`. Per Atlas\r\n// utility-currency convergence record; the no-handrolled-currency\r\n// ESLint rule's divideByHundred detector treats variable-name `Cents`\r\n// as drift but here it's real math.\r\n\r\n// Premium Ticket Experience — Constants & Defaults\r\n// Used by all design variants. DO NOT MODIFY per-variant.\r\n\r\n// This file is the canonical formatter module for public-calendar-flow: it\r\n// wraps + re-exports the timezone-aware production date/time formatters, plus\r\n// the shared sales-countdown formatter (formatSmartSalesDate) hoisted into\r\n// svelte-components (SC #471). No raw Intl date formatting lives here anymore.\r\n\r\nimport type {\r\n EventData,\r\n TicketTypeData,\r\n ScarcityLevel,\r\n CtaConfig,\r\n PromoCodeState,\r\n} from './types';\r\nimport { computeCtaState } from '$lib/api';\r\nimport {\r\n computeScarcityLevel,\r\n SCARCITY_THRESHOLDS,\r\n} from '$lib/constants/scarcity';\r\nimport type { Cents } from '@getmicdrop/svelte-components';\r\nimport { roundCurrency } from '@getmicdrop/svelte-components';\r\nimport { formatSmartSalesDate } from '@getmicdrop/svelte-components/utils/formatters';\r\nimport {\r\n formatFullDate,\r\n formatFullDateCompact,\r\n formatEventTime,\r\n formatTimeRange,\r\n formatDoorsTime,\r\n formatSalesDate,\r\n formatBrowseDate,\r\n formatEventDate,\r\n formatCleanTimeRange,\r\n getDateParts,\r\n} from '$lib/utils/datetime.js';\r\n\r\n// --- Re-export production date/time formatters (timezone-aware) ---\r\nexport {\r\n formatFullDate,\r\n formatFullDateCompact,\r\n formatEventTime,\r\n formatTimeRange,\r\n formatDoorsTime,\r\n formatSalesDate,\r\n formatBrowseDate,\r\n formatEventDate,\r\n formatCleanTimeRange,\r\n getDateParts,\r\n};\r\n\r\n// Shared sales-countdown formatter, adopted from svelte-components (SC #471).\r\n// Kept as a re-export so public-calendar-flow consumers import it from this\r\n// module unchanged. English defaults match VC's prior copy; the clock time\r\n// renders in UTC (matching the production TicketBlock origin) rather than the\r\n// old copy's viewer-local time.\r\nexport { formatSmartSalesDate };\r\n\r\n// --- Scarcity Badge Rules ---\r\n// Threshold logic lives in the ONE canonical computeScarcityLevel\r\n// ($lib/constants/scarcity) — including the sliding floor/cap that keeps a\r\n// 1,000-seat show from flagging \"Selling fast\" at 200 left. This module only\r\n// adapts the canon's tier enum ('sold-out'/'plenty') to public-calendar-flow's\r\n// display enum ('sold_out'/'none') and renders the copy.\r\nexport function getScarcityLevel(\r\n remaining: number,\r\n total: number\r\n): ScarcityLevel {\r\n const level = computeScarcityLevel(remaining, total);\r\n if (level === 'sold-out') return 'sold_out';\r\n if (level === 'plenty') return 'none';\r\n return level; // 'urgent' | 'low' — identical between the two enums\r\n}\r\n\r\nexport function getScarcityText(\r\n level: ScarcityLevel,\r\n remaining: number,\r\n context: 'browse' | 'event' | 'ticket',\r\n options?: { isFree?: boolean }\r\n): string | null {\r\n if (level === 'none') return null;\r\n if (level === 'sold_out') return 'Sold out';\r\n // No scarcity badges on free events/tickets — nothing to lose = no urgency\r\n if (options?.isFree) return null;\r\n if (\r\n level === 'urgent' &&\r\n context !== 'browse' &&\r\n remaining <= SCARCITY_THRESHOLDS.MAX_EXACT_COUNT\r\n ) {\r\n return `Only ${remaining} left`;\r\n }\r\n if (level === 'low' || level === 'urgent') return 'Selling fast';\r\n return null;\r\n}\r\n\r\n// --- CTA Rules ---\r\n// Delegates to production computeCtaState() but adapts our EventData shape.\r\n// Components keep calling getCtaConfig(event) — internal logic is production-aligned.\r\nexport function getCtaConfig(event: EventData): CtaConfig {\r\n // Map our EventData tickets to the shape computeCtaState expects.\r\n // `isHidden` flows through so computeCtaState can apply the hidden-only\r\n // \"Sales ended\" → \"Get tickets\" override (MIC-1039).\r\n const apiTickets = event.tickets.map(t => ({\r\n salesBegin: t.salesStartDate,\r\n salesEnd: t.salesEndDate,\r\n remainingCapacity: t.quantityAvailable,\r\n totalCapacity: t.quantityTotal,\r\n soldOut: t.status === 'sold_out',\r\n salesChannel: 1, // All our tickets are online (not \"at the door only\")\r\n isHidden: t.isHidden,\r\n }));\r\n\r\n // Handle statuses that computeCtaState doesn't compute from tickets\r\n if (event.status === 'cancelled') {\r\n return {\r\n text: 'Cancelled',\r\n disabled: true,\r\n reason: 'This event has been cancelled',\r\n };\r\n }\r\n if (event.status === 'past') {\r\n return {\r\n text: 'Event ended',\r\n disabled: true,\r\n reason: 'This event has ended',\r\n };\r\n }\r\n\r\n const result = computeCtaState(\r\n { startDateTime: event.startDateTime, endDateTime: event.endDateTime },\r\n apiTickets,\r\n {\r\n cancelled: false,\r\n isRegistration: event.isRegistrationEvent,\r\n waitlistEnabled: false,\r\n }\r\n );\r\n\r\n return {\r\n text: result.text,\r\n disabled: result.disabled,\r\n reason: result.disabled ? toFriendlyReason(result.reason) : undefined,\r\n };\r\n}\r\n\r\n/**\r\n * computeCtaState() returns machine-enum reasons ('event_past', 'sold_out',\r\n * 'coming_soon', etc) intended for branching, not display. The BookingWidget\r\n * and MobileCta render `reason` directly as supplementary copy below the\r\n * button text — which leaks raw enum strings to users.\r\n *\r\n * Map each enum to a friendly sentence, OR return undefined when the button\r\n * `text` already says everything (\"Sales ended\" / \"Sold out\" — no need for\r\n * a second line repeating it).\r\n */\r\nfunction toFriendlyReason(reason: string | undefined): string | undefined {\r\n if (!reason) return undefined;\r\n switch (reason) {\r\n case 'cancelled':\r\n return 'This event has been cancelled.';\r\n case 'event_past':\r\n return 'This event has already happened.';\r\n case 'no_tickets':\r\n return 'There are no tickets configured for this event.';\r\n case 'coming_soon':\r\n return undefined; // text already shows \"On sale <date>\"\r\n case 'sold_out':\r\n return undefined; // text already shows \"Sold out\"\r\n case 'sold_out_waitlist':\r\n return 'All tickets are claimed. Join the waitlist to be notified.';\r\n case 'sales_ended':\r\n return undefined; // text already shows \"Sales ended\"\r\n default:\r\n return undefined; // unknown enum — never leak it\r\n }\r\n}\r\n\r\n// --- Price Display Rules (from DECISIONS.md #1) ---\r\nexport function getPriceDisplay(event: EventData): string | null {\r\n const visibleTickets = event.tickets.filter(\r\n t => t.status === 'on_sale' && !t.isHidden\r\n );\r\n if (visibleTickets.length === 0) return null;\r\n\r\n const hasDonation = visibleTickets.some(\r\n t => t.isDonation || t.ticketType === 2\r\n );\r\n const paidTickets = visibleTickets.filter(\r\n t => !t.isDonation && t.ticketType !== 2\r\n );\r\n const hasFree = paidTickets.some(t => t.price === 0);\r\n const pricedTickets = paidTickets.filter(t => t.price > 0);\r\n\r\n // Only donation tickets → \"Donation\"\r\n if (pricedTickets.length === 0 && !hasFree && hasDonation) return 'Donation';\r\n\r\n // Only free tickets (no paid, no donation) → null (BookingWidget shows \"Free\" via isFreeEvent)\r\n if (pricedTickets.length === 0 && hasFree) return null;\r\n\r\n const minPrice = Math.min(...pricedTickets.map(t => t.price));\r\n\r\n // Free + paid → \"Free\" (free dominates the display). Non-donation free tickets\r\n // outrank the paid options in the headline, matching the shared \"Free\" label\r\n // every other price surface uses. Returning null here left the widget blank.\r\n if (hasFree) return 'Free';\r\n\r\n // Donation + paid → \"From $X\" (donation is an alternative option)\r\n if (hasDonation) return `From $${minPrice}`;\r\n\r\n // Single paid ticket type → \"$X\"\r\n if (pricedTickets.length === 1) return `$${minPrice}`;\r\n\r\n // Multiple paid ticket types → \"From $X\"\r\n return `From $${minPrice}`;\r\n}\r\n\r\n// --- Fee Calculation ---\r\nexport function calculateFee(\r\n price: number,\r\n feePercentage: number,\r\n feeCents: Cents\r\n): number {\r\n return roundCurrency(price * (feePercentage / 100) + feeCents / 100);\r\n}\r\n\r\nexport function calculateTax(amount: number, taxPercentage: number): number {\r\n return roundCurrency(amount * (taxPercentage / 100));\r\n}\r\n\r\n// --- Date Formatting ---\r\n// PREFERRED: Use the timezone-aware production formatters re-exported above:\r\n// formatBrowseDate(iso, tz) → \"Fri, Feb 20\"\r\n// formatFullDateCompact(iso, tz) → \"Friday, February 20\"\r\n// formatEventTime(iso, tz) → \"8:00 PM\"\r\n// formatTimeRange(start, end, tz) → \"8:00 PM - 10:00 PM\"\r\n// formatDoorsTime(doors, tz) → \"7:00 PM\"\r\n\r\n// --- Animation Durations ---\r\nexport const DURATION = {\r\n instant: 100,\r\n micro: 150,\r\n fast: 200,\r\n normal: 300,\r\n slow: 400,\r\n elaborate: 600,\r\n} as const;\r\n\r\n// --- Promo Code State Factory ---\r\nexport function createDefaultPromoState(): PromoCodeState {\r\n return {\r\n code: '',\r\n isApplied: false,\r\n isValidating: false,\r\n error: '',\r\n hint: '',\r\n discountAmount: 0,\r\n discountType: '',\r\n discountTicketIds: [],\r\n revealHiddenTickets: false,\r\n revealTicketIds: [],\r\n };\r\n}\r\n\r\n// --- Ticket helpers ---\r\nexport function getAvailableTickets(\r\n tickets: TicketTypeData[]\r\n): TicketTypeData[] {\r\n return tickets.filter(t => !t.isHidden && t.status === 'on_sale');\r\n}\r\n","<!-- @style-escape: widget-intentional. -->\r\n<script lang=\"ts\">\r\n import type { USD } from '@getmicdrop/svelte-components';\r\n import { Text, formatCurrency } from '@getmicdrop/svelte-components';\r\n import type { OrderTotals } from '$lib/public-calendar-flow/types';\r\n import { formatPriceOrFree } from '$lib/core';\r\n import { DURATION } from '$lib/public-calendar-flow/defaults';\r\n\r\n interface Props {\r\n orderTotals: OrderTotals;\r\n labels?: Record<string, string>;\r\n /**\r\n * Which section to render.\r\n * - `full` (default): ticket lines + totals stacked together.\r\n * - `lines` : ticket-line items only. Use when the parent scrolls\r\n * this section in a flex column.\r\n * - `totals` : subtotal/fees/taxes/promo/total only. Use in a fixed\r\n * footer alongside the action button.\r\n *\r\n * Splitting via `lines` / `totals` lets the sticky sidebars scroll\r\n * just the variable-length ticket list while keeping the summary\r\n * block and CTA always visible.\r\n */\r\n mode?: 'full' | 'lines' | 'totals';\r\n }\r\n\r\n let { orderTotals, labels = {}, mode = 'full' }: Props = $props();\r\n</script>\r\n\r\n<div class=\"space-y-2\" style=\"transition-duration: {DURATION.normal}ms;\">\r\n {#if mode !== 'totals'}\r\n <!-- Line items -->\r\n {#each orderTotals.lines as line (line.ticketId)}\r\n <div class=\"flex justify-between\">\r\n <Text size=\"sm\">{line.quantity}x {line.ticketName}</Text>\r\n <Text size=\"sm\"\r\n >{line.isDonation\r\n ? formatCurrency(line.subtotal as USD)\r\n : formatPriceOrFree(line.subtotal, labels)}</Text\r\n >\r\n </div>\r\n {/each}\r\n {/if}\r\n\r\n {#if mode !== 'lines'}\r\n <!-- Subtotal. In `totals` mode the parent supplies the separator above\r\n\t\t this block (BookingWidget wraps the totals block in border-t); a\r\n\t\t second internal border would render as a double line. Only show\r\n\t\t the internal border-t in `full` mode where lines + totals stack\r\n\t\t in one container with no external separator. -->\r\n {#if mode === 'full' && orderTotals.lines.length > 1}\r\n <div class=\"flex justify-between pt-1 border-t border-default\">\r\n <Text size=\"sm\" color=\"muted\">{labels.subtotal || 'Subtotal'}</Text>\r\n <Text size=\"sm\" color=\"muted\"\r\n >{formatCurrency(orderTotals.subtotal as USD)}</Text\r\n >\r\n </div>\r\n {:else if orderTotals.lines.length > 1}\r\n <div class=\"flex justify-between\">\r\n <Text size=\"sm\" color=\"muted\">{labels.subtotal || 'Subtotal'}</Text>\r\n <Text size=\"sm\" color=\"muted\"\r\n >{formatCurrency(orderTotals.subtotal as USD)}</Text\r\n >\r\n </div>\r\n {/if}\r\n\r\n <!-- Fees -->\r\n {#if orderTotals.fees > 0}\r\n <div class=\"flex justify-between\">\r\n <Text size=\"sm\" color=\"muted\"\r\n >{labels.serviceFees || 'Service fees'}</Text\r\n >\r\n <Text size=\"sm\" color=\"muted\"\r\n >{formatCurrency(orderTotals.fees as USD)}</Text\r\n >\r\n </div>\r\n {/if}\r\n\r\n <!-- Taxes -->\r\n {#if orderTotals.taxes > 0}\r\n <div class=\"flex justify-between\">\r\n <Text size=\"sm\" color=\"muted\">{labels.taxes || 'Taxes'}</Text>\r\n <Text size=\"sm\" color=\"muted\"\r\n >{formatCurrency(orderTotals.taxes as USD)}</Text\r\n >\r\n </div>\r\n {/if}\r\n\r\n <!-- Promo discount -->\r\n {#if orderTotals.promoDiscount > 0}\r\n <div class=\"flex justify-between\">\r\n <Text size=\"sm\" color=\"success\"\r\n >{labels.promoDiscount || 'Promo discount'}</Text\r\n >\r\n <Text size=\"sm\" color=\"success\"\r\n >-{formatCurrency(orderTotals.promoDiscount as USD)}</Text\r\n >\r\n </div>\r\n {/if}\r\n\r\n <!-- Gift card — deduction from the amount due; `total` already reflects it -->\r\n {#if orderTotals.giftCardAmount > 0}\r\n <div class=\"flex justify-between\">\r\n <Text size=\"sm\" color=\"success\">{labels.giftCard || 'Gift card'}</Text>\r\n <Text size=\"sm\" color=\"success\"\r\n >-{formatCurrency(orderTotals.giftCardAmount as USD)}</Text\r\n >\r\n </div>\r\n {/if}\r\n\r\n <!-- Total -->\r\n <div class=\"flex justify-between pt-2 border-t border-default\">\r\n <Text size=\"base\" weight=\"semibold\">{labels.total || 'Total'}</Text>\r\n <Text size=\"base\" weight=\"semibold\"\r\n >{formatCurrency(orderTotals.total as USD)}</Text\r\n >\r\n </div>\r\n {/if}\r\n</div>\r\n","/**\r\n * Default English labels for public-calendar-flow components.\r\n * Consumers override via the `labels` prop on any *Main component.\r\n *\r\n * Label keys use flat camelCase. For composed strings (e.g. aria-labels),\r\n * components build them from atomic label parts.\r\n */\r\nexport const defaultLabels = {\r\n // ── Ticket quantity controls ──────────────────────────────────────\r\n // Stepper aria-labels compose these into \"Increase <name> quantity\" etc.\r\n // `quantityNoun` is deliberately its OWN key (not the main i18n's `quantity`,\r\n // whose value is the sr-only display PREFIX 'Quantity:') so the main-i18n\r\n // merge can't leak a capital-Q + trailing colon into the button labels.\r\n // Overridable, same as increase/decrease, which main i18n also doesn't define.\r\n decrease: 'Decrease',\r\n increase: 'Increase',\r\n quantityNoun: 'quantity',\r\n\r\n // ── Ticket states ─────────────────────────────────────────────────\r\n soldOut: 'Sold out',\r\n free: 'Free',\r\n unavailable: 'Unavailable',\r\n eventSoldOut: 'This event is sold out',\r\n\r\n // ── Price display ─────────────────────────────────────────────────\r\n includesFees: 'Includes',\r\n fees: 'fees',\r\n fee: 'fee',\r\n\r\n // ── Checkout CTAs ─────────────────────────────────────────────────\r\n checkout: 'Checkout',\r\n getTickets: 'Get tickets',\r\n selectTickets: 'Select tickets',\r\n selectTicketsBelow: 'Select tickets below',\r\n selectTicketsToContinue: 'Select tickets to continue',\r\n reserveASpot: 'Reserve a spot',\r\n\r\n // ── Password modal / gate ─────────────────────────────────────────\r\n enterPassword: 'Enter password',\r\n enterEventPassword: 'Enter event password',\r\n passwordRequired: 'Password required',\r\n passwordRequiredShort: 'Password required',\r\n eventRequiresPassword: 'This event requires a password to purchase tickets.',\r\n eventRequiresPasswordAccess:\r\n 'This event requires a password to access tickets.',\r\n enterEventPasswordToView: 'Enter the event password to view tickets.',\r\n enterEventPasswordToViewAvailable:\r\n 'Enter the event password to view available tickets.',\r\n eventPassword: 'Event password',\r\n password: 'Password',\r\n pleaseEnterPassword: 'Please enter the event password',\r\n pleaseEnterAPassword: 'Please enter a password',\r\n eventRequiresPasswordShort: 'This event requires a password',\r\n unlockTickets: 'Unlock tickets',\r\n cancel: 'Cancel',\r\n continue: 'Continue',\r\n submit: 'Submit',\r\n\r\n // ── Order summary ─────────────────────────────────────────────────\r\n subtotal: 'Subtotal',\r\n serviceFees: 'Service fees',\r\n taxes: 'Taxes',\r\n tax: 'Tax',\r\n promoDiscount: 'Promo discount',\r\n giftCard: 'Gift card',\r\n total: 'Total',\r\n orderSummary: 'Order summary',\r\n yourOrder: 'Your order',\r\n\r\n // ── Ticket counts (used in CTA buttons) ───────────────────────────\r\n ticket: 'ticket',\r\n tickets: 'tickets',\r\n\r\n // ── Checkout form (public-calendar-flow) ───────────────────────────────\r\n yourDetails: 'Your details',\r\n attendeeDetails: 'Attendee details',\r\n attendee: 'Attendee',\r\n sameAsPurchaser: 'Same as purchaser',\r\n payment: 'Payment',\r\n noPaymentRequired: 'No payment required',\r\n freeEventMessage:\r\n 'This is a free event. Complete the form above to reserve your spot.',\r\n firstName: 'First name',\r\n lastName: 'Last name',\r\n emailAddress: 'Email address',\r\n email: 'Email',\r\n emailPlaceholder: 'you@example.com',\r\n attendeeEmailPlaceholder: 'attendee@example.com',\r\n cardNumber: 'Card number',\r\n cardPlaceholder: '4242 4242 4242 4242',\r\n expiryDate: 'Expiry date',\r\n expiryPlaceholder: 'MM / YY',\r\n cvc: 'CVC',\r\n cvcPlaceholder: '123',\r\n keepMeUpdated: 'Keep me updated about this event and similar events',\r\n agreeToTerms: 'I agree to the terms and conditions',\r\n goBack: 'Go back',\r\n loadingPaymentForm: 'Loading secure payment form...',\r\n\r\n // ── Checkout form validation ──────────────────────────────────────\r\n firstNameRequired: 'First name is required',\r\n lastNameRequired: 'Last name is required',\r\n emailRequired: 'Email is required',\r\n emailInvalid: 'Enter a valid email address',\r\n emailInvalidShort: 'Enter a valid email',\r\n cardNumberRequired: 'Card number is required',\r\n expiryRequired: 'Expiry date is required',\r\n cvcRequired: 'CVC is required',\r\n mustAgreeTerms: 'You must agree to the terms',\r\n\r\n // ── Place order CTAs ──────────────────────────────────────────────\r\n placeOrder: 'Place order',\r\n completeOrder: 'Complete order',\r\n placingOrder: 'Placing order...',\r\n\r\n // ── Promo code ────────────────────────────────────────────────────\r\n havePromoCode: 'Have a promo code?',\r\n promoCode: 'Promo code',\r\n enterCode: 'Enter code',\r\n apply: 'Apply',\r\n remove: 'Remove',\r\n removePromoCode: 'Remove promo code',\r\n applyPromoCode: 'Apply promo code',\r\n checkingPromoCode: 'Checking promo code',\r\n checking: 'Checking...',\r\n promoApplied: 'Promo applied',\r\n\r\n // ── Navigation tabs (app-segments) ────────────────────────────────\r\n about: 'About',\r\n ticketsTab: 'Tickets',\r\n eventSections: 'Event sections',\r\n\r\n // ── Event details ─────────────────────────────────────────────────\r\n eventDetails: 'Event details',\r\n performers: 'Performers',\r\n faq: 'FAQ',\r\n frequentlyAskedQuestions: 'Frequently asked questions',\r\n doors: 'Doors',\r\n doorsOpenAt: 'Doors open at',\r\n\r\n // ── Series occurrences ────────────────────────────────────────────\r\n upcomingDates: 'Upcoming dates',\r\n\r\n // ── Close / dismiss ───────────────────────────────────────────────\r\n closeTicketSelection: 'Close ticket selection',\r\n closeTicketSelector: 'Close ticket selector',\r\n\r\n // ── Accessibility ─────────────────────────────────────────────────\r\n ticketSelection: 'ticket selection',\r\n ticketsSelected: 'tickets selected',\r\n view: 'View',\r\n\r\n // ── Success page (public-calendar-flow) ────────────────────────────────\r\n youreIn: \"You're in\",\r\n youreRegistered: \"You're registered\",\r\n confirmed: 'confirmed',\r\n viewTickets: 'View tickets',\r\n order: 'Order',\r\n confirmationSentTo: 'Confirmation sent to',\r\n addToCalendar: 'Add to calendar',\r\n googleCalendar: 'Google Calendar',\r\n appleCalendar: 'Apple Calendar (.ics)',\r\n share: 'Share',\r\n map: 'Map',\r\n backToEvent: 'Back to event',\r\n needHelp: 'Need help?',\r\n linkCopied: 'Link copied to clipboard',\r\n copyLink: 'Copy this link:',\r\n addToAppleWallet: 'Add to Apple Wallet',\r\n saveToGoogleWallet: 'Save to Google Wallet',\r\n\r\n // ── Session timer / expiration modals ─────────────────────────────\r\n sessionExpiringSoon: 'Session expiring soon',\r\n sessionExpiringSoonMessage:\r\n 'Your checkout session will expire in {time}. Your selected tickets will be released back to inventory.',\r\n extensionsRemaining: '{count} extension{plural} remaining',\r\n continueCheckout: 'Continue checkout',\r\n okIllHurry: \"OK, I'll hurry\",\r\n maxExtensionsReached: 'Maximum extensions reached',\r\n wantToKeepTickets: 'Want to keep your tickets?',\r\n sessionExpiredMessage:\r\n 'Your checkout session has expired and your selected tickets have been released.',\r\n sessionExpired: 'Session expired',\r\n reservationTimedOut:\r\n 'Your reservation has timed out. Please select your tickets again to continue.',\r\n keepMyTickets: 'Keep my tickets',\r\n selectTicketsAgain: 'Select tickets again',\r\n extendingSession: 'Extending...',\r\n\r\n // ── MobileCta ─────────────────────────────────────────────────────\r\n selectTicketsLabel: 'Select tickets',\r\n\r\n // ── Waitlist (sold-out gating + tokenized unlock) ─────────────────\r\n joinWaitlist: 'Join waitlist',\r\n getNotifiedWhenAvailable: 'Get notified when tickets are available',\r\n // Tokenized-link unlock outcomes (decisions #3/#22/#36). Mapped from the\r\n // server's failure enum; shown as a small dismissible notice near the CTA.\r\n waitlistLinkInvalid:\r\n \"This link isn't valid. You're still on the waitlist — we'll email you if tickets free up.\",\r\n waitlistLinkExpired: \"This link has expired. You're still on the waitlist.\",\r\n waitlistLinkUsed:\r\n \"This link has already been used. You're still on the waitlist.\",\r\n waitlistLinkEmailMismatch:\r\n \"This link was sent to a different email address. You're still on the waitlist.\",\r\n waitlistLinkInventoryExhausted:\r\n \"Those tickets were just claimed. You're still on the waitlist — we'll email you if more free up.\",\r\n dismiss: 'Dismiss',\r\n};\r\n\r\n/**\r\n * Merge user-provided label overrides with the defaults.\r\n * Shallow merge — any key provided by the consumer wins.\r\n *\r\n * @param {Record<string, string>} [userLabels] - Partial label overrides\r\n * @returns {Record<string, string>} Merged labels object\r\n */\r\nexport function mergeLabels(userLabels = {}) {\r\n return { ...defaultLabels, ...userLabels };\r\n}\r\n"],"names":["size","$","$$props","color","className","ctx","useIconWeight","resolved","svg","root_2","path","root","$$render","consequent","alternate","styles","computeCtaState","event","tickets","options","cancelled","isRegistration","waitlistEnabled","now","browserNow","eventEnd","hiddenAvailable","isHiddenTicketPurchasable","publicTickets","t","hasPurchasable","allSoldOut","allComingSoon","earliestSalesStart","ticket","salesBegin","salesEnd","remaining","isSoldOut","isScheduled","hasSalesEnded","startDate","diffMs","diffHours","diffDays","timeLabel","d","formatLocal","dateText","getScarcityLevel","total","level","computeScarcityLevel","getScarcityText","context","SCARCITY_THRESHOLDS","getCtaConfig","apiTickets","result","toFriendlyReason","reason","getPriceDisplay","visibleTickets","hasDonation","paidTickets","hasFree","pricedTickets","minPrice","calculateTax","amount","taxPercentage","roundCurrency","DURATION","createDefaultPromoState","labels","mode","div","root_3","node_1","line","div_1","Text","node_2","text","node_3","formatCurrency","formatPriceOrFree","div_2","root_1","node_6","node_7","$0","text_3","div_3","node_8","node_9","text_5","consequent_1","consequent_2","div_4","node_11","node_12","text_7","consequent_3","div_5","node_14","node_15","text_9","consequent_4","div_6","node_17","node_18","text_11","consequent_5","div_7","node_20","node_21","text_13","consequent_6","div_8","node_19","node_22","node_23","text_15","consequent_7","defaultLabels","mergeLabels","userLabels"],"mappings":"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","x_google_ignoreList":[0]}
@@ -1,6 +1,6 @@
1
1
  import "svelte/internal/disclose-version";
2
2
  import * as e from "svelte/internal/client";
3
- import { aH as u, aI as d } from "./VenueCalendar-Dhoi9hF5.js";
3
+ import { aO as u, aP as d } from "./VenueCalendar-CU5N9klc.js";
4
4
  var f = e.from_html("<div><!></div>");
5
5
  function g(t, s) {
6
6
  e.push(s, !0), u();
@@ -53,4 +53,4 @@ export {
53
53
  g as M,
54
54
  m as c
55
55
  };
56
- //# sourceMappingURL=modalManager.svelte-BgW5Xd6y.js.map
56
+ //# sourceMappingURL=modalManager.svelte-Dbd1xgTQ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"modalManager.svelte-Dbd1xgTQ.js","sources":["../node_modules/@getmicdrop/svelte-components/dist/primitives/Modal/ModalHeader.svelte","../node_modules/@getmicdrop/svelte-components/dist/utils/modalManager.svelte.js"],"sourcesContent":["<script lang=\"ts\">\r\n import type { Snippet } from 'svelte';\r\n import { getModalContext } from './context.js';\r\n import { cn } from '../../utils/classNames.js';\r\n\r\n interface Props {\r\n class?: string;\r\n children?: Snippet;\r\n }\r\n\r\n let { class: className, children }: Props = $props();\r\n\r\n // Validates this component is inside ModalRoot\r\n getModalContext();\r\n</script>\r\n\r\n<div class={cn('shrink-0 px-6 pt-6 pb-3', className)}>\r\n {#if children}{@render children()}{/if}\r\n</div>\r\n","/**\n * behavior-modal-orchestration canonical (R-MODAL-1/3).\n *\n * Two rune primitives for modal open-state — pick by modal count:\n *\n * - `createModalState<T>()` — ONE modal. Replaces the dominant\n * `let showFooModal = $state(false)` + `let fooData = $state(null)` pair.\n * Use: `modal.isOpen`, `modal.data`, `modal.open(data?)`, `modal.close()`.\n *\n * - `createModalManager<Id>()` — a page with 3+ modals. Replaces N booleans\n * with one registry: `m.open(id, payload?)`, `m.close(id)`, `m.isOpen(id)`,\n * `m.payload(id)`, `m.active`, `m.closeAll()`. Coordinates exclusive-open\n * (opening one closes the others) and focus-return (focus goes back to the\n * element that was active before the first modal opened) in one place,\n * instead of the implicit-by-convention mutual exclusion seen across the\n * 4-modal accounts page and the 3-modal checkout hand-off chains.\n *\n * `createModalState` is lifted verbatim from micdrop-frontend's storeUtils\n * (zero consumers there); `createModalManager` is new — no modal coordinator\n * existed in any of the four repos.\n *\n * ## Binding to `ModalRoot` (`bind()`)\n * Both factories expose a `bind(...)` helper returning the props to spread onto a\n * `ModalRoot`, wiring its open-state to the manager:\n *\n * <ModalRoot {...modals.bind('edit')}>…</ModalRoot> // multi\n * <ModalRoot {...editModal.bind()}>…</ModalRoot> // single\n *\n * `bind()` returns a `{ get open, set open, oncancel }` object. The `open`\n * **getter** keeps `ModalRoot` reading the manager's live open-state (so opening\n * the modal anywhere re-renders it); `oncancel` closes the modal through the\n * manager. `ModalRoot`'s only self-close path (`resetModal`) always fires\n * `oncancel` before flipping its own local `open`, so escape / backdrop dismissal\n * routes back through the manager and the two never desync.\n *\n * This deliberately avoids the foot-gun it replaces: you can't write\n * `bind:open={modals.isOpen('edit')}` (a method call isn't an assignable lvalue),\n * and feeding `bind:open` a `$derived` is the read-only binding runtime bug. The\n * getter + `oncancel` spread sidesteps both — no per-page `$state` boolean, no\n * accidental derived binding. The `set open` setter completes the\n * getter/setter pair so the object also reads/writes cleanly when assigned to\n * programmatically. Scroll-lock + focus-trap stay in `ModalRoot`; the manager\n * owns only open-state, payload, exclusivity, and focus-return.\n */\n/**\n * Reactive open/close state for a single modal, with optional context data.\n *\n * @example\n * const editModal = createModalState<User>();\n * editModal.open(user); // editModal.isOpen === true, editModal.data === user\n * editModal.close(); // isOpen === false, data === null\n *\n * // Compose with ModalRoot by spreading the bind() props:\n * // <ModalRoot {...editModal.bind()}>…</ModalRoot>\n */\nexport function createModalState() {\n let isOpen = $state(false);\n let data = $state(null);\n return {\n get isOpen() {\n return isOpen;\n },\n get data() {\n return data;\n },\n open(newData) {\n data = newData ?? null;\n isOpen = true;\n },\n close() {\n isOpen = false;\n data = null;\n },\n toggle(newData) {\n if (isOpen) {\n isOpen = false;\n data = null;\n }\n else {\n data = newData ?? null;\n isOpen = true;\n }\n },\n bind() {\n return {\n get open() {\n return isOpen;\n },\n set open(value) {\n // Binding-driven open carries no data (data stays null); use the\n // explicit open(data) call when a payload is needed.\n if (value)\n isOpen = true;\n else {\n isOpen = false;\n data = null;\n }\n },\n oncancel() {\n isOpen = false;\n data = null;\n },\n };\n },\n };\n}\n/**\n * Coordinate a set of named modals on one page. See module docs for when to\n * reach for this over `createModalState`.\n *\n * @example\n * const modals = createModalManager<'create' | 'edit' | 'delete'>();\n * modals.open('edit', user);\n * modals.isOpen('edit'); // true\n * modals.payload<User>('edit');\n * modals.open('delete'); // 'edit' auto-closes (exclusive)\n * modals.closeAll(); // focus returns to the original trigger\n *\n * // Compose with ModalRoot by spreading the bind() props:\n * // <ModalRoot {...modals.bind('edit')}>…</ModalRoot>\n */\nexport function createModalManager(options = {}) {\n const exclusive = options.exclusive ?? true;\n const restoreFocus = options.restoreFocus ?? true;\n const modals = $state({});\n let returnFocusEl = null;\n function anyOpen() {\n return Object.values(modals).some((m) => m.open);\n }\n function isOpen(id) {\n return modals[id]?.open ?? false;\n }\n /** Remember the active element when transitioning from \"none open\" → \"open\". */\n function captureReturnFocus() {\n if (!restoreFocus || typeof document === 'undefined')\n return;\n if (!anyOpen()) {\n const el = document.activeElement;\n returnFocusEl = el instanceof HTMLElement ? el : null;\n }\n }\n /** Return focus to the captured trigger once everything is closed. */\n function restoreReturnFocus() {\n if (!restoreFocus)\n return;\n if (!anyOpen() && returnFocusEl) {\n returnFocusEl.focus();\n returnFocusEl = null;\n }\n }\n function open(id, payload) {\n captureReturnFocus();\n if (exclusive) {\n for (const key of Object.keys(modals)) {\n if (key !== id) {\n modals[key].open = false;\n modals[key].payload = null;\n }\n }\n }\n modals[id] = { open: true, payload: payload ?? null };\n }\n function close(id) {\n const entry = modals[id];\n if (entry) {\n entry.open = false;\n entry.payload = null;\n }\n restoreReturnFocus();\n }\n function toggle(id, payload) {\n if (isOpen(id))\n close(id);\n else\n open(id, payload);\n }\n function closeAll() {\n for (const key of Object.keys(modals)) {\n modals[key].open = false;\n modals[key].payload = null;\n }\n restoreReturnFocus();\n }\n return {\n isOpen,\n payload(id) {\n return modals[id]?.payload ?? null;\n },\n get active() {\n return Object.keys(modals).filter((key) => modals[key].open);\n },\n open,\n close,\n toggle,\n closeAll,\n bind(id) {\n return {\n get open() {\n return isOpen(id);\n },\n set open(value) {\n // Binding-driven open carries no payload; use open(id, payload) for that.\n if (value)\n open(id);\n else\n close(id);\n },\n oncancel() {\n close(id);\n },\n };\n },\n };\n}\n"],"names":["getModalContext","div","root","$0","$","cn","$$props","createModalState","isOpen","data","newData","value"],"mappings":";;;;iBAAA;iBAaEA,EAAe;MAGhBC,IAAGC,EAAA,eAAHD,CAAG;;;;;;;;;;UAAHA,CAAG,wCAAHA,GAAG,GAAAE,CAAA,GAAA,CAAA,MAAAC,EAAA,KAAQC,EAAG,2BAAyBC,EAAA,KAAA,CAAA,CAAA,CAAA,eAAvCL,CAAG;AAFI;ACyCD,SAASM,IAAmB;AAC/B,MAAIC,IAASJ,EAAA,MAAO,EAAK,GACrBK,IAAOL,EAAA,MAAO,IAAI;AACtB,SAAM;AAAA,IACF,IAAI,SAAS;AACT,mBAAOI,CAAM;AAAA,IACjB;AAAA,IACA,IAAI,OAAO;AACP,mBAAOC,CAAI;AAAA,IACf;AAAA,IACA,KAAKC,GAAS;YACVD,GAAOC,KAAW,MAAI,EAAA,GACtBN,EAAA,IAAAI,GAAS,EAAI;AAAA,IACjB;AAAA,IACA,QAAQ;AACJ,MAAAJ,EAAA,IAAAI,GAAS,EAAK,GACdJ,EAAA,IAAAK,GAAO,IAAI;AAAA,IACf;AAAA,IACA,OAAOC,GAAS;AACZ,MAAEN,EAAA,IAAEI,CAAM,KACNJ,EAAA,IAAAI,GAAS,EAAK,GACdJ,EAAA,IAAAK,GAAO,IAAI,YAGXA,GAAOC,KAAW,MAAI,EAAA,GACtBN,EAAA,IAAAI,GAAS,EAAI;AAAA,IAErB;AAAA,IACA,OAAO;AACH,aAAM;AAAA,QACF,IAAI,OAAO;AACP,uBAAOA,CAAM;AAAA,QACjB;AAAA,QACA,IAAI,KAAKG,GAAO;AAGZ,UAAIA,IAAKP,EAAA,IACLI,GAAS,EAAI,KAEbJ,EAAA,IAAAI,GAAS,EAAK,GACdJ,EAAA,IAAAK,GAAO,IAAI;AAAA,QAEnB;AAAA,QACA,WAAW;AACP,UAAAL,EAAA,IAAAI,GAAS,EAAK,GACdJ,EAAA,IAAAK,GAAO,IAAI;AAAA,QACf;AAAA;IAER;AAAA;AAER;","x_google_ignoreList":[0,1]}
@@ -0,0 +1,29 @@
1
+ import { ay as c, az as f, aA as m, aB as u } from "./VenueCalendar-CU5N9klc.js";
2
+ function l(r) {
3
+ return r === "percentage" || r === "%";
4
+ }
5
+ function t(r, e, s) {
6
+ if (!(e > 0) || !(r > 0)) return 0;
7
+ const n = l(s) ? r * e / 100 : e, a = Math.max(0, Math.min(r, n));
8
+ return Math.round(a * 100) / 100;
9
+ }
10
+ function C(r, e, s, n) {
11
+ if (!(s > 0)) return 0;
12
+ if (!l(n))
13
+ return t(e, s, n);
14
+ const a = r.filter(({ quantity: o }) => o > 0).map(
15
+ ({ unitPrice: o, quantity: i }) => c(
16
+ f(
17
+ t(o, s, n)
18
+ ),
19
+ i
20
+ )
21
+ );
22
+ return m(u(a));
23
+ }
24
+ export {
25
+ C as a,
26
+ l as i,
27
+ t as r
28
+ };
29
+ //# sourceMappingURL=promo-oWi_MKmY.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"promo-oWi_MKmY.js","sources":["../src/lib/utils/promo.ts"],"sourcesContent":["// Canonical promo-discount resolver.\r\n//\r\n// The promo apply endpoint returns a discount as { amount, discountType } where\r\n// a percentage promo's `amount` is the raw percent (e.g. 10 for \"10%\"). The\r\n// order-summary display path stores that raw number in the per-event\r\n// `checkout-promo-discount-${eventID}` cookie and subtracts it from the\r\n// subtotal as if it were dollars — so a \"10%\" promo renders as a flat \"$10 off\"\r\n// regardless of cart size. PromocodeInput cannot fix this at write-time: it has no subtotal\r\n// (it can even auto-apply before any ticket is chosen). The correct dollar\r\n// value is subtotal-dependent, so it must be resolved wherever the subtotal is\r\n// known, using the stored discount type.\r\n//\r\n// Single source of truth for that resolution. Two discountType vocabularies\r\n// exist in the codebase — the API/cookie form ('percentage' | 'fixed') and the\r\n// per-ticket/pcf form ('%' | '$') — so both are accepted.\r\n\r\nimport {\r\n dollarsToCents,\r\n mulCents,\r\n sumCents,\r\n centsToDollars,\r\n} from '@getmicdrop/svelte-components';\r\n\r\n// The meaningful discount-type values. The resolver accepts any string (the\r\n// value comes from a cookie / promo-change event, i.e. an untyped `string`) and\r\n// treats anything that isn't a percentage marker as a fixed dollar amount.\r\nexport type PromoDiscountType =\r\n | 'percentage'\r\n | 'fixed'\r\n | '%'\r\n | '$'\r\n | ''\r\n | null\r\n | undefined;\r\n\r\ntype PromoDiscountTypeInput = PromoDiscountType | string;\r\n\r\n/**\r\n * Is this promo a percentage promo?\r\n *\r\n * Callers need this to know WHERE a promo may be shown, not just how to size\r\n * it. A percentage promo is *per-ticket*: 20% off each unit summed over the\r\n * cart is exactly 20% off the subtotal, so a ticket row can show it and still\r\n * agree with the order summary. A fixed promo is *order-level*: \"$5 off\" is\r\n * taken once against the subtotal, so a row that shows \"$5 off\" on every unit\r\n * promises `amount × (qty − 1)` more than the order will give.\r\n *\r\n * Anything that isn't a percentage marker is treated as a fixed dollar amount\r\n * (the value arrives from a cookie / promo-change event, i.e. an untyped\r\n * `string`).\r\n */\r\nexport function isPercentageDiscount(\r\n discountType: PromoDiscountTypeInput\r\n): boolean {\r\n return discountType === 'percentage' || discountType === '%';\r\n}\r\n\r\n/**\r\n * Resolve a promo discount to a dollar amount against the current subtotal.\r\n *\r\n * @param subtotal - order subtotal in dollars.\r\n * @param rawAmount - the discount value from the promo response: a percent for\r\n * a percentage promo, a dollar amount for a fixed promo.\r\n * @param discountType - 'percentage'/'%' or 'fixed'/'$' (or empty → fixed).\r\n * @returns the discount in dollars, clamped to [0, subtotal].\r\n */\r\nexport function resolvePromoDiscountDollars(\r\n subtotal: number,\r\n rawAmount: number,\r\n discountType: PromoDiscountTypeInput\r\n): number {\r\n if (!(rawAmount > 0) || !(subtotal > 0)) return 0;\r\n\r\n const dollars = isPercentageDiscount(discountType)\r\n ? (subtotal * rawAmount) / 100\r\n : rawAmount;\r\n\r\n const clamped = Math.max(0, Math.min(subtotal, dollars));\r\n // Round to cents so the deduction matches the currency-formatted display.\r\n return Math.round(clamped * 100) / 100;\r\n}\r\n\r\n/** One cart line: a ticket's unit price (dollars) and how many are in the cart. */\r\nexport interface PromoDiscountLine {\r\n unitPrice: number;\r\n quantity: number;\r\n}\r\n\r\n/**\r\n * Resolve a promo discount for the WHOLE ORDER, rounding the SAME way the\r\n * ticket rows do — so the row and the order summary can never disagree by a\r\n * cent.\r\n *\r\n * A percentage promo shows on every ticket ROW. A row renders a unit price\r\n * rounded to cents, so the discount a buyer reads off the rows is\r\n * `Σ quantity × round(unitPrice × pct)`. If the summary instead rounds\r\n * `pct × subtotal` ONCE, the two round independently and can land up to a cent\r\n * apart per line — the buyer sees two different numbers for the same discount.\r\n * So the summary sums the per-unit rounded discounts: one rounding decision\r\n * (per unit), shared by both surfaces. Each per-unit discount comes from the\r\n * same canonical {@link resolvePromoDiscountDollars} the row calls, so there is\r\n * no second copy of the math.\r\n *\r\n * A fixed promo is order-level and never shown on a row, so it resolves once\r\n * against the subtotal, exactly as before.\r\n *\r\n * @param lines - the cart's ticket lines (unit price × quantity).\r\n * @param subtotal - order subtotal in dollars (used for a fixed, order-level promo).\r\n * @param rawAmount - a percent for a percentage promo, dollars for a fixed one.\r\n * @param discountType - 'percentage'/'%' or 'fixed'/'$' (or empty → fixed).\r\n * @returns the order discount in dollars.\r\n */\r\nexport function resolveOrderPromoDiscountDollars(\r\n lines: readonly PromoDiscountLine[],\r\n subtotal: number,\r\n rawAmount: number,\r\n discountType: PromoDiscountTypeInput\r\n): number {\r\n if (!(rawAmount > 0)) return 0;\r\n\r\n // A fixed promo is order-level and never rendered on a row, so it resolves\r\n // once against the subtotal — unchanged from the single-line resolver.\r\n if (!isPercentageDiscount(discountType)) {\r\n return resolvePromoDiscountDollars(subtotal, rawAmount, discountType);\r\n }\r\n\r\n // Percentage promo: round per unit exactly as the row does, then sum. The\r\n // canonical Cents algebra keeps the sum exact — 0.01 + 0.01 in floats is\r\n // 0.020000000000000004, and this feeds a currency display.\r\n const lineCents = lines\r\n .filter(({ quantity }) => quantity > 0)\r\n .map(({ unitPrice, quantity }) =>\r\n mulCents(\r\n dollarsToCents(\r\n resolvePromoDiscountDollars(unitPrice, rawAmount, discountType)\r\n ),\r\n quantity\r\n )\r\n );\r\n return centsToDollars(sumCents(lineCents));\r\n}\r\n"],"names":["isPercentageDiscount","discountType","resolvePromoDiscountDollars","subtotal","rawAmount","dollars","clamped","resolveOrderPromoDiscountDollars","lines","lineCents","quantity","unitPrice","mulCents","dollarsToCents","centsToDollars","sumCents"],"mappings":";AAmDO,SAASA,EACdC,GACS;AACT,SAAOA,MAAiB,gBAAgBA,MAAiB;AAC3D;AAWO,SAASC,EACdC,GACAC,GACAH,GACQ;AACR,MAAI,EAAEG,IAAY,MAAM,EAAED,IAAW,GAAI,QAAO;AAEhD,QAAME,IAAUL,EAAqBC,CAAY,IAC5CE,IAAWC,IAAa,MACzBA,GAEEE,IAAU,KAAK,IAAI,GAAG,KAAK,IAAIH,GAAUE,CAAO,CAAC;AAEvD,SAAO,KAAK,MAAMC,IAAU,GAAG,IAAI;AACrC;AAgCO,SAASC,EACdC,GACAL,GACAC,GACAH,GACQ;AACR,MAAI,EAAEG,IAAY,GAAI,QAAO;AAI7B,MAAI,CAACJ,EAAqBC,CAAY;AACpC,WAAOC,EAA4BC,GAAUC,GAAWH,CAAY;AAMtE,QAAMQ,IAAYD,EACf,OAAO,CAAC,EAAE,UAAAE,QAAeA,IAAW,CAAC,EACrC;AAAA,IAAI,CAAC,EAAE,WAAAC,GAAW,UAAAD,EAAA,MACjBE;AAAA,MACEC;AAAA,QACEX,EAA4BS,GAAWP,GAAWH,CAAY;AAAA,MAAA;AAAA,MAEhES;AAAA,IAAA;AAAA,EACF;AAEJ,SAAOI,EAAeC,EAASN,CAAS,CAAC;AAC3C;"}
@@ -63,6 +63,17 @@ export declare function getEventStatus(rawStatus: string | null | undefined): st
63
63
  * Extracted from EventStructuredData.svelte lines 137-157.
64
64
  */
65
65
  export declare function getTicketAvailability(ticket: EventTicketInput): string;
66
+ /**
67
+ * Build a schema.org price-range offer from a low/high price and availability.
68
+ *
69
+ * The shared primitive behind every JSON-LD offer block: emit an AggregateOffer
70
+ * when the range spans two prices, or a single Offer when low === high. Any
71
+ * caller-specific fields (a buy `url`, a `validFrom` sales-start) ride along in
72
+ * `extra`, spread verbatim after the core fields so each caller reproduces its
73
+ * exact prior shape — the event builder passes url/validFrom, the series builder
74
+ * passes nothing.
75
+ */
76
+ export declare function buildPriceRangeOffer(lowPrice: number, highPrice: number, availability: string, extra?: Record<string, unknown>): Record<string, unknown>;
66
77
  /**
67
78
  * Build offers from available tickets.
68
79
  *