@sonordev/site-kit 1.2.7

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