@sonordev/site-kit 1.3.4 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -98,6 +98,12 @@ function getApiConfig() {
98
98
  const apiKey = typeof window !== "undefined" ? window.__SITE_KIT_API_KEY__ || "" : "";
99
99
  return { apiUrl, apiKey };
100
100
  }
101
+ function getApiUrl() {
102
+ return getApiConfig().apiUrl;
103
+ }
104
+ function getApiKey() {
105
+ return getApiConfig().apiKey;
106
+ }
101
107
  async function apiPost(endpoint, body = {}) {
102
108
  const { apiUrl, apiKey } = getApiConfig();
103
109
  if (!apiKey) {
@@ -331,6 +337,29 @@ async function fetchProcessorConfig() {
331
337
  return null;
332
338
  }
333
339
  }
340
+ async function createPaymentIntent(options) {
341
+ const apiUrl = getApiUrl();
342
+ const apiKey = getApiKey();
343
+ const sessionId = typeof sessionStorage !== "undefined" ? sessionStorage.getItem("_uptrade_sid") : null;
344
+ try {
345
+ const response = await fetch(`${apiUrl}/api/public/commerce/create-payment-intent`, {
346
+ method: "POST",
347
+ headers: {
348
+ "Content-Type": "application/json",
349
+ "x-api-key": apiKey
350
+ },
351
+ body: JSON.stringify({
352
+ ...options,
353
+ analyticsSessionId: sessionId
354
+ })
355
+ });
356
+ const data = await response.json();
357
+ if (!response.ok) throw new Error(data.message || "Failed to create payment intent");
358
+ return data;
359
+ } catch (error) {
360
+ return { success: false, error: error?.message || "Network error. Please try again." };
361
+ }
362
+ }
334
363
  async function createCheckoutSession(optionsOrOfferingId, legacyOptions) {
335
364
  const { apiUrl, apiKey } = getApiConfig();
336
365
  const options = typeof optionsOrOfferingId === "string" ? { offeringId: optionsOrOfferingId, ...legacyOptions } : optionsOrOfferingId;
@@ -402,6 +431,10 @@ function OfferingCard({
402
431
  subscription: "Subscribe"
403
432
  }[offering.type] || "View Details";
404
433
  const handleClick = () => {
434
+ if (offering.external_url && typeof window !== "undefined") {
435
+ window.open(offering.external_url, "_blank", "noopener,noreferrer");
436
+ return;
437
+ }
405
438
  if (onCtaClick) {
406
439
  onCtaClick(offering);
407
440
  } else if (typeof window !== "undefined") {
@@ -793,6 +826,10 @@ function EventTile({
793
826
  const spotsRemaining = schedule ? getSpotsRemaining(schedule.capacity, schedule.current_registrations) : null;
794
827
  const defaultCtaText = event.price && event.price > 0 ? "Get Tickets" : "Register Free";
795
828
  const handleClick = async () => {
829
+ if (event.external_url) {
830
+ window.open(event.external_url, "_blank", "noopener,noreferrer");
831
+ return;
832
+ }
796
833
  if (onCtaClick) {
797
834
  onCtaClick(event);
798
835
  return;
@@ -1293,485 +1330,2413 @@ var tdStyle = {
1293
1330
  borderBottom: "1px solid rgba(128, 128, 128, 0.1)",
1294
1331
  whiteSpace: "nowrap"
1295
1332
  };
1296
- function ProductDetail({
1297
- product: propProduct,
1298
- slug,
1299
- showAddToCart = true,
1300
- showBuyNow = true,
1301
- showQuantity = true,
1302
- showVariants = true,
1303
- showGallery = true,
1304
- showFeatures = true,
1305
- showSpecifications = true,
1306
- successUrl,
1307
- cancelUrl,
1308
- onAddToCart,
1309
- onBuyNow,
1310
- onCheckoutSuccess,
1311
- onCheckoutError,
1312
- className = "",
1313
- style
1314
- }) {
1315
- const [product, setProduct] = React5.useState(propProduct || null);
1316
- const [loading, setLoading] = React5.useState(!propProduct && !!slug);
1317
- const [selectedVariant, setSelectedVariant] = React5.useState();
1318
- const [quantity, setQuantity] = React5.useState(1);
1319
- const [selectedImage, setSelectedImage] = React5.useState(0);
1320
- const [checkingOut, setCheckingOut] = React5.useState(false);
1321
- const analytics = chunkGTLIGQDM_js.useAnalyticsOptional();
1322
- React5.useEffect(() => {
1323
- if (!product || !analytics) return;
1324
- analytics.trackEvent({
1325
- name: "product_view",
1326
- properties: {
1327
- offering_id: product.id,
1328
- name: product.name,
1329
- price: product.price,
1330
- type: product.type,
1331
- category: product.category?.name
1332
- }
1333
- });
1334
- }, [product?.id, analytics]);
1335
- React5.useEffect(() => {
1336
- if (propProduct) {
1337
- setProduct(propProduct);
1338
- const defaultVariant = propProduct.variants?.find((v) => v.is_default) || propProduct.variants?.[0];
1339
- setSelectedVariant(defaultVariant);
1340
- return;
1341
- }
1342
- if (!slug) return;
1343
- async function load() {
1344
- setLoading(true);
1345
- try {
1346
- const data = await fetchProductBySlug(slug);
1347
- setProduct(data);
1348
- if (data?.variants?.length) {
1349
- const defaultVariant = data.variants.find((v) => v.is_default) || data.variants[0];
1350
- setSelectedVariant(defaultVariant);
1351
- }
1352
- } catch (e) {
1353
- console.error("Failed to load product:", e);
1354
- } finally {
1355
- setLoading(false);
1356
- }
1357
- }
1358
- load();
1359
- }, [propProduct, slug]);
1360
- if (loading) {
1361
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `site-kit-product-detail site-kit-product-detail--loading ${className}`, style, children: [
1362
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "site-kit-product-detail__loader", style: {
1363
- display: "flex",
1364
- justifyContent: "center",
1365
- alignItems: "center",
1366
- minHeight: "400px"
1367
- }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
1368
- width: "48px",
1369
- height: "48px",
1370
- border: "3px solid #e5e7eb",
1371
- borderTopColor: "#2563eb",
1372
- borderRadius: "50%",
1373
- animation: "spin 1s linear infinite"
1374
- } }) }),
1375
- /* @__PURE__ */ jsxRuntime.jsx("style", { children: `@keyframes spin { to { transform: rotate(360deg); } }` })
1376
- ] });
1333
+ var STYLE_BLOCK = `
1334
+ @keyframes skc-spin {
1335
+ to { transform: rotate(360deg); }
1336
+ }
1337
+ @keyframes skc-pulse {
1338
+ 0%, 100% { opacity: 1; }
1339
+ 50% { opacity: 0.6; }
1340
+ }
1341
+ @keyframes skc-fadeIn {
1342
+ from { opacity: 0; transform: translateY(8px); }
1343
+ to { opacity: 1; transform: translateY(0); }
1344
+ }
1345
+ @keyframes skc-slideUp {
1346
+ from { opacity: 0; transform: translateY(100%); }
1347
+ to { opacity: 1; transform: translateY(0); }
1348
+ }
1349
+ @keyframes skc-scaleIn {
1350
+ from { opacity: 0; transform: scale(0.95); }
1351
+ to { opacity: 1; transform: scale(1); }
1352
+ }
1353
+ @keyframes skc-checkmark {
1354
+ 0% { stroke-dashoffset: 24; }
1355
+ 100% { stroke-dashoffset: 0; }
1356
+ }
1357
+
1358
+ .skc-detail {
1359
+ --commerce-bg: transparent;
1360
+ --commerce-surface: #f9fafb;
1361
+ --commerce-surface-hover: #f3f4f6;
1362
+ --commerce-border: #e5e7eb;
1363
+ --commerce-text: #111827;
1364
+ --commerce-text-secondary: #6b7280;
1365
+ --commerce-text-muted: #9ca3af;
1366
+ --commerce-accent: #2563eb;
1367
+ --commerce-accent-hover: #1d4ed8;
1368
+ --commerce-accent-text: #ffffff;
1369
+ --commerce-success: #059669;
1370
+ --commerce-warning: #d97706;
1371
+ --commerce-danger: #dc2626;
1372
+ --commerce-radius: 12px;
1373
+ --commerce-radius-sm: 8px;
1374
+
1375
+ animation: skc-fadeIn 0.3s ease-out;
1376
+ }
1377
+
1378
+ .skc-detail *, .skc-detail *::before, .skc-detail *::after {
1379
+ box-sizing: border-box;
1380
+ }
1381
+
1382
+ .skc-detail-layout {
1383
+ display: grid;
1384
+ grid-template-columns: 1fr 1fr;
1385
+ gap: 2.5rem;
1386
+ align-items: start;
1387
+ }
1388
+
1389
+ @media (max-width: 768px) {
1390
+ .skc-detail-layout {
1391
+ grid-template-columns: 1fr;
1392
+ gap: 1.5rem;
1377
1393
  }
1378
- if (!product) {
1379
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `site-kit-product-detail site-kit-product-detail--not-found ${className}`, style, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { textAlign: "center", padding: "4rem 2rem", color: "#666" }, children: [
1380
- /* @__PURE__ */ jsxRuntime.jsx("h2", { style: { margin: 0, fontSize: "1.5rem", color: "#333" }, children: "Product Not Found" }),
1381
- /* @__PURE__ */ jsxRuntime.jsx("p", { style: { marginTop: "0.5rem" }, children: "The product you're looking for doesn't exist or has been removed." })
1382
- ] }) });
1394
+ .skc-detail-layout.skc-stacked {
1395
+ grid-template-columns: 1fr;
1383
1396
  }
1384
- const currentPrice = selectedVariant?.price ?? product.price ?? 0;
1385
- const compareAtPrice = product.compare_at_price;
1386
- const hasDiscount = compareAtPrice && compareAtPrice > currentPrice;
1387
- const allImages = [
1388
- product.featured_image_url,
1389
- ...product.gallery_images || [],
1390
- ...product.variants?.map((v) => v.image_url).filter(Boolean) || []
1391
- ].filter(Boolean);
1392
- const inventoryCount = selectedVariant?.inventory_count ?? product.inventory_count;
1393
- const isOutOfStock = product.track_inventory && inventoryCount !== void 0 && inventoryCount <= 0;
1394
- const isLowStock = product.track_inventory && inventoryCount !== void 0 && inventoryCount > 0 && inventoryCount <= 5;
1395
- const needsVariantSelection = (product.is_clothing || (product.variants?.length ?? 0) > 0) && !selectedVariant;
1396
- const handleAddToCart = () => {
1397
- analytics?.trackEvent({
1398
- name: "add_to_cart",
1399
- properties: {
1400
- offering_id: product.id,
1401
- variant_id: selectedVariant?.id,
1402
- quantity,
1403
- price: selectedVariant?.price ?? product.price,
1404
- name: product.name
1405
- }
1406
- });
1407
- if (onAddToCart) {
1408
- onAddToCart(product, selectedVariant, quantity);
1409
- }
1397
+ }
1398
+
1399
+ .skc-detail-layout.skc-stacked {
1400
+ grid-template-columns: 1fr;
1401
+ max-width: 640px;
1402
+ }
1403
+
1404
+ /* Gallery */
1405
+ .skc-gallery-main {
1406
+ position: relative;
1407
+ overflow: hidden;
1408
+ border-radius: var(--commerce-radius);
1409
+ background: var(--commerce-surface);
1410
+ cursor: crosshair;
1411
+ aspect-ratio: 1;
1412
+ }
1413
+ .skc-gallery-main img {
1414
+ width: 100%;
1415
+ height: 100%;
1416
+ object-fit: cover;
1417
+ transition: transform 0.15s ease-out;
1418
+ will-change: transform;
1419
+ }
1420
+ .skc-gallery-thumbs {
1421
+ display: flex;
1422
+ gap: 0.5rem;
1423
+ margin-top: 0.75rem;
1424
+ overflow-x: auto;
1425
+ scrollbar-width: thin;
1426
+ -webkit-overflow-scrolling: touch;
1427
+ padding-bottom: 4px;
1428
+ }
1429
+ .skc-gallery-thumb {
1430
+ flex: 0 0 auto;
1431
+ width: 64px;
1432
+ height: 64px;
1433
+ border-radius: var(--commerce-radius-sm);
1434
+ overflow: hidden;
1435
+ border: 2px solid transparent;
1436
+ padding: 0;
1437
+ cursor: pointer;
1438
+ background: var(--commerce-surface);
1439
+ transition: border-color 0.15s ease;
1440
+ }
1441
+ .skc-gallery-thumb:hover {
1442
+ border-color: var(--commerce-text-muted);
1443
+ }
1444
+ .skc-gallery-thumb.skc-active {
1445
+ border-color: var(--commerce-accent);
1446
+ }
1447
+ .skc-gallery-thumb img {
1448
+ width: 100%;
1449
+ height: 100%;
1450
+ object-fit: cover;
1451
+ }
1452
+
1453
+ /* Sticky buy bar */
1454
+ .skc-sticky-bar {
1455
+ position: fixed;
1456
+ bottom: 0;
1457
+ left: 0;
1458
+ right: 0;
1459
+ z-index: 999;
1460
+ background: white;
1461
+ border-top: 1px solid var(--commerce-border);
1462
+ padding: 0.75rem 1rem;
1463
+ display: flex;
1464
+ align-items: center;
1465
+ justify-content: space-between;
1466
+ gap: 1rem;
1467
+ animation: skc-slideUp 0.25s ease-out;
1468
+ box-shadow: 0 -4px 20px rgba(0,0,0,0.08);
1469
+ }
1470
+ @media (min-width: 769px) {
1471
+ .skc-sticky-bar { display: none; }
1472
+ }
1473
+
1474
+ /* Tabs */
1475
+ .skc-tabs-list {
1476
+ display: flex;
1477
+ border-bottom: 1px solid var(--commerce-border);
1478
+ gap: 0;
1479
+ overflow-x: auto;
1480
+ scrollbar-width: none;
1481
+ }
1482
+ .skc-tabs-list::-webkit-scrollbar { display: none; }
1483
+ .skc-tab-btn {
1484
+ padding: 0.75rem 1.25rem;
1485
+ border: none;
1486
+ background: none;
1487
+ font-size: 0.875rem;
1488
+ font-weight: 500;
1489
+ color: var(--commerce-text-secondary);
1490
+ cursor: pointer;
1491
+ border-bottom: 2px solid transparent;
1492
+ white-space: nowrap;
1493
+ transition: color 0.15s ease, border-color 0.15s ease;
1494
+ }
1495
+ .skc-tab-btn:hover {
1496
+ color: var(--commerce-text);
1497
+ }
1498
+ .skc-tab-btn.skc-active {
1499
+ color: var(--commerce-accent);
1500
+ border-bottom-color: var(--commerce-accent);
1501
+ }
1502
+
1503
+ /* Checkout overlay */
1504
+ .skc-checkout-overlay {
1505
+ position: fixed;
1506
+ inset: 0;
1507
+ z-index: 10000;
1508
+ background: rgba(0,0,0,0.5);
1509
+ backdrop-filter: blur(4px);
1510
+ display: flex;
1511
+ align-items: center;
1512
+ justify-content: center;
1513
+ padding: 1rem;
1514
+ animation: skc-fadeIn 0.2s ease-out;
1515
+ }
1516
+ .skc-checkout-panel {
1517
+ position: relative;
1518
+ width: 100%;
1519
+ max-width: 480px;
1520
+ max-height: 90vh;
1521
+ overflow-y: auto;
1522
+ background: white;
1523
+ border-radius: calc(var(--commerce-radius) + 4px);
1524
+ box-shadow: 0 25px 50px -12px rgba(0,0,0,0.25);
1525
+ animation: skc-scaleIn 0.25s ease-out;
1526
+ }
1527
+
1528
+ /* Form inputs */
1529
+ .skc-input {
1530
+ width: 100%;
1531
+ padding: 0.625rem 0.75rem;
1532
+ border-radius: var(--commerce-radius-sm);
1533
+ border: 1px solid var(--commerce-border);
1534
+ font-size: 0.9375rem;
1535
+ color: var(--commerce-text);
1536
+ background: white;
1537
+ transition: border-color 0.15s ease, box-shadow 0.15s ease;
1538
+ outline: none;
1539
+ }
1540
+ .skc-input:focus {
1541
+ border-color: var(--commerce-accent);
1542
+ box-shadow: 0 0 0 3px rgba(37,99,235,0.1);
1543
+ }
1544
+ .skc-input::placeholder {
1545
+ color: var(--commerce-text-muted);
1546
+ }
1547
+
1548
+ /* Primary button */
1549
+ .skc-btn-primary {
1550
+ display: inline-flex;
1551
+ align-items: center;
1552
+ justify-content: center;
1553
+ gap: 0.5rem;
1554
+ width: 100%;
1555
+ padding: 0.875rem 1.5rem;
1556
+ border-radius: var(--commerce-radius-sm);
1557
+ border: none;
1558
+ background: var(--commerce-accent);
1559
+ color: var(--commerce-accent-text);
1560
+ font-size: 1rem;
1561
+ font-weight: 600;
1562
+ cursor: pointer;
1563
+ transition: background-color 0.15s ease, transform 0.1s ease;
1564
+ }
1565
+ .skc-btn-primary:hover:not(:disabled) {
1566
+ background: var(--commerce-accent-hover);
1567
+ }
1568
+ .skc-btn-primary:active:not(:disabled) {
1569
+ transform: scale(0.98);
1570
+ }
1571
+ .skc-btn-primary:disabled {
1572
+ opacity: 0.55;
1573
+ cursor: not-allowed;
1574
+ }
1575
+
1576
+ /* Secondary button */
1577
+ .skc-btn-secondary {
1578
+ display: inline-flex;
1579
+ align-items: center;
1580
+ justify-content: center;
1581
+ gap: 0.5rem;
1582
+ width: 100%;
1583
+ padding: 0.875rem 1.5rem;
1584
+ border-radius: var(--commerce-radius-sm);
1585
+ border: 2px solid var(--commerce-accent);
1586
+ background: transparent;
1587
+ color: var(--commerce-accent);
1588
+ font-size: 1rem;
1589
+ font-weight: 600;
1590
+ cursor: pointer;
1591
+ transition: background-color 0.15s ease;
1592
+ }
1593
+ .skc-btn-secondary:hover:not(:disabled) {
1594
+ background: rgba(37,99,235,0.05);
1595
+ }
1596
+ .skc-btn-secondary:disabled {
1597
+ opacity: 0.55;
1598
+ cursor: not-allowed;
1599
+ }
1600
+
1601
+ /* Low-stock pulse */
1602
+ .skc-pulse {
1603
+ animation: skc-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
1604
+ }
1605
+
1606
+ /* Step indicator */
1607
+ .skc-step-dots {
1608
+ display: flex;
1609
+ align-items: center;
1610
+ justify-content: center;
1611
+ gap: 0.5rem;
1612
+ padding: 1rem 0 0.5rem;
1613
+ }
1614
+ .skc-step-dot {
1615
+ width: 8px;
1616
+ height: 8px;
1617
+ border-radius: 50%;
1618
+ background: var(--commerce-border);
1619
+ transition: background 0.2s ease, transform 0.2s ease;
1620
+ }
1621
+ .skc-step-dot.skc-active {
1622
+ background: var(--commerce-accent);
1623
+ transform: scale(1.3);
1624
+ }
1625
+ .skc-step-dot.skc-done {
1626
+ background: var(--commerce-success);
1627
+ }
1628
+ .skc-step-connector {
1629
+ width: 24px;
1630
+ height: 2px;
1631
+ background: var(--commerce-border);
1632
+ transition: background 0.2s ease;
1633
+ }
1634
+ .skc-step-connector.skc-done {
1635
+ background: var(--commerce-success);
1636
+ }
1637
+ `;
1638
+ function loadSquareSDK(env) {
1639
+ return new Promise((resolve, reject) => {
1640
+ if (typeof window === "undefined") return reject(new Error("No window"));
1641
+ if (window.Square) return resolve();
1642
+ const script = document.createElement("script");
1643
+ script.src = env === "sandbox" ? "https://sandbox.web.squarecdn.com/v1/square.js" : "https://web.squarecdn.com/v1/square.js";
1644
+ script.onload = () => resolve();
1645
+ script.onerror = () => reject(new Error("Failed to load Square SDK"));
1646
+ document.head.appendChild(script);
1647
+ });
1648
+ }
1649
+ function loadStripeSDK() {
1650
+ return new Promise((resolve, reject) => {
1651
+ if (typeof window === "undefined") return reject(new Error("No window"));
1652
+ if (window.Stripe) return resolve();
1653
+ const script = document.createElement("script");
1654
+ script.src = "https://js.stripe.com/v3/";
1655
+ script.onload = () => resolve();
1656
+ script.onerror = () => reject(new Error("Failed to load Stripe"));
1657
+ document.head.appendChild(script);
1658
+ });
1659
+ }
1660
+ var IconLock = () => /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1661
+ /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "3", y: "11", width: "18", height: "11", rx: "2", ry: "2" }),
1662
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M7 11V7a5 5 0 0 1 10 0v4" })
1663
+ ] });
1664
+ var IconTruck = () => /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1665
+ /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "1", y: "3", width: "15", height: "13" }),
1666
+ /* @__PURE__ */ jsxRuntime.jsx("polygon", { points: "16 8 20 8 23 11 23 16 16 16 16 8" }),
1667
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "5.5", cy: "18.5", r: "2.5" }),
1668
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "18.5", cy: "18.5", r: "2.5" })
1669
+ ] });
1670
+ var IconReturn = () => /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1671
+ /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "1 4 1 10 7 10" }),
1672
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3.51 15a9 9 0 1 0 2.13-9.36L1 10" })
1673
+ ] });
1674
+ var IconShield = () => /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" }) });
1675
+ var IconChevronLeft = () => /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "15 18 9 12 15 6" }) });
1676
+ var IconChevronRight = () => /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "9 18 15 12 9 6" }) });
1677
+ var IconCheck = () => /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "20 6 9 17 4 12" }) });
1678
+ var IconAlert = () => /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1679
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "10" }),
1680
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "12", y1: "8", x2: "12", y2: "12" }),
1681
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "12", y1: "16", x2: "12.01", y2: "16" })
1682
+ ] });
1683
+ var IconCalendar = () => /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1684
+ /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "3", y: "4", width: "18", height: "18", rx: "2", ry: "2" }),
1685
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "16", y1: "2", x2: "16", y2: "6" }),
1686
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "8", y1: "2", x2: "8", y2: "6" }),
1687
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "3", y1: "10", x2: "21", y2: "10" })
1688
+ ] });
1689
+ var IconMapPin = () => /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1690
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z" }),
1691
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "10", r: "3" })
1692
+ ] });
1693
+ var IconUsers = () => /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1694
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2" }),
1695
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "9", cy: "7", r: "4" }),
1696
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M23 21v-2a4 4 0 0 0-3-3.87" }),
1697
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M16 3.13a4 4 0 0 1 0 7.75" })
1698
+ ] });
1699
+ var IconExternalLink = () => /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1700
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" }),
1701
+ /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "15 3 21 3 21 9" }),
1702
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "10", y1: "14", x2: "21", y2: "3" })
1703
+ ] });
1704
+ var IconX = () => /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1705
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
1706
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
1707
+ ] });
1708
+ var ICON_MAP = {
1709
+ lock: IconLock,
1710
+ truck: IconTruck,
1711
+ return: IconReturn,
1712
+ shield: IconShield
1713
+ };
1714
+ function ProductGallery({ images, productName, selectedIndex, onSelect }) {
1715
+ const [zoomStyle, setZoomStyle] = React5.useState(null);
1716
+ const [isHovering, setIsHovering] = React5.useState(false);
1717
+ const handleMouseMove = (e) => {
1718
+ const rect = e.currentTarget.getBoundingClientRect();
1719
+ const x = (e.clientX - rect.left) / rect.width * 100;
1720
+ const y = (e.clientY - rect.top) / rect.height * 100;
1721
+ setZoomStyle({ transformOrigin: `${x}% ${y}%`, transform: "scale(2)" });
1410
1722
  };
1411
- const handleBuyNow = async () => {
1412
- analytics?.trackEvent({
1413
- name: "add_to_cart",
1414
- properties: {
1415
- offering_id: product.id,
1416
- variant_id: selectedVariant?.id,
1417
- quantity,
1418
- price: selectedVariant?.price ?? product.price,
1419
- name: product.name
1420
- }
1421
- });
1422
- if (onBuyNow) {
1423
- onBuyNow(product, selectedVariant, quantity);
1424
- return;
1425
- }
1426
- setCheckingOut(true);
1427
- try {
1428
- const result = await createCheckoutSession({
1429
- offeringId: product.id,
1430
- variantId: selectedVariant?.id,
1431
- quantity,
1432
- successUrl: successUrl || `${window.location.origin}/checkout/success`,
1433
- cancelUrl: cancelUrl || window.location.href
1434
- });
1435
- if (result.success && result.checkout_url) {
1436
- onCheckoutSuccess?.(result);
1437
- window.location.href = result.checkout_url;
1438
- } else {
1439
- throw new Error(result.error || "Failed to create checkout");
1440
- }
1441
- } catch (error) {
1442
- console.error("Checkout error:", error);
1443
- onCheckoutError?.(error.message || "Checkout failed");
1444
- } finally {
1445
- setCheckingOut(false);
1446
- }
1723
+ const handlePrev = (e) => {
1724
+ e.stopPropagation();
1725
+ onSelect(selectedIndex === 0 ? images.length - 1 : selectedIndex - 1);
1447
1726
  };
1448
- const handleVariantChange = (variant) => {
1449
- setSelectedVariant(variant);
1450
- if (variant.image_url) {
1451
- const imageIndex = allImages.indexOf(variant.image_url);
1452
- if (imageIndex >= 0) setSelectedImage(imageIndex);
1453
- }
1727
+ const handleNext = (e) => {
1728
+ e.stopPropagation();
1729
+ onSelect(selectedIndex === images.length - 1 ? 0 : selectedIndex + 1);
1454
1730
  };
1455
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `site-kit-product-detail ${className}`, style: {
1456
- display: "grid",
1457
- gridTemplateColumns: "repeat(auto-fit, minmax(320px, 1fr))",
1458
- gap: "2rem",
1459
- ...style
1460
- }, children: [
1461
- showGallery && allImages.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "site-kit-product-detail__gallery", children: [
1462
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "site-kit-product-detail__main-image", style: {
1463
- aspectRatio: "1",
1464
- borderRadius: "12px",
1465
- overflow: "hidden",
1466
- backgroundColor: "#f9fafb"
1467
- }, children: /* @__PURE__ */ jsxRuntime.jsx(
1468
- "img",
1469
- {
1470
- src: allImages[selectedImage],
1471
- alt: product.name,
1472
- style: {
1473
- width: "100%",
1474
- height: "100%",
1475
- objectFit: "cover"
1731
+ if (!images.length) return null;
1732
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1733
+ /* @__PURE__ */ jsxRuntime.jsxs(
1734
+ "div",
1735
+ {
1736
+ className: "skc-gallery-main",
1737
+ onMouseMove: handleMouseMove,
1738
+ onMouseEnter: () => setIsHovering(true),
1739
+ onMouseLeave: () => {
1740
+ setIsHovering(false);
1741
+ setZoomStyle(null);
1742
+ },
1743
+ role: "img",
1744
+ "aria-label": `${productName} image ${selectedIndex + 1} of ${images.length}`,
1745
+ children: [
1746
+ /* @__PURE__ */ jsxRuntime.jsx(
1747
+ "img",
1748
+ {
1749
+ src: images[selectedIndex],
1750
+ alt: `${productName} - Image ${selectedIndex + 1}`,
1751
+ style: isHovering && zoomStyle ? zoomStyle : void 0,
1752
+ draggable: false
1753
+ }
1754
+ ),
1755
+ images.length > 1 && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1756
+ /* @__PURE__ */ jsxRuntime.jsx(
1757
+ "button",
1758
+ {
1759
+ onClick: handlePrev,
1760
+ "aria-label": "Previous image",
1761
+ style: {
1762
+ position: "absolute",
1763
+ left: 8,
1764
+ top: "50%",
1765
+ transform: "translateY(-50%)",
1766
+ width: 36,
1767
+ height: 36,
1768
+ borderRadius: "50%",
1769
+ border: "none",
1770
+ background: "rgba(255,255,255,0.9)",
1771
+ cursor: "pointer",
1772
+ display: "flex",
1773
+ alignItems: "center",
1774
+ justifyContent: "center",
1775
+ opacity: isHovering ? 1 : 0,
1776
+ transition: "opacity 0.2s ease",
1777
+ boxShadow: "0 2px 8px rgba(0,0,0,0.1)"
1778
+ },
1779
+ children: /* @__PURE__ */ jsxRuntime.jsx(IconChevronLeft, {})
1780
+ }
1781
+ ),
1782
+ /* @__PURE__ */ jsxRuntime.jsx(
1783
+ "button",
1784
+ {
1785
+ onClick: handleNext,
1786
+ "aria-label": "Next image",
1787
+ style: {
1788
+ position: "absolute",
1789
+ right: 8,
1790
+ top: "50%",
1791
+ transform: "translateY(-50%)",
1792
+ width: 36,
1793
+ height: 36,
1794
+ borderRadius: "50%",
1795
+ border: "none",
1796
+ background: "rgba(255,255,255,0.9)",
1797
+ cursor: "pointer",
1798
+ display: "flex",
1799
+ alignItems: "center",
1800
+ justifyContent: "center",
1801
+ opacity: isHovering ? 1 : 0,
1802
+ transition: "opacity 0.2s ease",
1803
+ boxShadow: "0 2px 8px rgba(0,0,0,0.1)"
1804
+ },
1805
+ children: /* @__PURE__ */ jsxRuntime.jsx(IconChevronRight, {})
1806
+ }
1807
+ )
1808
+ ] }),
1809
+ images.length > 1 && /* @__PURE__ */ jsxRuntime.jsxs(
1810
+ "div",
1811
+ {
1812
+ style: {
1813
+ position: "absolute",
1814
+ bottom: 8,
1815
+ right: 8,
1816
+ background: "rgba(0,0,0,0.6)",
1817
+ color: "white",
1818
+ fontSize: "0.75rem",
1819
+ padding: "2px 8px",
1820
+ borderRadius: 12
1821
+ },
1822
+ children: [
1823
+ selectedIndex + 1,
1824
+ " / ",
1825
+ images.length
1826
+ ]
1827
+ }
1828
+ )
1829
+ ]
1830
+ }
1831
+ ),
1832
+ images.length > 1 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "skc-gallery-thumbs", role: "listbox", "aria-label": "Image thumbnails", children: images.map((img, idx) => /* @__PURE__ */ jsxRuntime.jsx(
1833
+ "button",
1834
+ {
1835
+ className: `skc-gallery-thumb${idx === selectedIndex ? " skc-active" : ""}`,
1836
+ onClick: () => onSelect(idx),
1837
+ role: "option",
1838
+ "aria-selected": idx === selectedIndex,
1839
+ "aria-label": `View image ${idx + 1}`,
1840
+ children: /* @__PURE__ */ jsxRuntime.jsx("img", { src: img, alt: `${productName} thumbnail ${idx + 1}`, draggable: false })
1841
+ },
1842
+ idx
1843
+ )) })
1844
+ ] });
1845
+ }
1846
+ function VariantSelector({ variants, selected, isClothing, showInventory, onSelect }) {
1847
+ if (!variants.length) return null;
1848
+ const label = isClothing ? "Size" : "Options";
1849
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { marginTop: "1.25rem" }, children: [
1850
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: "0.5rem" }, children: /* @__PURE__ */ jsxRuntime.jsxs(
1851
+ "label",
1852
+ {
1853
+ style: {
1854
+ fontSize: "0.875rem",
1855
+ fontWeight: 600,
1856
+ color: "var(--commerce-text)"
1857
+ },
1858
+ children: [
1859
+ label,
1860
+ selected && /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { fontWeight: 400, color: "var(--commerce-text-secondary)", marginLeft: 6 }, children: [
1861
+ "\u2014 ",
1862
+ selected.options?.Size || selected.name
1863
+ ] })
1864
+ ]
1865
+ }
1866
+ ) }),
1867
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexWrap: "wrap", gap: "0.5rem" }, role: "radiogroup", "aria-label": label, children: variants.map((variant) => {
1868
+ const isSelected = selected?.id === variant.id;
1869
+ const variantOutOfStock = variant.track_inventory !== false && (variant.inventory_count ?? 0) <= 0;
1870
+ const isLow = variant.track_inventory !== false && variant.inventory_count != null && variant.inventory_count > 0 && variant.inventory_count <= 5;
1871
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1872
+ "button",
1873
+ {
1874
+ role: "radio",
1875
+ "aria-checked": isSelected,
1876
+ "aria-label": `${variant.options?.Size || variant.name}${variantOutOfStock ? " - Out of stock" : ""}`,
1877
+ onClick: () => !variantOutOfStock && onSelect(variant),
1878
+ disabled: variantOutOfStock,
1879
+ style: {
1880
+ position: "relative",
1881
+ padding: "0.5rem 1rem",
1882
+ borderRadius: "var(--commerce-radius-sm)",
1883
+ border: isSelected ? "2px solid var(--commerce-accent)" : "1px solid var(--commerce-border)",
1884
+ backgroundColor: isSelected ? "rgba(37,99,235,0.05)" : "white",
1885
+ color: variantOutOfStock ? "var(--commerce-text-muted)" : "var(--commerce-text)",
1886
+ fontSize: "0.875rem",
1887
+ fontWeight: 500,
1888
+ cursor: variantOutOfStock ? "not-allowed" : "pointer",
1889
+ opacity: variantOutOfStock ? 0.5 : 1,
1890
+ transition: "all 0.15s ease",
1891
+ textDecoration: variantOutOfStock ? "line-through" : "none"
1892
+ },
1893
+ children: [
1894
+ variant.options?.Size || variant.name,
1895
+ showInventory && !variantOutOfStock && /* @__PURE__ */ jsxRuntime.jsx(
1896
+ "span",
1897
+ {
1898
+ style: {
1899
+ position: "absolute",
1900
+ top: -3,
1901
+ right: -3,
1902
+ width: 8,
1903
+ height: 8,
1904
+ borderRadius: "50%",
1905
+ backgroundColor: isLow ? "var(--commerce-warning)" : "var(--commerce-success)",
1906
+ border: "2px solid white"
1907
+ },
1908
+ title: isLow ? `Only ${variant.inventory_count} left` : "In stock"
1909
+ }
1910
+ )
1911
+ ]
1912
+ },
1913
+ variant.id
1914
+ );
1915
+ }) })
1916
+ ] });
1917
+ }
1918
+ function QuantitySelector({ quantity, max, onChange }) {
1919
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { marginTop: "1.25rem" }, children: [
1920
+ /* @__PURE__ */ jsxRuntime.jsx(
1921
+ "label",
1922
+ {
1923
+ style: {
1924
+ display: "block",
1925
+ fontSize: "0.875rem",
1926
+ fontWeight: 600,
1927
+ color: "var(--commerce-text)",
1928
+ marginBottom: "0.5rem"
1929
+ },
1930
+ children: "Quantity"
1931
+ }
1932
+ ),
1933
+ /* @__PURE__ */ jsxRuntime.jsxs(
1934
+ "div",
1935
+ {
1936
+ style: {
1937
+ display: "inline-flex",
1938
+ alignItems: "center",
1939
+ border: "1px solid var(--commerce-border)",
1940
+ borderRadius: "var(--commerce-radius-sm)",
1941
+ overflow: "hidden"
1942
+ },
1943
+ children: [
1944
+ /* @__PURE__ */ jsxRuntime.jsx(
1945
+ "button",
1946
+ {
1947
+ onClick: () => onChange(Math.max(1, quantity - 1)),
1948
+ disabled: quantity <= 1,
1949
+ "aria-label": "Decrease quantity",
1950
+ style: {
1951
+ width: 40,
1952
+ height: 40,
1953
+ border: "none",
1954
+ background: "var(--commerce-surface)",
1955
+ fontSize: "1.125rem",
1956
+ cursor: quantity <= 1 ? "not-allowed" : "pointer",
1957
+ opacity: quantity <= 1 ? 0.4 : 1,
1958
+ display: "flex",
1959
+ alignItems: "center",
1960
+ justifyContent: "center",
1961
+ color: "var(--commerce-text)"
1962
+ },
1963
+ children: "-"
1964
+ }
1965
+ ),
1966
+ /* @__PURE__ */ jsxRuntime.jsx(
1967
+ "input",
1968
+ {
1969
+ type: "number",
1970
+ min: 1,
1971
+ max,
1972
+ value: quantity,
1973
+ onChange: (e) => {
1974
+ const val = parseInt(e.target.value) || 1;
1975
+ onChange(Math.max(1, Math.min(max, val)));
1976
+ },
1977
+ "aria-label": "Quantity",
1978
+ style: {
1979
+ width: 48,
1980
+ height: 40,
1981
+ textAlign: "center",
1982
+ border: "none",
1983
+ borderLeft: "1px solid var(--commerce-border)",
1984
+ borderRight: "1px solid var(--commerce-border)",
1985
+ fontSize: "0.9375rem",
1986
+ fontWeight: 500,
1987
+ color: "var(--commerce-text)",
1988
+ outline: "none",
1989
+ MozAppearance: "textfield",
1990
+ appearance: "textfield"
1991
+ }
1992
+ }
1993
+ ),
1994
+ /* @__PURE__ */ jsxRuntime.jsx(
1995
+ "button",
1996
+ {
1997
+ onClick: () => onChange(Math.min(max, quantity + 1)),
1998
+ disabled: quantity >= max,
1999
+ "aria-label": "Increase quantity",
2000
+ style: {
2001
+ width: 40,
2002
+ height: 40,
2003
+ border: "none",
2004
+ background: "var(--commerce-surface)",
2005
+ fontSize: "1.125rem",
2006
+ cursor: quantity >= max ? "not-allowed" : "pointer",
2007
+ opacity: quantity >= max ? 0.4 : 1,
2008
+ display: "flex",
2009
+ alignItems: "center",
2010
+ justifyContent: "center",
2011
+ color: "var(--commerce-text)"
2012
+ },
2013
+ children: "+"
2014
+ }
2015
+ )
2016
+ ]
2017
+ }
2018
+ )
2019
+ ] });
2020
+ }
2021
+ var DEFAULT_TRUST_BADGES = [
2022
+ { icon: "lock", label: "Secure Checkout", sublabel: "SSL encrypted" },
2023
+ { icon: "truck", label: "Fast Shipping", sublabel: "Free over $50" },
2024
+ { icon: "return", label: "Easy Returns", sublabel: "30-day policy" }
2025
+ ];
2026
+ function TrustBadges({ badges = DEFAULT_TRUST_BADGES }) {
2027
+ return /* @__PURE__ */ jsxRuntime.jsx(
2028
+ "div",
2029
+ {
2030
+ style: {
2031
+ marginTop: "1.5rem",
2032
+ display: "grid",
2033
+ gridTemplateColumns: `repeat(${Math.min(badges.length, 3)}, 1fr)`,
2034
+ gap: "0.75rem"
2035
+ },
2036
+ children: badges.map((badge, idx) => {
2037
+ const Icon = badge.icon ? ICON_MAP[badge.icon] : IconShield;
2038
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2039
+ "div",
2040
+ {
2041
+ style: {
2042
+ display: "flex",
2043
+ flexDirection: "column",
2044
+ alignItems: "center",
2045
+ textAlign: "center",
2046
+ padding: "0.75rem 0.5rem",
2047
+ borderRadius: "var(--commerce-radius-sm)",
2048
+ background: "var(--commerce-surface)"
2049
+ },
2050
+ children: [
2051
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "var(--commerce-text-secondary)", marginBottom: 4 }, children: Icon && /* @__PURE__ */ jsxRuntime.jsx(Icon, {}) }),
2052
+ /* @__PURE__ */ jsxRuntime.jsx(
2053
+ "span",
2054
+ {
2055
+ style: {
2056
+ fontSize: "0.75rem",
2057
+ fontWeight: 600,
2058
+ color: "var(--commerce-text)",
2059
+ lineHeight: 1.3
2060
+ },
2061
+ children: badge.label
2062
+ }
2063
+ ),
2064
+ badge.sublabel && /* @__PURE__ */ jsxRuntime.jsx(
2065
+ "span",
2066
+ {
2067
+ style: {
2068
+ fontSize: "0.6875rem",
2069
+ color: "var(--commerce-text-muted)",
2070
+ lineHeight: 1.3
2071
+ },
2072
+ children: badge.sublabel
2073
+ }
2074
+ )
2075
+ ]
2076
+ },
2077
+ idx
2078
+ );
2079
+ })
2080
+ }
2081
+ );
2082
+ }
2083
+ function ProductTabs({
2084
+ features,
2085
+ specifications,
2086
+ description,
2087
+ showFeatures,
2088
+ showSpecifications,
2089
+ showDescription
2090
+ }) {
2091
+ const tabs = [];
2092
+ if (showFeatures && features?.length) tabs.push({ id: "features", label: "Features" });
2093
+ if (showSpecifications && specifications && Object.keys(specifications).length)
2094
+ tabs.push({ id: "specs", label: "Specifications" });
2095
+ if (showDescription && description) tabs.push({ id: "description", label: "Description" });
2096
+ const [active, setActive] = React5.useState(tabs[0]?.id || "");
2097
+ React5.useEffect(() => {
2098
+ if (tabs.length && !tabs.find((t) => t.id === active)) {
2099
+ setActive(tabs[0].id);
2100
+ }
2101
+ }, [tabs.length]);
2102
+ if (!tabs.length) return null;
2103
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { marginTop: "2rem" }, children: [
2104
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "skc-tabs-list", role: "tablist", children: tabs.map((tab) => /* @__PURE__ */ jsxRuntime.jsx(
2105
+ "button",
2106
+ {
2107
+ className: `skc-tab-btn${active === tab.id ? " skc-active" : ""}`,
2108
+ role: "tab",
2109
+ "aria-selected": active === tab.id,
2110
+ "aria-controls": `skc-tabpanel-${tab.id}`,
2111
+ onClick: () => setActive(tab.id),
2112
+ children: tab.label
2113
+ },
2114
+ tab.id
2115
+ )) }),
2116
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { padding: "1.25rem 0", animation: "skc-fadeIn 0.2s ease-out" }, children: [
2117
+ active === "features" && features && /* @__PURE__ */ jsxRuntime.jsx("div", { id: "skc-tabpanel-features", role: "tabpanel", children: /* @__PURE__ */ jsxRuntime.jsx(
2118
+ "ul",
2119
+ {
2120
+ style: {
2121
+ margin: 0,
2122
+ paddingLeft: "1.25rem",
2123
+ display: "flex",
2124
+ flexDirection: "column",
2125
+ gap: "0.5rem"
2126
+ },
2127
+ children: features.map((f, i) => /* @__PURE__ */ jsxRuntime.jsx(
2128
+ "li",
2129
+ {
2130
+ style: {
2131
+ color: "var(--commerce-text-secondary)",
2132
+ fontSize: "0.9375rem",
2133
+ lineHeight: 1.6
2134
+ },
2135
+ children: f
2136
+ },
2137
+ i
2138
+ ))
2139
+ }
2140
+ ) }),
2141
+ active === "specs" && specifications && /* @__PURE__ */ jsxRuntime.jsx("div", { id: "skc-tabpanel-specs", role: "tabpanel", children: /* @__PURE__ */ jsxRuntime.jsx(
2142
+ "dl",
2143
+ {
2144
+ style: {
2145
+ margin: 0,
2146
+ display: "grid",
2147
+ gridTemplateColumns: "minmax(120px, auto) 1fr",
2148
+ gap: "0.625rem 1.5rem"
2149
+ },
2150
+ children: Object.entries(specifications).map(([key, value]) => /* @__PURE__ */ jsxRuntime.jsxs(React5__default.default.Fragment, { children: [
2151
+ /* @__PURE__ */ jsxRuntime.jsx(
2152
+ "dt",
2153
+ {
2154
+ style: {
2155
+ fontSize: "0.875rem",
2156
+ color: "var(--commerce-text-muted)",
2157
+ fontWeight: 500
2158
+ },
2159
+ children: key
2160
+ }
2161
+ ),
2162
+ /* @__PURE__ */ jsxRuntime.jsx(
2163
+ "dd",
2164
+ {
2165
+ style: {
2166
+ margin: 0,
2167
+ fontSize: "0.875rem",
2168
+ color: "var(--commerce-text)"
2169
+ },
2170
+ children: value
2171
+ }
2172
+ )
2173
+ ] }, key))
2174
+ }
2175
+ ) }),
2176
+ active === "description" && description && /* @__PURE__ */ jsxRuntime.jsx(
2177
+ "div",
2178
+ {
2179
+ id: "skc-tabpanel-description",
2180
+ role: "tabpanel",
2181
+ style: {
2182
+ color: "var(--commerce-text-secondary)",
2183
+ lineHeight: 1.7,
2184
+ fontSize: "0.9375rem"
2185
+ },
2186
+ dangerouslySetInnerHTML: { __html: description }
2187
+ }
2188
+ )
2189
+ ] })
2190
+ ] });
2191
+ }
2192
+ function EventInfoBlock({ product, schedule }) {
2193
+ schedule ? getSpotsRemaining(schedule.capacity, schedule.current_registrations ?? (schedule.capacity != null ? schedule.capacity - (schedule.spots_remaining ?? schedule.capacity) : 0)) : null;
2194
+ const soldOut = schedule ? isEventSoldOut(schedule.capacity, schedule.current_registrations ?? (schedule.capacity != null ? schedule.capacity - (schedule.spots_remaining ?? schedule.capacity) : 0)) : false;
2195
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2196
+ "div",
2197
+ {
2198
+ style: {
2199
+ marginTop: "1.25rem",
2200
+ padding: "1rem",
2201
+ borderRadius: "var(--commerce-radius-sm)",
2202
+ background: "var(--commerce-surface)",
2203
+ display: "flex",
2204
+ flexDirection: "column",
2205
+ gap: "0.5rem"
2206
+ },
2207
+ children: [
2208
+ schedule && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", gap: 6, fontSize: "0.875rem", color: "var(--commerce-text-secondary)" }, children: [
2209
+ /* @__PURE__ */ jsxRuntime.jsx(IconCalendar, {}),
2210
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
2211
+ formatDate(schedule.starts_at),
2212
+ " at ",
2213
+ formatTime(schedule.starts_at)
2214
+ ] })
2215
+ ] }),
2216
+ product.location && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", gap: 6, fontSize: "0.875rem", color: "var(--commerce-text-secondary)" }, children: [
2217
+ /* @__PURE__ */ jsxRuntime.jsx(IconMapPin, {}),
2218
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: product.location })
2219
+ ] }),
2220
+ product.is_virtual && product.virtual_meeting_url && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", gap: 6, fontSize: "0.875rem", color: "var(--commerce-accent)" }, children: [
2221
+ /* @__PURE__ */ jsxRuntime.jsx(IconExternalLink, {}),
2222
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Virtual Event" })
2223
+ ] }),
2224
+ schedule?.capacity != null && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", gap: 6, fontSize: "0.875rem", color: "var(--commerce-text-secondary)" }, children: [
2225
+ /* @__PURE__ */ jsxRuntime.jsx(IconUsers, {}),
2226
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: soldOut ? /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "var(--commerce-danger)", fontWeight: 600 }, children: "Sold Out" }) : schedule.spots_remaining != null && schedule.spots_remaining <= 10 ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "skc-pulse", style: { color: "var(--commerce-warning)", fontWeight: 600 }, children: [
2227
+ "Only ",
2228
+ schedule.spots_remaining,
2229
+ " spot",
2230
+ schedule.spots_remaining !== 1 ? "s" : "",
2231
+ " left!"
2232
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
2233
+ schedule.spots_remaining ?? schedule.capacity,
2234
+ " spots available"
2235
+ ] }) })
2236
+ ] })
2237
+ ]
2238
+ }
2239
+ );
2240
+ }
2241
+ function CheckoutStepIndicator({ current, steps }) {
2242
+ const currentIdx = steps.indexOf(current);
2243
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "skc-step-dots", children: steps.map((step, idx) => /* @__PURE__ */ jsxRuntime.jsxs(React5__default.default.Fragment, { children: [
2244
+ idx > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: `skc-step-connector${idx <= currentIdx ? " skc-done" : ""}` }),
2245
+ /* @__PURE__ */ jsxRuntime.jsx(
2246
+ "div",
2247
+ {
2248
+ className: `skc-step-dot${idx === currentIdx ? " skc-active" : idx < currentIdx ? " skc-done" : ""}`,
2249
+ title: step.replace("-", " ")
2250
+ }
2251
+ )
2252
+ ] }, step)) });
2253
+ }
2254
+ function CustomerInfoStep({ customer, onChange, onNext, onBack }) {
2255
+ const handleSubmit = (e) => {
2256
+ e.preventDefault();
2257
+ onNext();
2258
+ };
2259
+ return /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit, style: { display: "flex", flexDirection: "column", gap: "0.875rem" }, children: [
2260
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { style: { margin: 0, fontSize: "1.125rem", fontWeight: 600, color: "var(--commerce-text)" }, children: "Contact Information" }),
2261
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2262
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: { display: "block", fontSize: "0.8125rem", fontWeight: 500, color: "var(--commerce-text-secondary)", marginBottom: 4 }, children: "Full Name *" }),
2263
+ /* @__PURE__ */ jsxRuntime.jsx(
2264
+ "input",
2265
+ {
2266
+ className: "skc-input",
2267
+ type: "text",
2268
+ required: true,
2269
+ value: customer.name,
2270
+ onChange: (e) => onChange({ ...customer, name: e.target.value }),
2271
+ placeholder: "Jane Smith",
2272
+ autoFocus: true
2273
+ }
2274
+ )
2275
+ ] }),
2276
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2277
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: { display: "block", fontSize: "0.8125rem", fontWeight: 500, color: "var(--commerce-text-secondary)", marginBottom: 4 }, children: "Email Address *" }),
2278
+ /* @__PURE__ */ jsxRuntime.jsx(
2279
+ "input",
2280
+ {
2281
+ className: "skc-input",
2282
+ type: "email",
2283
+ required: true,
2284
+ value: customer.email,
2285
+ onChange: (e) => onChange({ ...customer, email: e.target.value }),
2286
+ placeholder: "jane@example.com"
2287
+ }
2288
+ )
2289
+ ] }),
2290
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2291
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: { display: "block", fontSize: "0.8125rem", fontWeight: 500, color: "var(--commerce-text-secondary)", marginBottom: 4 }, children: "Phone Number" }),
2292
+ /* @__PURE__ */ jsxRuntime.jsx(
2293
+ "input",
2294
+ {
2295
+ className: "skc-input",
2296
+ type: "tel",
2297
+ value: customer.phone || "",
2298
+ onChange: (e) => onChange({ ...customer, phone: e.target.value }),
2299
+ placeholder: "(555) 123-4567"
2300
+ }
2301
+ )
2302
+ ] }),
2303
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: "0.75rem", marginTop: "0.5rem" }, children: [
2304
+ /* @__PURE__ */ jsxRuntime.jsx(
2305
+ "button",
2306
+ {
2307
+ type: "button",
2308
+ onClick: onBack,
2309
+ style: {
2310
+ padding: "0.75rem 1.25rem",
2311
+ borderRadius: "var(--commerce-radius-sm)",
2312
+ border: "1px solid var(--commerce-border)",
2313
+ background: "white",
2314
+ color: "var(--commerce-text-secondary)",
2315
+ fontSize: "0.875rem",
2316
+ fontWeight: 500,
2317
+ cursor: "pointer"
2318
+ },
2319
+ children: "Back"
2320
+ }
2321
+ ),
2322
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "submit", className: "skc-btn-primary", style: { flex: 1 }, children: "Continue" })
2323
+ ] })
2324
+ ] });
2325
+ }
2326
+ function ShippingAddressStep({ address, onChange, onNext, onBack, loading }) {
2327
+ const handleSubmit = (e) => {
2328
+ e.preventDefault();
2329
+ onNext();
2330
+ };
2331
+ const update = (field, value) => {
2332
+ onChange({ ...address, [field]: value });
2333
+ };
2334
+ return /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit, style: { display: "flex", flexDirection: "column", gap: "0.875rem" }, children: [
2335
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { style: { margin: 0, fontSize: "1.125rem", fontWeight: 600, color: "var(--commerce-text)" }, children: "Shipping Address" }),
2336
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2337
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: { display: "block", fontSize: "0.8125rem", fontWeight: 500, color: "var(--commerce-text-secondary)", marginBottom: 4 }, children: "Street Address *" }),
2338
+ /* @__PURE__ */ jsxRuntime.jsx(
2339
+ "input",
2340
+ {
2341
+ className: "skc-input",
2342
+ type: "text",
2343
+ required: true,
2344
+ value: address.street1,
2345
+ onChange: (e) => update("street1", e.target.value),
2346
+ placeholder: "123 Main St",
2347
+ autoFocus: true
2348
+ }
2349
+ )
2350
+ ] }),
2351
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2352
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: { display: "block", fontSize: "0.8125rem", fontWeight: 500, color: "var(--commerce-text-secondary)", marginBottom: 4 }, children: "Apt / Suite" }),
2353
+ /* @__PURE__ */ jsxRuntime.jsx(
2354
+ "input",
2355
+ {
2356
+ className: "skc-input",
2357
+ type: "text",
2358
+ value: address.street2 || "",
2359
+ onChange: (e) => update("street2", e.target.value),
2360
+ placeholder: "Apt 4B"
2361
+ }
2362
+ )
2363
+ ] }),
2364
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: "0.75rem" }, children: [
2365
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2366
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: { display: "block", fontSize: "0.8125rem", fontWeight: 500, color: "var(--commerce-text-secondary)", marginBottom: 4 }, children: "City *" }),
2367
+ /* @__PURE__ */ jsxRuntime.jsx(
2368
+ "input",
2369
+ {
2370
+ className: "skc-input",
2371
+ type: "text",
2372
+ required: true,
2373
+ value: address.city,
2374
+ onChange: (e) => update("city", e.target.value),
2375
+ placeholder: "New York"
2376
+ }
2377
+ )
2378
+ ] }),
2379
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2380
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: { display: "block", fontSize: "0.8125rem", fontWeight: 500, color: "var(--commerce-text-secondary)", marginBottom: 4 }, children: "State *" }),
2381
+ /* @__PURE__ */ jsxRuntime.jsx(
2382
+ "input",
2383
+ {
2384
+ className: "skc-input",
2385
+ type: "text",
2386
+ required: true,
2387
+ value: address.state,
2388
+ onChange: (e) => update("state", e.target.value),
2389
+ placeholder: "NY"
2390
+ }
2391
+ )
2392
+ ] })
2393
+ ] }),
2394
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: "0.75rem" }, children: [
2395
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2396
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: { display: "block", fontSize: "0.8125rem", fontWeight: 500, color: "var(--commerce-text-secondary)", marginBottom: 4 }, children: "ZIP Code *" }),
2397
+ /* @__PURE__ */ jsxRuntime.jsx(
2398
+ "input",
2399
+ {
2400
+ className: "skc-input",
2401
+ type: "text",
2402
+ required: true,
2403
+ value: address.zip,
2404
+ onChange: (e) => update("zip", e.target.value),
2405
+ placeholder: "10001"
2406
+ }
2407
+ )
2408
+ ] }),
2409
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2410
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: { display: "block", fontSize: "0.8125rem", fontWeight: 500, color: "var(--commerce-text-secondary)", marginBottom: 4 }, children: "Country" }),
2411
+ /* @__PURE__ */ jsxRuntime.jsx(
2412
+ "input",
2413
+ {
2414
+ className: "skc-input",
2415
+ type: "text",
2416
+ value: address.country || "US",
2417
+ onChange: (e) => update("country", e.target.value),
2418
+ placeholder: "US"
2419
+ }
2420
+ )
2421
+ ] })
2422
+ ] }),
2423
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: "0.75rem", marginTop: "0.5rem" }, children: [
2424
+ /* @__PURE__ */ jsxRuntime.jsx(
2425
+ "button",
2426
+ {
2427
+ type: "button",
2428
+ onClick: onBack,
2429
+ style: {
2430
+ padding: "0.75rem 1.25rem",
2431
+ borderRadius: "var(--commerce-radius-sm)",
2432
+ border: "1px solid var(--commerce-border)",
2433
+ background: "white",
2434
+ color: "var(--commerce-text-secondary)",
2435
+ fontSize: "0.875rem",
2436
+ fontWeight: 500,
2437
+ cursor: "pointer"
2438
+ },
2439
+ children: "Back"
2440
+ }
2441
+ ),
2442
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "submit", className: "skc-btn-primary", style: { flex: 1 }, disabled: loading, children: loading ? "Getting rates..." : "Continue to Shipping" })
2443
+ ] })
2444
+ ] });
2445
+ }
2446
+ function ShippingRatesStep({ rates, selected, onSelect, onNext, onBack, loading, currency }) {
2447
+ if (loading) {
2448
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { textAlign: "center", padding: "2rem 0" }, children: [
2449
+ /* @__PURE__ */ jsxRuntime.jsx(
2450
+ "div",
2451
+ {
2452
+ style: {
2453
+ width: 32,
2454
+ height: 32,
2455
+ border: "3px solid var(--commerce-border)",
2456
+ borderTopColor: "var(--commerce-accent)",
2457
+ borderRadius: "50%",
2458
+ animation: "skc-spin 1s linear infinite",
2459
+ margin: "0 auto 1rem"
2460
+ }
2461
+ }
2462
+ ),
2463
+ /* @__PURE__ */ jsxRuntime.jsx("p", { style: { color: "var(--commerce-text-secondary)", fontSize: "0.875rem", margin: 0 }, children: "Calculating shipping rates..." })
2464
+ ] });
2465
+ }
2466
+ if (!rates.length) {
2467
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { textAlign: "center", padding: "1.5rem 0" }, children: [
2468
+ /* @__PURE__ */ jsxRuntime.jsx("p", { style: { color: "var(--commerce-text-secondary)", fontSize: "0.875rem", margin: "0 0 1rem" }, children: "No shipping rates available for this address. Please check your address and try again." }),
2469
+ /* @__PURE__ */ jsxRuntime.jsx(
2470
+ "button",
2471
+ {
2472
+ type: "button",
2473
+ onClick: onBack,
2474
+ style: {
2475
+ padding: "0.75rem 1.5rem",
2476
+ borderRadius: "var(--commerce-radius-sm)",
2477
+ border: "1px solid var(--commerce-border)",
2478
+ background: "white",
2479
+ color: "var(--commerce-text-secondary)",
2480
+ fontSize: "0.875rem",
2481
+ fontWeight: 500,
2482
+ cursor: "pointer"
2483
+ },
2484
+ children: "Edit Address"
2485
+ }
2486
+ )
2487
+ ] });
2488
+ }
2489
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.875rem" }, children: [
2490
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { style: { margin: 0, fontSize: "1.125rem", fontWeight: 600, color: "var(--commerce-text)" }, children: "Shipping Method" }),
2491
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, role: "radiogroup", "aria-label": "Shipping options", children: rates.map((rate, idx) => {
2492
+ const isSelected = selected?.objectId === rate.objectId || selected === null && idx === 0;
2493
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2494
+ "button",
2495
+ {
2496
+ role: "radio",
2497
+ "aria-checked": isSelected,
2498
+ onClick: () => onSelect(rate),
2499
+ style: {
2500
+ display: "flex",
2501
+ alignItems: "center",
2502
+ justifyContent: "space-between",
2503
+ padding: "0.875rem 1rem",
2504
+ borderRadius: "var(--commerce-radius-sm)",
2505
+ border: isSelected ? "2px solid var(--commerce-accent)" : "1px solid var(--commerce-border)",
2506
+ background: isSelected ? "rgba(37,99,235,0.03)" : "white",
2507
+ cursor: "pointer",
2508
+ textAlign: "left",
2509
+ width: "100%"
2510
+ },
2511
+ children: [
2512
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2513
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { fontSize: "0.875rem", fontWeight: 600, color: "var(--commerce-text)" }, children: [
2514
+ rate.carrier,
2515
+ " \u2014 ",
2516
+ rate.service
2517
+ ] }),
2518
+ rate.estimatedDays != null && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: "0.8125rem", color: "var(--commerce-text-muted)", marginTop: 2 }, children: rate.estimatedDays === 1 ? "1 business day" : `${rate.estimatedDays} business days` })
2519
+ ] }),
2520
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: "0.9375rem", fontWeight: 600, color: "var(--commerce-text)" }, children: formatPrice(parseFloat(rate.amount), rate.currency || currency) })
2521
+ ]
2522
+ },
2523
+ rate.objectId || idx
2524
+ );
2525
+ }) }),
2526
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: "0.75rem", marginTop: "0.5rem" }, children: [
2527
+ /* @__PURE__ */ jsxRuntime.jsx(
2528
+ "button",
2529
+ {
2530
+ type: "button",
2531
+ onClick: onBack,
2532
+ style: {
2533
+ padding: "0.75rem 1.25rem",
2534
+ borderRadius: "var(--commerce-radius-sm)",
2535
+ border: "1px solid var(--commerce-border)",
2536
+ background: "white",
2537
+ color: "var(--commerce-text-secondary)",
2538
+ fontSize: "0.875rem",
2539
+ fontWeight: 500,
2540
+ cursor: "pointer"
2541
+ },
2542
+ children: "Back"
2543
+ }
2544
+ ),
2545
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "skc-btn-primary", style: { flex: 1 }, onClick: onNext, children: "Continue to Payment" })
2546
+ ] })
2547
+ ] });
2548
+ }
2549
+ function PaymentStep({
2550
+ processor,
2551
+ config,
2552
+ product,
2553
+ variant,
2554
+ quantity,
2555
+ customer,
2556
+ shippingRate,
2557
+ shippingAddress,
2558
+ needsShipping,
2559
+ onBack,
2560
+ onSuccess,
2561
+ onError,
2562
+ onProcessing,
2563
+ successUrl,
2564
+ cancelUrl
2565
+ }) {
2566
+ const [cardElement, setCardElement] = React5.useState(null);
2567
+ const [stripeInstance, setStripeInstance] = React5.useState(null);
2568
+ const [stripeElements, setStripeElements] = React5.useState(null);
2569
+ const [cardReady, setCardReady] = React5.useState(false);
2570
+ const [error, setError] = React5.useState(null);
2571
+ const [submitting, setSubmitting] = React5.useState(false);
2572
+ const cardContainerRef = React5.useRef(null);
2573
+ const currentPrice = variant?.price ?? product.price ?? 0;
2574
+ const subtotal = currentPrice * quantity;
2575
+ const shippingCost = shippingRate ? parseFloat(shippingRate.amount) : 0;
2576
+ const total = subtotal + shippingCost;
2577
+ React5.useEffect(() => {
2578
+ if (processor !== "square" || !config?.squareAppId) return;
2579
+ let destroyed = false;
2580
+ let card = null;
2581
+ loadSquareSDK(config.squareEnvironment || "production").then(async () => {
2582
+ if (destroyed) return;
2583
+ const payments = window.Square.payments(
2584
+ config.squareAppId,
2585
+ config.squareLocationId
2586
+ );
2587
+ card = await payments.card({
2588
+ style: {
2589
+ ".input-container": { borderRadius: "8px" },
2590
+ ".input-container.is-focus": { borderColor: "#2563eb" },
2591
+ ".input-container.is-error": { borderColor: "#dc2626" }
2592
+ }
2593
+ });
2594
+ if (destroyed) {
2595
+ card.destroy?.();
2596
+ return;
2597
+ }
2598
+ await card.attach("#skc-card-container");
2599
+ setCardElement(card);
2600
+ setCardReady(true);
2601
+ }).catch((err) => {
2602
+ console.error("[Commerce] Square card init failed:", err);
2603
+ setError("Failed to load payment form. Please refresh and try again.");
2604
+ });
2605
+ return () => {
2606
+ destroyed = true;
2607
+ if (card) card.destroy?.().catch(() => {
2608
+ });
2609
+ setCardElement(null);
2610
+ setCardReady(false);
2611
+ };
2612
+ }, [processor, config?.squareAppId]);
2613
+ React5.useEffect(() => {
2614
+ if (processor !== "stripe" || !config?.stripePublishableKey) return;
2615
+ let destroyed = false;
2616
+ (async () => {
2617
+ try {
2618
+ await loadStripeSDK();
2619
+ if (destroyed) return;
2620
+ const checkoutOpts = {
2621
+ offeringId: product.id,
2622
+ variantId: variant?.id,
2623
+ quantity,
2624
+ customer,
2625
+ successUrl: successUrl || window.location.href,
2626
+ cancelUrl: cancelUrl || window.location.href
2627
+ };
2628
+ if (needsShipping && shippingAddress) {
2629
+ checkoutOpts.shippingAddress = shippingAddress;
2630
+ checkoutOpts.shippingCarrier = shippingRate?.carrier;
2631
+ checkoutOpts.shippingService = shippingRate?.service;
2632
+ checkoutOpts.shippingCost = shippingCost;
2633
+ }
2634
+ const piResult = await createPaymentIntent(checkoutOpts);
2635
+ if (destroyed) return;
2636
+ if (!piResult.success || !piResult.clientSecret) {
2637
+ setError(piResult.error || "Failed to initialize payment. Please try again.");
2638
+ return;
2639
+ }
2640
+ const stripe = window.Stripe(config.stripePublishableKey);
2641
+ const elements = stripe.elements({ clientSecret: piResult.clientSecret });
2642
+ const paymentElement = elements.create("payment", {
2643
+ layout: "tabs"
2644
+ });
2645
+ if (destroyed) return;
2646
+ paymentElement.mount("#skc-card-container");
2647
+ paymentElement.on("ready", () => {
2648
+ if (!destroyed) setCardReady(true);
2649
+ });
2650
+ setStripeInstance(stripe);
2651
+ setStripeElements(elements);
2652
+ setCardElement(paymentElement);
2653
+ cardContainerRef.current?.__saleId && delete cardContainerRef.current.__saleId;
2654
+ if (cardContainerRef.current) {
2655
+ ;
2656
+ cardContainerRef.current.__saleId = piResult.saleId;
2657
+ cardContainerRef.current.__confirmationNumber = piResult.confirmationNumber;
2658
+ }
2659
+ } catch (err) {
2660
+ console.error("[Commerce] Stripe init failed:", err);
2661
+ if (!destroyed) setError("Failed to load payment form. Please refresh and try again.");
2662
+ }
2663
+ })();
2664
+ return () => {
2665
+ destroyed = true;
2666
+ setCardElement(null);
2667
+ setStripeInstance(null);
2668
+ setStripeElements(null);
2669
+ setCardReady(false);
2670
+ };
2671
+ }, [processor, config?.stripePublishableKey]);
2672
+ const handleSubmit = async () => {
2673
+ if (!cardReady || submitting) return;
2674
+ setSubmitting(true);
2675
+ setError(null);
2676
+ onProcessing(true);
2677
+ try {
2678
+ if (processor === "square" && cardElement) {
2679
+ const tokenResult = await cardElement.tokenize();
2680
+ if (tokenResult.status !== "OK") {
2681
+ throw new Error(
2682
+ tokenResult.errors?.[0]?.message || "Card verification failed. Please check your card details."
2683
+ );
2684
+ }
2685
+ const checkoutOpts = {
2686
+ offeringId: product.id,
2687
+ variantId: variant?.id,
2688
+ quantity,
2689
+ customer,
2690
+ sourceId: tokenResult.token,
2691
+ successUrl: successUrl || window.location.href,
2692
+ cancelUrl: cancelUrl || window.location.href
2693
+ };
2694
+ if (needsShipping && shippingAddress) {
2695
+ checkoutOpts.shippingAddress = shippingAddress;
2696
+ checkoutOpts.shippingCarrier = shippingRate?.carrier;
2697
+ checkoutOpts.shippingService = shippingRate?.service;
2698
+ checkoutOpts.shippingCost = shippingCost;
2699
+ }
2700
+ const result = await createCheckoutSession(checkoutOpts);
2701
+ if (result.success && !result.payment_url) {
2702
+ onSuccess(result);
2703
+ } else if (result.success && result.payment_url) {
2704
+ window.location.href = result.payment_url;
2705
+ } else {
2706
+ throw new Error(result.error || "Payment failed. Please try again.");
2707
+ }
2708
+ } else if (processor === "stripe" && stripeInstance && stripeElements) {
2709
+ const { error: stripeError, paymentIntent } = await stripeInstance.confirmPayment({
2710
+ elements: stripeElements,
2711
+ confirmParams: {
2712
+ return_url: successUrl || window.location.href
2713
+ },
2714
+ redirect: "if_required"
2715
+ });
2716
+ if (stripeError) {
2717
+ throw new Error(stripeError.message || "Payment failed. Please try again.");
2718
+ }
2719
+ if (paymentIntent && paymentIntent.status === "succeeded") {
2720
+ const saleId = cardContainerRef.current?.__saleId;
2721
+ const confirmationNumber = cardContainerRef.current?.__confirmationNumber;
2722
+ onSuccess({
2723
+ success: true,
2724
+ sale_id: saleId,
2725
+ confirmation_number: confirmationNumber
2726
+ });
2727
+ }
2728
+ } else {
2729
+ const checkoutOpts = {
2730
+ offeringId: product.id,
2731
+ variantId: variant?.id,
2732
+ quantity,
2733
+ customer,
2734
+ successUrl: successUrl || `${window.location.origin}/checkout/success`,
2735
+ cancelUrl: cancelUrl || window.location.href
2736
+ };
2737
+ if (needsShipping && shippingAddress) {
2738
+ checkoutOpts.shippingAddress = shippingAddress;
2739
+ checkoutOpts.shippingCarrier = shippingRate?.carrier;
2740
+ checkoutOpts.shippingService = shippingRate?.service;
2741
+ checkoutOpts.shippingCost = shippingCost;
2742
+ }
2743
+ const result = await createCheckoutSession(checkoutOpts);
2744
+ if (result.success && result.checkout_url) {
2745
+ window.location.href = result.checkout_url;
2746
+ } else {
2747
+ throw new Error(result.error || "Checkout failed.");
2748
+ }
2749
+ }
2750
+ } catch (err) {
2751
+ const msg = err?.message || "Payment failed. Please try again.";
2752
+ setError(msg);
2753
+ onError(msg);
2754
+ } finally {
2755
+ setSubmitting(false);
2756
+ onProcessing(false);
2757
+ }
2758
+ };
2759
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "1rem" }, children: [
2760
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { style: { margin: 0, fontSize: "1.125rem", fontWeight: 600, color: "var(--commerce-text)" }, children: "Payment" }),
2761
+ /* @__PURE__ */ jsxRuntime.jsxs(
2762
+ "div",
2763
+ {
2764
+ style: {
2765
+ padding: "1rem",
2766
+ borderRadius: "var(--commerce-radius-sm)",
2767
+ background: "var(--commerce-surface)",
2768
+ display: "flex",
2769
+ flexDirection: "column",
2770
+ gap: "0.375rem",
2771
+ fontSize: "0.875rem"
2772
+ },
2773
+ children: [
2774
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between", color: "var(--commerce-text-secondary)" }, children: [
2775
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
2776
+ product.name,
2777
+ " ",
2778
+ variant ? `(${variant.options?.Size || variant.name})` : "",
2779
+ " x ",
2780
+ quantity
2781
+ ] }),
2782
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: formatPrice(subtotal, product.currency) })
2783
+ ] }),
2784
+ shippingRate && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between", color: "var(--commerce-text-secondary)" }, children: [
2785
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
2786
+ "Shipping (",
2787
+ shippingRate.carrier,
2788
+ " ",
2789
+ shippingRate.service,
2790
+ ")"
2791
+ ] }),
2792
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: formatPrice(shippingCost, shippingRate.currency || product.currency) })
2793
+ ] }),
2794
+ /* @__PURE__ */ jsxRuntime.jsxs(
2795
+ "div",
2796
+ {
2797
+ style: {
2798
+ display: "flex",
2799
+ justifyContent: "space-between",
2800
+ fontWeight: 700,
2801
+ color: "var(--commerce-text)",
2802
+ fontSize: "1rem",
2803
+ paddingTop: "0.5rem",
2804
+ borderTop: "1px solid var(--commerce-border)",
2805
+ marginTop: "0.25rem"
2806
+ },
2807
+ children: [
2808
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Total" }),
2809
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: formatPrice(total, product.currency) })
2810
+ ]
2811
+ }
2812
+ )
2813
+ ]
2814
+ }
2815
+ ),
2816
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2817
+ /* @__PURE__ */ jsxRuntime.jsx(
2818
+ "label",
2819
+ {
2820
+ style: {
2821
+ display: "block",
2822
+ fontSize: "0.8125rem",
2823
+ fontWeight: 500,
2824
+ color: "var(--commerce-text-secondary)",
2825
+ marginBottom: 6
2826
+ },
2827
+ children: "Card Details"
2828
+ }
2829
+ ),
2830
+ /* @__PURE__ */ jsxRuntime.jsx(
2831
+ "div",
2832
+ {
2833
+ id: "skc-card-container",
2834
+ ref: cardContainerRef,
2835
+ style: {
2836
+ minHeight: processor === "stripe" ? 80 : 44,
2837
+ border: "1px solid var(--commerce-border)",
2838
+ borderRadius: "var(--commerce-radius-sm)",
2839
+ padding: processor === "stripe" ? "0.75rem" : "0.5rem 0.75rem",
2840
+ background: "white"
2841
+ }
2842
+ }
2843
+ ),
2844
+ !cardReady && !error && /* @__PURE__ */ jsxRuntime.jsx("p", { style: { fontSize: "0.75rem", color: "var(--commerce-text-muted)", marginTop: 4, marginBottom: 0 }, children: "Loading secure payment form..." })
2845
+ ] }),
2846
+ error && /* @__PURE__ */ jsxRuntime.jsxs(
2847
+ "div",
2848
+ {
2849
+ style: {
2850
+ display: "flex",
2851
+ alignItems: "flex-start",
2852
+ gap: 8,
2853
+ padding: "0.75rem",
2854
+ background: "#fef2f2",
2855
+ border: "1px solid #fecaca",
2856
+ borderRadius: "var(--commerce-radius-sm)",
2857
+ color: "var(--commerce-danger)",
2858
+ fontSize: "0.875rem"
2859
+ },
2860
+ children: [
2861
+ /* @__PURE__ */ jsxRuntime.jsx(IconAlert, {}),
2862
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: error })
2863
+ ]
2864
+ }
2865
+ ),
2866
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: "0.75rem" }, children: [
2867
+ /* @__PURE__ */ jsxRuntime.jsx(
2868
+ "button",
2869
+ {
2870
+ type: "button",
2871
+ onClick: onBack,
2872
+ disabled: submitting,
2873
+ style: {
2874
+ padding: "0.75rem 1.25rem",
2875
+ borderRadius: "var(--commerce-radius-sm)",
2876
+ border: "1px solid var(--commerce-border)",
2877
+ background: "white",
2878
+ color: "var(--commerce-text-secondary)",
2879
+ fontSize: "0.875rem",
2880
+ fontWeight: 500,
2881
+ cursor: submitting ? "not-allowed" : "pointer",
2882
+ opacity: submitting ? 0.5 : 1
2883
+ },
2884
+ children: "Back"
2885
+ }
2886
+ ),
2887
+ /* @__PURE__ */ jsxRuntime.jsx(
2888
+ "button",
2889
+ {
2890
+ type: "button",
2891
+ className: "skc-btn-primary",
2892
+ style: { flex: 1 },
2893
+ onClick: handleSubmit,
2894
+ disabled: !cardReady || submitting,
2895
+ children: submitting ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2896
+ /* @__PURE__ */ jsxRuntime.jsx(
2897
+ "span",
2898
+ {
2899
+ style: {
2900
+ width: 16,
2901
+ height: 16,
2902
+ border: "2px solid rgba(255,255,255,0.3)",
2903
+ borderTopColor: "white",
2904
+ borderRadius: "50%",
2905
+ animation: "skc-spin 0.8s linear infinite",
2906
+ display: "inline-block"
2907
+ }
2908
+ }
2909
+ ),
2910
+ "Processing..."
2911
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2912
+ /* @__PURE__ */ jsxRuntime.jsx(IconLock, {}),
2913
+ "Pay ",
2914
+ formatPrice(total, product.currency)
2915
+ ] })
2916
+ }
2917
+ )
2918
+ ] }),
2919
+ processor && /* @__PURE__ */ jsxRuntime.jsxs(
2920
+ "p",
2921
+ {
2922
+ style: {
2923
+ textAlign: "center",
2924
+ fontSize: "0.6875rem",
2925
+ color: "var(--commerce-text-muted)",
2926
+ margin: "0.25rem 0 0"
2927
+ },
2928
+ children: [
2929
+ "Powered by ",
2930
+ processor === "stripe" ? "Stripe" : "Square"
2931
+ ]
2932
+ }
2933
+ )
2934
+ ] });
2935
+ }
2936
+ function SuccessStep({ result, product, onClose }) {
2937
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2938
+ "div",
2939
+ {
2940
+ style: {
2941
+ textAlign: "center",
2942
+ padding: "2rem 1rem",
2943
+ animation: "skc-fadeIn 0.3s ease-out"
2944
+ },
2945
+ children: [
2946
+ /* @__PURE__ */ jsxRuntime.jsx(
2947
+ "div",
2948
+ {
2949
+ style: {
2950
+ width: 64,
2951
+ height: 64,
2952
+ borderRadius: "50%",
2953
+ background: "rgba(5,150,105,0.1)",
2954
+ display: "flex",
2955
+ alignItems: "center",
2956
+ justifyContent: "center",
2957
+ margin: "0 auto 1rem"
2958
+ },
2959
+ children: /* @__PURE__ */ jsxRuntime.jsx(
2960
+ "svg",
2961
+ {
2962
+ width: "32",
2963
+ height: "32",
2964
+ viewBox: "0 0 24 24",
2965
+ fill: "none",
2966
+ stroke: "var(--commerce-success)",
2967
+ strokeWidth: "2.5",
2968
+ strokeLinecap: "round",
2969
+ strokeLinejoin: "round",
2970
+ children: /* @__PURE__ */ jsxRuntime.jsx(
2971
+ "polyline",
2972
+ {
2973
+ points: "20 6 9 17 4 12",
2974
+ style: { strokeDasharray: 24, strokeDashoffset: 0, animation: "skc-checkmark 0.5s ease-out" }
2975
+ }
2976
+ )
2977
+ }
2978
+ )
2979
+ }
2980
+ ),
2981
+ /* @__PURE__ */ jsxRuntime.jsx(
2982
+ "h3",
2983
+ {
2984
+ style: {
2985
+ margin: "0 0 0.5rem",
2986
+ fontSize: "1.375rem",
2987
+ fontWeight: 700,
2988
+ color: "var(--commerce-success)"
2989
+ },
2990
+ children: "Order Confirmed!"
2991
+ }
2992
+ ),
2993
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { style: { color: "var(--commerce-text-secondary)", margin: "0 0 0.5rem", fontSize: "0.9375rem" }, children: [
2994
+ "Thank you for your purchase of ",
2995
+ product.name,
2996
+ "."
2997
+ ] }),
2998
+ result.confirmation_number && /* @__PURE__ */ jsxRuntime.jsxs("p", { style: { color: "var(--commerce-text-muted)", margin: "0 0 1rem", fontSize: "0.8125rem" }, children: [
2999
+ "Confirmation: ",
3000
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { style: { color: "var(--commerce-text)" }, children: result.confirmation_number })
3001
+ ] }),
3002
+ /* @__PURE__ */ jsxRuntime.jsx("p", { style: { color: "var(--commerce-text-muted)", margin: "0 0 1.5rem", fontSize: "0.875rem" }, children: "A confirmation email has been sent to your inbox." }),
3003
+ /* @__PURE__ */ jsxRuntime.jsx("button", { className: "skc-btn-primary", onClick: onClose, style: { maxWidth: 240 }, children: "Done" })
3004
+ ]
3005
+ }
3006
+ );
3007
+ }
3008
+ function ProductDetail({
3009
+ product: propProduct,
3010
+ slug,
3011
+ successUrl,
3012
+ cancelUrl,
3013
+ showGallery = true,
3014
+ showVariants = true,
3015
+ showQuantity = true,
3016
+ showSizeChart = true,
3017
+ showFeatures = true,
3018
+ showSpecifications = true,
3019
+ showDescription = true,
3020
+ showTrustBadges = true,
3021
+ showInventory = true,
3022
+ trustBadges,
3023
+ onAddToCart,
3024
+ onCheckoutSuccess,
3025
+ onCheckoutError,
3026
+ className = "",
3027
+ style: customStyle,
3028
+ layout = "horizontal"
3029
+ }) {
3030
+ const [product, setProduct] = React5.useState(propProduct || null);
3031
+ const [loading, setLoading] = React5.useState(!propProduct && !!slug);
3032
+ const [selectedVariant, setSelectedVariant] = React5.useState();
3033
+ const [quantity, setQuantity] = React5.useState(1);
3034
+ const [selectedImage, setSelectedImage] = React5.useState(0);
3035
+ const [checkoutState, setCheckoutState] = React5.useState("browsing");
3036
+ const [customer, setCustomer] = React5.useState({ name: "", email: "", phone: "" });
3037
+ const [shippingAddress, setShippingAddress] = React5.useState({
3038
+ street1: "",
3039
+ city: "",
3040
+ state: "",
3041
+ zip: "",
3042
+ country: "US"
3043
+ });
3044
+ const [shippingRates, setShippingRates] = React5.useState([]);
3045
+ const [selectedShippingRate, setSelectedShippingRate] = React5.useState(null);
3046
+ const [ratesLoading, setRatesLoading] = React5.useState(false);
3047
+ const [processorConfig, setProcessorConfig] = React5.useState(null);
3048
+ const [checkoutResult, setCheckoutResult] = React5.useState(null);
3049
+ const [checkoutError, setCheckoutError] = React5.useState(null);
3050
+ const [showStickyBar, setShowStickyBar] = React5.useState(false);
3051
+ const buyButtonRef = React5.useRef(null);
3052
+ const analytics = chunkGTLIGQDM_js.useAnalyticsOptional();
3053
+ React5.useEffect(() => {
3054
+ if (propProduct) {
3055
+ setProduct(propProduct);
3056
+ const dv = propProduct.variants?.find((v) => v.is_default) || propProduct.variants?.[0];
3057
+ setSelectedVariant(dv);
3058
+ return;
3059
+ }
3060
+ if (!slug) return;
3061
+ let cancelled = false;
3062
+ setLoading(true);
3063
+ fetchProductBySlug(slug).then((data) => {
3064
+ if (cancelled) return;
3065
+ setProduct(data);
3066
+ if (data?.variants?.length) {
3067
+ setSelectedVariant(data.variants.find((v) => v.is_default) || data.variants[0]);
3068
+ }
3069
+ setLoading(false);
3070
+ }).catch(() => {
3071
+ if (!cancelled) setLoading(false);
3072
+ });
3073
+ return () => {
3074
+ cancelled = true;
3075
+ };
3076
+ }, [propProduct, slug]);
3077
+ React5.useEffect(() => {
3078
+ if (!product || !analytics) return;
3079
+ analytics.trackEvent({
3080
+ name: "product_view",
3081
+ properties: {
3082
+ offering_id: product.id,
3083
+ name: product.name,
3084
+ price: product.price,
3085
+ type: product.type,
3086
+ category: product.category?.name
3087
+ }
3088
+ });
3089
+ }, [product?.id]);
3090
+ React5.useEffect(() => {
3091
+ if (!product) return;
3092
+ fetchProcessorConfig().then((c) => {
3093
+ if (c) setProcessorConfig(c);
3094
+ });
3095
+ }, [product?.id]);
3096
+ React5.useEffect(() => {
3097
+ if (!buyButtonRef.current) return;
3098
+ const observer = new IntersectionObserver(
3099
+ ([entry]) => setShowStickyBar(!entry.isIntersecting),
3100
+ { threshold: 0 }
3101
+ );
3102
+ observer.observe(buyButtonRef.current);
3103
+ return () => observer.disconnect();
3104
+ }, [product?.id, checkoutState]);
3105
+ React5.useEffect(() => {
3106
+ if (checkoutState === "browsing") return;
3107
+ const handleKey = (e) => {
3108
+ if (e.key === "Escape") setCheckoutState("browsing");
3109
+ };
3110
+ document.addEventListener("keydown", handleKey);
3111
+ return () => document.removeEventListener("keydown", handleKey);
3112
+ }, [checkoutState]);
3113
+ React5.useEffect(() => {
3114
+ if (checkoutState !== "browsing" && checkoutState !== "success") {
3115
+ document.body.style.overflow = "hidden";
3116
+ } else {
3117
+ document.body.style.overflow = "";
3118
+ }
3119
+ return () => {
3120
+ document.body.style.overflow = "";
3121
+ };
3122
+ }, [checkoutState]);
3123
+ const allImages = React5.useMemo(() => {
3124
+ if (!product) return [];
3125
+ return [
3126
+ product.featured_image_url,
3127
+ ...product.gallery_images || [],
3128
+ ...product.variants?.map((v) => v.image_url).filter(Boolean) || []
3129
+ ].filter(Boolean);
3130
+ }, [product]);
3131
+ if (!product) {
3132
+ if (loading) {
3133
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `skc-detail ${className}`, style: customStyle, children: [
3134
+ /* @__PURE__ */ jsxRuntime.jsx("style", { children: STYLE_BLOCK }),
3135
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", justifyContent: "center", alignItems: "center", minHeight: 400 }, children: /* @__PURE__ */ jsxRuntime.jsx(
3136
+ "div",
3137
+ {
3138
+ style: {
3139
+ width: 48,
3140
+ height: 48,
3141
+ border: "3px solid var(--commerce-border)",
3142
+ borderTopColor: "var(--commerce-accent)",
3143
+ borderRadius: "50%",
3144
+ animation: "skc-spin 1s linear infinite"
3145
+ }
3146
+ }
3147
+ ) })
3148
+ ] });
3149
+ }
3150
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `skc-detail ${className}`, style: customStyle, children: [
3151
+ /* @__PURE__ */ jsxRuntime.jsx("style", { children: STYLE_BLOCK }),
3152
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { textAlign: "center", padding: "4rem 2rem", color: "var(--commerce-text-secondary)" }, children: [
3153
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { style: { margin: 0, fontSize: "1.5rem", color: "var(--commerce-text)" }, children: "Product Not Found" }),
3154
+ /* @__PURE__ */ jsxRuntime.jsx("p", { style: { marginTop: "0.5rem" }, children: "The product you are looking for does not exist or has been removed." })
3155
+ ] })
3156
+ ] });
3157
+ }
3158
+ const currentPrice = selectedVariant?.price ?? product.price ?? 0;
3159
+ const compareAtPrice = product.compare_at_price;
3160
+ const hasDiscount = compareAtPrice != null && compareAtPrice > currentPrice;
3161
+ const discountPercent = hasDiscount ? Math.round((compareAtPrice - currentPrice) / compareAtPrice * 100) : 0;
3162
+ const inventoryCount = selectedVariant?.inventory_count ?? product.inventory_count;
3163
+ const isOutOfStock = product.track_inventory && inventoryCount != null && inventoryCount <= 0;
3164
+ const isLowStock = product.track_inventory && inventoryCount != null && inventoryCount > 0 && inventoryCount <= 5;
3165
+ const needsVariantSelection = (product.is_clothing || (product.variants?.length ?? 0) > 1) && !selectedVariant;
3166
+ const isEvent = product.type === "event";
3167
+ const isService = product.type === "service";
3168
+ const hasExternalUrl = !!product.external_url;
3169
+ const isFree = !product.price || product.price === 0;
3170
+ const needsShipping = !!processorConfig?.shipping_enabled && product.type === "product";
3171
+ const schedule = product.schedules?.[0] || product.next_schedule;
3172
+ const checkoutSteps = React5.useMemo(() => {
3173
+ const steps = ["customer-info"];
3174
+ if (needsShipping) {
3175
+ steps.push("shipping", "rates");
3176
+ }
3177
+ if (!isFree) {
3178
+ steps.push("payment");
3179
+ }
3180
+ return steps;
3181
+ }, [needsShipping, isFree]);
3182
+ const handleVariantChange = (variant) => {
3183
+ setSelectedVariant(variant);
3184
+ if (variant.image_url) {
3185
+ const idx = allImages.indexOf(variant.image_url);
3186
+ if (idx >= 0) setSelectedImage(idx);
3187
+ }
3188
+ };
3189
+ const handleAddToCart = () => {
3190
+ analytics?.trackEvent({
3191
+ name: "add_to_cart",
3192
+ properties: {
3193
+ offering_id: product.id,
3194
+ variant_id: selectedVariant?.id,
3195
+ quantity,
3196
+ price: currentPrice,
3197
+ name: product.name
3198
+ }
3199
+ });
3200
+ onAddToCart?.(product, selectedVariant, quantity);
3201
+ };
3202
+ const handleBuyNow = () => {
3203
+ if (hasExternalUrl) {
3204
+ window.open(product.external_url, "_blank", "noopener");
3205
+ return;
3206
+ }
3207
+ analytics?.trackEvent({
3208
+ name: "begin_checkout",
3209
+ properties: {
3210
+ offering_id: product.id,
3211
+ variant_id: selectedVariant?.id,
3212
+ quantity,
3213
+ price: currentPrice,
3214
+ name: product.name
3215
+ }
3216
+ });
3217
+ setCheckoutError(null);
3218
+ setCheckoutState("customer-info");
3219
+ };
3220
+ const handleCheckoutBack = () => {
3221
+ const currentIdx = checkoutSteps.indexOf(checkoutState);
3222
+ if (currentIdx <= 0) {
3223
+ setCheckoutState("browsing");
3224
+ } else {
3225
+ setCheckoutState(checkoutSteps[currentIdx - 1]);
3226
+ }
3227
+ };
3228
+ const handleCustomerNext = async () => {
3229
+ if (isFree && isEvent && schedule) {
3230
+ setCheckoutState("processing");
3231
+ try {
3232
+ const result = await registerForEvent(product.id, schedule.id, customer);
3233
+ if (result.success) {
3234
+ setCheckoutResult(result);
3235
+ setCheckoutState("success");
3236
+ onCheckoutSuccess?.(result);
3237
+ } else {
3238
+ setCheckoutError(result.error || "Registration failed");
3239
+ setCheckoutState("customer-info");
3240
+ }
3241
+ } catch (err) {
3242
+ setCheckoutError(err?.message || "Registration failed");
3243
+ setCheckoutState("customer-info");
3244
+ }
3245
+ return;
3246
+ }
3247
+ if (needsShipping) {
3248
+ setCheckoutState("shipping");
3249
+ } else if (!isFree) {
3250
+ setCheckoutState("payment");
3251
+ } else {
3252
+ setCheckoutState("processing");
3253
+ try {
3254
+ const result = await createCheckoutSession({
3255
+ offeringId: product.id,
3256
+ variantId: selectedVariant?.id,
3257
+ quantity,
3258
+ customer,
3259
+ successUrl: successUrl || window.location.href,
3260
+ cancelUrl: cancelUrl || window.location.href
3261
+ });
3262
+ if (result.success) {
3263
+ setCheckoutResult(result);
3264
+ setCheckoutState("success");
3265
+ onCheckoutSuccess?.(result);
3266
+ } else {
3267
+ setCheckoutError(result.error || "Checkout failed");
3268
+ setCheckoutState("customer-info");
3269
+ }
3270
+ } catch (err) {
3271
+ setCheckoutError(err?.message || "Checkout failed");
3272
+ setCheckoutState("customer-info");
3273
+ }
3274
+ }
3275
+ };
3276
+ const handleShippingNext = async () => {
3277
+ setRatesLoading(true);
3278
+ setCheckoutState("rates");
3279
+ try {
3280
+ const rates = await fetchShippingRates(shippingAddress, [
3281
+ { offering_id: product.id, quantity }
3282
+ ]);
3283
+ setShippingRates(rates);
3284
+ if (rates.length) setSelectedShippingRate(rates[0]);
3285
+ } catch {
3286
+ setShippingRates([]);
3287
+ } finally {
3288
+ setRatesLoading(false);
3289
+ }
3290
+ };
3291
+ const handleRatesNext = () => {
3292
+ if (!isFree) {
3293
+ setCheckoutState("payment");
3294
+ }
3295
+ };
3296
+ const handlePaymentSuccess = (result) => {
3297
+ setCheckoutResult(result);
3298
+ setCheckoutState("success");
3299
+ analytics?.trackEvent({
3300
+ name: "purchase",
3301
+ properties: {
3302
+ offering_id: product.id,
3303
+ variant_id: selectedVariant?.id,
3304
+ quantity,
3305
+ price: currentPrice,
3306
+ name: product.name,
3307
+ sale_id: result.sale_id
3308
+ }
3309
+ });
3310
+ onCheckoutSuccess?.(result);
3311
+ };
3312
+ const handlePaymentError = (error) => {
3313
+ setCheckoutError(error);
3314
+ onCheckoutError?.(error);
3315
+ };
3316
+ const handleCloseCheckout = () => {
3317
+ setCheckoutState("browsing");
3318
+ if (checkoutResult) {
3319
+ setCustomer({ name: "", email: "", phone: "" });
3320
+ setShippingAddress({ street1: "", city: "", state: "", zip: "", country: "US" });
3321
+ setShippingRates([]);
3322
+ setSelectedShippingRate(null);
3323
+ setCheckoutResult(null);
3324
+ }
3325
+ };
3326
+ const ctaLabel = React5.useMemo(() => {
3327
+ if (isOutOfStock) return "Out of Stock";
3328
+ if (needsVariantSelection) return product.is_clothing ? "Select Size" : "Select Option";
3329
+ if (hasExternalUrl) return product.type === "event" ? "Get Tickets" : "Learn More";
3330
+ if (isEvent) return isFree ? "Register Free" : "Get Tickets";
3331
+ if (isService) return "Book Now";
3332
+ return isFree ? "Get It Free" : "Buy Now";
3333
+ }, [isOutOfStock, needsVariantSelection, hasExternalUrl, isEvent, isService, isFree, product.is_clothing]);
3334
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `skc-detail ${className}`, style: customStyle, children: [
3335
+ /* @__PURE__ */ jsxRuntime.jsx("style", { children: STYLE_BLOCK }),
3336
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `skc-detail-layout${layout === "stacked" ? " skc-stacked" : ""}`, children: [
3337
+ showGallery && allImages.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
3338
+ ProductGallery,
3339
+ {
3340
+ images: allImages,
3341
+ productName: product.name,
3342
+ selectedIndex: selectedImage,
3343
+ onSelect: setSelectedImage
3344
+ }
3345
+ ),
3346
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
3347
+ product.category && /* @__PURE__ */ jsxRuntime.jsx(
3348
+ "div",
3349
+ {
3350
+ style: {
3351
+ fontSize: "0.75rem",
3352
+ fontWeight: 600,
3353
+ color: "var(--commerce-accent)",
3354
+ textTransform: "uppercase",
3355
+ letterSpacing: "0.05em",
3356
+ marginBottom: "0.375rem"
3357
+ },
3358
+ children: product.category.name
3359
+ }
3360
+ ),
3361
+ /* @__PURE__ */ jsxRuntime.jsx(
3362
+ "h1",
3363
+ {
3364
+ style: {
3365
+ margin: 0,
3366
+ fontSize: "1.875rem",
3367
+ fontWeight: 700,
3368
+ color: "var(--commerce-text)",
3369
+ lineHeight: 1.2
3370
+ },
3371
+ children: product.name
3372
+ }
3373
+ ),
3374
+ product.short_description && /* @__PURE__ */ jsxRuntime.jsx(
3375
+ "p",
3376
+ {
3377
+ style: {
3378
+ marginTop: "0.625rem",
3379
+ marginBottom: 0,
3380
+ fontSize: "1rem",
3381
+ color: "var(--commerce-text-secondary)",
3382
+ lineHeight: 1.6
3383
+ },
3384
+ children: product.short_description
1476
3385
  }
1477
- }
1478
- ) }),
1479
- allImages.length > 1 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "site-kit-product-detail__thumbnails", style: {
1480
- display: "flex",
1481
- gap: "0.5rem",
1482
- marginTop: "0.75rem",
1483
- overflowX: "auto"
1484
- }, children: allImages.map((img, idx) => /* @__PURE__ */ jsxRuntime.jsx(
1485
- "button",
1486
- {
1487
- onClick: () => setSelectedImage(idx),
1488
- style: {
1489
- flex: "0 0 auto",
1490
- width: "64px",
1491
- height: "64px",
1492
- borderRadius: "8px",
1493
- overflow: "hidden",
1494
- border: idx === selectedImage ? "2px solid #2563eb" : "2px solid transparent",
1495
- padding: 0,
1496
- cursor: "pointer",
1497
- backgroundColor: "#f9fafb"
1498
- },
1499
- children: /* @__PURE__ */ jsxRuntime.jsx(
1500
- "img",
1501
- {
1502
- src: img,
1503
- alt: `${product.name} ${idx + 1}`,
1504
- style: {
1505
- width: "100%",
1506
- height: "100%",
1507
- objectFit: "cover"
1508
- }
1509
- }
1510
- )
1511
- },
1512
- idx
1513
- )) })
1514
- ] }),
1515
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "site-kit-product-detail__info", children: [
1516
- product.category && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "site-kit-product-detail__category", style: {
1517
- fontSize: "0.875rem",
1518
- color: "#6b7280",
1519
- marginBottom: "0.5rem",
1520
- textTransform: "uppercase",
1521
- letterSpacing: "0.05em"
1522
- }, children: product.category.name }),
1523
- /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "site-kit-product-detail__title", style: {
1524
- margin: 0,
1525
- fontSize: "2rem",
1526
- fontWeight: 700,
1527
- color: "#111827",
1528
- lineHeight: 1.2
1529
- }, children: product.name }),
1530
- product.short_description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "site-kit-product-detail__short-description", style: {
1531
- marginTop: "0.75rem",
1532
- fontSize: "1rem",
1533
- color: "#4b5563",
1534
- lineHeight: 1.6
1535
- }, children: product.short_description }),
1536
- product.price_is_public && currentPrice !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "site-kit-product-detail__price", style: {
1537
- marginTop: "1rem",
1538
- display: "flex",
1539
- alignItems: "baseline",
1540
- gap: "0.75rem"
1541
- }, children: [
1542
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: {
1543
- fontSize: "1.75rem",
1544
- fontWeight: 700,
1545
- color: hasDiscount ? "#dc2626" : "#111827"
1546
- }, children: formatPrice(currentPrice, product.currency) }),
1547
- hasDiscount && /* @__PURE__ */ jsxRuntime.jsx("span", { style: {
1548
- fontSize: "1.25rem",
1549
- color: "#9ca3af",
1550
- textDecoration: "line-through"
1551
- }, children: formatPrice(compareAtPrice, product.currency) })
1552
- ] }),
1553
- product.track_inventory && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "site-kit-product-detail__stock", style: {
1554
- marginTop: "0.75rem",
1555
- fontSize: "0.875rem",
1556
- fontWeight: 500
1557
- }, children: isOutOfStock ? /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "#dc2626" }, children: "Out of Stock" }) : isLowStock ? /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { color: "#f59e0b" }, children: [
1558
- "Only ",
1559
- inventoryCount,
1560
- " left!"
1561
- ] }) : /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "#10b981" }, children: "In Stock" }) }),
1562
- showVariants && product.variants && (product.variants.length > 1 || product.is_clothing) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "site-kit-product-detail__variants", style: { marginTop: "1.5rem" }, children: [
1563
- /* @__PURE__ */ jsxRuntime.jsx("label", { style: {
1564
- display: "block",
1565
- fontSize: "0.875rem",
1566
- fontWeight: 600,
1567
- color: "#374151",
1568
- marginBottom: "0.5rem"
1569
- }, children: product.is_clothing ? "Size" : "Options" }),
1570
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexWrap: "wrap", gap: "0.5rem" }, children: product.variants.map((variant) => {
1571
- const variantOutOfStock = variant.track_inventory !== false && (variant.inventory_count ?? 0) <= 0;
1572
- return /* @__PURE__ */ jsxRuntime.jsxs(
3386
+ ),
3387
+ product.price_is_public && currentPrice != null && /* @__PURE__ */ jsxRuntime.jsxs(
3388
+ "div",
3389
+ {
3390
+ style: {
3391
+ marginTop: "1rem",
3392
+ display: "flex",
3393
+ alignItems: "center",
3394
+ gap: "0.75rem",
3395
+ flexWrap: "wrap"
3396
+ },
3397
+ children: [
3398
+ /* @__PURE__ */ jsxRuntime.jsx(
3399
+ "span",
3400
+ {
3401
+ style: {
3402
+ fontSize: "1.75rem",
3403
+ fontWeight: 700,
3404
+ color: hasDiscount ? "var(--commerce-danger)" : "var(--commerce-text)"
3405
+ },
3406
+ children: formatPrice(currentPrice, product.currency)
3407
+ }
3408
+ ),
3409
+ hasDiscount && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3410
+ /* @__PURE__ */ jsxRuntime.jsx(
3411
+ "span",
3412
+ {
3413
+ style: {
3414
+ fontSize: "1.125rem",
3415
+ color: "var(--commerce-text-muted)",
3416
+ textDecoration: "line-through"
3417
+ },
3418
+ children: formatPrice(compareAtPrice, product.currency)
3419
+ }
3420
+ ),
3421
+ /* @__PURE__ */ jsxRuntime.jsxs(
3422
+ "span",
3423
+ {
3424
+ style: {
3425
+ fontSize: "0.75rem",
3426
+ fontWeight: 700,
3427
+ color: "var(--commerce-accent-text)",
3428
+ background: "var(--commerce-danger)",
3429
+ padding: "2px 8px",
3430
+ borderRadius: 4
3431
+ },
3432
+ children: [
3433
+ "-",
3434
+ discountPercent,
3435
+ "%"
3436
+ ]
3437
+ }
3438
+ )
3439
+ ] }),
3440
+ product.billing_period && /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { fontSize: "0.875rem", color: "var(--commerce-text-muted)" }, children: [
3441
+ "/ ",
3442
+ product.billing_period
3443
+ ] })
3444
+ ]
3445
+ }
3446
+ ),
3447
+ product.track_inventory && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { marginTop: "0.75rem", display: "flex", alignItems: "center", gap: 6 }, children: isOutOfStock ? /* @__PURE__ */ jsxRuntime.jsxs(
3448
+ "span",
3449
+ {
3450
+ style: {
3451
+ fontSize: "0.8125rem",
3452
+ fontWeight: 600,
3453
+ color: "var(--commerce-danger)",
3454
+ display: "flex",
3455
+ alignItems: "center",
3456
+ gap: 4
3457
+ },
3458
+ children: [
3459
+ /* @__PURE__ */ jsxRuntime.jsx(IconAlert, {}),
3460
+ " Out of Stock"
3461
+ ]
3462
+ }
3463
+ ) : isLowStock ? /* @__PURE__ */ jsxRuntime.jsxs(
3464
+ "span",
3465
+ {
3466
+ className: "skc-pulse",
3467
+ style: {
3468
+ fontSize: "0.8125rem",
3469
+ fontWeight: 600,
3470
+ color: "var(--commerce-warning)",
3471
+ display: "flex",
3472
+ alignItems: "center",
3473
+ gap: 4
3474
+ },
3475
+ children: [
3476
+ /* @__PURE__ */ jsxRuntime.jsx(IconAlert, {}),
3477
+ " Only ",
3478
+ inventoryCount,
3479
+ " left!"
3480
+ ]
3481
+ }
3482
+ ) : /* @__PURE__ */ jsxRuntime.jsxs(
3483
+ "span",
3484
+ {
3485
+ style: {
3486
+ fontSize: "0.8125rem",
3487
+ fontWeight: 500,
3488
+ color: "var(--commerce-success)",
3489
+ display: "flex",
3490
+ alignItems: "center",
3491
+ gap: 4
3492
+ },
3493
+ children: [
3494
+ /* @__PURE__ */ jsxRuntime.jsx(IconCheck, {}),
3495
+ " In Stock"
3496
+ ]
3497
+ }
3498
+ ) }),
3499
+ isEvent && schedule && /* @__PURE__ */ jsxRuntime.jsx(EventInfoBlock, { product, schedule }),
3500
+ showVariants && product.variants && (product.variants.length > 1 || product.is_clothing) && /* @__PURE__ */ jsxRuntime.jsx(
3501
+ VariantSelector,
3502
+ {
3503
+ variants: product.variants,
3504
+ selected: selectedVariant,
3505
+ isClothing: !!product.is_clothing,
3506
+ showInventory,
3507
+ onSelect: handleVariantChange
3508
+ }
3509
+ ),
3510
+ showSizeChart && product.is_clothing && product.size_chart && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { marginTop: "0.625rem" }, children: /* @__PURE__ */ jsxRuntime.jsx(
3511
+ SizeChart,
3512
+ {
3513
+ chart: product.size_chart,
3514
+ selectedSize: selectedVariant?.options?.["Size"]
3515
+ }
3516
+ ) }),
3517
+ showQuantity && !isOutOfStock && !isEvent && !isService && /* @__PURE__ */ jsxRuntime.jsx(
3518
+ QuantitySelector,
3519
+ {
3520
+ quantity,
3521
+ max: product.track_inventory && inventoryCount != null ? inventoryCount : 99,
3522
+ onChange: setQuantity
3523
+ }
3524
+ ),
3525
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { marginTop: "1.5rem", display: "flex", flexDirection: "column", gap: "0.625rem" }, children: [
3526
+ /* @__PURE__ */ jsxRuntime.jsxs(
1573
3527
  "button",
1574
3528
  {
1575
- onClick: () => !variantOutOfStock && handleVariantChange(variant),
1576
- disabled: variantOutOfStock,
1577
- style: {
1578
- padding: "0.5rem 1rem",
1579
- borderRadius: "8px",
1580
- border: selectedVariant?.id === variant.id ? "2px solid #2563eb" : "1px solid #d1d5db",
1581
- backgroundColor: selectedVariant?.id === variant.id ? "#eff6ff" : "white",
1582
- color: variantOutOfStock ? "#9ca3af" : "#374151",
1583
- fontSize: "0.875rem",
1584
- fontWeight: 500,
1585
- cursor: variantOutOfStock ? "not-allowed" : "pointer",
1586
- opacity: variantOutOfStock ? 0.6 : 1,
1587
- transition: "all 0.15s ease"
1588
- },
3529
+ ref: buyButtonRef,
3530
+ className: "skc-btn-primary",
3531
+ onClick: handleBuyNow,
3532
+ disabled: isOutOfStock || needsVariantSelection,
3533
+ "aria-label": ctaLabel,
1589
3534
  children: [
1590
- variant.options?.Size || variant.name,
1591
- variantOutOfStock && " (Out of stock)"
3535
+ hasExternalUrl && /* @__PURE__ */ jsxRuntime.jsx(IconExternalLink, {}),
3536
+ ctaLabel
1592
3537
  ]
1593
- },
1594
- variant.id
1595
- );
1596
- }) })
1597
- ] }),
1598
- product.is_clothing && product.size_chart && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { marginTop: "0.75rem" }, children: /* @__PURE__ */ jsxRuntime.jsx(
1599
- SizeChart,
1600
- {
1601
- chart: product.size_chart,
1602
- selectedSize: selectedVariant?.options?.["Size"]
1603
- }
1604
- ) }),
1605
- showQuantity && !isOutOfStock && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "site-kit-product-detail__quantity", style: { marginTop: "1.5rem" }, children: [
1606
- /* @__PURE__ */ jsxRuntime.jsx("label", { style: {
1607
- display: "block",
1608
- fontSize: "0.875rem",
1609
- fontWeight: 600,
1610
- color: "#374151",
1611
- marginBottom: "0.5rem"
1612
- }, children: "Quantity" }),
1613
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", gap: "0.5rem" }, children: [
1614
- /* @__PURE__ */ jsxRuntime.jsx(
1615
- "button",
1616
- {
1617
- onClick: () => setQuantity(Math.max(1, quantity - 1)),
1618
- disabled: quantity <= 1,
1619
- style: {
1620
- width: "40px",
1621
- height: "40px",
1622
- borderRadius: "8px",
1623
- border: "1px solid #d1d5db",
1624
- backgroundColor: "white",
1625
- fontSize: "1.25rem",
1626
- cursor: quantity <= 1 ? "not-allowed" : "pointer",
1627
- opacity: quantity <= 1 ? 0.5 : 1
1628
- },
1629
- children: "\u2212"
1630
- }
1631
- ),
1632
- /* @__PURE__ */ jsxRuntime.jsx(
1633
- "input",
1634
- {
1635
- type: "number",
1636
- min: "1",
1637
- max: inventoryCount ?? 99,
1638
- value: quantity,
1639
- onChange: (e) => setQuantity(Math.max(1, parseInt(e.target.value) || 1)),
1640
- style: {
1641
- width: "60px",
1642
- height: "40px",
1643
- textAlign: "center",
1644
- borderRadius: "8px",
1645
- border: "1px solid #d1d5db",
1646
- fontSize: "1rem"
1647
- }
1648
3538
  }
1649
3539
  ),
1650
- /* @__PURE__ */ jsxRuntime.jsx(
3540
+ onAddToCart && !isEvent && !isService && !hasExternalUrl && /* @__PURE__ */ jsxRuntime.jsx(
1651
3541
  "button",
1652
3542
  {
1653
- onClick: () => setQuantity(quantity + 1),
1654
- disabled: product.track_inventory && inventoryCount !== void 0 && quantity >= inventoryCount,
1655
- style: {
1656
- width: "40px",
1657
- height: "40px",
1658
- borderRadius: "8px",
1659
- border: "1px solid #d1d5db",
1660
- backgroundColor: "white",
1661
- fontSize: "1.25rem",
1662
- cursor: "pointer"
1663
- },
1664
- children: "+"
3543
+ className: "skc-btn-secondary",
3544
+ onClick: handleAddToCart,
3545
+ disabled: isOutOfStock || needsVariantSelection,
3546
+ children: "Add to Cart"
1665
3547
  }
1666
3548
  )
1667
- ] })
1668
- ] }),
1669
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "site-kit-product-detail__actions", style: {
1670
- marginTop: "1.5rem",
1671
- display: "flex",
1672
- flexDirection: "column",
1673
- gap: "0.75rem"
1674
- }, children: [
1675
- showBuyNow && /* @__PURE__ */ jsxRuntime.jsx(
1676
- "button",
3549
+ ] }),
3550
+ checkoutError && checkoutState === "browsing" && /* @__PURE__ */ jsxRuntime.jsxs(
3551
+ "div",
1677
3552
  {
1678
- onClick: handleBuyNow,
1679
- disabled: isOutOfStock || checkingOut || needsVariantSelection,
1680
- className: "site-kit-product-detail__buy-now",
1681
3553
  style: {
1682
- padding: "1rem 2rem",
1683
- borderRadius: "8px",
1684
- border: "none",
1685
- backgroundColor: isOutOfStock ? "#d1d5db" : "#2563eb",
1686
- color: "white",
1687
- fontSize: "1rem",
1688
- fontWeight: 600,
1689
- cursor: isOutOfStock ? "not-allowed" : "pointer",
1690
- transition: "all 0.15s ease"
3554
+ marginTop: "0.75rem",
3555
+ padding: "0.75rem",
3556
+ background: "#fef2f2",
3557
+ border: "1px solid #fecaca",
3558
+ borderRadius: "var(--commerce-radius-sm)",
3559
+ color: "var(--commerce-danger)",
3560
+ fontSize: "0.875rem",
3561
+ display: "flex",
3562
+ alignItems: "flex-start",
3563
+ gap: 8
1691
3564
  },
1692
- children: checkingOut ? "Processing..." : needsVariantSelection ? "Select Size" : isOutOfStock ? "Out of Stock" : "Buy Now"
3565
+ children: [
3566
+ /* @__PURE__ */ jsxRuntime.jsx(IconAlert, {}),
3567
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: checkoutError })
3568
+ ]
1693
3569
  }
1694
3570
  ),
1695
- showAddToCart && onAddToCart && /* @__PURE__ */ jsxRuntime.jsx(
1696
- "button",
3571
+ showTrustBadges && /* @__PURE__ */ jsxRuntime.jsx(TrustBadges, { badges: trustBadges }),
3572
+ /* @__PURE__ */ jsxRuntime.jsx(
3573
+ ProductTabs,
1697
3574
  {
1698
- onClick: handleAddToCart,
1699
- disabled: isOutOfStock || needsVariantSelection,
1700
- className: "site-kit-product-detail__add-to-cart",
1701
- style: {
1702
- padding: "1rem 2rem",
1703
- borderRadius: "8px",
1704
- border: "2px solid #2563eb",
1705
- backgroundColor: "white",
1706
- color: "#2563eb",
1707
- fontSize: "1rem",
1708
- fontWeight: 600,
1709
- cursor: isOutOfStock || needsVariantSelection ? "not-allowed" : "pointer",
1710
- transition: "all 0.15s ease"
1711
- },
1712
- children: needsVariantSelection ? "Select Size" : isOutOfStock ? "Out of Stock" : "Add to Cart"
3575
+ features: product.features,
3576
+ specifications: product.specifications,
3577
+ description: product.long_description,
3578
+ showFeatures,
3579
+ showSpecifications,
3580
+ showDescription
1713
3581
  }
1714
3582
  )
1715
- ] }),
1716
- showFeatures && product.features && product.features.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "site-kit-product-detail__features", style: { marginTop: "2rem" }, children: [
1717
- /* @__PURE__ */ jsxRuntime.jsx("h3", { style: {
1718
- fontSize: "1rem",
1719
- fontWeight: 600,
1720
- color: "#111827",
1721
- marginBottom: "0.75rem"
1722
- }, children: "Features" }),
1723
- /* @__PURE__ */ jsxRuntime.jsx("ul", { style: {
1724
- margin: 0,
1725
- paddingLeft: "1.25rem",
1726
- display: "flex",
1727
- flexDirection: "column",
1728
- gap: "0.5rem"
1729
- }, children: product.features.map((feature, idx) => /* @__PURE__ */ jsxRuntime.jsx("li", { style: { color: "#4b5563", fontSize: "0.9375rem" }, children: feature }, idx)) })
1730
- ] }),
1731
- showSpecifications && product.specifications && Object.keys(product.specifications).length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "site-kit-product-detail__specifications", style: { marginTop: "2rem" }, children: [
1732
- /* @__PURE__ */ jsxRuntime.jsx("h3", { style: {
1733
- fontSize: "1rem",
1734
- fontWeight: 600,
1735
- color: "#111827",
1736
- marginBottom: "0.75rem"
1737
- }, children: "Specifications" }),
1738
- /* @__PURE__ */ jsxRuntime.jsx("dl", { style: {
1739
- margin: 0,
1740
- display: "grid",
1741
- gridTemplateColumns: "auto 1fr",
1742
- gap: "0.5rem 1rem"
1743
- }, children: Object.entries(product.specifications).map(([key, value]) => /* @__PURE__ */ jsxRuntime.jsxs(React5__default.default.Fragment, { children: [
1744
- /* @__PURE__ */ jsxRuntime.jsx("dt", { style: { color: "#6b7280", fontSize: "0.875rem" }, children: key }),
1745
- /* @__PURE__ */ jsxRuntime.jsx("dd", { style: { margin: 0, color: "#111827", fontSize: "0.875rem" }, children: value })
1746
- ] }, key)) })
1747
3583
  ] })
1748
3584
  ] }),
1749
- product.long_description && /* @__PURE__ */ jsxRuntime.jsxs(
3585
+ showStickyBar && checkoutState === "browsing" && !isOutOfStock && !needsVariantSelection && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "skc-sticky-bar", children: [
3586
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
3587
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontWeight: 600, fontSize: "0.875rem", color: "var(--commerce-text)", lineHeight: 1.2 }, children: product.name }),
3588
+ product.price_is_public && currentPrice != null && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontWeight: 700, fontSize: "1rem", color: hasDiscount ? "var(--commerce-danger)" : "var(--commerce-text)" }, children: formatPrice(currentPrice, product.currency) })
3589
+ ] }),
3590
+ /* @__PURE__ */ jsxRuntime.jsx(
3591
+ "button",
3592
+ {
3593
+ className: "skc-btn-primary",
3594
+ onClick: handleBuyNow,
3595
+ style: { width: "auto", padding: "0.625rem 1.5rem", fontSize: "0.875rem" },
3596
+ children: ctaLabel
3597
+ }
3598
+ )
3599
+ ] }),
3600
+ checkoutState !== "browsing" && /* @__PURE__ */ jsxRuntime.jsx(
1750
3601
  "div",
1751
3602
  {
1752
- className: "site-kit-product-detail__description",
1753
- style: {
1754
- gridColumn: "1 / -1",
1755
- marginTop: "2rem",
1756
- padding: "2rem",
1757
- backgroundColor: "#f9fafb",
1758
- borderRadius: "12px"
3603
+ className: "skc-checkout-overlay",
3604
+ onClick: (e) => {
3605
+ if (e.target === e.currentTarget && checkoutState !== "processing") {
3606
+ handleCloseCheckout();
3607
+ }
1759
3608
  },
1760
- children: [
1761
- /* @__PURE__ */ jsxRuntime.jsx("h2", { style: {
1762
- fontSize: "1.25rem",
1763
- fontWeight: 600,
1764
- color: "#111827",
1765
- marginBottom: "1rem"
1766
- }, children: "About This Product" }),
1767
- /* @__PURE__ */ jsxRuntime.jsx(
1768
- "div",
1769
- {
1770
- style: { color: "#4b5563", lineHeight: 1.7 },
1771
- dangerouslySetInnerHTML: { __html: product.long_description }
1772
- }
1773
- )
1774
- ]
3609
+ role: "dialog",
3610
+ "aria-modal": "true",
3611
+ "aria-label": "Checkout",
3612
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
3613
+ "div",
3614
+ {
3615
+ className: "skc-checkout-panel",
3616
+ onClick: (e) => e.stopPropagation(),
3617
+ children: [
3618
+ checkoutState !== "processing" && /* @__PURE__ */ jsxRuntime.jsx(
3619
+ "button",
3620
+ {
3621
+ onClick: handleCloseCheckout,
3622
+ "aria-label": "Close checkout",
3623
+ style: {
3624
+ position: "absolute",
3625
+ top: 12,
3626
+ right: 12,
3627
+ width: 32,
3628
+ height: 32,
3629
+ borderRadius: "50%",
3630
+ border: "none",
3631
+ background: "var(--commerce-surface)",
3632
+ cursor: "pointer",
3633
+ display: "flex",
3634
+ alignItems: "center",
3635
+ justifyContent: "center",
3636
+ zIndex: 10,
3637
+ color: "var(--commerce-text-secondary)"
3638
+ },
3639
+ children: /* @__PURE__ */ jsxRuntime.jsx(IconX, {})
3640
+ }
3641
+ ),
3642
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { padding: "1.5rem" }, children: [
3643
+ checkoutState !== "success" && checkoutState !== "processing" && /* @__PURE__ */ jsxRuntime.jsx(CheckoutStepIndicator, { current: checkoutState, steps: checkoutSteps }),
3644
+ checkoutState === "processing" && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { textAlign: "center", padding: "3rem 0" }, children: [
3645
+ /* @__PURE__ */ jsxRuntime.jsx(
3646
+ "div",
3647
+ {
3648
+ style: {
3649
+ width: 48,
3650
+ height: 48,
3651
+ border: "3px solid var(--commerce-border)",
3652
+ borderTopColor: "var(--commerce-accent)",
3653
+ borderRadius: "50%",
3654
+ animation: "skc-spin 0.8s linear infinite",
3655
+ margin: "0 auto 1.5rem"
3656
+ }
3657
+ }
3658
+ ),
3659
+ /* @__PURE__ */ jsxRuntime.jsx("p", { style: { color: "var(--commerce-text-secondary)", fontSize: "0.9375rem", margin: 0 }, children: "Processing your order..." })
3660
+ ] }),
3661
+ checkoutState === "success" && checkoutResult && /* @__PURE__ */ jsxRuntime.jsx(SuccessStep, { result: checkoutResult, product, onClose: handleCloseCheckout }),
3662
+ checkoutState === "customer-info" && /* @__PURE__ */ jsxRuntime.jsx(
3663
+ CustomerInfoStep,
3664
+ {
3665
+ customer,
3666
+ onChange: setCustomer,
3667
+ onNext: handleCustomerNext,
3668
+ onBack: handleCloseCheckout
3669
+ }
3670
+ ),
3671
+ checkoutState === "shipping" && /* @__PURE__ */ jsxRuntime.jsx(
3672
+ ShippingAddressStep,
3673
+ {
3674
+ address: shippingAddress,
3675
+ onChange: setShippingAddress,
3676
+ onNext: handleShippingNext,
3677
+ onBack: handleCheckoutBack,
3678
+ loading: ratesLoading
3679
+ }
3680
+ ),
3681
+ checkoutState === "rates" && /* @__PURE__ */ jsxRuntime.jsx(
3682
+ ShippingRatesStep,
3683
+ {
3684
+ rates: shippingRates,
3685
+ selected: selectedShippingRate,
3686
+ onSelect: setSelectedShippingRate,
3687
+ onNext: handleRatesNext,
3688
+ onBack: handleCheckoutBack,
3689
+ loading: ratesLoading,
3690
+ currency: product.currency
3691
+ }
3692
+ ),
3693
+ checkoutState === "payment" && /* @__PURE__ */ jsxRuntime.jsx(
3694
+ PaymentStep,
3695
+ {
3696
+ processor: processorConfig?.processor || null,
3697
+ config: processorConfig,
3698
+ product,
3699
+ variant: selectedVariant,
3700
+ quantity,
3701
+ customer,
3702
+ shippingRate: selectedShippingRate,
3703
+ shippingAddress: needsShipping ? shippingAddress : null,
3704
+ needsShipping,
3705
+ onBack: handleCheckoutBack,
3706
+ onSuccess: handlePaymentSuccess,
3707
+ onError: handlePaymentError,
3708
+ onProcessing: (p) => {
3709
+ if (p) setCheckoutState("processing");
3710
+ },
3711
+ successUrl,
3712
+ cancelUrl
3713
+ }
3714
+ ),
3715
+ checkoutError && checkoutState !== "payment" && checkoutState !== "processing" && checkoutState !== "success" && /* @__PURE__ */ jsxRuntime.jsxs(
3716
+ "div",
3717
+ {
3718
+ style: {
3719
+ marginTop: "0.75rem",
3720
+ padding: "0.75rem",
3721
+ background: "#fef2f2",
3722
+ border: "1px solid #fecaca",
3723
+ borderRadius: "var(--commerce-radius-sm)",
3724
+ color: "var(--commerce-danger)",
3725
+ fontSize: "0.875rem",
3726
+ display: "flex",
3727
+ alignItems: "flex-start",
3728
+ gap: 8
3729
+ },
3730
+ children: [
3731
+ /* @__PURE__ */ jsxRuntime.jsx(IconAlert, {}),
3732
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: checkoutError })
3733
+ ]
3734
+ }
3735
+ )
3736
+ ] })
3737
+ ]
3738
+ }
3739
+ )
1775
3740
  }
1776
3741
  )
1777
3742
  ] });
@@ -2186,8 +4151,6 @@ function ProductPage({
2186
4151
  ProductDetail,
2187
4152
  {
2188
4153
  product,
2189
- showAddToCart: !!onAddToCart,
2190
- showBuyNow: true,
2191
4154
  showQuantity: true,
2192
4155
  showVariants: true,
2193
4156
  showGallery: true,
@@ -3398,7 +5361,7 @@ function CalendarView({
3398
5361
  }, children: "Loading..." })
3399
5362
  ] });
3400
5363
  }
3401
- function loadSquareSDK(environment) {
5364
+ function loadSquareSDK2(environment) {
3402
5365
  return new Promise((resolve, reject) => {
3403
5366
  if (typeof window === "undefined") return reject(new Error("No window"));
3404
5367
  if (window.Square) return resolve();
@@ -3445,7 +5408,7 @@ function EventModal({
3445
5408
  if (config?.processor) setProcessor(config.processor);
3446
5409
  if (config?.processor === "square" && config.squareAppId && config.squareLocationId) {
3447
5410
  try {
3448
- await loadSquareSDK(config.squareEnvironment || "production");
5411
+ await loadSquareSDK2(config.squareEnvironment || "production");
3449
5412
  const Square = window.Square;
3450
5413
  const payments = Square.payments(config.squareAppId, config.squareLocationId);
3451
5414
  const card = await payments.card({
@@ -4108,8 +6071,8 @@ function EventsWidget({
4108
6071
  return;
4109
6072
  }
4110
6073
  async function loadEvents() {
4111
- const apiUrl = getApiUrl();
4112
- const apiKey = getApiKey();
6074
+ const apiUrl = getApiUrl2();
6075
+ const apiKey = getApiKey2();
4113
6076
  if (!apiKey) {
4114
6077
  if (retryCount < 3) {
4115
6078
  setTimeout(() => setRetryCount((c) => c + 1), 100);
@@ -4584,13 +6547,13 @@ function EventsWidget({
4584
6547
  )
4585
6548
  ] });
4586
6549
  }
4587
- function getApiUrl() {
6550
+ function getApiUrl2() {
4588
6551
  if (typeof window !== "undefined") {
4589
6552
  return window.__SITE_KIT_API_URL__ || "https://api.sonor.io";
4590
6553
  }
4591
6554
  return "https://api.sonor.io";
4592
6555
  }
4593
- function getApiKey() {
6556
+ function getApiKey2() {
4594
6557
  if (typeof window !== "undefined") {
4595
6558
  return window.__SITE_KIT_API_KEY__ || "";
4596
6559
  }
@@ -4614,6 +6577,7 @@ exports.RegistrationForm = RegistrationForm;
4614
6577
  exports.SizeChart = SizeChart;
4615
6578
  exports.UpcomingEvents = UpcomingEvents;
4616
6579
  exports.createCheckoutSession = createCheckoutSession;
6580
+ exports.createPaymentIntent = createPaymentIntent;
4617
6581
  exports.fetchActiveProcessor = fetchActiveProcessor;
4618
6582
  exports.fetchCategories = fetchCategories;
4619
6583
  exports.fetchLatestOffering = fetchLatestOffering;
@@ -4639,5 +6603,5 @@ exports.isEventSoldOut = isEventSoldOut;
4639
6603
  exports.registerForEvent = registerForEvent;
4640
6604
  exports.useEventModal = useEventModal;
4641
6605
  exports.validateAddress = validateAddress;
4642
- //# sourceMappingURL=chunk-MSBWUOIU.js.map
4643
- //# sourceMappingURL=chunk-MSBWUOIU.js.map
6606
+ //# sourceMappingURL=chunk-JDC3UINW.js.map
6607
+ //# sourceMappingURL=chunk-JDC3UINW.js.map