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