@uptrademedia/site-kit 1.0.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.
Files changed (120) hide show
  1. package/README.md +305 -0
  2. package/dist/analytics/index.js +88 -0
  3. package/dist/analytics/index.js.map +1 -0
  4. package/dist/analytics/index.mjs +70 -0
  5. package/dist/analytics/index.mjs.map +1 -0
  6. package/dist/api-N35S3EES.js +57 -0
  7. package/dist/api-N35S3EES.js.map +1 -0
  8. package/dist/api-SYBTK7Z7.mjs +4 -0
  9. package/dist/api-SYBTK7Z7.mjs.map +1 -0
  10. package/dist/blog/index.js +200 -0
  11. package/dist/blog/index.js.map +1 -0
  12. package/dist/blog/index.mjs +194 -0
  13. package/dist/blog/index.mjs.map +1 -0
  14. package/dist/chunk-3MUOUXHV.js +3721 -0
  15. package/dist/chunk-3MUOUXHV.js.map +1 -0
  16. package/dist/chunk-4HVYXYQL 2.mjs +255 -0
  17. package/dist/chunk-4HVYXYQL.mjs +255 -0
  18. package/dist/chunk-4HVYXYQL.mjs.map +1 -0
  19. package/dist/chunk-7H6I3ECV.mjs +120 -0
  20. package/dist/chunk-7H6I3ECV.mjs.map +1 -0
  21. package/dist/chunk-COI6GOX2.mjs +3679 -0
  22. package/dist/chunk-COI6GOX2.mjs.map +1 -0
  23. package/dist/chunk-EQCVQC35.js +35 -0
  24. package/dist/chunk-EQCVQC35.js 2.map +1 -0
  25. package/dist/chunk-EQCVQC35.js.map +1 -0
  26. package/dist/chunk-FEBYQGY4 2.mjs +251 -0
  27. package/dist/chunk-FEBYQGY4.mjs +251 -0
  28. package/dist/chunk-FEBYQGY4.mjs.map +1 -0
  29. package/dist/chunk-FKVJOT2F.mjs +796 -0
  30. package/dist/chunk-FKVJOT2F.mjs.map +1 -0
  31. package/dist/chunk-GQ6ZOU2N.mjs +134 -0
  32. package/dist/chunk-GQ6ZOU2N.mjs.map +1 -0
  33. package/dist/chunk-HCFPU7TU.js +137 -0
  34. package/dist/chunk-HCFPU7TU.js.map +1 -0
  35. package/dist/chunk-NYKRE2FL 2.mjs +31 -0
  36. package/dist/chunk-NYKRE2FL.mjs +31 -0
  37. package/dist/chunk-NYKRE2FL.mjs 2.map +1 -0
  38. package/dist/chunk-NYKRE2FL.mjs.map +1 -0
  39. package/dist/chunk-QP5NCO2E.js +133 -0
  40. package/dist/chunk-QP5NCO2E.js.map +1 -0
  41. package/dist/chunk-RV7H3I6J.js +255 -0
  42. package/dist/chunk-RV7H3I6J.js 2.map +1 -0
  43. package/dist/chunk-RV7H3I6J.js.map +1 -0
  44. package/dist/chunk-SBVEYCSV.js +140 -0
  45. package/dist/chunk-SBVEYCSV.js.map +1 -0
  46. package/dist/chunk-TUKGA3UK.js +257 -0
  47. package/dist/chunk-TUKGA3UK.js 2.map +1 -0
  48. package/dist/chunk-TUKGA3UK.js.map +1 -0
  49. package/dist/chunk-V3F5J6CV.js +801 -0
  50. package/dist/chunk-V3F5J6CV.js.map +1 -0
  51. package/dist/chunk-WPSRS352.mjs +135 -0
  52. package/dist/chunk-WPSRS352.mjs.map +1 -0
  53. package/dist/commerce/index.js +157 -0
  54. package/dist/commerce/index.js.map +1 -0
  55. package/dist/commerce/index.mjs +4 -0
  56. package/dist/commerce/index.mjs.map +1 -0
  57. package/dist/commerce/server.js +186 -0
  58. package/dist/commerce/server.js.map +1 -0
  59. package/dist/commerce/server.mjs +176 -0
  60. package/dist/commerce/server.mjs.map +1 -0
  61. package/dist/engage/index.js +50 -0
  62. package/dist/engage/index.js.map +1 -0
  63. package/dist/engage/index.mjs +44 -0
  64. package/dist/engage/index.mjs.map +1 -0
  65. package/dist/forms/index.js +1053 -0
  66. package/dist/forms/index.js.map +1 -0
  67. package/dist/forms/index.mjs +1035 -0
  68. package/dist/forms/index.mjs.map +1 -0
  69. package/dist/generators-7Y5ABRYV 2.mjs +161 -0
  70. package/dist/generators-7Y5ABRYV.mjs +161 -0
  71. package/dist/generators-7Y5ABRYV.mjs 2.map +1 -0
  72. package/dist/generators-7Y5ABRYV.mjs.map +1 -0
  73. package/dist/generators-GWIYCA5M.js +171 -0
  74. package/dist/generators-GWIYCA5M.js 2.map +1 -0
  75. package/dist/generators-GWIYCA5M.js.map +1 -0
  76. package/dist/index 2.mjs +74 -0
  77. package/dist/index.js +326 -0
  78. package/dist/index.js 2.map +1 -0
  79. package/dist/index.js.map +1 -0
  80. package/dist/index.mjs +222 -0
  81. package/dist/index.mjs.map +1 -0
  82. package/dist/migrator-V6KS75EA 2.mjs +265 -0
  83. package/dist/migrator-V6KS75EA.mjs +265 -0
  84. package/dist/migrator-V6KS75EA.mjs 2.map +1 -0
  85. package/dist/migrator-V6KS75EA.mjs.map +1 -0
  86. package/dist/migrator-XKM7YQCY.js +272 -0
  87. package/dist/migrator-XKM7YQCY.js 2.map +1 -0
  88. package/dist/migrator-XKM7YQCY.js.map +1 -0
  89. package/dist/scanner-MF7P3CDE 2.mjs +14386 -0
  90. package/dist/scanner-MF7P3CDE.mjs +14386 -0
  91. package/dist/scanner-MF7P3CDE.mjs 2.map +1 -0
  92. package/dist/scanner-MF7P3CDE.mjs.map +1 -0
  93. package/dist/scanner-NT6YG4TD 2.js +14397 -0
  94. package/dist/scanner-NT6YG4TD.js +14397 -0
  95. package/dist/scanner-NT6YG4TD.js 2.map +1 -0
  96. package/dist/scanner-NT6YG4TD.js.map +1 -0
  97. package/dist/seo/index.js +447 -0
  98. package/dist/seo/index.js.map +1 -0
  99. package/dist/seo/index.mjs +411 -0
  100. package/dist/seo/index.mjs.map +1 -0
  101. package/dist/seo/server.js +66 -0
  102. package/dist/seo/server.js.map +1 -0
  103. package/dist/seo/server.mjs +5 -0
  104. package/dist/seo/server.mjs.map +1 -0
  105. package/dist/setup/index.js +1050 -0
  106. package/dist/setup/index.js.map +1 -0
  107. package/dist/setup/index.mjs +1046 -0
  108. package/dist/setup/index.mjs.map +1 -0
  109. package/dist/sitemap/index.js +212 -0
  110. package/dist/sitemap/index.js.map +1 -0
  111. package/dist/sitemap/index.mjs +206 -0
  112. package/dist/sitemap/index.mjs.map +1 -0
  113. package/dist/web-vitals-BH55V7EJ.js +252 -0
  114. package/dist/web-vitals-BH55V7EJ.js 2.map +1 -0
  115. package/dist/web-vitals-BH55V7EJ.js.map +1 -0
  116. package/dist/web-vitals-RJYPWAR3 2.mjs +241 -0
  117. package/dist/web-vitals-RJYPWAR3.mjs +241 -0
  118. package/dist/web-vitals-RJYPWAR3.mjs 2.map +1 -0
  119. package/dist/web-vitals-RJYPWAR3.mjs.map +1 -0
  120. package/package.json +118 -0
@@ -0,0 +1,3721 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+ var React5 = require('react');
5
+
6
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
7
+
8
+ var React5__default = /*#__PURE__*/_interopDefault(React5);
9
+
10
+ // src/commerce/utils.ts
11
+ function formatPrice(amount, currency = "USD") {
12
+ return new Intl.NumberFormat("en-US", {
13
+ style: "currency",
14
+ currency
15
+ }).format(amount);
16
+ }
17
+ function formatDate(dateString) {
18
+ const date = new Date(dateString);
19
+ return new Intl.DateTimeFormat("en-US", {
20
+ weekday: "short",
21
+ month: "short",
22
+ day: "numeric",
23
+ year: "numeric"
24
+ }).format(date);
25
+ }
26
+ function formatDateTime(dateString) {
27
+ const date = new Date(dateString);
28
+ return new Intl.DateTimeFormat("en-US", {
29
+ weekday: "short",
30
+ month: "short",
31
+ day: "numeric",
32
+ year: "numeric",
33
+ hour: "numeric",
34
+ minute: "2-digit"
35
+ }).format(date);
36
+ }
37
+ function formatTime(dateString) {
38
+ const date = new Date(dateString);
39
+ return new Intl.DateTimeFormat("en-US", {
40
+ hour: "numeric",
41
+ minute: "2-digit"
42
+ }).format(date);
43
+ }
44
+ function formatDateRange(startDate, endDate) {
45
+ const start = new Date(startDate);
46
+ const end = endDate ? new Date(endDate) : null;
47
+ const startFormatted = formatDateTime(startDate);
48
+ if (!end) return startFormatted;
49
+ if (start.toDateString() === end.toDateString()) {
50
+ return `${startFormatted} - ${formatTime(endDate)}`;
51
+ }
52
+ return `${startFormatted} - ${formatDateTime(endDate)}`;
53
+ }
54
+ function getRelativeTimeUntil(dateString) {
55
+ const date = new Date(dateString);
56
+ const now = /* @__PURE__ */ new Date();
57
+ const diffMs = date.getTime() - now.getTime();
58
+ const diffDays = Math.floor(diffMs / (1e3 * 60 * 60 * 24));
59
+ if (diffDays < 0) return "Past";
60
+ if (diffDays === 0) return "Today";
61
+ if (diffDays === 1) return "Tomorrow";
62
+ if (diffDays < 7) return `In ${diffDays} days`;
63
+ if (diffDays < 30) {
64
+ const weeks = Math.floor(diffDays / 7);
65
+ return `In ${weeks} week${weeks > 1 ? "s" : ""}`;
66
+ }
67
+ if (diffDays < 365) {
68
+ const months = Math.floor(diffDays / 30);
69
+ return `In ${months} month${months > 1 ? "s" : ""}`;
70
+ }
71
+ return formatDate(dateString);
72
+ }
73
+ function getSpotsRemaining(capacity, registrations = 0) {
74
+ if (capacity == null) return null;
75
+ return Math.max(0, capacity - registrations);
76
+ }
77
+ function isEventSoldOut(capacity, registrations = 0) {
78
+ const remaining = getSpotsRemaining(capacity, registrations);
79
+ return remaining !== null && remaining <= 0;
80
+ }
81
+ function getOfferingUrl(slug, type, basePaths) {
82
+ const defaults = {
83
+ product: "/shop",
84
+ service: "/services",
85
+ event: "/events",
86
+ class: "/classes"
87
+ };
88
+ const paths = { ...defaults, ...basePaths };
89
+ const base = paths[type] || "/offerings";
90
+ return `${base}/${slug}`;
91
+ }
92
+
93
+ // src/commerce/api.ts
94
+ function getApiConfig() {
95
+ const apiUrl = typeof window !== "undefined" ? window.__SITE_KIT_API_URL__ || "https://api.uptrademedia.com" : "https://api.uptrademedia.com";
96
+ const apiKey = typeof window !== "undefined" ? window.__SITE_KIT_API_KEY__ || "" : "";
97
+ return { apiUrl, apiKey };
98
+ }
99
+ async function apiPost(endpoint, body = {}) {
100
+ const { apiUrl, apiKey } = getApiConfig();
101
+ if (!apiKey) {
102
+ console.error("[Commerce] No API key configured");
103
+ return null;
104
+ }
105
+ try {
106
+ const response = await fetch(`${apiUrl}${endpoint}`, {
107
+ method: "POST",
108
+ headers: {
109
+ "Content-Type": "application/json",
110
+ "x-api-key": apiKey
111
+ },
112
+ body: JSON.stringify(body)
113
+ });
114
+ if (!response.ok) {
115
+ console.error(`[Commerce] API error: ${response.statusText}`);
116
+ return null;
117
+ }
118
+ return await response.json();
119
+ } catch (error) {
120
+ console.error("[Commerce] Network error:", error);
121
+ return null;
122
+ }
123
+ }
124
+ async function fetchOfferings(options = {}) {
125
+ const result = await apiPost(
126
+ "/api/public/commerce/offerings",
127
+ {
128
+ type: options.type,
129
+ category: options.category,
130
+ status: options.status || "active",
131
+ limit: options.limit,
132
+ offset: options.offset,
133
+ orderBy: options.orderBy || "sort_order",
134
+ order: options.order || "asc"
135
+ }
136
+ );
137
+ return result?.offerings || [];
138
+ }
139
+ async function fetchOffering(slug) {
140
+ const result = await apiPost(
141
+ "/api/public/commerce/offering",
142
+ { slug }
143
+ );
144
+ return result?.offering || null;
145
+ }
146
+ async function fetchLatestOffering(type, category) {
147
+ const result = await apiPost(
148
+ "/api/public/commerce/offerings",
149
+ {
150
+ type,
151
+ category,
152
+ status: "active",
153
+ limit: 1,
154
+ orderBy: "created_at",
155
+ order: "desc"
156
+ }
157
+ );
158
+ return result?.offerings?.[0] || null;
159
+ }
160
+ async function fetchUpcomingEvents(options = {}) {
161
+ const result = await apiPost(
162
+ "/api/public/commerce/events",
163
+ {
164
+ type: options.type || "event",
165
+ category: options.category,
166
+ limit: options.limit,
167
+ includePast: options.past
168
+ }
169
+ );
170
+ return result?.events || [];
171
+ }
172
+ async function fetchNextEvent(category) {
173
+ const events = await fetchUpcomingEvents({ limit: 1, category });
174
+ return events[0] || null;
175
+ }
176
+ async function fetchProducts(options = {}) {
177
+ return fetchOfferings({ ...options, type: "product" });
178
+ }
179
+ async function fetchServices(options = {}) {
180
+ return fetchOfferings({ ...options, type: "service" });
181
+ }
182
+ async function fetchProductsPublic(options = {}) {
183
+ const result = await apiPost(
184
+ "/api/public/commerce/products",
185
+ options
186
+ );
187
+ return {
188
+ products: result?.products || [],
189
+ total: result?.total || 0
190
+ };
191
+ }
192
+ async function fetchProductBySlug(slug) {
193
+ const result = await apiPost(
194
+ "/api/public/commerce/product",
195
+ { slug }
196
+ );
197
+ return result?.product || null;
198
+ }
199
+ async function fetchCategories() {
200
+ const result = await apiPost(
201
+ "/api/public/commerce/categories",
202
+ {}
203
+ );
204
+ return result?.categories || [];
205
+ }
206
+ async function registerForEvent(eventId, scheduleId, customer) {
207
+ const { apiUrl, apiKey } = getApiConfig();
208
+ const analyticsSessionId = typeof sessionStorage !== "undefined" ? sessionStorage.getItem("_uptrade_sid") : null;
209
+ try {
210
+ const response = await fetch(`${apiUrl}/api/public/commerce/register`, {
211
+ method: "POST",
212
+ headers: {
213
+ "Content-Type": "application/json",
214
+ "x-api-key": apiKey
215
+ },
216
+ body: JSON.stringify({
217
+ offeringId: eventId,
218
+ scheduleId,
219
+ customer,
220
+ analyticsSessionId
221
+ // Pass for conversion tracking
222
+ })
223
+ });
224
+ if (!response.ok) {
225
+ const error = await response.json();
226
+ return { success: false, error: error.message || "Registration failed" };
227
+ }
228
+ const result = await response.json();
229
+ return {
230
+ success: true,
231
+ sale_id: result.sale_id,
232
+ confirmation_number: result.confirmation_number
233
+ };
234
+ } catch (error) {
235
+ return { success: false, error: "Network error. Please try again." };
236
+ }
237
+ }
238
+ async function createCheckoutSession(optionsOrOfferingId, legacyOptions) {
239
+ const { apiUrl, apiKey } = getApiConfig();
240
+ const options = typeof optionsOrOfferingId === "string" ? { offeringId: optionsOrOfferingId, ...legacyOptions } : optionsOrOfferingId;
241
+ const analyticsSessionId = typeof sessionStorage !== "undefined" ? sessionStorage.getItem("_uptrade_sid") : null;
242
+ try {
243
+ const response = await fetch(`${apiUrl}/api/public/commerce/checkout`, {
244
+ method: "POST",
245
+ headers: {
246
+ "Content-Type": "application/json",
247
+ "x-api-key": apiKey
248
+ },
249
+ body: JSON.stringify({
250
+ ...options,
251
+ analyticsSessionId,
252
+ // Pass for conversion tracking
253
+ successUrl: options.successUrl || (typeof window !== "undefined" ? window.location.href : ""),
254
+ cancelUrl: options.cancelUrl || (typeof window !== "undefined" ? window.location.href : "")
255
+ })
256
+ });
257
+ if (!response.ok) {
258
+ const error = await response.json();
259
+ return { success: false, error: error.message || "Checkout failed" };
260
+ }
261
+ const result = await response.json();
262
+ return {
263
+ success: true,
264
+ payment_url: result.checkout_url,
265
+ checkout_url: result.checkout_url,
266
+ sale_id: result.sale_id,
267
+ confirmation_number: result.confirmation_number
268
+ };
269
+ } catch (error) {
270
+ return { success: false, error: "Network error. Please try again." };
271
+ }
272
+ }
273
+ function OfferingCard({
274
+ offering,
275
+ variant = "card",
276
+ showImage = true,
277
+ showPrice = true,
278
+ showDescription = true,
279
+ showCta = true,
280
+ ctaText,
281
+ onCtaClick,
282
+ className = "",
283
+ imageClassName = "",
284
+ titleClassName = "",
285
+ priceClassName = "",
286
+ descriptionClassName = "",
287
+ ctaClassName = ""
288
+ }) {
289
+ const isEvent = offering.type === "event" || offering.type === "class";
290
+ const nextSchedule = offering.schedules?.[0] || offering.next_schedule;
291
+ const defaultCtaText = {
292
+ product: "Buy Now",
293
+ service: "Book Now",
294
+ class: "Register",
295
+ event: "Get Tickets",
296
+ subscription: "Subscribe"
297
+ }[offering.type] || "View Details";
298
+ const handleClick = () => {
299
+ if (onCtaClick) {
300
+ onCtaClick(offering);
301
+ } else if (typeof window !== "undefined") {
302
+ const basePath = offering.type === "event" ? "/events" : offering.type === "product" ? "/shop" : "/services";
303
+ window.location.href = `${basePath}/${offering.slug}`;
304
+ }
305
+ };
306
+ if (variant === "minimal") {
307
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `site-kit-offering-minimal ${className}`, children: [
308
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: `site-kit-offering-title ${titleClassName}`, children: offering.name }),
309
+ showPrice && offering.price_is_public && offering.price != null && /* @__PURE__ */ jsxRuntime.jsx("span", { className: `site-kit-offering-price ${priceClassName}`, children: formatPrice(offering.price, offering.currency) }),
310
+ showCta && /* @__PURE__ */ jsxRuntime.jsx(
311
+ "button",
312
+ {
313
+ onClick: handleClick,
314
+ className: `site-kit-offering-cta ${ctaClassName}`,
315
+ children: ctaText || defaultCtaText
316
+ }
317
+ )
318
+ ] });
319
+ }
320
+ if (variant === "horizontal") {
321
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `site-kit-offering-horizontal ${className}`, style: {
322
+ display: "flex",
323
+ gap: "1rem",
324
+ alignItems: "flex-start"
325
+ }, children: [
326
+ showImage && offering.featured_image_url && /* @__PURE__ */ jsxRuntime.jsx(
327
+ "img",
328
+ {
329
+ src: offering.featured_image_url,
330
+ alt: offering.name,
331
+ className: `site-kit-offering-image ${imageClassName}`,
332
+ style: {
333
+ width: "120px",
334
+ height: "120px",
335
+ objectFit: "cover",
336
+ borderRadius: "8px"
337
+ }
338
+ }
339
+ ),
340
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { flex: 1 }, children: [
341
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: `site-kit-offering-title ${titleClassName}`, style: {
342
+ margin: 0,
343
+ fontSize: "1.125rem",
344
+ fontWeight: 600
345
+ }, children: offering.name }),
346
+ isEvent && nextSchedule && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "site-kit-offering-date", style: {
347
+ color: "#666",
348
+ fontSize: "0.875rem",
349
+ marginTop: "0.25rem"
350
+ }, children: [
351
+ formatDate(nextSchedule.starts_at),
352
+ offering.location && ` \u2022 ${offering.location}`
353
+ ] }),
354
+ showDescription && offering.short_description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: `site-kit-offering-description ${descriptionClassName}`, style: {
355
+ color: "#666",
356
+ margin: "0.5rem 0",
357
+ fontSize: "0.875rem"
358
+ }, children: offering.short_description }),
359
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", gap: "1rem", marginTop: "0.5rem" }, children: [
360
+ showPrice && offering.price_is_public && offering.price != null && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: `site-kit-offering-price ${priceClassName}`, style: {
361
+ fontWeight: 600,
362
+ color: "#333"
363
+ }, children: [
364
+ formatPrice(offering.price, offering.currency),
365
+ offering.compare_at_price && /* @__PURE__ */ jsxRuntime.jsx("span", { style: {
366
+ textDecoration: "line-through",
367
+ color: "#999",
368
+ marginLeft: "0.5rem",
369
+ fontWeight: 400
370
+ }, children: formatPrice(offering.compare_at_price, offering.currency) })
371
+ ] }),
372
+ showCta && /* @__PURE__ */ jsxRuntime.jsx(
373
+ "button",
374
+ {
375
+ onClick: handleClick,
376
+ className: `site-kit-offering-cta ${ctaClassName}`,
377
+ style: {
378
+ padding: "0.5rem 1rem",
379
+ borderRadius: "6px",
380
+ border: "none",
381
+ background: "#2563eb",
382
+ color: "white",
383
+ cursor: "pointer",
384
+ fontWeight: 500
385
+ },
386
+ children: ctaText || defaultCtaText
387
+ }
388
+ )
389
+ ] })
390
+ ] })
391
+ ] });
392
+ }
393
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `site-kit-offering-card ${className}`, style: {
394
+ borderRadius: "12px",
395
+ overflow: "hidden",
396
+ boxShadow: "0 1px 3px rgba(0,0,0,0.1)",
397
+ background: "white"
398
+ }, children: [
399
+ showImage && offering.featured_image_url && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { position: "relative" }, children: [
400
+ /* @__PURE__ */ jsxRuntime.jsx(
401
+ "img",
402
+ {
403
+ src: offering.featured_image_url,
404
+ alt: offering.name,
405
+ className: `site-kit-offering-image ${imageClassName}`,
406
+ style: {
407
+ width: "100%",
408
+ height: "200px",
409
+ objectFit: "cover"
410
+ }
411
+ }
412
+ ),
413
+ offering.compare_at_price && offering.price_is_public && /* @__PURE__ */ jsxRuntime.jsx("span", { style: {
414
+ position: "absolute",
415
+ top: "12px",
416
+ right: "12px",
417
+ background: "#ef4444",
418
+ color: "white",
419
+ padding: "4px 8px",
420
+ borderRadius: "4px",
421
+ fontSize: "0.75rem",
422
+ fontWeight: 600
423
+ }, children: "Sale" })
424
+ ] }),
425
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { padding: "1rem" }, children: [
426
+ isEvent && nextSchedule && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "site-kit-offering-date", style: {
427
+ color: "#2563eb",
428
+ fontSize: "0.875rem",
429
+ fontWeight: 500,
430
+ marginBottom: "0.25rem"
431
+ }, children: formatDate(nextSchedule.starts_at) }),
432
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: `site-kit-offering-title ${titleClassName}`, style: {
433
+ margin: 0,
434
+ fontSize: "1.125rem",
435
+ fontWeight: 600,
436
+ color: "#111"
437
+ }, children: offering.name }),
438
+ isEvent && offering.location && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { color: "#666", fontSize: "0.875rem", marginTop: "0.25rem" }, children: [
439
+ "\u{1F4CD} ",
440
+ offering.location
441
+ ] }),
442
+ showDescription && offering.short_description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: `site-kit-offering-description ${descriptionClassName}`, style: {
443
+ color: "#666",
444
+ margin: "0.75rem 0",
445
+ fontSize: "0.875rem",
446
+ lineHeight: 1.5
447
+ }, children: offering.short_description }),
448
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
449
+ display: "flex",
450
+ alignItems: "center",
451
+ justifyContent: "space-between",
452
+ marginTop: "1rem"
453
+ }, children: [
454
+ showPrice && offering.price_is_public && offering.price != null ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `site-kit-offering-price ${priceClassName}`, children: [
455
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: 600, fontSize: "1.25rem", color: "#111" }, children: formatPrice(offering.price, offering.currency) }),
456
+ offering.compare_at_price && /* @__PURE__ */ jsxRuntime.jsx("span", { style: {
457
+ textDecoration: "line-through",
458
+ color: "#999",
459
+ marginLeft: "0.5rem",
460
+ fontSize: "0.875rem"
461
+ }, children: formatPrice(offering.compare_at_price, offering.currency) })
462
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx("div", {}),
463
+ showCta && /* @__PURE__ */ jsxRuntime.jsx(
464
+ "button",
465
+ {
466
+ onClick: handleClick,
467
+ className: `site-kit-offering-cta ${ctaClassName}`,
468
+ style: {
469
+ padding: "0.625rem 1.25rem",
470
+ borderRadius: "6px",
471
+ border: "none",
472
+ background: "#2563eb",
473
+ color: "white",
474
+ cursor: "pointer",
475
+ fontWeight: 500,
476
+ fontSize: "0.875rem"
477
+ },
478
+ children: ctaText || defaultCtaText
479
+ }
480
+ )
481
+ ] })
482
+ ] })
483
+ ] });
484
+ }
485
+ function OfferingList({
486
+ // Data options
487
+ offerings: propOfferings,
488
+ type,
489
+ category,
490
+ limit,
491
+ status = "active",
492
+ // Display options
493
+ layout = "grid",
494
+ columns = 3,
495
+ cardVariant = "card",
496
+ showFilters = false,
497
+ emptyMessage = "No items found.",
498
+ // Card options
499
+ showImage = true,
500
+ showPrice = true,
501
+ showDescription = true,
502
+ showCta = true,
503
+ ctaText,
504
+ onCtaClick,
505
+ // Styling
506
+ className = "",
507
+ cardClassName = "",
508
+ filterClassName = "",
509
+ // Custom render
510
+ renderCard,
511
+ renderEmpty
512
+ }) {
513
+ const [offerings, setOfferings] = React5.useState(propOfferings || []);
514
+ const [loading, setLoading] = React5.useState(!propOfferings);
515
+ const [error, setError] = React5.useState(null);
516
+ const [activeFilter, setActiveFilter] = React5.useState(null);
517
+ React5.useEffect(() => {
518
+ if (propOfferings) {
519
+ setOfferings(propOfferings);
520
+ return;
521
+ }
522
+ async function load() {
523
+ setLoading(true);
524
+ setError(null);
525
+ try {
526
+ let data;
527
+ if (type === "product") {
528
+ data = await fetchProducts({ category, limit, status });
529
+ } else if (type === "event") {
530
+ data = await fetchUpcomingEvents({ category, limit });
531
+ } else {
532
+ data = await fetchOfferings({ type, category, limit, status });
533
+ }
534
+ setOfferings(data);
535
+ } catch (e) {
536
+ console.error("Failed to load offerings:", e);
537
+ setError("Failed to load items.");
538
+ } finally {
539
+ setLoading(false);
540
+ }
541
+ }
542
+ load();
543
+ }, [propOfferings, type, category, limit, status]);
544
+ const categories = React5.useMemo(() => {
545
+ const cats = offerings.filter((o) => o.category).map((o) => o.category);
546
+ return Array.from(new Map(cats.map((c) => [c.id, c])).values());
547
+ }, [offerings]);
548
+ const filteredOfferings = React5.useMemo(() => {
549
+ if (!activeFilter) return offerings;
550
+ return offerings.filter((o) => o.category?.id === activeFilter);
551
+ }, [offerings, activeFilter]);
552
+ if (loading) {
553
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `site-kit-offerings-loading ${className}`, style: {
554
+ display: "flex",
555
+ justifyContent: "center",
556
+ padding: "2rem"
557
+ }, children: [
558
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
559
+ width: "40px",
560
+ height: "40px",
561
+ border: "3px solid #e5e7eb",
562
+ borderTopColor: "#2563eb",
563
+ borderRadius: "50%",
564
+ animation: "spin 1s linear infinite"
565
+ } }),
566
+ /* @__PURE__ */ jsxRuntime.jsx("style", { children: `
567
+ @keyframes spin {
568
+ to { transform: rotate(360deg); }
569
+ }
570
+ ` })
571
+ ] });
572
+ }
573
+ if (error) {
574
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `site-kit-offerings-error ${className}`, style: {
575
+ textAlign: "center",
576
+ padding: "2rem",
577
+ color: "#ef4444"
578
+ }, children: error });
579
+ }
580
+ if (filteredOfferings.length === 0) {
581
+ if (renderEmpty) {
582
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: renderEmpty() });
583
+ }
584
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `site-kit-offerings-empty ${className}`, style: {
585
+ textAlign: "center",
586
+ padding: "2rem",
587
+ color: "#666"
588
+ }, children: emptyMessage });
589
+ }
590
+ const gridStyles = layout === "grid" ? {
591
+ display: "grid",
592
+ gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))`,
593
+ gap: "1.5rem"
594
+ } : {
595
+ display: "flex",
596
+ flexDirection: "column",
597
+ gap: "1rem"
598
+ };
599
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `site-kit-offerings ${className}`, children: [
600
+ showFilters && categories.length > 1 && /* @__PURE__ */ jsxRuntime.jsxs(
601
+ "div",
602
+ {
603
+ className: `site-kit-offerings-filters ${filterClassName}`,
604
+ style: {
605
+ display: "flex",
606
+ gap: "0.5rem",
607
+ marginBottom: "1.5rem",
608
+ flexWrap: "wrap"
609
+ },
610
+ children: [
611
+ /* @__PURE__ */ jsxRuntime.jsx(
612
+ "button",
613
+ {
614
+ onClick: () => setActiveFilter(null),
615
+ style: {
616
+ padding: "0.5rem 1rem",
617
+ borderRadius: "9999px",
618
+ border: "1px solid",
619
+ borderColor: activeFilter === null ? "#2563eb" : "#e5e7eb",
620
+ background: activeFilter === null ? "#2563eb" : "white",
621
+ color: activeFilter === null ? "white" : "#333",
622
+ cursor: "pointer",
623
+ fontSize: "0.875rem"
624
+ },
625
+ children: "All"
626
+ }
627
+ ),
628
+ categories.map((cat) => /* @__PURE__ */ jsxRuntime.jsx(
629
+ "button",
630
+ {
631
+ onClick: () => setActiveFilter(cat.id),
632
+ style: {
633
+ padding: "0.5rem 1rem",
634
+ borderRadius: "9999px",
635
+ border: "1px solid",
636
+ borderColor: activeFilter === cat.id ? "#2563eb" : "#e5e7eb",
637
+ background: activeFilter === cat.id ? "#2563eb" : "white",
638
+ color: activeFilter === cat.id ? "white" : "#333",
639
+ cursor: "pointer",
640
+ fontSize: "0.875rem"
641
+ },
642
+ children: cat.name
643
+ },
644
+ cat.id
645
+ ))
646
+ ]
647
+ }
648
+ ),
649
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "site-kit-offerings-grid", style: gridStyles, children: filteredOfferings.map((offering) => renderCard ? renderCard(offering) : /* @__PURE__ */ jsxRuntime.jsx(
650
+ OfferingCard,
651
+ {
652
+ offering,
653
+ variant: layout === "list" ? "horizontal" : cardVariant,
654
+ showImage,
655
+ showPrice,
656
+ showDescription,
657
+ showCta,
658
+ ctaText,
659
+ onCtaClick,
660
+ className: cardClassName
661
+ },
662
+ offering.id
663
+ )) })
664
+ ] });
665
+ }
666
+ function EventTile({
667
+ event,
668
+ variant = "standard",
669
+ showDate = true,
670
+ showTime = true,
671
+ showLocation = true,
672
+ showCapacity = true,
673
+ showPrice = true,
674
+ showCta = true,
675
+ ctaText,
676
+ onRegister,
677
+ onCtaClick,
678
+ className = "",
679
+ dateClassName = "",
680
+ titleClassName = "",
681
+ ctaClassName = ""
682
+ }) {
683
+ const [loading, setLoading] = React5.useState(false);
684
+ const schedule = event.schedules?.[0] || event.next_schedule;
685
+ const soldOut = schedule ? isEventSoldOut(schedule.capacity, schedule.current_registrations) : false;
686
+ const spotsRemaining = schedule ? getSpotsRemaining(schedule.capacity, schedule.current_registrations) : null;
687
+ const defaultCtaText = event.price && event.price > 0 ? "Get Tickets" : "Register Free";
688
+ const handleClick = async () => {
689
+ if (onCtaClick) {
690
+ onCtaClick(event);
691
+ return;
692
+ }
693
+ if (!schedule) {
694
+ window.location.href = `/events/${event.slug}`;
695
+ return;
696
+ }
697
+ if (onRegister) {
698
+ onRegister(event, schedule.id);
699
+ return;
700
+ }
701
+ setLoading(true);
702
+ try {
703
+ if (event.price && event.price > 0) {
704
+ const result = await createCheckoutSession(event.id, { scheduleId: schedule.id });
705
+ if (result.payment_url) {
706
+ window.location.href = result.payment_url;
707
+ }
708
+ } else {
709
+ window.location.href = `/events/${event.slug}/register`;
710
+ }
711
+ } catch (e) {
712
+ console.error("Registration error:", e);
713
+ } finally {
714
+ setLoading(false);
715
+ }
716
+ };
717
+ if (variant === "compact") {
718
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `site-kit-event-tile-compact ${className}`, style: {
719
+ display: "flex",
720
+ alignItems: "center",
721
+ gap: "0.75rem",
722
+ padding: "0.75rem",
723
+ background: "white",
724
+ borderRadius: "8px",
725
+ boxShadow: "0 1px 2px rgba(0,0,0,0.05)"
726
+ }, children: [
727
+ showDate && schedule && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `site-kit-event-date ${dateClassName}`, style: {
728
+ minWidth: "48px",
729
+ textAlign: "center",
730
+ padding: "0.5rem",
731
+ background: "#f3f4f6",
732
+ borderRadius: "6px"
733
+ }, children: [
734
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: "0.75rem", color: "#666", textTransform: "uppercase" }, children: new Date(schedule.starts_at).toLocaleDateString("en-US", { month: "short" }) }),
735
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: "1.25rem", fontWeight: 700, color: "#111" }, children: new Date(schedule.starts_at).getDate() })
736
+ ] }),
737
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { flex: 1, minWidth: 0 }, children: [
738
+ /* @__PURE__ */ jsxRuntime.jsx("h4", { className: `site-kit-event-title ${titleClassName}`, style: {
739
+ margin: 0,
740
+ fontSize: "0.875rem",
741
+ fontWeight: 600,
742
+ whiteSpace: "nowrap",
743
+ overflow: "hidden",
744
+ textOverflow: "ellipsis"
745
+ }, children: event.name }),
746
+ showTime && schedule && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { fontSize: "0.75rem", color: "#666" }, children: [
747
+ formatTime(schedule.starts_at),
748
+ showLocation && event.location && ` \u2022 ${event.location}`
749
+ ] })
750
+ ] }),
751
+ showCta && /* @__PURE__ */ jsxRuntime.jsx(
752
+ "button",
753
+ {
754
+ onClick: handleClick,
755
+ disabled: soldOut || loading,
756
+ className: `site-kit-event-cta ${ctaClassName}`,
757
+ style: {
758
+ padding: "0.375rem 0.75rem",
759
+ fontSize: "0.75rem",
760
+ borderRadius: "4px",
761
+ border: "none",
762
+ background: soldOut ? "#e5e7eb" : "#2563eb",
763
+ color: soldOut ? "#666" : "white",
764
+ cursor: soldOut ? "not-allowed" : "pointer",
765
+ fontWeight: 500,
766
+ whiteSpace: "nowrap"
767
+ },
768
+ children: soldOut ? "Sold Out" : loading ? "..." : ctaText || defaultCtaText
769
+ }
770
+ )
771
+ ] });
772
+ }
773
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `site-kit-event-tile ${className}`, style: {
774
+ background: "white",
775
+ borderRadius: "12px",
776
+ overflow: "hidden",
777
+ boxShadow: "0 1px 3px rgba(0,0,0,0.1)"
778
+ }, children: [
779
+ event.featured_image_url && /* @__PURE__ */ jsxRuntime.jsx(
780
+ "img",
781
+ {
782
+ src: event.featured_image_url,
783
+ alt: event.name,
784
+ style: {
785
+ width: "100%",
786
+ height: "140px",
787
+ objectFit: "cover"
788
+ }
789
+ }
790
+ ),
791
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { padding: "1rem" }, children: [
792
+ showDate && schedule && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `site-kit-event-date ${dateClassName}`, style: {
793
+ display: "flex",
794
+ alignItems: "center",
795
+ gap: "0.5rem",
796
+ marginBottom: "0.5rem"
797
+ }, children: [
798
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: {
799
+ background: "#dbeafe",
800
+ color: "#1d4ed8",
801
+ padding: "0.25rem 0.5rem",
802
+ borderRadius: "4px",
803
+ fontSize: "0.75rem",
804
+ fontWeight: 600
805
+ }, children: getRelativeTimeUntil(schedule.starts_at) }),
806
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: "0.875rem", color: "#666" }, children: formatDate(schedule.starts_at) })
807
+ ] }),
808
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: `site-kit-event-title ${titleClassName}`, style: {
809
+ margin: "0 0 0.5rem",
810
+ fontSize: "1.125rem",
811
+ fontWeight: 600,
812
+ color: "#111"
813
+ }, children: event.name }),
814
+ showLocation && event.location && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { fontSize: "0.875rem", color: "#666", marginBottom: "0.5rem" }, children: [
815
+ "\u{1F4CD} ",
816
+ event.location
817
+ ] }),
818
+ showTime && schedule && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { fontSize: "0.875rem", color: "#666", marginBottom: "0.75rem" }, children: [
819
+ "\u{1F550} ",
820
+ formatTime(schedule.starts_at),
821
+ schedule.ends_at && ` - ${formatTime(schedule.ends_at)}`
822
+ ] }),
823
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
824
+ display: "flex",
825
+ justifyContent: "space-between",
826
+ alignItems: "center",
827
+ marginTop: "0.75rem"
828
+ }, children: [
829
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
830
+ showPrice && event.price_is_public && event.price != null && /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: 600, color: "#111" }, children: event.price === 0 ? "Free" : `$${event.price}` }),
831
+ showCapacity && spotsRemaining !== null && spotsRemaining <= 10 && !soldOut && /* @__PURE__ */ jsxRuntime.jsxs("span", { style: {
832
+ fontSize: "0.75rem",
833
+ color: "#dc2626",
834
+ marginLeft: "0.5rem"
835
+ }, children: [
836
+ "Only ",
837
+ spotsRemaining,
838
+ " spots left!"
839
+ ] })
840
+ ] }),
841
+ showCta && /* @__PURE__ */ jsxRuntime.jsx(
842
+ "button",
843
+ {
844
+ onClick: handleClick,
845
+ disabled: soldOut || loading,
846
+ className: `site-kit-event-cta ${ctaClassName}`,
847
+ style: {
848
+ padding: "0.5rem 1rem",
849
+ borderRadius: "6px",
850
+ border: "none",
851
+ background: soldOut ? "#e5e7eb" : "#2563eb",
852
+ color: soldOut ? "#666" : "white",
853
+ cursor: soldOut ? "not-allowed" : "pointer",
854
+ fontWeight: 500,
855
+ fontSize: "0.875rem"
856
+ },
857
+ children: soldOut ? "Sold Out" : loading ? "Loading..." : ctaText || defaultCtaText
858
+ }
859
+ )
860
+ ] })
861
+ ] })
862
+ ] });
863
+ }
864
+ function UpcomingEvents({
865
+ events: propEvents,
866
+ limit = 3,
867
+ category,
868
+ variant = "standard",
869
+ layout = "vertical",
870
+ showViewAll = true,
871
+ viewAllUrl = "/events",
872
+ viewAllText = "View All Events",
873
+ emptyMessage = "No upcoming events.",
874
+ title,
875
+ onRegister,
876
+ onCtaClick,
877
+ className = "",
878
+ titleClassName = "",
879
+ eventClassName = ""
880
+ }) {
881
+ const [events, setEvents] = React5.useState(propEvents || []);
882
+ const [loading, setLoading] = React5.useState(!propEvents);
883
+ React5.useEffect(() => {
884
+ if (propEvents) {
885
+ setEvents(propEvents);
886
+ return;
887
+ }
888
+ async function load() {
889
+ setLoading(true);
890
+ try {
891
+ const data = await fetchUpcomingEvents({ limit, category });
892
+ setEvents(data);
893
+ } catch (e) {
894
+ console.error("Failed to load events:", e);
895
+ } finally {
896
+ setLoading(false);
897
+ }
898
+ }
899
+ load();
900
+ }, [propEvents, limit, category]);
901
+ if (loading) {
902
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `site-kit-upcoming-events ${className}`, children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: "2rem", textAlign: "center", color: "#666" }, children: "Loading events..." }) });
903
+ }
904
+ if (events.length === 0) {
905
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `site-kit-upcoming-events ${className}`, children: [
906
+ title && /* @__PURE__ */ jsxRuntime.jsx("h2", { className: `site-kit-upcoming-events-title ${titleClassName}`, style: {
907
+ margin: "0 0 1rem",
908
+ fontSize: "1.5rem",
909
+ fontWeight: 600
910
+ }, children: title }),
911
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: "2rem", textAlign: "center", color: "#666" }, children: emptyMessage })
912
+ ] });
913
+ }
914
+ const layoutStyles = layout === "horizontal" ? {
915
+ display: "flex",
916
+ gap: "1rem",
917
+ overflowX: "auto"
918
+ } : {
919
+ display: "flex",
920
+ flexDirection: "column",
921
+ gap: "1rem"
922
+ };
923
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `site-kit-upcoming-events ${className}`, children: [
924
+ title && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
925
+ display: "flex",
926
+ justifyContent: "space-between",
927
+ alignItems: "center",
928
+ marginBottom: "1rem"
929
+ }, children: [
930
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { className: `site-kit-upcoming-events-title ${titleClassName}`, style: {
931
+ margin: 0,
932
+ fontSize: "1.5rem",
933
+ fontWeight: 600
934
+ }, children: title }),
935
+ showViewAll && events.length >= limit && /* @__PURE__ */ jsxRuntime.jsxs(
936
+ "a",
937
+ {
938
+ href: viewAllUrl,
939
+ style: {
940
+ color: "#2563eb",
941
+ textDecoration: "none",
942
+ fontSize: "0.875rem",
943
+ fontWeight: 500
944
+ },
945
+ children: [
946
+ viewAllText,
947
+ " \u2192"
948
+ ]
949
+ }
950
+ )
951
+ ] }),
952
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: layoutStyles, children: events.map((event) => /* @__PURE__ */ jsxRuntime.jsx(
953
+ "div",
954
+ {
955
+ className: eventClassName,
956
+ style: layout === "horizontal" ? { minWidth: "280px", flex: "0 0 auto" } : void 0,
957
+ children: /* @__PURE__ */ jsxRuntime.jsx(
958
+ EventTile,
959
+ {
960
+ event,
961
+ variant,
962
+ onRegister,
963
+ onCtaClick
964
+ }
965
+ )
966
+ },
967
+ event.id
968
+ )) }),
969
+ showViewAll && events.length >= limit && !title && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { textAlign: "center", marginTop: "1.5rem" }, children: /* @__PURE__ */ jsxRuntime.jsx(
970
+ "a",
971
+ {
972
+ href: viewAllUrl,
973
+ style: {
974
+ display: "inline-block",
975
+ padding: "0.75rem 1.5rem",
976
+ background: "#f3f4f6",
977
+ color: "#333",
978
+ borderRadius: "8px",
979
+ textDecoration: "none",
980
+ fontWeight: 500
981
+ },
982
+ children: viewAllText
983
+ }
984
+ ) })
985
+ ] });
986
+ }
987
+ function ProductEmbed({
988
+ product: propProduct,
989
+ slug,
990
+ mode = "specific",
991
+ // 'specific', 'latest', 'featured'
992
+ category,
993
+ variant = "card",
994
+ showImage = true,
995
+ showPrice = true,
996
+ showDescription = true,
997
+ showCta = true,
998
+ ctaText = "Shop Now",
999
+ onCtaClick,
1000
+ className = ""
1001
+ }) {
1002
+ const [product, setProduct] = React5.useState(propProduct || null);
1003
+ const [loading, setLoading] = React5.useState(!propProduct && !!slug);
1004
+ React5.useEffect(() => {
1005
+ if (propProduct) {
1006
+ setProduct(propProduct);
1007
+ return;
1008
+ }
1009
+ async function load() {
1010
+ setLoading(true);
1011
+ try {
1012
+ let data = null;
1013
+ if (mode === "specific" && slug) {
1014
+ data = await fetchOffering(slug);
1015
+ } else if (mode === "latest" || mode === "featured") {
1016
+ data = await fetchLatestOffering("product", category);
1017
+ }
1018
+ setProduct(data);
1019
+ } catch (e) {
1020
+ console.error("Failed to load product:", e);
1021
+ } finally {
1022
+ setLoading(false);
1023
+ }
1024
+ }
1025
+ load();
1026
+ }, [propProduct, slug, mode, category]);
1027
+ if (loading) {
1028
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `site-kit-product-embed ${className}`, style: {
1029
+ padding: "2rem",
1030
+ textAlign: "center",
1031
+ background: "#f9fafb",
1032
+ borderRadius: "12px"
1033
+ }, children: [
1034
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
1035
+ width: "40px",
1036
+ height: "40px",
1037
+ margin: "0 auto",
1038
+ border: "3px solid #e5e7eb",
1039
+ borderTopColor: "#2563eb",
1040
+ borderRadius: "50%",
1041
+ animation: "spin 1s linear infinite"
1042
+ } }),
1043
+ /* @__PURE__ */ jsxRuntime.jsx("style", { children: `
1044
+ @keyframes spin {
1045
+ to { transform: rotate(360deg); }
1046
+ }
1047
+ ` })
1048
+ ] });
1049
+ }
1050
+ if (!product) {
1051
+ return null;
1052
+ }
1053
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `site-kit-product-embed ${className}`, children: /* @__PURE__ */ jsxRuntime.jsx(
1054
+ OfferingCard,
1055
+ {
1056
+ offering: product,
1057
+ variant,
1058
+ showImage,
1059
+ showPrice,
1060
+ showDescription,
1061
+ showCta,
1062
+ ctaText,
1063
+ onCtaClick
1064
+ }
1065
+ ) });
1066
+ }
1067
+ function ProductDetail({
1068
+ product: propProduct,
1069
+ slug,
1070
+ showAddToCart = true,
1071
+ showBuyNow = true,
1072
+ showQuantity = true,
1073
+ showVariants = true,
1074
+ showGallery = true,
1075
+ showFeatures = true,
1076
+ showSpecifications = true,
1077
+ successUrl,
1078
+ cancelUrl,
1079
+ onAddToCart,
1080
+ onBuyNow,
1081
+ onCheckoutSuccess,
1082
+ onCheckoutError,
1083
+ className = "",
1084
+ style
1085
+ }) {
1086
+ const [product, setProduct] = React5.useState(propProduct || null);
1087
+ const [loading, setLoading] = React5.useState(!propProduct && !!slug);
1088
+ const [selectedVariant, setSelectedVariant] = React5.useState();
1089
+ const [quantity, setQuantity] = React5.useState(1);
1090
+ const [selectedImage, setSelectedImage] = React5.useState(0);
1091
+ const [checkingOut, setCheckingOut] = React5.useState(false);
1092
+ React5.useEffect(() => {
1093
+ if (propProduct) {
1094
+ setProduct(propProduct);
1095
+ const defaultVariant = propProduct.variants?.find((v) => v.is_default) || propProduct.variants?.[0];
1096
+ setSelectedVariant(defaultVariant);
1097
+ return;
1098
+ }
1099
+ if (!slug) return;
1100
+ async function load() {
1101
+ setLoading(true);
1102
+ try {
1103
+ const data = await fetchOffering(slug);
1104
+ setProduct(data);
1105
+ if (data?.variants?.length) {
1106
+ const defaultVariant = data.variants.find((v) => v.is_default) || data.variants[0];
1107
+ setSelectedVariant(defaultVariant);
1108
+ }
1109
+ } catch (e) {
1110
+ console.error("Failed to load product:", e);
1111
+ } finally {
1112
+ setLoading(false);
1113
+ }
1114
+ }
1115
+ load();
1116
+ }, [propProduct, slug]);
1117
+ if (loading) {
1118
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `site-kit-product-detail site-kit-product-detail--loading ${className}`, style, children: [
1119
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "site-kit-product-detail__loader", style: {
1120
+ display: "flex",
1121
+ justifyContent: "center",
1122
+ alignItems: "center",
1123
+ minHeight: "400px"
1124
+ }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
1125
+ width: "48px",
1126
+ height: "48px",
1127
+ border: "3px solid #e5e7eb",
1128
+ borderTopColor: "#2563eb",
1129
+ borderRadius: "50%",
1130
+ animation: "spin 1s linear infinite"
1131
+ } }) }),
1132
+ /* @__PURE__ */ jsxRuntime.jsx("style", { children: `@keyframes spin { to { transform: rotate(360deg); } }` })
1133
+ ] });
1134
+ }
1135
+ if (!product) {
1136
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `site-kit-product-detail site-kit-product-detail--not-found ${className}`, style, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { textAlign: "center", padding: "4rem 2rem", color: "#666" }, children: [
1137
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { style: { margin: 0, fontSize: "1.5rem", color: "#333" }, children: "Product Not Found" }),
1138
+ /* @__PURE__ */ jsxRuntime.jsx("p", { style: { marginTop: "0.5rem" }, children: "The product you're looking for doesn't exist or has been removed." })
1139
+ ] }) });
1140
+ }
1141
+ const currentPrice = selectedVariant?.price ?? product.price ?? 0;
1142
+ const compareAtPrice = product.compare_at_price;
1143
+ const hasDiscount = compareAtPrice && compareAtPrice > currentPrice;
1144
+ const allImages = [
1145
+ product.featured_image_url,
1146
+ ...product.gallery_images || [],
1147
+ ...product.variants?.map((v) => v.image_url).filter(Boolean) || []
1148
+ ].filter(Boolean);
1149
+ const inventoryCount = selectedVariant?.inventory_count ?? product.inventory_count;
1150
+ const isOutOfStock = product.track_inventory && inventoryCount !== void 0 && inventoryCount <= 0;
1151
+ const isLowStock = product.track_inventory && inventoryCount !== void 0 && inventoryCount > 0 && inventoryCount <= 5;
1152
+ const handleAddToCart = () => {
1153
+ if (onAddToCart) {
1154
+ onAddToCart(product, selectedVariant, quantity);
1155
+ }
1156
+ };
1157
+ const handleBuyNow = async () => {
1158
+ if (onBuyNow) {
1159
+ onBuyNow(product, selectedVariant, quantity);
1160
+ return;
1161
+ }
1162
+ setCheckingOut(true);
1163
+ try {
1164
+ const result = await createCheckoutSession({
1165
+ offeringId: product.id,
1166
+ variantId: selectedVariant?.id,
1167
+ quantity,
1168
+ successUrl: successUrl || `${window.location.origin}/checkout/success`,
1169
+ cancelUrl: cancelUrl || window.location.href
1170
+ });
1171
+ if (result.success && result.checkout_url) {
1172
+ onCheckoutSuccess?.(result);
1173
+ window.location.href = result.checkout_url;
1174
+ } else {
1175
+ throw new Error(result.error || "Failed to create checkout");
1176
+ }
1177
+ } catch (error) {
1178
+ console.error("Checkout error:", error);
1179
+ onCheckoutError?.(error.message || "Checkout failed");
1180
+ } finally {
1181
+ setCheckingOut(false);
1182
+ }
1183
+ };
1184
+ const handleVariantChange = (variant) => {
1185
+ setSelectedVariant(variant);
1186
+ if (variant.image_url) {
1187
+ const imageIndex = allImages.indexOf(variant.image_url);
1188
+ if (imageIndex >= 0) setSelectedImage(imageIndex);
1189
+ }
1190
+ };
1191
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `site-kit-product-detail ${className}`, style: {
1192
+ display: "grid",
1193
+ gridTemplateColumns: "repeat(auto-fit, minmax(320px, 1fr))",
1194
+ gap: "2rem",
1195
+ ...style
1196
+ }, children: [
1197
+ showGallery && allImages.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "site-kit-product-detail__gallery", children: [
1198
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "site-kit-product-detail__main-image", style: {
1199
+ aspectRatio: "1",
1200
+ borderRadius: "12px",
1201
+ overflow: "hidden",
1202
+ backgroundColor: "#f9fafb"
1203
+ }, children: /* @__PURE__ */ jsxRuntime.jsx(
1204
+ "img",
1205
+ {
1206
+ src: allImages[selectedImage],
1207
+ alt: product.name,
1208
+ style: {
1209
+ width: "100%",
1210
+ height: "100%",
1211
+ objectFit: "cover"
1212
+ }
1213
+ }
1214
+ ) }),
1215
+ allImages.length > 1 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "site-kit-product-detail__thumbnails", style: {
1216
+ display: "flex",
1217
+ gap: "0.5rem",
1218
+ marginTop: "0.75rem",
1219
+ overflowX: "auto"
1220
+ }, children: allImages.map((img, idx) => /* @__PURE__ */ jsxRuntime.jsx(
1221
+ "button",
1222
+ {
1223
+ onClick: () => setSelectedImage(idx),
1224
+ style: {
1225
+ flex: "0 0 auto",
1226
+ width: "64px",
1227
+ height: "64px",
1228
+ borderRadius: "8px",
1229
+ overflow: "hidden",
1230
+ border: idx === selectedImage ? "2px solid #2563eb" : "2px solid transparent",
1231
+ padding: 0,
1232
+ cursor: "pointer",
1233
+ backgroundColor: "#f9fafb"
1234
+ },
1235
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1236
+ "img",
1237
+ {
1238
+ src: img,
1239
+ alt: `${product.name} ${idx + 1}`,
1240
+ style: {
1241
+ width: "100%",
1242
+ height: "100%",
1243
+ objectFit: "cover"
1244
+ }
1245
+ }
1246
+ )
1247
+ },
1248
+ idx
1249
+ )) })
1250
+ ] }),
1251
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "site-kit-product-detail__info", children: [
1252
+ product.category && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "site-kit-product-detail__category", style: {
1253
+ fontSize: "0.875rem",
1254
+ color: "#6b7280",
1255
+ marginBottom: "0.5rem",
1256
+ textTransform: "uppercase",
1257
+ letterSpacing: "0.05em"
1258
+ }, children: product.category.name }),
1259
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "site-kit-product-detail__title", style: {
1260
+ margin: 0,
1261
+ fontSize: "2rem",
1262
+ fontWeight: 700,
1263
+ color: "#111827",
1264
+ lineHeight: 1.2
1265
+ }, children: product.name }),
1266
+ product.short_description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "site-kit-product-detail__short-description", style: {
1267
+ marginTop: "0.75rem",
1268
+ fontSize: "1rem",
1269
+ color: "#4b5563",
1270
+ lineHeight: 1.6
1271
+ }, children: product.short_description }),
1272
+ product.price_is_public && currentPrice !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "site-kit-product-detail__price", style: {
1273
+ marginTop: "1rem",
1274
+ display: "flex",
1275
+ alignItems: "baseline",
1276
+ gap: "0.75rem"
1277
+ }, children: [
1278
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: {
1279
+ fontSize: "1.75rem",
1280
+ fontWeight: 700,
1281
+ color: hasDiscount ? "#dc2626" : "#111827"
1282
+ }, children: formatPrice(currentPrice, product.currency) }),
1283
+ hasDiscount && /* @__PURE__ */ jsxRuntime.jsx("span", { style: {
1284
+ fontSize: "1.25rem",
1285
+ color: "#9ca3af",
1286
+ textDecoration: "line-through"
1287
+ }, children: formatPrice(compareAtPrice, product.currency) })
1288
+ ] }),
1289
+ product.track_inventory && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "site-kit-product-detail__stock", style: {
1290
+ marginTop: "0.75rem",
1291
+ fontSize: "0.875rem",
1292
+ fontWeight: 500
1293
+ }, children: isOutOfStock ? /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "#dc2626" }, children: "Out of Stock" }) : isLowStock ? /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { color: "#f59e0b" }, children: [
1294
+ "Only ",
1295
+ inventoryCount,
1296
+ " left!"
1297
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "#10b981" }, children: "In Stock" }) }),
1298
+ showVariants && product.variants && product.variants.length > 1 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "site-kit-product-detail__variants", style: { marginTop: "1.5rem" }, children: [
1299
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: {
1300
+ display: "block",
1301
+ fontSize: "0.875rem",
1302
+ fontWeight: 600,
1303
+ color: "#374151",
1304
+ marginBottom: "0.5rem"
1305
+ }, children: "Options" }),
1306
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexWrap: "wrap", gap: "0.5rem" }, children: product.variants.map((variant) => /* @__PURE__ */ jsxRuntime.jsx(
1307
+ "button",
1308
+ {
1309
+ onClick: () => handleVariantChange(variant),
1310
+ style: {
1311
+ padding: "0.5rem 1rem",
1312
+ borderRadius: "8px",
1313
+ border: selectedVariant?.id === variant.id ? "2px solid #2563eb" : "1px solid #d1d5db",
1314
+ backgroundColor: selectedVariant?.id === variant.id ? "#eff6ff" : "white",
1315
+ color: "#374151",
1316
+ fontSize: "0.875rem",
1317
+ fontWeight: 500,
1318
+ cursor: "pointer",
1319
+ transition: "all 0.15s ease"
1320
+ },
1321
+ children: variant.name
1322
+ },
1323
+ variant.id
1324
+ )) })
1325
+ ] }),
1326
+ showQuantity && !isOutOfStock && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "site-kit-product-detail__quantity", style: { marginTop: "1.5rem" }, children: [
1327
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: {
1328
+ display: "block",
1329
+ fontSize: "0.875rem",
1330
+ fontWeight: 600,
1331
+ color: "#374151",
1332
+ marginBottom: "0.5rem"
1333
+ }, children: "Quantity" }),
1334
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", gap: "0.5rem" }, children: [
1335
+ /* @__PURE__ */ jsxRuntime.jsx(
1336
+ "button",
1337
+ {
1338
+ onClick: () => setQuantity(Math.max(1, quantity - 1)),
1339
+ disabled: quantity <= 1,
1340
+ style: {
1341
+ width: "40px",
1342
+ height: "40px",
1343
+ borderRadius: "8px",
1344
+ border: "1px solid #d1d5db",
1345
+ backgroundColor: "white",
1346
+ fontSize: "1.25rem",
1347
+ cursor: quantity <= 1 ? "not-allowed" : "pointer",
1348
+ opacity: quantity <= 1 ? 0.5 : 1
1349
+ },
1350
+ children: "\u2212"
1351
+ }
1352
+ ),
1353
+ /* @__PURE__ */ jsxRuntime.jsx(
1354
+ "input",
1355
+ {
1356
+ type: "number",
1357
+ min: "1",
1358
+ max: inventoryCount ?? 99,
1359
+ value: quantity,
1360
+ onChange: (e) => setQuantity(Math.max(1, parseInt(e.target.value) || 1)),
1361
+ style: {
1362
+ width: "60px",
1363
+ height: "40px",
1364
+ textAlign: "center",
1365
+ borderRadius: "8px",
1366
+ border: "1px solid #d1d5db",
1367
+ fontSize: "1rem"
1368
+ }
1369
+ }
1370
+ ),
1371
+ /* @__PURE__ */ jsxRuntime.jsx(
1372
+ "button",
1373
+ {
1374
+ onClick: () => setQuantity(quantity + 1),
1375
+ disabled: product.track_inventory && inventoryCount !== void 0 && quantity >= inventoryCount,
1376
+ style: {
1377
+ width: "40px",
1378
+ height: "40px",
1379
+ borderRadius: "8px",
1380
+ border: "1px solid #d1d5db",
1381
+ backgroundColor: "white",
1382
+ fontSize: "1.25rem",
1383
+ cursor: "pointer"
1384
+ },
1385
+ children: "+"
1386
+ }
1387
+ )
1388
+ ] })
1389
+ ] }),
1390
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "site-kit-product-detail__actions", style: {
1391
+ marginTop: "1.5rem",
1392
+ display: "flex",
1393
+ flexDirection: "column",
1394
+ gap: "0.75rem"
1395
+ }, children: [
1396
+ showBuyNow && /* @__PURE__ */ jsxRuntime.jsx(
1397
+ "button",
1398
+ {
1399
+ onClick: handleBuyNow,
1400
+ disabled: isOutOfStock || checkingOut,
1401
+ className: "site-kit-product-detail__buy-now",
1402
+ style: {
1403
+ padding: "1rem 2rem",
1404
+ borderRadius: "8px",
1405
+ border: "none",
1406
+ backgroundColor: isOutOfStock ? "#d1d5db" : "#2563eb",
1407
+ color: "white",
1408
+ fontSize: "1rem",
1409
+ fontWeight: 600,
1410
+ cursor: isOutOfStock ? "not-allowed" : "pointer",
1411
+ transition: "all 0.15s ease"
1412
+ },
1413
+ children: checkingOut ? "Processing..." : isOutOfStock ? "Out of Stock" : "Buy Now"
1414
+ }
1415
+ ),
1416
+ showAddToCart && onAddToCart && /* @__PURE__ */ jsxRuntime.jsx(
1417
+ "button",
1418
+ {
1419
+ onClick: handleAddToCart,
1420
+ disabled: isOutOfStock,
1421
+ className: "site-kit-product-detail__add-to-cart",
1422
+ style: {
1423
+ padding: "1rem 2rem",
1424
+ borderRadius: "8px",
1425
+ border: "2px solid #2563eb",
1426
+ backgroundColor: "white",
1427
+ color: "#2563eb",
1428
+ fontSize: "1rem",
1429
+ fontWeight: 600,
1430
+ cursor: isOutOfStock ? "not-allowed" : "pointer",
1431
+ transition: "all 0.15s ease"
1432
+ },
1433
+ children: "Add to Cart"
1434
+ }
1435
+ )
1436
+ ] }),
1437
+ showFeatures && product.features && product.features.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "site-kit-product-detail__features", style: { marginTop: "2rem" }, children: [
1438
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { style: {
1439
+ fontSize: "1rem",
1440
+ fontWeight: 600,
1441
+ color: "#111827",
1442
+ marginBottom: "0.75rem"
1443
+ }, children: "Features" }),
1444
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { style: {
1445
+ margin: 0,
1446
+ paddingLeft: "1.25rem",
1447
+ display: "flex",
1448
+ flexDirection: "column",
1449
+ gap: "0.5rem"
1450
+ }, children: product.features.map((feature, idx) => /* @__PURE__ */ jsxRuntime.jsx("li", { style: { color: "#4b5563", fontSize: "0.9375rem" }, children: feature }, idx)) })
1451
+ ] }),
1452
+ showSpecifications && product.specifications && Object.keys(product.specifications).length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "site-kit-product-detail__specifications", style: { marginTop: "2rem" }, children: [
1453
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { style: {
1454
+ fontSize: "1rem",
1455
+ fontWeight: 600,
1456
+ color: "#111827",
1457
+ marginBottom: "0.75rem"
1458
+ }, children: "Specifications" }),
1459
+ /* @__PURE__ */ jsxRuntime.jsx("dl", { style: {
1460
+ margin: 0,
1461
+ display: "grid",
1462
+ gridTemplateColumns: "auto 1fr",
1463
+ gap: "0.5rem 1rem"
1464
+ }, children: Object.entries(product.specifications).map(([key, value]) => /* @__PURE__ */ jsxRuntime.jsxs(React5__default.default.Fragment, { children: [
1465
+ /* @__PURE__ */ jsxRuntime.jsx("dt", { style: { color: "#6b7280", fontSize: "0.875rem" }, children: key }),
1466
+ /* @__PURE__ */ jsxRuntime.jsx("dd", { style: { margin: 0, color: "#111827", fontSize: "0.875rem" }, children: value })
1467
+ ] }, key)) })
1468
+ ] })
1469
+ ] }),
1470
+ product.long_description && /* @__PURE__ */ jsxRuntime.jsxs(
1471
+ "div",
1472
+ {
1473
+ className: "site-kit-product-detail__description",
1474
+ style: {
1475
+ gridColumn: "1 / -1",
1476
+ marginTop: "2rem",
1477
+ padding: "2rem",
1478
+ backgroundColor: "#f9fafb",
1479
+ borderRadius: "12px"
1480
+ },
1481
+ children: [
1482
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { style: {
1483
+ fontSize: "1.25rem",
1484
+ fontWeight: 600,
1485
+ color: "#111827",
1486
+ marginBottom: "1rem"
1487
+ }, children: "About This Product" }),
1488
+ /* @__PURE__ */ jsxRuntime.jsx(
1489
+ "div",
1490
+ {
1491
+ style: { color: "#4b5563", lineHeight: 1.7 },
1492
+ dangerouslySetInnerHTML: { __html: product.long_description }
1493
+ }
1494
+ )
1495
+ ]
1496
+ }
1497
+ )
1498
+ ] });
1499
+ }
1500
+ function ProductGrid({
1501
+ products: propProducts,
1502
+ limit,
1503
+ category: propCategory,
1504
+ showCategoryFilter = false,
1505
+ showSort = true,
1506
+ showSearch = true,
1507
+ columns = 3,
1508
+ skeletonCount = 6,
1509
+ emptyMessage = "No products found",
1510
+ onProductClick,
1511
+ linkToProduct = true,
1512
+ productBasePath = "/shop",
1513
+ className = "",
1514
+ cardVariant = "card",
1515
+ style
1516
+ }) {
1517
+ const [products, setProducts] = React5.useState(propProducts || []);
1518
+ const [loading, setLoading] = React5.useState(!propProducts);
1519
+ const [searchQuery, setSearchQuery] = React5.useState("");
1520
+ const [selectedCategory, setSelectedCategory] = React5.useState(propCategory);
1521
+ const [sortBy, setSortBy] = React5.useState("newest");
1522
+ const categories = React5.useMemo(() => {
1523
+ const categoryMap = /* @__PURE__ */ new Map();
1524
+ products.forEach((p) => {
1525
+ if (p.category) {
1526
+ categoryMap.set(p.category.id, p.category);
1527
+ }
1528
+ });
1529
+ return Array.from(categoryMap.values());
1530
+ }, [products]);
1531
+ React5.useEffect(() => {
1532
+ if (propProducts) {
1533
+ setProducts(propProducts);
1534
+ return;
1535
+ }
1536
+ async function load() {
1537
+ setLoading(true);
1538
+ try {
1539
+ const data = await fetchOfferings({
1540
+ type: "product",
1541
+ category: selectedCategory,
1542
+ limit,
1543
+ orderBy: "created_at",
1544
+ order: "desc"
1545
+ });
1546
+ setProducts(data);
1547
+ } catch (e) {
1548
+ console.error("Failed to load products:", e);
1549
+ } finally {
1550
+ setLoading(false);
1551
+ }
1552
+ }
1553
+ load();
1554
+ }, [propProducts, selectedCategory, limit]);
1555
+ const filteredProducts = React5.useMemo(() => {
1556
+ let filtered = [...products];
1557
+ if (searchQuery) {
1558
+ const query = searchQuery.toLowerCase();
1559
+ filtered = filtered.filter(
1560
+ (p) => p.name.toLowerCase().includes(query) || p.short_description?.toLowerCase().includes(query) || p.tags?.some((tag) => tag.toLowerCase().includes(query))
1561
+ );
1562
+ }
1563
+ if (selectedCategory && !propCategory) {
1564
+ filtered = filtered.filter((p) => p.category_id === selectedCategory);
1565
+ }
1566
+ switch (sortBy) {
1567
+ case "newest":
1568
+ filtered.sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime());
1569
+ break;
1570
+ case "oldest":
1571
+ filtered.sort((a, b) => new Date(a.created_at).getTime() - new Date(b.created_at).getTime());
1572
+ break;
1573
+ case "price-low":
1574
+ filtered.sort((a, b) => (a.price || 0) - (b.price || 0));
1575
+ break;
1576
+ case "price-high":
1577
+ filtered.sort((a, b) => (b.price || 0) - (a.price || 0));
1578
+ break;
1579
+ case "name-az":
1580
+ filtered.sort((a, b) => a.name.localeCompare(b.name));
1581
+ break;
1582
+ case "name-za":
1583
+ filtered.sort((a, b) => b.name.localeCompare(a.name));
1584
+ break;
1585
+ }
1586
+ return filtered;
1587
+ }, [products, searchQuery, selectedCategory, sortBy, propCategory]);
1588
+ const handleProductClick = (product) => {
1589
+ if (onProductClick) {
1590
+ onProductClick(product);
1591
+ } else if (linkToProduct && typeof window !== "undefined") {
1592
+ window.location.href = `${productBasePath}/${product.slug}`;
1593
+ }
1594
+ };
1595
+ const gridColumns = {
1596
+ 2: "repeat(auto-fill, minmax(280px, 1fr))",
1597
+ 3: "repeat(auto-fill, minmax(240px, 1fr))",
1598
+ 4: "repeat(auto-fill, minmax(200px, 1fr))"
1599
+ };
1600
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `site-kit-product-grid ${className}`, style, children: [
1601
+ (showSearch || showSort || showCategoryFilter) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "site-kit-product-grid__controls", style: {
1602
+ display: "flex",
1603
+ flexWrap: "wrap",
1604
+ gap: "1rem",
1605
+ marginBottom: "1.5rem",
1606
+ alignItems: "center"
1607
+ }, children: [
1608
+ showSearch && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "site-kit-product-grid__search", style: { flex: "1 1 200px" }, children: /* @__PURE__ */ jsxRuntime.jsx(
1609
+ "input",
1610
+ {
1611
+ type: "search",
1612
+ placeholder: "Search products...",
1613
+ value: searchQuery,
1614
+ onChange: (e) => setSearchQuery(e.target.value),
1615
+ style: {
1616
+ width: "100%",
1617
+ padding: "0.625rem 1rem",
1618
+ borderRadius: "8px",
1619
+ border: "1px solid #d1d5db",
1620
+ fontSize: "0.9375rem"
1621
+ }
1622
+ }
1623
+ ) }),
1624
+ showCategoryFilter && categories.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
1625
+ "select",
1626
+ {
1627
+ value: selectedCategory || "",
1628
+ onChange: (e) => setSelectedCategory(e.target.value || void 0),
1629
+ className: "site-kit-product-grid__category-filter",
1630
+ style: {
1631
+ padding: "0.625rem 1rem",
1632
+ borderRadius: "8px",
1633
+ border: "1px solid #d1d5db",
1634
+ fontSize: "0.9375rem",
1635
+ backgroundColor: "white",
1636
+ minWidth: "150px"
1637
+ },
1638
+ children: [
1639
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: "All Categories" }),
1640
+ categories.map((cat) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: cat.id, children: cat.name }, cat.id))
1641
+ ]
1642
+ }
1643
+ ),
1644
+ showSort && /* @__PURE__ */ jsxRuntime.jsxs(
1645
+ "select",
1646
+ {
1647
+ value: sortBy,
1648
+ onChange: (e) => setSortBy(e.target.value),
1649
+ className: "site-kit-product-grid__sort",
1650
+ style: {
1651
+ padding: "0.625rem 1rem",
1652
+ borderRadius: "8px",
1653
+ border: "1px solid #d1d5db",
1654
+ fontSize: "0.9375rem",
1655
+ backgroundColor: "white"
1656
+ },
1657
+ children: [
1658
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "newest", children: "Newest First" }),
1659
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "oldest", children: "Oldest First" }),
1660
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "price-low", children: "Price: Low to High" }),
1661
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "price-high", children: "Price: High to Low" }),
1662
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "name-az", children: "Name: A-Z" }),
1663
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "name-za", children: "Name: Z-A" })
1664
+ ]
1665
+ }
1666
+ ),
1667
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "site-kit-product-grid__count", style: {
1668
+ marginLeft: "auto",
1669
+ fontSize: "0.875rem",
1670
+ color: "#6b7280"
1671
+ }, children: [
1672
+ filteredProducts.length,
1673
+ " product",
1674
+ filteredProducts.length !== 1 ? "s" : ""
1675
+ ] })
1676
+ ] }),
1677
+ loading && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "site-kit-product-grid__grid", style: {
1678
+ display: "grid",
1679
+ gridTemplateColumns: gridColumns[columns],
1680
+ gap: "1.5rem"
1681
+ }, children: [
1682
+ Array.from({ length: skeletonCount }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "site-kit-product-grid__skeleton", style: {
1683
+ aspectRatio: "1",
1684
+ backgroundColor: "#f3f4f6",
1685
+ borderRadius: "12px",
1686
+ animation: "pulse 2s infinite"
1687
+ } }, i)),
1688
+ /* @__PURE__ */ jsxRuntime.jsx("style", { children: `
1689
+ @keyframes pulse {
1690
+ 0%, 100% { opacity: 1; }
1691
+ 50% { opacity: 0.5; }
1692
+ }
1693
+ ` })
1694
+ ] }),
1695
+ !loading && filteredProducts.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "site-kit-product-grid__grid", style: {
1696
+ display: "grid",
1697
+ gridTemplateColumns: gridColumns[columns],
1698
+ gap: "1.5rem"
1699
+ }, children: filteredProducts.map((product) => /* @__PURE__ */ jsxRuntime.jsx(
1700
+ OfferingCard,
1701
+ {
1702
+ offering: product,
1703
+ variant: cardVariant,
1704
+ showImage: true,
1705
+ showPrice: true,
1706
+ showDescription: true,
1707
+ showCta: true,
1708
+ ctaText: "View Product",
1709
+ onCtaClick: () => handleProductClick(product)
1710
+ },
1711
+ product.id
1712
+ )) }),
1713
+ !loading && filteredProducts.length === 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "site-kit-product-grid__empty", style: {
1714
+ textAlign: "center",
1715
+ padding: "4rem 2rem",
1716
+ backgroundColor: "#f9fafb",
1717
+ borderRadius: "12px"
1718
+ }, children: [
1719
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: "3rem", marginBottom: "1rem" }, children: "\u{1F6CD}\uFE0F" }),
1720
+ /* @__PURE__ */ jsxRuntime.jsx("p", { style: {
1721
+ margin: 0,
1722
+ color: "#6b7280",
1723
+ fontSize: "1rem"
1724
+ }, children: searchQuery ? `No products match "${searchQuery}"` : emptyMessage }),
1725
+ searchQuery && /* @__PURE__ */ jsxRuntime.jsx(
1726
+ "button",
1727
+ {
1728
+ onClick: () => setSearchQuery(""),
1729
+ style: {
1730
+ marginTop: "1rem",
1731
+ padding: "0.5rem 1rem",
1732
+ borderRadius: "6px",
1733
+ border: "none",
1734
+ backgroundColor: "#2563eb",
1735
+ color: "white",
1736
+ fontSize: "0.875rem",
1737
+ cursor: "pointer"
1738
+ },
1739
+ children: "Clear Search"
1740
+ }
1741
+ )
1742
+ ] })
1743
+ ] });
1744
+ }
1745
+ function ProductPage({
1746
+ product: propProduct,
1747
+ slug,
1748
+ showBreadcrumbs = true,
1749
+ showRelatedProducts = true,
1750
+ relatedProductsLimit = 4,
1751
+ showBackLink = true,
1752
+ shopBasePath = "/shop",
1753
+ successUrl,
1754
+ cancelUrl,
1755
+ onAddToCart,
1756
+ renderBreadcrumbs,
1757
+ renderHead,
1758
+ className = "",
1759
+ style
1760
+ }) {
1761
+ const [product, setProduct] = React5.useState(propProduct || null);
1762
+ const [relatedProducts, setRelatedProducts] = React5.useState([]);
1763
+ const [loading, setLoading] = React5.useState(!propProduct && !!slug);
1764
+ React5.useEffect(() => {
1765
+ if (propProduct) {
1766
+ setProduct(propProduct);
1767
+ return;
1768
+ }
1769
+ if (!slug) return;
1770
+ async function load() {
1771
+ setLoading(true);
1772
+ try {
1773
+ const data = await fetchOffering(slug);
1774
+ setProduct(data);
1775
+ } catch (e) {
1776
+ console.error("Failed to load product:", e);
1777
+ } finally {
1778
+ setLoading(false);
1779
+ }
1780
+ }
1781
+ load();
1782
+ }, [propProduct, slug]);
1783
+ React5.useEffect(() => {
1784
+ if (!product || !showRelatedProducts) return;
1785
+ async function loadRelated() {
1786
+ try {
1787
+ const data = await fetchOfferings({
1788
+ type: "product",
1789
+ category: product?.category_id,
1790
+ limit: relatedProductsLimit + 1
1791
+ // Fetch one extra to exclude current
1792
+ });
1793
+ const filtered = data.filter((p) => p.id !== product?.id).slice(0, relatedProductsLimit);
1794
+ setRelatedProducts(filtered);
1795
+ } catch (e) {
1796
+ console.error("Failed to load related products:", e);
1797
+ }
1798
+ }
1799
+ loadRelated();
1800
+ }, [product, showRelatedProducts, relatedProductsLimit]);
1801
+ React5.useEffect(() => {
1802
+ if (product && typeof document !== "undefined") {
1803
+ document.title = product.seo_title || `${product.name} | Shop`;
1804
+ const metaDesc = document.querySelector('meta[name="description"]');
1805
+ if (metaDesc && (product.seo_description || product.short_description)) {
1806
+ metaDesc.setAttribute("content", product.seo_description || product.short_description || "");
1807
+ }
1808
+ }
1809
+ }, [product]);
1810
+ if (loading) {
1811
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `site-kit-product-page site-kit-product-page--loading ${className}`, style, children: [
1812
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
1813
+ display: "flex",
1814
+ justifyContent: "center",
1815
+ alignItems: "center",
1816
+ minHeight: "60vh"
1817
+ }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
1818
+ width: "48px",
1819
+ height: "48px",
1820
+ border: "3px solid #e5e7eb",
1821
+ borderTopColor: "#2563eb",
1822
+ borderRadius: "50%",
1823
+ animation: "spin 1s linear infinite"
1824
+ } }) }),
1825
+ /* @__PURE__ */ jsxRuntime.jsx("style", { children: `@keyframes spin { to { transform: rotate(360deg); } }` })
1826
+ ] });
1827
+ }
1828
+ if (!product) {
1829
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `site-kit-product-page site-kit-product-page--not-found ${className}`, style, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
1830
+ textAlign: "center",
1831
+ padding: "6rem 2rem"
1832
+ }, children: [
1833
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: "4rem", marginBottom: "1rem" }, children: "\u{1F50D}" }),
1834
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { style: { margin: 0, fontSize: "2rem", color: "#111827" }, children: "Product Not Found" }),
1835
+ /* @__PURE__ */ jsxRuntime.jsx("p", { style: { marginTop: "0.75rem", color: "#6b7280" }, children: "The product you're looking for doesn't exist or has been removed." }),
1836
+ /* @__PURE__ */ jsxRuntime.jsx(
1837
+ "a",
1838
+ {
1839
+ href: shopBasePath,
1840
+ style: {
1841
+ display: "inline-block",
1842
+ marginTop: "1.5rem",
1843
+ padding: "0.75rem 1.5rem",
1844
+ borderRadius: "8px",
1845
+ backgroundColor: "#2563eb",
1846
+ color: "white",
1847
+ textDecoration: "none",
1848
+ fontWeight: 600
1849
+ },
1850
+ children: "Back to Shop"
1851
+ }
1852
+ )
1853
+ ] }) });
1854
+ }
1855
+ const defaultBreadcrumbs = /* @__PURE__ */ jsxRuntime.jsx("nav", { className: "site-kit-product-page__breadcrumbs", "aria-label": "Breadcrumb", style: {
1856
+ marginBottom: "1.5rem",
1857
+ fontSize: "0.875rem"
1858
+ }, children: /* @__PURE__ */ jsxRuntime.jsxs("ol", { style: {
1859
+ display: "flex",
1860
+ flexWrap: "wrap",
1861
+ alignItems: "center",
1862
+ gap: "0.5rem",
1863
+ listStyle: "none",
1864
+ margin: 0,
1865
+ padding: 0
1866
+ }, children: [
1867
+ /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx("a", { href: "/", style: { color: "#6b7280", textDecoration: "none" }, children: "Home" }) }),
1868
+ /* @__PURE__ */ jsxRuntime.jsx("li", { style: { color: "#9ca3af" }, children: "/" }),
1869
+ /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx("a", { href: shopBasePath, style: { color: "#6b7280", textDecoration: "none" }, children: "Shop" }) }),
1870
+ product.category && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1871
+ /* @__PURE__ */ jsxRuntime.jsx("li", { style: { color: "#9ca3af" }, children: "/" }),
1872
+ /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx(
1873
+ "a",
1874
+ {
1875
+ href: `${shopBasePath}?category=${product.category.id}`,
1876
+ style: { color: "#6b7280", textDecoration: "none" },
1877
+ children: product.category.name
1878
+ }
1879
+ ) })
1880
+ ] }),
1881
+ /* @__PURE__ */ jsxRuntime.jsx("li", { style: { color: "#9ca3af" }, children: "/" }),
1882
+ /* @__PURE__ */ jsxRuntime.jsx("li", { style: { color: "#111827", fontWeight: 500 }, children: product.name })
1883
+ ] }) });
1884
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `site-kit-product-page ${className}`, style, children: [
1885
+ renderHead?.(product),
1886
+ showBackLink && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "site-kit-product-page__back", style: { marginBottom: "1rem" }, children: /* @__PURE__ */ jsxRuntime.jsxs(
1887
+ "a",
1888
+ {
1889
+ href: shopBasePath,
1890
+ style: {
1891
+ display: "inline-flex",
1892
+ alignItems: "center",
1893
+ gap: "0.5rem",
1894
+ color: "#6b7280",
1895
+ textDecoration: "none",
1896
+ fontSize: "0.875rem"
1897
+ },
1898
+ children: [
1899
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "\u2190" }),
1900
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Back to Shop" })
1901
+ ]
1902
+ }
1903
+ ) }),
1904
+ showBreadcrumbs && (renderBreadcrumbs ? renderBreadcrumbs(product) : defaultBreadcrumbs),
1905
+ /* @__PURE__ */ jsxRuntime.jsx(
1906
+ ProductDetail,
1907
+ {
1908
+ product,
1909
+ showAddToCart: !!onAddToCart,
1910
+ showBuyNow: true,
1911
+ showQuantity: true,
1912
+ showVariants: true,
1913
+ showGallery: true,
1914
+ showFeatures: true,
1915
+ showSpecifications: true,
1916
+ successUrl,
1917
+ cancelUrl,
1918
+ onAddToCart
1919
+ }
1920
+ ),
1921
+ showRelatedProducts && relatedProducts.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "site-kit-product-page__related", style: { marginTop: "4rem" }, children: [
1922
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { style: {
1923
+ fontSize: "1.5rem",
1924
+ fontWeight: 600,
1925
+ color: "#111827",
1926
+ marginBottom: "1.5rem"
1927
+ }, children: product.category ? `More ${product.category.name}` : "Related Products" }),
1928
+ /* @__PURE__ */ jsxRuntime.jsx(
1929
+ ProductGrid,
1930
+ {
1931
+ products: relatedProducts,
1932
+ showSearch: false,
1933
+ showSort: false,
1934
+ showCategoryFilter: false,
1935
+ columns: 4,
1936
+ productBasePath: shopBasePath
1937
+ }
1938
+ )
1939
+ ] })
1940
+ ] });
1941
+ }
1942
+ function EventEmbed({
1943
+ event: propEvent,
1944
+ slug,
1945
+ mode = "next",
1946
+ // 'specific', 'next'
1947
+ category,
1948
+ variant = "standard",
1949
+ showDate = true,
1950
+ showTime = true,
1951
+ showLocation = true,
1952
+ showCapacity = true,
1953
+ showPrice = true,
1954
+ showCta = true,
1955
+ ctaText,
1956
+ onRegister,
1957
+ onCtaClick,
1958
+ className = ""
1959
+ }) {
1960
+ const [event, setEvent] = React5.useState(propEvent || null);
1961
+ const [loading, setLoading] = React5.useState(!propEvent && (!!slug || mode === "next"));
1962
+ React5.useEffect(() => {
1963
+ if (propEvent) {
1964
+ setEvent(propEvent);
1965
+ return;
1966
+ }
1967
+ async function load() {
1968
+ setLoading(true);
1969
+ try {
1970
+ let data = null;
1971
+ if (mode === "specific" && slug) {
1972
+ data = await fetchOffering(slug);
1973
+ } else if (mode === "next") {
1974
+ data = await fetchNextEvent(category);
1975
+ }
1976
+ setEvent(data);
1977
+ } catch (e) {
1978
+ console.error("Failed to load event:", e);
1979
+ } finally {
1980
+ setLoading(false);
1981
+ }
1982
+ }
1983
+ load();
1984
+ }, [propEvent, slug, mode, category]);
1985
+ if (loading) {
1986
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `site-kit-event-embed ${className}`, style: {
1987
+ padding: "2rem",
1988
+ textAlign: "center",
1989
+ background: "#f9fafb",
1990
+ borderRadius: "12px"
1991
+ }, children: [
1992
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
1993
+ width: "40px",
1994
+ height: "40px",
1995
+ margin: "0 auto",
1996
+ border: "3px solid #e5e7eb",
1997
+ borderTopColor: "#2563eb",
1998
+ borderRadius: "50%",
1999
+ animation: "spin 1s linear infinite"
2000
+ } }),
2001
+ /* @__PURE__ */ jsxRuntime.jsx("style", { children: `
2002
+ @keyframes spin {
2003
+ to { transform: rotate(360deg); }
2004
+ }
2005
+ ` })
2006
+ ] });
2007
+ }
2008
+ if (!event) {
2009
+ return null;
2010
+ }
2011
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `site-kit-event-embed ${className}`, children: /* @__PURE__ */ jsxRuntime.jsx(
2012
+ EventTile,
2013
+ {
2014
+ event,
2015
+ variant,
2016
+ showDate,
2017
+ showTime,
2018
+ showLocation,
2019
+ showCapacity,
2020
+ showPrice,
2021
+ showCta,
2022
+ ctaText,
2023
+ onRegister,
2024
+ onCtaClick
2025
+ }
2026
+ ) });
2027
+ }
2028
+ function CheckoutForm({
2029
+ offering,
2030
+ scheduleId,
2031
+ variantId,
2032
+ quantity: initialQuantity = 1,
2033
+ mode = "checkout",
2034
+ // 'checkout' | 'register'
2035
+ showQuantity = true,
2036
+ submitText,
2037
+ onSuccess,
2038
+ onError,
2039
+ className = "",
2040
+ formClassName = "",
2041
+ inputClassName = "",
2042
+ buttonClassName = ""
2043
+ }) {
2044
+ const [loading, setLoading] = React5.useState(false);
2045
+ const [error, setError] = React5.useState(null);
2046
+ const [success, setSuccess] = React5.useState(false);
2047
+ const [quantity, setQuantity] = React5.useState(initialQuantity);
2048
+ const [customer, setCustomer] = React5.useState({
2049
+ email: "",
2050
+ name: "",
2051
+ phone: ""
2052
+ });
2053
+ const isEvent = offering.type === "event" || offering.type === "class";
2054
+ const isFree = !offering.price || offering.price === 0;
2055
+ const actualMode = isEvent && isFree ? "register" : mode;
2056
+ const defaultSubmitText = actualMode === "register" ? "Register" : isFree ? "Complete Order" : "Continue to Payment";
2057
+ const total = offering.price ? offering.price * quantity : 0;
2058
+ const handleSubmit = async (e) => {
2059
+ e.preventDefault();
2060
+ setLoading(true);
2061
+ setError(null);
2062
+ try {
2063
+ if (actualMode === "register" && isEvent && scheduleId) {
2064
+ const result = await registerForEvent(offering.id, scheduleId, customer);
2065
+ if (result.success) {
2066
+ setSuccess(true);
2067
+ onSuccess?.(result);
2068
+ } else {
2069
+ setError(result.error || "Registration failed");
2070
+ onError?.(result.error || "Registration failed");
2071
+ }
2072
+ } else {
2073
+ const result = await createCheckoutSession(offering.id, {
2074
+ variantId,
2075
+ scheduleId,
2076
+ quantity,
2077
+ customer
2078
+ });
2079
+ if (result.success && result.payment_url) {
2080
+ window.location.href = result.payment_url;
2081
+ } else {
2082
+ setError(result.error || "Checkout failed");
2083
+ onError?.(result.error || "Checkout failed");
2084
+ }
2085
+ }
2086
+ } catch (err) {
2087
+ const message = err instanceof Error ? err.message : "An error occurred";
2088
+ setError(message);
2089
+ onError?.(message);
2090
+ } finally {
2091
+ setLoading(false);
2092
+ }
2093
+ };
2094
+ const updateCustomer = (field, value) => {
2095
+ setCustomer((prev) => ({ ...prev, [field]: value }));
2096
+ };
2097
+ if (success) {
2098
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `site-kit-checkout-success ${className}`, style: {
2099
+ padding: "2rem",
2100
+ textAlign: "center",
2101
+ background: "#f0fdf4",
2102
+ borderRadius: "12px",
2103
+ border: "1px solid #bbf7d0"
2104
+ }, children: [
2105
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: "3rem", marginBottom: "1rem" }, children: "\u{1F389}" }),
2106
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { style: { margin: "0 0 0.5rem", color: "#166534" }, children: actualMode === "register" ? "Registration Complete!" : "Order Confirmed!" }),
2107
+ /* @__PURE__ */ jsxRuntime.jsx("p", { style: { color: "#15803d", margin: 0 }, children: actualMode === "register" ? `You're registered for ${offering.name}. Check your email for confirmation.` : `Thank you for your order! Check your email for details.` })
2108
+ ] });
2109
+ }
2110
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `site-kit-checkout ${className}`, children: /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit, className: formClassName, children: [
2111
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
2112
+ padding: "1rem",
2113
+ background: "#f9fafb",
2114
+ borderRadius: "8px",
2115
+ marginBottom: "1.5rem"
2116
+ }, children: [
2117
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "flex-start" }, children: [
2118
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2119
+ /* @__PURE__ */ jsxRuntime.jsx("h4", { style: { margin: "0 0 0.25rem", fontSize: "1rem" }, children: offering.name }),
2120
+ offering.short_description && /* @__PURE__ */ jsxRuntime.jsx("p", { style: { margin: 0, fontSize: "0.875rem", color: "#666" }, children: offering.short_description })
2121
+ ] }),
2122
+ offering.price_is_public && offering.price != null && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontWeight: 600, fontSize: "1.125rem" }, children: offering.price === 0 ? "Free" : formatPrice(offering.price, offering.currency) })
2123
+ ] }),
2124
+ showQuantity && !isEvent && offering.price && offering.price > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { marginTop: "1rem", display: "flex", alignItems: "center", gap: "0.5rem" }, children: [
2125
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: { fontSize: "0.875rem", color: "#666" }, children: "Quantity:" }),
2126
+ /* @__PURE__ */ jsxRuntime.jsx(
2127
+ "select",
2128
+ {
2129
+ value: quantity,
2130
+ onChange: (e) => setQuantity(Number(e.target.value)),
2131
+ className: inputClassName,
2132
+ style: {
2133
+ padding: "0.375rem 0.75rem",
2134
+ borderRadius: "6px",
2135
+ border: "1px solid #d1d5db",
2136
+ background: "white"
2137
+ },
2138
+ children: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map((n) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: n, children: n }, n))
2139
+ }
2140
+ ),
2141
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { marginLeft: "auto", fontWeight: 600 }, children: [
2142
+ "Total: ",
2143
+ formatPrice(total, offering.currency)
2144
+ ] })
2145
+ ] })
2146
+ ] }),
2147
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "1rem" }, children: [
2148
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2149
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: { display: "block", fontSize: "0.875rem", fontWeight: 500, marginBottom: "0.25rem" }, children: "Full Name *" }),
2150
+ /* @__PURE__ */ jsxRuntime.jsx(
2151
+ "input",
2152
+ {
2153
+ type: "text",
2154
+ required: true,
2155
+ value: customer.name,
2156
+ onChange: (e) => updateCustomer("name", e.target.value),
2157
+ className: inputClassName,
2158
+ style: {
2159
+ width: "100%",
2160
+ padding: "0.625rem 0.75rem",
2161
+ borderRadius: "6px",
2162
+ border: "1px solid #d1d5db",
2163
+ fontSize: "1rem"
2164
+ }
2165
+ }
2166
+ )
2167
+ ] }),
2168
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2169
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: { display: "block", fontSize: "0.875rem", fontWeight: 500, marginBottom: "0.25rem" }, children: "Email Address *" }),
2170
+ /* @__PURE__ */ jsxRuntime.jsx(
2171
+ "input",
2172
+ {
2173
+ type: "email",
2174
+ required: true,
2175
+ value: customer.email,
2176
+ onChange: (e) => updateCustomer("email", e.target.value),
2177
+ className: inputClassName,
2178
+ style: {
2179
+ width: "100%",
2180
+ padding: "0.625rem 0.75rem",
2181
+ borderRadius: "6px",
2182
+ border: "1px solid #d1d5db",
2183
+ fontSize: "1rem"
2184
+ }
2185
+ }
2186
+ )
2187
+ ] }),
2188
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2189
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: { display: "block", fontSize: "0.875rem", fontWeight: 500, marginBottom: "0.25rem" }, children: "Phone Number" }),
2190
+ /* @__PURE__ */ jsxRuntime.jsx(
2191
+ "input",
2192
+ {
2193
+ type: "tel",
2194
+ value: customer.phone || "",
2195
+ onChange: (e) => updateCustomer("phone", e.target.value),
2196
+ className: inputClassName,
2197
+ style: {
2198
+ width: "100%",
2199
+ padding: "0.625rem 0.75rem",
2200
+ borderRadius: "6px",
2201
+ border: "1px solid #d1d5db",
2202
+ fontSize: "1rem"
2203
+ }
2204
+ }
2205
+ )
2206
+ ] })
2207
+ ] }),
2208
+ error && /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
2209
+ marginTop: "1rem",
2210
+ padding: "0.75rem",
2211
+ background: "#fef2f2",
2212
+ border: "1px solid #fecaca",
2213
+ borderRadius: "6px",
2214
+ color: "#dc2626",
2215
+ fontSize: "0.875rem"
2216
+ }, children: error }),
2217
+ /* @__PURE__ */ jsxRuntime.jsx(
2218
+ "button",
2219
+ {
2220
+ type: "submit",
2221
+ disabled: loading,
2222
+ className: buttonClassName,
2223
+ style: {
2224
+ width: "100%",
2225
+ marginTop: "1.5rem",
2226
+ padding: "0.875rem",
2227
+ fontSize: "1rem",
2228
+ fontWeight: 600,
2229
+ borderRadius: "8px",
2230
+ border: "none",
2231
+ background: loading ? "#93c5fd" : "#2563eb",
2232
+ color: "white",
2233
+ cursor: loading ? "not-allowed" : "pointer"
2234
+ },
2235
+ children: loading ? "Processing..." : submitText || defaultSubmitText
2236
+ }
2237
+ ),
2238
+ !isFree && /* @__PURE__ */ jsxRuntime.jsx("p", { style: {
2239
+ textAlign: "center",
2240
+ fontSize: "0.75rem",
2241
+ color: "#666",
2242
+ marginTop: "0.75rem"
2243
+ }, children: "You'll be redirected to our secure payment page" })
2244
+ ] }) });
2245
+ }
2246
+ function RegistrationForm({
2247
+ event,
2248
+ scheduleId,
2249
+ title = "Register for Event",
2250
+ submitText = "Register",
2251
+ successMessage,
2252
+ collectPhone = false,
2253
+ additionalFields = [],
2254
+ onSuccess,
2255
+ onError,
2256
+ className = "",
2257
+ formClassName = "",
2258
+ inputClassName = "",
2259
+ buttonClassName = ""
2260
+ }) {
2261
+ const [loading, setLoading] = React5.useState(false);
2262
+ const [error, setError] = React5.useState(null);
2263
+ const [success, setSuccess] = React5.useState(false);
2264
+ const [customer, setCustomer] = React5.useState({
2265
+ email: "",
2266
+ name: "",
2267
+ phone: ""
2268
+ });
2269
+ const [additionalData, setAdditionalData] = React5.useState({});
2270
+ const handleSubmit = async (e) => {
2271
+ e.preventDefault();
2272
+ setLoading(true);
2273
+ setError(null);
2274
+ try {
2275
+ const result = await registerForEvent(event.id, scheduleId, {
2276
+ ...customer,
2277
+ ...additionalData
2278
+ });
2279
+ if (result.success) {
2280
+ setSuccess(true);
2281
+ onSuccess?.(result);
2282
+ } else {
2283
+ setError(result.error || "Registration failed");
2284
+ onError?.(result.error || "Registration failed");
2285
+ }
2286
+ } catch (err) {
2287
+ const message = err instanceof Error ? err.message : "An error occurred";
2288
+ setError(message);
2289
+ onError?.(message);
2290
+ } finally {
2291
+ setLoading(false);
2292
+ }
2293
+ };
2294
+ if (success) {
2295
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `site-kit-registration-success ${className}`, style: {
2296
+ padding: "2rem",
2297
+ textAlign: "center",
2298
+ background: "#f0fdf4",
2299
+ borderRadius: "12px",
2300
+ border: "1px solid #bbf7d0"
2301
+ }, children: [
2302
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: "3rem", marginBottom: "1rem" }, children: "\u{1F389}" }),
2303
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { style: { margin: "0 0 0.5rem", color: "#166534" }, children: "You're Registered!" }),
2304
+ /* @__PURE__ */ jsxRuntime.jsx("p", { style: { color: "#15803d", margin: 0 }, children: successMessage || `You've been registered for ${event.name}. Check your email for confirmation.` })
2305
+ ] });
2306
+ }
2307
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `site-kit-registration ${className}`, children: [
2308
+ title && /* @__PURE__ */ jsxRuntime.jsx("h3", { style: { margin: "0 0 1.5rem", fontSize: "1.25rem", fontWeight: 600 }, children: title }),
2309
+ /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit, className: formClassName, children: [
2310
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "1rem" }, children: [
2311
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2312
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: { display: "block", fontSize: "0.875rem", fontWeight: 500, marginBottom: "0.25rem" }, children: "Full Name *" }),
2313
+ /* @__PURE__ */ jsxRuntime.jsx(
2314
+ "input",
2315
+ {
2316
+ type: "text",
2317
+ required: true,
2318
+ value: customer.name,
2319
+ onChange: (e) => setCustomer((prev) => ({ ...prev, name: e.target.value })),
2320
+ className: inputClassName,
2321
+ style: {
2322
+ width: "100%",
2323
+ padding: "0.625rem 0.75rem",
2324
+ borderRadius: "6px",
2325
+ border: "1px solid #d1d5db",
2326
+ fontSize: "1rem"
2327
+ }
2328
+ }
2329
+ )
2330
+ ] }),
2331
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2332
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: { display: "block", fontSize: "0.875rem", fontWeight: 500, marginBottom: "0.25rem" }, children: "Email Address *" }),
2333
+ /* @__PURE__ */ jsxRuntime.jsx(
2334
+ "input",
2335
+ {
2336
+ type: "email",
2337
+ required: true,
2338
+ value: customer.email,
2339
+ onChange: (e) => setCustomer((prev) => ({ ...prev, email: e.target.value })),
2340
+ className: inputClassName,
2341
+ style: {
2342
+ width: "100%",
2343
+ padding: "0.625rem 0.75rem",
2344
+ borderRadius: "6px",
2345
+ border: "1px solid #d1d5db",
2346
+ fontSize: "1rem"
2347
+ }
2348
+ }
2349
+ )
2350
+ ] }),
2351
+ collectPhone && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2352
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: { display: "block", fontSize: "0.875rem", fontWeight: 500, marginBottom: "0.25rem" }, children: "Phone Number" }),
2353
+ /* @__PURE__ */ jsxRuntime.jsx(
2354
+ "input",
2355
+ {
2356
+ type: "tel",
2357
+ value: customer.phone || "",
2358
+ onChange: (e) => setCustomer((prev) => ({ ...prev, phone: e.target.value })),
2359
+ className: inputClassName,
2360
+ style: {
2361
+ width: "100%",
2362
+ padding: "0.625rem 0.75rem",
2363
+ borderRadius: "6px",
2364
+ border: "1px solid #d1d5db",
2365
+ fontSize: "1rem"
2366
+ }
2367
+ }
2368
+ )
2369
+ ] }),
2370
+ additionalFields.map((field) => /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2371
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { style: { display: "block", fontSize: "0.875rem", fontWeight: 500, marginBottom: "0.25rem" }, children: [
2372
+ field.label,
2373
+ " ",
2374
+ field.required && "*"
2375
+ ] }),
2376
+ field.type === "textarea" ? /* @__PURE__ */ jsxRuntime.jsx(
2377
+ "textarea",
2378
+ {
2379
+ required: field.required,
2380
+ placeholder: field.placeholder,
2381
+ value: additionalData[field.name] || "",
2382
+ onChange: (e) => setAdditionalData((prev) => ({ ...prev, [field.name]: e.target.value })),
2383
+ className: inputClassName,
2384
+ style: {
2385
+ width: "100%",
2386
+ padding: "0.625rem 0.75rem",
2387
+ borderRadius: "6px",
2388
+ border: "1px solid #d1d5db",
2389
+ fontSize: "1rem",
2390
+ minHeight: "80px"
2391
+ }
2392
+ }
2393
+ ) : field.type === "select" && field.options ? /* @__PURE__ */ jsxRuntime.jsxs(
2394
+ "select",
2395
+ {
2396
+ required: field.required,
2397
+ value: additionalData[field.name] || "",
2398
+ onChange: (e) => setAdditionalData((prev) => ({ ...prev, [field.name]: e.target.value })),
2399
+ className: inputClassName,
2400
+ style: {
2401
+ width: "100%",
2402
+ padding: "0.625rem 0.75rem",
2403
+ borderRadius: "6px",
2404
+ border: "1px solid #d1d5db",
2405
+ fontSize: "1rem",
2406
+ background: "white"
2407
+ },
2408
+ children: [
2409
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: "Select..." }),
2410
+ field.options.map((opt) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: opt.value, children: opt.label }, opt.value))
2411
+ ]
2412
+ }
2413
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
2414
+ "input",
2415
+ {
2416
+ type: field.type || "text",
2417
+ required: field.required,
2418
+ placeholder: field.placeholder,
2419
+ value: additionalData[field.name] || "",
2420
+ onChange: (e) => setAdditionalData((prev) => ({ ...prev, [field.name]: e.target.value })),
2421
+ className: inputClassName,
2422
+ style: {
2423
+ width: "100%",
2424
+ padding: "0.625rem 0.75rem",
2425
+ borderRadius: "6px",
2426
+ border: "1px solid #d1d5db",
2427
+ fontSize: "1rem"
2428
+ }
2429
+ }
2430
+ )
2431
+ ] }, field.name))
2432
+ ] }),
2433
+ error && /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
2434
+ marginTop: "1rem",
2435
+ padding: "0.75rem",
2436
+ background: "#fef2f2",
2437
+ border: "1px solid #fecaca",
2438
+ borderRadius: "6px",
2439
+ color: "#dc2626",
2440
+ fontSize: "0.875rem"
2441
+ }, children: error }),
2442
+ /* @__PURE__ */ jsxRuntime.jsx(
2443
+ "button",
2444
+ {
2445
+ type: "submit",
2446
+ disabled: loading,
2447
+ className: buttonClassName,
2448
+ style: {
2449
+ width: "100%",
2450
+ marginTop: "1.5rem",
2451
+ padding: "0.875rem",
2452
+ fontSize: "1rem",
2453
+ fontWeight: 600,
2454
+ borderRadius: "8px",
2455
+ border: "none",
2456
+ background: loading ? "#93c5fd" : "#2563eb",
2457
+ color: "white",
2458
+ cursor: loading ? "not-allowed" : "pointer"
2459
+ },
2460
+ children: loading ? "Registering..." : submitText
2461
+ }
2462
+ )
2463
+ ] })
2464
+ ] });
2465
+ }
2466
+ var DAYS_SHORT = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
2467
+ var MONTHS = [
2468
+ "January",
2469
+ "February",
2470
+ "March",
2471
+ "April",
2472
+ "May",
2473
+ "June",
2474
+ "July",
2475
+ "August",
2476
+ "September",
2477
+ "October",
2478
+ "November",
2479
+ "December"
2480
+ ];
2481
+ function CalendarView({
2482
+ events: propEvents,
2483
+ initialDate,
2484
+ category,
2485
+ onEventClick,
2486
+ onDayClick,
2487
+ showNavigation = true,
2488
+ showHeader = true,
2489
+ weekStartsOn = 0,
2490
+ minDate,
2491
+ maxDate,
2492
+ className = "",
2493
+ headerClassName = "",
2494
+ dayClassName = "",
2495
+ eventClassName = "",
2496
+ todayClassName = ""
2497
+ }) {
2498
+ const [currentDate, setCurrentDate] = React5.useState(initialDate || /* @__PURE__ */ new Date());
2499
+ const [events, setEvents] = React5.useState(propEvents || []);
2500
+ const [loading, setLoading] = React5.useState(!propEvents);
2501
+ React5.useEffect(() => {
2502
+ if (propEvents) {
2503
+ setEvents(propEvents);
2504
+ return;
2505
+ }
2506
+ async function load() {
2507
+ setLoading(true);
2508
+ try {
2509
+ const data = await fetchUpcomingEvents({ limit: 100, category });
2510
+ setEvents(data);
2511
+ } catch (e) {
2512
+ console.error("Failed to load events:", e);
2513
+ } finally {
2514
+ setLoading(false);
2515
+ }
2516
+ }
2517
+ load();
2518
+ }, [propEvents, category]);
2519
+ const calendarDays = React5.useMemo(() => {
2520
+ const year = currentDate.getFullYear();
2521
+ const month = currentDate.getMonth();
2522
+ const firstDay = new Date(year, month, 1);
2523
+ const lastDay = new Date(year, month + 1, 0);
2524
+ const startDate = new Date(firstDay);
2525
+ const dayOfWeek = startDate.getDay();
2526
+ const daysToSubtract = (dayOfWeek - weekStartsOn + 7) % 7;
2527
+ startDate.setDate(startDate.getDate() - daysToSubtract);
2528
+ const endDate = new Date(lastDay);
2529
+ const endDayOfWeek = endDate.getDay();
2530
+ const daysToAdd = (6 - endDayOfWeek + weekStartsOn) % 7;
2531
+ endDate.setDate(endDate.getDate() + daysToAdd);
2532
+ const eventsByDate = /* @__PURE__ */ new Map();
2533
+ events.forEach((event) => {
2534
+ const schedules = event.schedules || [];
2535
+ schedules.forEach((schedule) => {
2536
+ const scheduleDate = new Date(schedule.starts_at);
2537
+ const dateKey = `${scheduleDate.getFullYear()}-${scheduleDate.getMonth()}-${scheduleDate.getDate()}`;
2538
+ if (!eventsByDate.has(dateKey)) {
2539
+ eventsByDate.set(dateKey, []);
2540
+ }
2541
+ eventsByDate.get(dateKey).push({ event, schedule });
2542
+ });
2543
+ });
2544
+ const days = [];
2545
+ const today = /* @__PURE__ */ new Date();
2546
+ const todayKey = `${today.getFullYear()}-${today.getMonth()}-${today.getDate()}`;
2547
+ const current = new Date(startDate);
2548
+ while (current <= endDate) {
2549
+ const dateKey = `${current.getFullYear()}-${current.getMonth()}-${current.getDate()}`;
2550
+ days.push({
2551
+ date: new Date(current),
2552
+ isCurrentMonth: current.getMonth() === month,
2553
+ isToday: dateKey === todayKey,
2554
+ events: eventsByDate.get(dateKey) || []
2555
+ });
2556
+ current.setDate(current.getDate() + 1);
2557
+ }
2558
+ return days;
2559
+ }, [currentDate, events, weekStartsOn]);
2560
+ const goToPreviousMonth = () => {
2561
+ const newDate = new Date(currentDate);
2562
+ newDate.setMonth(newDate.getMonth() - 1);
2563
+ if (!minDate || newDate >= minDate) {
2564
+ setCurrentDate(newDate);
2565
+ }
2566
+ };
2567
+ const goToNextMonth = () => {
2568
+ const newDate = new Date(currentDate);
2569
+ newDate.setMonth(newDate.getMonth() + 1);
2570
+ if (!maxDate || newDate <= maxDate) {
2571
+ setCurrentDate(newDate);
2572
+ }
2573
+ };
2574
+ const goToToday = () => {
2575
+ setCurrentDate(/* @__PURE__ */ new Date());
2576
+ };
2577
+ const dayHeaders = weekStartsOn === 1 ? [...DAYS_SHORT.slice(1), DAYS_SHORT[0]] : DAYS_SHORT;
2578
+ const handleEventClick = (e, event, schedule) => {
2579
+ e.stopPropagation();
2580
+ if (onEventClick) {
2581
+ onEventClick(event, schedule);
2582
+ } else {
2583
+ window.location.href = `/events/${event.slug}`;
2584
+ }
2585
+ };
2586
+ const handleDayClick = (day) => {
2587
+ if (onDayClick) {
2588
+ onDayClick(day.date, day.events);
2589
+ }
2590
+ };
2591
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `site-kit-calendar ${className}`, style: {
2592
+ background: "white",
2593
+ borderRadius: "12px",
2594
+ overflow: "hidden",
2595
+ boxShadow: "0 1px 3px rgba(0,0,0,0.1)"
2596
+ }, children: [
2597
+ showHeader && /* @__PURE__ */ jsxRuntime.jsxs(
2598
+ "div",
2599
+ {
2600
+ className: `site-kit-calendar-header ${headerClassName}`,
2601
+ style: {
2602
+ display: "flex",
2603
+ alignItems: "center",
2604
+ justifyContent: "space-between",
2605
+ padding: "1rem 1.25rem",
2606
+ borderBottom: "1px solid #e5e7eb"
2607
+ },
2608
+ children: [
2609
+ showNavigation && /* @__PURE__ */ jsxRuntime.jsx(
2610
+ "button",
2611
+ {
2612
+ onClick: goToPreviousMonth,
2613
+ style: {
2614
+ padding: "0.5rem",
2615
+ border: "none",
2616
+ background: "#f3f4f6",
2617
+ borderRadius: "6px",
2618
+ cursor: "pointer",
2619
+ fontSize: "1.25rem",
2620
+ lineHeight: 1
2621
+ },
2622
+ "aria-label": "Previous month",
2623
+ children: "\u2190"
2624
+ }
2625
+ ),
2626
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { textAlign: "center" }, children: [
2627
+ /* @__PURE__ */ jsxRuntime.jsxs("h2", { style: { margin: 0, fontSize: "1.25rem", fontWeight: 600 }, children: [
2628
+ MONTHS[currentDate.getMonth()],
2629
+ " ",
2630
+ currentDate.getFullYear()
2631
+ ] }),
2632
+ showNavigation && /* @__PURE__ */ jsxRuntime.jsx(
2633
+ "button",
2634
+ {
2635
+ onClick: goToToday,
2636
+ style: {
2637
+ marginTop: "0.25rem",
2638
+ padding: "0.25rem 0.5rem",
2639
+ fontSize: "0.75rem",
2640
+ border: "none",
2641
+ background: "transparent",
2642
+ color: "#2563eb",
2643
+ cursor: "pointer"
2644
+ },
2645
+ children: "Today"
2646
+ }
2647
+ )
2648
+ ] }),
2649
+ showNavigation && /* @__PURE__ */ jsxRuntime.jsx(
2650
+ "button",
2651
+ {
2652
+ onClick: goToNextMonth,
2653
+ style: {
2654
+ padding: "0.5rem",
2655
+ border: "none",
2656
+ background: "#f3f4f6",
2657
+ borderRadius: "6px",
2658
+ cursor: "pointer",
2659
+ fontSize: "1.25rem",
2660
+ lineHeight: 1
2661
+ },
2662
+ "aria-label": "Next month",
2663
+ children: "\u2192"
2664
+ }
2665
+ )
2666
+ ]
2667
+ }
2668
+ ),
2669
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
2670
+ display: "grid",
2671
+ gridTemplateColumns: "repeat(7, 1fr)",
2672
+ borderBottom: "1px solid #e5e7eb"
2673
+ }, children: dayHeaders.map((day) => /* @__PURE__ */ jsxRuntime.jsx(
2674
+ "div",
2675
+ {
2676
+ style: {
2677
+ padding: "0.75rem 0.5rem",
2678
+ textAlign: "center",
2679
+ fontSize: "0.75rem",
2680
+ fontWeight: 600,
2681
+ color: "#666",
2682
+ textTransform: "uppercase"
2683
+ },
2684
+ children: day
2685
+ },
2686
+ day
2687
+ )) }),
2688
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
2689
+ display: "grid",
2690
+ gridTemplateColumns: "repeat(7, 1fr)"
2691
+ }, children: calendarDays.map((day, index) => /* @__PURE__ */ jsxRuntime.jsxs(
2692
+ "div",
2693
+ {
2694
+ onClick: () => handleDayClick(day),
2695
+ className: `site-kit-calendar-day ${dayClassName} ${day.isToday ? `site-kit-calendar-today ${todayClassName}` : ""}`,
2696
+ style: {
2697
+ minHeight: "100px",
2698
+ padding: "0.5rem",
2699
+ borderRight: (index + 1) % 7 !== 0 ? "1px solid #e5e7eb" : "none",
2700
+ borderBottom: "1px solid #e5e7eb",
2701
+ background: day.isCurrentMonth ? "white" : "#f9fafb",
2702
+ cursor: day.events.length > 0 || onDayClick ? "pointer" : "default"
2703
+ },
2704
+ children: [
2705
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
2706
+ display: "flex",
2707
+ justifyContent: "flex-end",
2708
+ marginBottom: "0.25rem"
2709
+ }, children: /* @__PURE__ */ jsxRuntime.jsx("span", { style: {
2710
+ display: "inline-flex",
2711
+ alignItems: "center",
2712
+ justifyContent: "center",
2713
+ width: "28px",
2714
+ height: "28px",
2715
+ borderRadius: "50%",
2716
+ fontSize: "0.875rem",
2717
+ fontWeight: day.isToday ? 600 : 400,
2718
+ color: day.isToday ? "white" : day.isCurrentMonth ? "#111" : "#9ca3af",
2719
+ background: day.isToday ? "#2563eb" : "transparent"
2720
+ }, children: day.date.getDate() }) }),
2721
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "2px" }, children: [
2722
+ day.events.slice(0, 3).map((item, eventIndex) => /* @__PURE__ */ jsxRuntime.jsx(
2723
+ "button",
2724
+ {
2725
+ onClick: (e) => handleEventClick(e, item.event, item.schedule),
2726
+ className: `site-kit-calendar-event ${eventClassName}`,
2727
+ style: {
2728
+ display: "block",
2729
+ width: "100%",
2730
+ padding: "2px 4px",
2731
+ fontSize: "0.7rem",
2732
+ fontWeight: 500,
2733
+ textAlign: "left",
2734
+ border: "none",
2735
+ borderRadius: "3px",
2736
+ background: "#dbeafe",
2737
+ color: "#1d4ed8",
2738
+ cursor: "pointer",
2739
+ overflow: "hidden",
2740
+ whiteSpace: "nowrap",
2741
+ textOverflow: "ellipsis"
2742
+ },
2743
+ title: `${item.event.name} - ${formatTime(item.schedule.starts_at)}`,
2744
+ children: item.event.name
2745
+ },
2746
+ `${item.event.id}-${item.schedule.id}`
2747
+ )),
2748
+ day.events.length > 3 && /* @__PURE__ */ jsxRuntime.jsxs("span", { style: {
2749
+ fontSize: "0.65rem",
2750
+ color: "#666",
2751
+ textAlign: "center"
2752
+ }, children: [
2753
+ "+",
2754
+ day.events.length - 3,
2755
+ " more"
2756
+ ] })
2757
+ ] })
2758
+ ]
2759
+ },
2760
+ index
2761
+ )) }),
2762
+ loading && /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
2763
+ position: "absolute",
2764
+ inset: 0,
2765
+ display: "flex",
2766
+ alignItems: "center",
2767
+ justifyContent: "center",
2768
+ background: "rgba(255,255,255,0.8)"
2769
+ }, children: "Loading..." })
2770
+ ] });
2771
+ }
2772
+ function EventModal({
2773
+ event,
2774
+ schedule: propSchedule,
2775
+ isOpen,
2776
+ onClose,
2777
+ onSuccess,
2778
+ onError,
2779
+ collectPhone = false,
2780
+ additionalFields = [],
2781
+ className = "",
2782
+ overlayClassName = "",
2783
+ contentClassName = ""
2784
+ }) {
2785
+ const [loading, setLoading] = React5.useState(false);
2786
+ const [error, setError] = React5.useState(null);
2787
+ const [success, setSuccess] = React5.useState(false);
2788
+ const [quantity, setQuantity] = React5.useState(1);
2789
+ const [customer, setCustomer] = React5.useState({
2790
+ email: "",
2791
+ name: "",
2792
+ phone: ""
2793
+ });
2794
+ const [additionalData, setAdditionalData] = React5.useState({});
2795
+ const schedule = propSchedule || event?.schedules?.[0] || event?.next_schedule;
2796
+ React5.useEffect(() => {
2797
+ if (isOpen && event) {
2798
+ setError(null);
2799
+ setSuccess(false);
2800
+ setQuantity(1);
2801
+ setCustomer({ email: "", name: "", phone: "" });
2802
+ setAdditionalData({});
2803
+ }
2804
+ }, [isOpen, event?.id]);
2805
+ React5.useEffect(() => {
2806
+ const handleEscape = (e) => {
2807
+ if (e.key === "Escape" && isOpen) {
2808
+ onClose();
2809
+ }
2810
+ };
2811
+ document.addEventListener("keydown", handleEscape);
2812
+ return () => document.removeEventListener("keydown", handleEscape);
2813
+ }, [isOpen, onClose]);
2814
+ React5.useEffect(() => {
2815
+ if (isOpen) {
2816
+ document.body.style.overflow = "hidden";
2817
+ } else {
2818
+ document.body.style.overflow = "";
2819
+ }
2820
+ return () => {
2821
+ document.body.style.overflow = "";
2822
+ };
2823
+ }, [isOpen]);
2824
+ const handleOverlayClick = React5.useCallback((e) => {
2825
+ if (e.target === e.currentTarget) {
2826
+ onClose();
2827
+ }
2828
+ }, [onClose]);
2829
+ if (!isOpen || !event) return null;
2830
+ const isFree = !event.price || event.price === 0;
2831
+ const soldOut = schedule ? isEventSoldOut(schedule.capacity, schedule.current_registrations) : false;
2832
+ const spotsRemaining = schedule ? getSpotsRemaining(schedule.capacity, schedule.current_registrations) : null;
2833
+ const total = event.price ? event.price * quantity : 0;
2834
+ const handleSubmit = async (e) => {
2835
+ e.preventDefault();
2836
+ if (!schedule) {
2837
+ setError("No schedule available for this event");
2838
+ return;
2839
+ }
2840
+ setLoading(true);
2841
+ setError(null);
2842
+ try {
2843
+ if (isFree) {
2844
+ const result = await registerForEvent(event.id, schedule.id, {
2845
+ ...customer,
2846
+ ...additionalData
2847
+ });
2848
+ if (result.success) {
2849
+ setSuccess(true);
2850
+ onSuccess?.(result);
2851
+ } else {
2852
+ setError(result.error || "Registration failed");
2853
+ onError?.(result.error || "Registration failed");
2854
+ }
2855
+ } else {
2856
+ const result = await createCheckoutSession(event.id, {
2857
+ scheduleId: schedule.id,
2858
+ quantity,
2859
+ customer: {
2860
+ ...customer,
2861
+ ...additionalData
2862
+ },
2863
+ successUrl: window.location.href + "?registration=success",
2864
+ cancelUrl: window.location.href
2865
+ });
2866
+ if (result.success && result.payment_url) {
2867
+ window.location.href = result.payment_url;
2868
+ } else {
2869
+ setError(result.error || "Checkout failed");
2870
+ onError?.(result.error || "Checkout failed");
2871
+ }
2872
+ }
2873
+ } catch (err) {
2874
+ const message = err instanceof Error ? err.message : "An error occurred";
2875
+ setError(message);
2876
+ onError?.(message);
2877
+ } finally {
2878
+ setLoading(false);
2879
+ }
2880
+ };
2881
+ const updateCustomer = (field, value) => {
2882
+ setCustomer((prev) => ({ ...prev, [field]: value }));
2883
+ };
2884
+ return /* @__PURE__ */ jsxRuntime.jsx(
2885
+ "div",
2886
+ {
2887
+ className: `site-kit-modal-overlay ${overlayClassName}`,
2888
+ onClick: handleOverlayClick,
2889
+ style: {
2890
+ position: "fixed",
2891
+ inset: 0,
2892
+ zIndex: 9999,
2893
+ display: "flex",
2894
+ alignItems: "center",
2895
+ justifyContent: "center",
2896
+ padding: "1rem",
2897
+ background: "rgba(0, 0, 0, 0.5)",
2898
+ backdropFilter: "blur(4px)"
2899
+ },
2900
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
2901
+ "div",
2902
+ {
2903
+ className: `site-kit-modal ${className}`,
2904
+ style: {
2905
+ position: "relative",
2906
+ width: "100%",
2907
+ maxWidth: "500px",
2908
+ maxHeight: "90vh",
2909
+ overflow: "auto",
2910
+ background: "white",
2911
+ borderRadius: "16px",
2912
+ boxShadow: "0 25px 50px -12px rgba(0, 0, 0, 0.25)"
2913
+ },
2914
+ onClick: (e) => e.stopPropagation(),
2915
+ children: [
2916
+ /* @__PURE__ */ jsxRuntime.jsx(
2917
+ "button",
2918
+ {
2919
+ onClick: onClose,
2920
+ style: {
2921
+ position: "absolute",
2922
+ top: "1rem",
2923
+ right: "1rem",
2924
+ padding: "0.5rem",
2925
+ border: "none",
2926
+ background: "#f3f4f6",
2927
+ borderRadius: "50%",
2928
+ cursor: "pointer",
2929
+ fontSize: "1.25rem",
2930
+ lineHeight: 1,
2931
+ width: "36px",
2932
+ height: "36px",
2933
+ display: "flex",
2934
+ alignItems: "center",
2935
+ justifyContent: "center",
2936
+ zIndex: 10
2937
+ },
2938
+ "aria-label": "Close",
2939
+ children: "\xD7"
2940
+ }
2941
+ ),
2942
+ event.featured_image_url && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { position: "relative" }, children: [
2943
+ /* @__PURE__ */ jsxRuntime.jsx(
2944
+ "img",
2945
+ {
2946
+ src: event.featured_image_url,
2947
+ alt: event.name,
2948
+ style: {
2949
+ width: "100%",
2950
+ height: "180px",
2951
+ objectFit: "cover",
2952
+ borderRadius: "16px 16px 0 0"
2953
+ }
2954
+ }
2955
+ ),
2956
+ soldOut && /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
2957
+ position: "absolute",
2958
+ top: "1rem",
2959
+ left: "1rem",
2960
+ background: "#ef4444",
2961
+ color: "white",
2962
+ padding: "0.25rem 0.75rem",
2963
+ borderRadius: "4px",
2964
+ fontSize: "0.875rem",
2965
+ fontWeight: 600
2966
+ }, children: "Sold Out" })
2967
+ ] }),
2968
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: `site-kit-modal-content ${contentClassName}`, style: { padding: "1.5rem" }, children: success ? /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { textAlign: "center", padding: "2rem 0" }, children: [
2969
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: "4rem", marginBottom: "1rem" }, children: "\u{1F389}" }),
2970
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { style: { margin: "0 0 0.5rem", color: "#166534" }, children: "You're Registered!" }),
2971
+ /* @__PURE__ */ jsxRuntime.jsx("p", { style: { color: "#15803d", margin: "0 0 1.5rem" }, children: "Check your email for confirmation details." }),
2972
+ /* @__PURE__ */ jsxRuntime.jsx(
2973
+ "button",
2974
+ {
2975
+ onClick: onClose,
2976
+ style: {
2977
+ padding: "0.75rem 2rem",
2978
+ fontSize: "1rem",
2979
+ fontWeight: 500,
2980
+ border: "none",
2981
+ borderRadius: "8px",
2982
+ background: "#2563eb",
2983
+ color: "white",
2984
+ cursor: "pointer"
2985
+ },
2986
+ children: "Done"
2987
+ }
2988
+ )
2989
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2990
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { marginBottom: "1.5rem" }, children: [
2991
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { style: { margin: "0 0 0.5rem", fontSize: "1.5rem", fontWeight: 600, paddingRight: "2rem" }, children: event.name }),
2992
+ schedule && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flexWrap: "wrap", gap: "1rem", color: "#666", fontSize: "0.9rem" }, children: [
2993
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
2994
+ "\u{1F4C5} ",
2995
+ formatDate(schedule.starts_at)
2996
+ ] }),
2997
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
2998
+ "\u{1F550} ",
2999
+ formatTime(schedule.starts_at)
3000
+ ] }),
3001
+ event.location && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
3002
+ "\u{1F4CD} ",
3003
+ event.location
3004
+ ] })
3005
+ ] }),
3006
+ event.short_description && /* @__PURE__ */ jsxRuntime.jsx("p", { style: { margin: "0.75rem 0 0", color: "#666", fontSize: "0.9rem" }, children: event.short_description }),
3007
+ spotsRemaining !== null && spotsRemaining <= 10 && spotsRemaining > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
3008
+ marginTop: "0.75rem",
3009
+ padding: "0.5rem 0.75rem",
3010
+ background: "#fef3c7",
3011
+ borderRadius: "6px",
3012
+ color: "#92400e",
3013
+ fontSize: "0.875rem"
3014
+ }, children: [
3015
+ "\u26A0\uFE0F Only ",
3016
+ spotsRemaining,
3017
+ " spot",
3018
+ spotsRemaining > 1 ? "s" : "",
3019
+ " remaining!"
3020
+ ] })
3021
+ ] }),
3022
+ soldOut ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
3023
+ padding: "2rem",
3024
+ textAlign: "center",
3025
+ background: "#f3f4f6",
3026
+ borderRadius: "8px"
3027
+ }, children: /* @__PURE__ */ jsxRuntime.jsx("p", { style: { margin: 0, color: "#666" }, children: "This event is sold out. Check back for future dates!" }) }) : /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit, children: [
3028
+ !isFree && event.price_is_public && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
3029
+ padding: "1rem",
3030
+ background: "#f9fafb",
3031
+ borderRadius: "8px",
3032
+ marginBottom: "1rem"
3033
+ }, children: [
3034
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [
3035
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
3036
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: 600, fontSize: "1.25rem" }, children: formatPrice(event.price, event.currency) }),
3037
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "#666", fontSize: "0.875rem" }, children: " per ticket" })
3038
+ ] }),
3039
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", gap: "0.5rem" }, children: [
3040
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: { fontSize: "0.875rem", color: "#666" }, children: "Qty:" }),
3041
+ /* @__PURE__ */ jsxRuntime.jsx(
3042
+ "select",
3043
+ {
3044
+ value: quantity,
3045
+ onChange: (e) => setQuantity(Number(e.target.value)),
3046
+ style: {
3047
+ padding: "0.5rem",
3048
+ borderRadius: "6px",
3049
+ border: "1px solid #d1d5db",
3050
+ background: "white",
3051
+ fontSize: "1rem"
3052
+ },
3053
+ children: [...Array(Math.min(10, spotsRemaining || 10))].map((_, i) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: i + 1, children: i + 1 }, i + 1))
3054
+ }
3055
+ )
3056
+ ] })
3057
+ ] }),
3058
+ quantity > 1 && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
3059
+ marginTop: "0.75rem",
3060
+ paddingTop: "0.75rem",
3061
+ borderTop: "1px solid #e5e7eb",
3062
+ display: "flex",
3063
+ justifyContent: "space-between"
3064
+ }, children: [
3065
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: 500 }, children: "Total" }),
3066
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: 600, fontSize: "1.125rem" }, children: formatPrice(total, event.currency) })
3067
+ ] })
3068
+ ] }),
3069
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.875rem" }, children: [
3070
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
3071
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: { display: "block", fontSize: "0.875rem", fontWeight: 500, marginBottom: "0.25rem" }, children: "Full Name *" }),
3072
+ /* @__PURE__ */ jsxRuntime.jsx(
3073
+ "input",
3074
+ {
3075
+ type: "text",
3076
+ required: true,
3077
+ value: customer.name,
3078
+ onChange: (e) => updateCustomer("name", e.target.value),
3079
+ placeholder: "John Smith",
3080
+ style: {
3081
+ width: "100%",
3082
+ padding: "0.625rem 0.75rem",
3083
+ borderRadius: "6px",
3084
+ border: "1px solid #d1d5db",
3085
+ fontSize: "1rem"
3086
+ }
3087
+ }
3088
+ )
3089
+ ] }),
3090
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
3091
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: { display: "block", fontSize: "0.875rem", fontWeight: 500, marginBottom: "0.25rem" }, children: "Email Address *" }),
3092
+ /* @__PURE__ */ jsxRuntime.jsx(
3093
+ "input",
3094
+ {
3095
+ type: "email",
3096
+ required: true,
3097
+ value: customer.email,
3098
+ onChange: (e) => updateCustomer("email", e.target.value),
3099
+ placeholder: "john@example.com",
3100
+ style: {
3101
+ width: "100%",
3102
+ padding: "0.625rem 0.75rem",
3103
+ borderRadius: "6px",
3104
+ border: "1px solid #d1d5db",
3105
+ fontSize: "1rem"
3106
+ }
3107
+ }
3108
+ )
3109
+ ] }),
3110
+ collectPhone && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
3111
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: { display: "block", fontSize: "0.875rem", fontWeight: 500, marginBottom: "0.25rem" }, children: "Phone Number" }),
3112
+ /* @__PURE__ */ jsxRuntime.jsx(
3113
+ "input",
3114
+ {
3115
+ type: "tel",
3116
+ value: customer.phone || "",
3117
+ onChange: (e) => updateCustomer("phone", e.target.value),
3118
+ placeholder: "(555) 123-4567",
3119
+ style: {
3120
+ width: "100%",
3121
+ padding: "0.625rem 0.75rem",
3122
+ borderRadius: "6px",
3123
+ border: "1px solid #d1d5db",
3124
+ fontSize: "1rem"
3125
+ }
3126
+ }
3127
+ )
3128
+ ] }),
3129
+ additionalFields.map((field) => /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
3130
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { style: { display: "block", fontSize: "0.875rem", fontWeight: 500, marginBottom: "0.25rem" }, children: [
3131
+ field.label,
3132
+ " ",
3133
+ field.required && "*"
3134
+ ] }),
3135
+ field.type === "textarea" ? /* @__PURE__ */ jsxRuntime.jsx(
3136
+ "textarea",
3137
+ {
3138
+ required: field.required,
3139
+ placeholder: field.placeholder,
3140
+ value: additionalData[field.name] || "",
3141
+ onChange: (e) => setAdditionalData((prev) => ({ ...prev, [field.name]: e.target.value })),
3142
+ style: {
3143
+ width: "100%",
3144
+ padding: "0.625rem 0.75rem",
3145
+ borderRadius: "6px",
3146
+ border: "1px solid #d1d5db",
3147
+ fontSize: "1rem",
3148
+ minHeight: "80px",
3149
+ resize: "vertical"
3150
+ }
3151
+ }
3152
+ ) : field.type === "select" && field.options ? /* @__PURE__ */ jsxRuntime.jsxs(
3153
+ "select",
3154
+ {
3155
+ required: field.required,
3156
+ value: additionalData[field.name] || "",
3157
+ onChange: (e) => setAdditionalData((prev) => ({ ...prev, [field.name]: e.target.value })),
3158
+ style: {
3159
+ width: "100%",
3160
+ padding: "0.625rem 0.75rem",
3161
+ borderRadius: "6px",
3162
+ border: "1px solid #d1d5db",
3163
+ fontSize: "1rem",
3164
+ background: "white"
3165
+ },
3166
+ children: [
3167
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: "Select..." }),
3168
+ field.options.map((opt) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: opt.value, children: opt.label }, opt.value))
3169
+ ]
3170
+ }
3171
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
3172
+ "input",
3173
+ {
3174
+ type: field.type || "text",
3175
+ required: field.required,
3176
+ placeholder: field.placeholder,
3177
+ value: additionalData[field.name] || "",
3178
+ onChange: (e) => setAdditionalData((prev) => ({ ...prev, [field.name]: e.target.value })),
3179
+ style: {
3180
+ width: "100%",
3181
+ padding: "0.625rem 0.75rem",
3182
+ borderRadius: "6px",
3183
+ border: "1px solid #d1d5db",
3184
+ fontSize: "1rem"
3185
+ }
3186
+ }
3187
+ )
3188
+ ] }, field.name))
3189
+ ] }),
3190
+ error && /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
3191
+ marginTop: "1rem",
3192
+ padding: "0.75rem",
3193
+ background: "#fef2f2",
3194
+ border: "1px solid #fecaca",
3195
+ borderRadius: "6px",
3196
+ color: "#dc2626",
3197
+ fontSize: "0.875rem"
3198
+ }, children: error }),
3199
+ /* @__PURE__ */ jsxRuntime.jsx(
3200
+ "button",
3201
+ {
3202
+ type: "submit",
3203
+ disabled: loading,
3204
+ style: {
3205
+ width: "100%",
3206
+ marginTop: "1.25rem",
3207
+ padding: "0.875rem",
3208
+ fontSize: "1rem",
3209
+ fontWeight: 600,
3210
+ borderRadius: "8px",
3211
+ border: "none",
3212
+ background: loading ? "#93c5fd" : "#2563eb",
3213
+ color: "white",
3214
+ cursor: loading ? "not-allowed" : "pointer"
3215
+ },
3216
+ children: loading ? "Processing..." : isFree ? "Register Free" : `Pay ${formatPrice(total, event.currency)}`
3217
+ }
3218
+ ),
3219
+ !isFree && /* @__PURE__ */ jsxRuntime.jsx("p", { style: {
3220
+ textAlign: "center",
3221
+ fontSize: "0.75rem",
3222
+ color: "#666",
3223
+ margin: "0.75rem 0 0"
3224
+ }, children: "\u{1F512} Secure checkout via Stripe" })
3225
+ ] })
3226
+ ] }) })
3227
+ ]
3228
+ }
3229
+ )
3230
+ }
3231
+ );
3232
+ }
3233
+ function useEventModal() {
3234
+ const [event, setEvent] = React5.useState(null);
3235
+ const [schedule, setSchedule] = React5.useState(null);
3236
+ const [isOpen, setIsOpen] = React5.useState(false);
3237
+ const openModal = React5.useCallback((newEvent, newSchedule) => {
3238
+ setEvent(newEvent);
3239
+ setSchedule(newSchedule || newEvent.schedules?.[0] || null);
3240
+ setIsOpen(true);
3241
+ }, []);
3242
+ const closeModal = React5.useCallback(() => {
3243
+ setIsOpen(false);
3244
+ setTimeout(() => {
3245
+ setEvent(null);
3246
+ setSchedule(null);
3247
+ }, 200);
3248
+ }, []);
3249
+ return {
3250
+ event,
3251
+ schedule,
3252
+ isOpen,
3253
+ openModal,
3254
+ closeModal
3255
+ };
3256
+ }
3257
+ function EventCalendar({
3258
+ onRegistrationSuccess,
3259
+ onRegistrationError,
3260
+ collectPhone = false,
3261
+ additionalFields = [],
3262
+ modalClassName,
3263
+ modalOverlayClassName,
3264
+ modalContentClassName,
3265
+ ...calendarProps
3266
+ }) {
3267
+ const { event, schedule, isOpen, openModal, closeModal } = useEventModal();
3268
+ const handleEventClick = (clickedEvent, clickedSchedule) => {
3269
+ openModal(clickedEvent, clickedSchedule);
3270
+ };
3271
+ const handleSuccess = (result) => {
3272
+ onRegistrationSuccess?.(result);
3273
+ };
3274
+ const handleError = (error) => {
3275
+ onRegistrationError?.(error);
3276
+ };
3277
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3278
+ /* @__PURE__ */ jsxRuntime.jsx(
3279
+ CalendarView,
3280
+ {
3281
+ ...calendarProps,
3282
+ onEventClick: handleEventClick
3283
+ }
3284
+ ),
3285
+ /* @__PURE__ */ jsxRuntime.jsx(
3286
+ EventModal,
3287
+ {
3288
+ event,
3289
+ schedule,
3290
+ isOpen,
3291
+ onClose: closeModal,
3292
+ onSuccess: handleSuccess,
3293
+ onError: handleError,
3294
+ collectPhone,
3295
+ additionalFields,
3296
+ className: modalClassName,
3297
+ overlayClassName: modalOverlayClassName,
3298
+ contentClassName: modalContentClassName
3299
+ }
3300
+ )
3301
+ ] });
3302
+ }
3303
+ var CalendarIcon = () => /* @__PURE__ */ jsxRuntime.jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
3304
+ /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "3", y: "4", width: "18", height: "18", rx: "2", ry: "2" }),
3305
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "16", y1: "2", x2: "16", y2: "6" }),
3306
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "8", y1: "2", x2: "8", y2: "6" }),
3307
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "3", y1: "10", x2: "21", y2: "10" })
3308
+ ] });
3309
+ var ListIcon = () => /* @__PURE__ */ jsxRuntime.jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
3310
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "8", y1: "6", x2: "21", y2: "6" }),
3311
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "8", y1: "12", x2: "21", y2: "12" }),
3312
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "8", y1: "18", x2: "21", y2: "18" }),
3313
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "3", y1: "6", x2: "3.01", y2: "6" }),
3314
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "3", y1: "12", x2: "3.01", y2: "12" }),
3315
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "3", y1: "18", x2: "3.01", y2: "18" })
3316
+ ] });
3317
+ var ClockIcon = () => /* @__PURE__ */ jsxRuntime.jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
3318
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "10" }),
3319
+ /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "12 6 12 12 16 14" })
3320
+ ] });
3321
+ var LocationIcon = () => /* @__PURE__ */ jsxRuntime.jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
3322
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z" }),
3323
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "10", r: "3" })
3324
+ ] });
3325
+ function EventsWidget({
3326
+ events: propEvents,
3327
+ defaultView = "list",
3328
+ showViewToggle = true,
3329
+ title,
3330
+ subtitle,
3331
+ category,
3332
+ limit = 10,
3333
+ showViewAll = false,
3334
+ viewAllUrl = "/events",
3335
+ viewAllText = "View All Events",
3336
+ emptyMessage = "No upcoming events scheduled.",
3337
+ showEmptyIcon = true,
3338
+ collectPhone = false,
3339
+ additionalFields = [],
3340
+ onRegistrationSuccess,
3341
+ onRegistrationError,
3342
+ onEventClick,
3343
+ className = "",
3344
+ headerClassName = "",
3345
+ toggleClassName = "",
3346
+ listClassName = "",
3347
+ calendarClassName = "",
3348
+ eventCardClassName = "",
3349
+ modalClassName = ""
3350
+ }) {
3351
+ const [viewMode, setViewMode] = React5.useState(defaultView);
3352
+ const [events, setEvents] = React5.useState(propEvents || []);
3353
+ const [loading, setLoading] = React5.useState(!propEvents);
3354
+ const [error, setError] = React5.useState(null);
3355
+ const [retryCount, setRetryCount] = React5.useState(0);
3356
+ const { event, schedule, isOpen, openModal, closeModal } = useEventModal();
3357
+ React5.useEffect(() => {
3358
+ if (propEvents) {
3359
+ setEvents(propEvents);
3360
+ return;
3361
+ }
3362
+ async function loadEvents() {
3363
+ const apiUrl = getApiUrl();
3364
+ const apiKey = getApiKey();
3365
+ if (!apiKey) {
3366
+ if (retryCount < 3) {
3367
+ setTimeout(() => setRetryCount((c) => c + 1), 100);
3368
+ return;
3369
+ }
3370
+ console.warn("[EventsWidget] No API key configured. Make sure SiteKitProvider is wrapping your app.");
3371
+ setError(null);
3372
+ setEvents([]);
3373
+ setLoading(false);
3374
+ return;
3375
+ }
3376
+ setLoading(true);
3377
+ setError(null);
3378
+ try {
3379
+ const response = await fetch(`${apiUrl}/api/public/commerce/events`, {
3380
+ method: "POST",
3381
+ headers: {
3382
+ "Content-Type": "application/json",
3383
+ "x-api-key": apiKey
3384
+ },
3385
+ body: JSON.stringify({
3386
+ type: "event",
3387
+ category,
3388
+ limit: limit * 2
3389
+ // Fetch extra for calendar view
3390
+ })
3391
+ });
3392
+ if (!response.ok) {
3393
+ throw new Error("Failed to fetch events");
3394
+ }
3395
+ const data = await response.json();
3396
+ setEvents(data.events || []);
3397
+ } catch (err) {
3398
+ console.error("Error loading events:", err);
3399
+ setError("Unable to load events. Please try again later.");
3400
+ } finally {
3401
+ setLoading(false);
3402
+ }
3403
+ }
3404
+ loadEvents();
3405
+ }, [propEvents, category, limit, retryCount]);
3406
+ const handleEventClick = React5.useCallback((clickedEvent, clickedSchedule) => {
3407
+ onEventClick?.(clickedEvent, clickedSchedule);
3408
+ openModal(clickedEvent, clickedSchedule);
3409
+ }, [onEventClick, openModal]);
3410
+ const handleSuccess = React5.useCallback((result) => {
3411
+ onRegistrationSuccess?.(result);
3412
+ }, [onRegistrationSuccess]);
3413
+ const handleError = React5.useCallback((err) => {
3414
+ onRegistrationError?.(err);
3415
+ }, [onRegistrationError]);
3416
+ if (loading) {
3417
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `site-kit-events-widget ${className}`, children: [
3418
+ (title || subtitle) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `site-kit-events-header ${headerClassName}`, style: { marginBottom: "1.5rem" }, children: [
3419
+ title && /* @__PURE__ */ jsxRuntime.jsx("h2", { style: { margin: 0, fontSize: "1.5rem", fontWeight: 600 }, children: title }),
3420
+ subtitle && /* @__PURE__ */ jsxRuntime.jsx("p", { style: { margin: "0.5rem 0 0", color: "#666" }, children: subtitle })
3421
+ ] }),
3422
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { textAlign: "center", padding: "3rem 1rem", color: "#666" }, children: [
3423
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
3424
+ width: "40px",
3425
+ height: "40px",
3426
+ margin: "0 auto 1rem",
3427
+ border: "3px solid #e5e7eb",
3428
+ borderTopColor: "#3b82f6",
3429
+ borderRadius: "50%",
3430
+ animation: "site-kit-spin 1s linear infinite"
3431
+ } }),
3432
+ /* @__PURE__ */ jsxRuntime.jsx("p", { children: "Loading events..." })
3433
+ ] }),
3434
+ /* @__PURE__ */ jsxRuntime.jsx("style", { children: `
3435
+ @keyframes site-kit-spin {
3436
+ to { transform: rotate(360deg); }
3437
+ }
3438
+ ` })
3439
+ ] });
3440
+ }
3441
+ if (error) {
3442
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `site-kit-events-widget ${className}`, children: [
3443
+ (title || subtitle) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `site-kit-events-header ${headerClassName}`, style: { marginBottom: "1.5rem" }, children: [
3444
+ title && /* @__PURE__ */ jsxRuntime.jsx("h2", { style: { margin: 0, fontSize: "1.5rem", fontWeight: 600 }, children: title }),
3445
+ subtitle && /* @__PURE__ */ jsxRuntime.jsx("p", { style: { margin: "0.5rem 0 0", color: "#666" }, children: subtitle })
3446
+ ] }),
3447
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { textAlign: "center", padding: "3rem 1rem", color: "#dc2626" }, children: /* @__PURE__ */ jsxRuntime.jsx("p", { children: error }) })
3448
+ ] });
3449
+ }
3450
+ if (events.length === 0) {
3451
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `site-kit-events-widget ${className}`, children: [
3452
+ (title || subtitle) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `site-kit-events-header ${headerClassName}`, style: { marginBottom: "1.5rem" }, children: [
3453
+ title && /* @__PURE__ */ jsxRuntime.jsx("h2", { style: { margin: 0, fontSize: "1.5rem", fontWeight: 600 }, children: title }),
3454
+ subtitle && /* @__PURE__ */ jsxRuntime.jsx("p", { style: { margin: "0.5rem 0 0", color: "#666" }, children: subtitle })
3455
+ ] }),
3456
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { textAlign: "center", padding: "3rem 1rem", color: "#666" }, children: [
3457
+ showEmptyIcon && /* @__PURE__ */ jsxRuntime.jsx(
3458
+ "svg",
3459
+ {
3460
+ style: { width: "64px", height: "64px", margin: "0 auto 1rem", color: "#d1d5db" },
3461
+ fill: "none",
3462
+ stroke: "currentColor",
3463
+ viewBox: "0 0 24 24",
3464
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" })
3465
+ }
3466
+ ),
3467
+ /* @__PURE__ */ jsxRuntime.jsx("p", { style: { fontSize: "1.125rem", fontWeight: 500, margin: 0 }, children: emptyMessage })
3468
+ ] })
3469
+ ] });
3470
+ }
3471
+ const displayEvents = viewMode === "list" ? events.slice(0, limit) : events;
3472
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `site-kit-events-widget ${className}`, children: [
3473
+ (title || subtitle || showViewToggle) && /* @__PURE__ */ jsxRuntime.jsxs(
3474
+ "div",
3475
+ {
3476
+ className: `site-kit-events-header ${headerClassName}`,
3477
+ style: {
3478
+ display: "flex",
3479
+ justifyContent: "space-between",
3480
+ alignItems: "flex-start",
3481
+ marginBottom: "1.5rem",
3482
+ flexWrap: "wrap",
3483
+ gap: "1rem"
3484
+ },
3485
+ children: [
3486
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
3487
+ title && /* @__PURE__ */ jsxRuntime.jsx("h2", { style: { margin: 0, fontSize: "1.5rem", fontWeight: 600 }, children: title }),
3488
+ subtitle && /* @__PURE__ */ jsxRuntime.jsx("p", { style: { margin: "0.5rem 0 0", color: "#666" }, children: subtitle })
3489
+ ] }),
3490
+ showViewToggle && /* @__PURE__ */ jsxRuntime.jsxs(
3491
+ "div",
3492
+ {
3493
+ className: `site-kit-events-toggle ${toggleClassName}`,
3494
+ style: {
3495
+ display: "flex",
3496
+ gap: "0.25rem",
3497
+ background: "#f3f4f6",
3498
+ padding: "0.25rem",
3499
+ borderRadius: "0.5rem"
3500
+ },
3501
+ children: [
3502
+ /* @__PURE__ */ jsxRuntime.jsxs(
3503
+ "button",
3504
+ {
3505
+ onClick: () => setViewMode("list"),
3506
+ style: {
3507
+ display: "flex",
3508
+ alignItems: "center",
3509
+ gap: "0.5rem",
3510
+ padding: "0.5rem 1rem",
3511
+ border: "none",
3512
+ borderRadius: "0.375rem",
3513
+ background: viewMode === "list" ? "#fff" : "transparent",
3514
+ color: viewMode === "list" ? "#1f2937" : "#6b7280",
3515
+ fontWeight: 500,
3516
+ fontSize: "0.875rem",
3517
+ cursor: "pointer",
3518
+ boxShadow: viewMode === "list" ? "0 1px 2px rgba(0,0,0,0.05)" : "none",
3519
+ transition: "all 150ms"
3520
+ },
3521
+ children: [
3522
+ /* @__PURE__ */ jsxRuntime.jsx(ListIcon, {}),
3523
+ "List"
3524
+ ]
3525
+ }
3526
+ ),
3527
+ /* @__PURE__ */ jsxRuntime.jsxs(
3528
+ "button",
3529
+ {
3530
+ onClick: () => setViewMode("calendar"),
3531
+ style: {
3532
+ display: "flex",
3533
+ alignItems: "center",
3534
+ gap: "0.5rem",
3535
+ padding: "0.5rem 1rem",
3536
+ border: "none",
3537
+ borderRadius: "0.375rem",
3538
+ background: viewMode === "calendar" ? "#fff" : "transparent",
3539
+ color: viewMode === "calendar" ? "#1f2937" : "#6b7280",
3540
+ fontWeight: 500,
3541
+ fontSize: "0.875rem",
3542
+ cursor: "pointer",
3543
+ boxShadow: viewMode === "calendar" ? "0 1px 2px rgba(0,0,0,0.05)" : "none",
3544
+ transition: "all 150ms"
3545
+ },
3546
+ children: [
3547
+ /* @__PURE__ */ jsxRuntime.jsx(CalendarIcon, {}),
3548
+ "Calendar"
3549
+ ]
3550
+ }
3551
+ )
3552
+ ]
3553
+ }
3554
+ )
3555
+ ]
3556
+ }
3557
+ ),
3558
+ viewMode === "list" ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `site-kit-events-list ${listClassName}`, children: [
3559
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexDirection: "column", gap: "1rem" }, children: displayEvents.map((eventItem) => {
3560
+ const nextSchedule = eventItem.next_schedule || eventItem.schedules?.[0];
3561
+ const isFree = !eventItem.price || eventItem.price === 0;
3562
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3563
+ "div",
3564
+ {
3565
+ className: `site-kit-event-card ${eventCardClassName}`,
3566
+ onClick: () => nextSchedule && handleEventClick(eventItem, nextSchedule),
3567
+ style: {
3568
+ display: "flex",
3569
+ flexDirection: "column",
3570
+ gap: "0.75rem",
3571
+ padding: "1.25rem",
3572
+ background: "#fff",
3573
+ border: "1px solid #e5e7eb",
3574
+ borderRadius: "0.75rem",
3575
+ cursor: nextSchedule ? "pointer" : "default",
3576
+ transition: "all 150ms"
3577
+ },
3578
+ onMouseEnter: (e) => {
3579
+ if (nextSchedule) {
3580
+ e.currentTarget.style.borderColor = "#3b82f6";
3581
+ e.currentTarget.style.boxShadow = "0 4px 6px -1px rgba(0, 0, 0, 0.1)";
3582
+ }
3583
+ },
3584
+ onMouseLeave: (e) => {
3585
+ e.currentTarget.style.borderColor = "#e5e7eb";
3586
+ e.currentTarget.style.boxShadow = "none";
3587
+ },
3588
+ children: [
3589
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "flex-start", gap: "1rem" }, children: [
3590
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { flex: 1 }, children: [
3591
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { style: { margin: 0, fontSize: "1.125rem", fontWeight: 600, color: "#1f2937" }, children: eventItem.name }),
3592
+ eventItem.short_description && /* @__PURE__ */ jsxRuntime.jsx("p", { style: { margin: "0.5rem 0 0", color: "#6b7280", fontSize: "0.875rem", lineHeight: 1.5 }, children: eventItem.short_description })
3593
+ ] }),
3594
+ eventItem.price_is_public && /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
3595
+ padding: "0.375rem 0.75rem",
3596
+ background: isFree ? "#dcfce7" : "#dbeafe",
3597
+ color: isFree ? "#166534" : "#1e40af",
3598
+ borderRadius: "9999px",
3599
+ fontSize: "0.875rem",
3600
+ fontWeight: 600,
3601
+ whiteSpace: "nowrap"
3602
+ }, children: isFree ? "Free" : formatPrice(eventItem.price ?? 0, eventItem.currency) })
3603
+ ] }),
3604
+ nextSchedule && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flexWrap: "wrap", gap: "1rem", fontSize: "0.875rem", color: "#6b7280" }, children: [
3605
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { display: "flex", alignItems: "center", gap: "0.375rem" }, children: [
3606
+ /* @__PURE__ */ jsxRuntime.jsx(CalendarIcon, {}),
3607
+ formatDate(nextSchedule.starts_at)
3608
+ ] }),
3609
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { display: "flex", alignItems: "center", gap: "0.375rem" }, children: [
3610
+ /* @__PURE__ */ jsxRuntime.jsx(ClockIcon, {}),
3611
+ formatTime(nextSchedule.starts_at)
3612
+ ] }),
3613
+ eventItem.location && /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { display: "flex", alignItems: "center", gap: "0.375rem" }, children: [
3614
+ /* @__PURE__ */ jsxRuntime.jsx(LocationIcon, {}),
3615
+ eventItem.location
3616
+ ] }),
3617
+ nextSchedule.spots_remaining !== null && nextSchedule.spots_remaining !== void 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { style: {
3618
+ color: nextSchedule.spots_remaining < 5 ? "#dc2626" : "#6b7280",
3619
+ fontWeight: nextSchedule.spots_remaining < 5 ? 500 : 400
3620
+ }, children: nextSchedule.spots_remaining === 0 ? "Sold Out" : `${nextSchedule.spots_remaining} spots left` })
3621
+ ] })
3622
+ ]
3623
+ },
3624
+ eventItem.id
3625
+ );
3626
+ }) }),
3627
+ showViewAll && events.length > limit && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { textAlign: "center", marginTop: "1.5rem" }, children: /* @__PURE__ */ jsxRuntime.jsx(
3628
+ "a",
3629
+ {
3630
+ href: viewAllUrl,
3631
+ style: {
3632
+ display: "inline-block",
3633
+ padding: "0.75rem 1.5rem",
3634
+ background: "#f3f4f6",
3635
+ color: "#1f2937",
3636
+ borderRadius: "0.5rem",
3637
+ textDecoration: "none",
3638
+ fontWeight: 500,
3639
+ fontSize: "0.875rem",
3640
+ transition: "all 150ms"
3641
+ },
3642
+ children: viewAllText
3643
+ }
3644
+ ) })
3645
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: `site-kit-events-calendar ${calendarClassName}`, children: /* @__PURE__ */ jsxRuntime.jsx(
3646
+ CalendarView,
3647
+ {
3648
+ events,
3649
+ onEventClick: handleEventClick,
3650
+ showNavigation: true,
3651
+ showHeader: true
3652
+ }
3653
+ ) }),
3654
+ /* @__PURE__ */ jsxRuntime.jsx(
3655
+ EventModal,
3656
+ {
3657
+ event,
3658
+ schedule,
3659
+ isOpen,
3660
+ onClose: closeModal,
3661
+ onSuccess: handleSuccess,
3662
+ onError: handleError,
3663
+ collectPhone,
3664
+ additionalFields,
3665
+ className: modalClassName
3666
+ }
3667
+ )
3668
+ ] });
3669
+ }
3670
+ function getApiUrl() {
3671
+ if (typeof window !== "undefined") {
3672
+ return window.__SITE_KIT_API_URL__ || "https://api.uptrademedia.com";
3673
+ }
3674
+ return "https://api.uptrademedia.com";
3675
+ }
3676
+ function getApiKey() {
3677
+ if (typeof window !== "undefined") {
3678
+ return window.__SITE_KIT_API_KEY__ || "";
3679
+ }
3680
+ return "";
3681
+ }
3682
+
3683
+ exports.CalendarView = CalendarView;
3684
+ exports.CheckoutForm = CheckoutForm;
3685
+ exports.EventCalendar = EventCalendar;
3686
+ exports.EventEmbed = EventEmbed;
3687
+ exports.EventModal = EventModal;
3688
+ exports.EventTile = EventTile;
3689
+ exports.EventsWidget = EventsWidget;
3690
+ exports.OfferingCard = OfferingCard;
3691
+ exports.OfferingList = OfferingList;
3692
+ exports.ProductDetail = ProductDetail;
3693
+ exports.ProductEmbed = ProductEmbed;
3694
+ exports.ProductGrid = ProductGrid;
3695
+ exports.ProductPage = ProductPage;
3696
+ exports.RegistrationForm = RegistrationForm;
3697
+ exports.UpcomingEvents = UpcomingEvents;
3698
+ exports.createCheckoutSession = createCheckoutSession;
3699
+ exports.fetchCategories = fetchCategories;
3700
+ exports.fetchLatestOffering = fetchLatestOffering;
3701
+ exports.fetchNextEvent = fetchNextEvent;
3702
+ exports.fetchOffering = fetchOffering;
3703
+ exports.fetchOfferings = fetchOfferings;
3704
+ exports.fetchProductBySlug = fetchProductBySlug;
3705
+ exports.fetchProducts = fetchProducts;
3706
+ exports.fetchProductsPublic = fetchProductsPublic;
3707
+ exports.fetchServices = fetchServices;
3708
+ exports.fetchUpcomingEvents = fetchUpcomingEvents;
3709
+ exports.formatDate = formatDate;
3710
+ exports.formatDateRange = formatDateRange;
3711
+ exports.formatDateTime = formatDateTime;
3712
+ exports.formatPrice = formatPrice;
3713
+ exports.formatTime = formatTime;
3714
+ exports.getOfferingUrl = getOfferingUrl;
3715
+ exports.getRelativeTimeUntil = getRelativeTimeUntil;
3716
+ exports.getSpotsRemaining = getSpotsRemaining;
3717
+ exports.isEventSoldOut = isEventSoldOut;
3718
+ exports.registerForEvent = registerForEvent;
3719
+ exports.useEventModal = useEventModal;
3720
+ //# sourceMappingURL=chunk-3MUOUXHV.js.map
3721
+ //# sourceMappingURL=chunk-3MUOUXHV.js.map