@cimplify/sdk 0.22.5 → 0.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/dist/advanced.d.mts +2 -2
  2. package/dist/advanced.d.ts +2 -2
  3. package/dist/advanced.js +21 -21
  4. package/dist/advanced.mjs +2 -2
  5. package/dist/{chunk-4Z74TIJP.mjs → chunk-E3HC2YAE.mjs} +32 -1
  6. package/dist/{chunk-Y2BD2XFJ.mjs → chunk-H34GSEGR.mjs} +2 -2
  7. package/dist/{chunk-YMXFVI3N.js → chunk-I4F4Y3D4.js} +20 -20
  8. package/dist/{chunk-KLRTWBDF.js → chunk-IYQGGFVQ.js} +39 -39
  9. package/dist/{chunk-5FK7MDHS.js → chunk-PEDLCL72.js} +34 -0
  10. package/dist/{chunk-DNN5VN64.mjs → chunk-TBZLJPM4.mjs} +1 -1
  11. package/dist/{index-uvCOGdBp.d.ts → index-CJZMsbDi.d.ts} +1 -1
  12. package/dist/index-DCoxHrmr.d.mts +70 -0
  13. package/dist/{index-v1NFqZFG.d.mts → index-DIHoZUz_.d.mts} +1 -1
  14. package/dist/index-DT0Mzy8v.d.ts +70 -0
  15. package/dist/index.d.mts +5 -5
  16. package/dist/index.d.ts +5 -5
  17. package/dist/index.js +110 -98
  18. package/dist/index.mjs +3 -3
  19. package/dist/{payment-DazihbCY.d.mts → payment-DqiwuLma.d.mts} +9 -1
  20. package/dist/{payment-DazihbCY.d.ts → payment-DqiwuLma.d.ts} +9 -1
  21. package/dist/{price-5_L8WK6Q.d.ts → price-BZlddg1A.d.ts} +1 -1
  22. package/dist/{price-BcHVTqqu.d.mts → price-DVQrpE7j.d.mts} +1 -1
  23. package/dist/react.d.mts +106 -25
  24. package/dist/react.d.ts +106 -25
  25. package/dist/react.js +1063 -240
  26. package/dist/react.mjs +990 -182
  27. package/dist/styles.css +1 -1
  28. package/dist/utils.d.mts +4 -64
  29. package/dist/utils.d.ts +4 -64
  30. package/dist/utils.js +28 -28
  31. package/dist/utils.mjs +1 -1
  32. package/package.json +1 -1
  33. package/registry/product-customizer.json +1 -1
  34. package/registry/product-page.json +1 -1
package/dist/react.js CHANGED
@@ -1,9 +1,9 @@
1
1
  "use client";
2
2
  'use strict';
3
3
 
4
- var chunkKLRTWBDF_js = require('./chunk-KLRTWBDF.js');
5
- var chunkYMXFVI3N_js = require('./chunk-YMXFVI3N.js');
6
- var chunk5FK7MDHS_js = require('./chunk-5FK7MDHS.js');
4
+ var chunkIYQGGFVQ_js = require('./chunk-IYQGGFVQ.js');
5
+ var chunkI4F4Y3D4_js = require('./chunk-I4F4Y3D4.js');
6
+ var chunkPEDLCL72_js = require('./chunk-PEDLCL72.js');
7
7
  var React3 = require('react');
8
8
  var jsxRuntime = require('react/jsx-runtime');
9
9
  var numberField = require('@base-ui/react/number-field');
@@ -475,13 +475,13 @@ function buildLineKey(productId, options) {
475
475
  return parts.join("|");
476
476
  }
477
477
  function calculateLineSubtotal(item) {
478
- let unitPrice = chunk5FK7MDHS_js.parsePrice(item.product.default_price);
478
+ let unitPrice = chunkPEDLCL72_js.parsePrice(item.product.default_price);
479
479
  if (item.variant?.price_adjustment) {
480
- unitPrice += chunk5FK7MDHS_js.parsePrice(item.variant.price_adjustment);
480
+ unitPrice += chunkPEDLCL72_js.parsePrice(item.variant.price_adjustment);
481
481
  }
482
482
  for (const option of item.addOnOptions || []) {
483
483
  if (option.default_price) {
484
- unitPrice += chunk5FK7MDHS_js.parsePrice(option.default_price);
484
+ unitPrice += chunkPEDLCL72_js.parsePrice(option.default_price);
485
485
  }
486
486
  }
487
487
  return roundMoney(unitPrice * item.quantity);
@@ -1061,7 +1061,7 @@ var DEFAULT_COUNTRY = "US";
1061
1061
  function createDefaultClient() {
1062
1062
  const processRef = globalThis.process;
1063
1063
  const envPublicKey = processRef?.env?.NEXT_PUBLIC_CIMPLIFY_PUBLIC_KEY || "";
1064
- return chunkKLRTWBDF_js.createCimplifyClient({ publicKey: envPublicKey });
1064
+ return chunkIYQGGFVQ_js.createCimplifyClient({ publicKey: envPublicKey });
1065
1065
  }
1066
1066
  function getStoredLocationId() {
1067
1067
  if (typeof window === "undefined" || !window.localStorage) {
@@ -1144,7 +1144,7 @@ function CimplifyProvider({
1144
1144
  const setDisplayCurrency = React3.useCallback(
1145
1145
  (currency) => {
1146
1146
  const normalized = currency?.trim().toUpperCase() || null;
1147
- if (normalized && !chunk5FK7MDHS_js.isSupportedCurrency(normalized)) {
1147
+ if (normalized && !chunkPEDLCL72_js.isSupportedCurrency(normalized)) {
1148
1148
  return;
1149
1149
  }
1150
1150
  setDisplayCurrencyOverride(normalized);
@@ -1706,7 +1706,7 @@ function Price({ amount, className, prefix }) {
1706
1706
  const { displayCurrency, convertPrice } = useCimplify();
1707
1707
  return /* @__PURE__ */ jsxRuntime.jsxs("span", { className, children: [
1708
1708
  prefix,
1709
- chunk5FK7MDHS_js.formatPrice(convertPrice(amount), displayCurrency)
1709
+ chunkPEDLCL72_js.formatPrice(convertPrice(amount), displayCurrency)
1710
1710
  ] });
1711
1711
  }
1712
1712
  function createCachedQuery(config) {
@@ -2713,16 +2713,16 @@ function useProductPrice(input) {
2713
2713
  if (bundleTotalPrice != null) {
2714
2714
  unitPrice = bundleTotalPrice;
2715
2715
  } else if (compositePrice) {
2716
- unitPrice = chunk5FK7MDHS_js.parsePrice(compositePrice.final_price);
2716
+ unitPrice = chunkPEDLCL72_js.parsePrice(compositePrice.final_price);
2717
2717
  } else {
2718
- unitPrice = chunk5FK7MDHS_js.parsePrice(product.default_price);
2718
+ unitPrice = chunkPEDLCL72_js.parsePrice(product.default_price);
2719
2719
  if (variant?.price_adjustment) {
2720
- unitPrice += chunk5FK7MDHS_js.parsePrice(variant.price_adjustment);
2720
+ unitPrice += chunkPEDLCL72_js.parsePrice(variant.price_adjustment);
2721
2721
  }
2722
2722
  if (addOnOptions) {
2723
2723
  for (const option of addOnOptions) {
2724
2724
  if (option.default_price) {
2725
- unitPrice += chunk5FK7MDHS_js.parsePrice(option.default_price);
2725
+ unitPrice += chunkPEDLCL72_js.parsePrice(option.default_price);
2726
2726
  }
2727
2727
  }
2728
2728
  }
@@ -3212,19 +3212,19 @@ function AuthElement({
3212
3212
  }, [onReady, onAuthenticated, onRequiresOtp, onError]);
3213
3213
  React3.useEffect(() => {
3214
3214
  if (!elements || !containerRef.current) return;
3215
- const element = elements.create(chunkYMXFVI3N_js.ELEMENT_TYPES.AUTH, { prefillEmail });
3215
+ const element = elements.create(chunkI4F4Y3D4_js.ELEMENT_TYPES.AUTH, { prefillEmail });
3216
3216
  elementRef.current = element;
3217
- element.on(chunkYMXFVI3N_js.EVENT_TYPES.READY, () => onReadyRef.current?.());
3217
+ element.on(chunkI4F4Y3D4_js.EVENT_TYPES.READY, () => onReadyRef.current?.());
3218
3218
  element.on(
3219
- chunkYMXFVI3N_js.EVENT_TYPES.AUTHENTICATED,
3219
+ chunkI4F4Y3D4_js.EVENT_TYPES.AUTHENTICATED,
3220
3220
  (data) => onAuthenticatedRef.current?.(data)
3221
3221
  );
3222
3222
  element.on(
3223
- chunkYMXFVI3N_js.EVENT_TYPES.REQUIRES_OTP,
3223
+ chunkI4F4Y3D4_js.EVENT_TYPES.REQUIRES_OTP,
3224
3224
  (data) => onRequiresOtpRef.current?.(data)
3225
3225
  );
3226
3226
  element.on(
3227
- chunkYMXFVI3N_js.EVENT_TYPES.ERROR,
3227
+ chunkI4F4Y3D4_js.EVENT_TYPES.ERROR,
3228
3228
  (data) => onErrorRef.current?.(data)
3229
3229
  );
3230
3230
  element.mount(containerRef.current);
@@ -3253,15 +3253,15 @@ function AddressElement({
3253
3253
  }, [onReady, onChange, onError]);
3254
3254
  React3.useEffect(() => {
3255
3255
  if (!elements || !containerRef.current) return;
3256
- const element = elements.create(chunkYMXFVI3N_js.ELEMENT_TYPES.ADDRESS, { mode });
3256
+ const element = elements.create(chunkI4F4Y3D4_js.ELEMENT_TYPES.ADDRESS, { mode });
3257
3257
  elementRef.current = element;
3258
- element.on(chunkYMXFVI3N_js.EVENT_TYPES.READY, () => onReadyRef.current?.());
3258
+ element.on(chunkI4F4Y3D4_js.EVENT_TYPES.READY, () => onReadyRef.current?.());
3259
3259
  element.on(
3260
- chunkYMXFVI3N_js.EVENT_TYPES.CHANGE,
3260
+ chunkI4F4Y3D4_js.EVENT_TYPES.CHANGE,
3261
3261
  (data) => onChangeRef.current?.(data)
3262
3262
  );
3263
3263
  element.on(
3264
- chunkYMXFVI3N_js.EVENT_TYPES.ERROR,
3264
+ chunkI4F4Y3D4_js.EVENT_TYPES.ERROR,
3265
3265
  (data) => onErrorRef.current?.(data)
3266
3266
  );
3267
3267
  element.mount(containerRef.current);
@@ -3291,15 +3291,15 @@ function PaymentElement({
3291
3291
  }, [onReady, onChange, onError]);
3292
3292
  React3.useEffect(() => {
3293
3293
  if (!elements || !containerRef.current) return;
3294
- const element = elements.create(chunkYMXFVI3N_js.ELEMENT_TYPES.PAYMENT, { amount, currency });
3294
+ const element = elements.create(chunkI4F4Y3D4_js.ELEMENT_TYPES.PAYMENT, { amount, currency });
3295
3295
  elementRef.current = element;
3296
- element.on(chunkYMXFVI3N_js.EVENT_TYPES.READY, () => onReadyRef.current?.());
3296
+ element.on(chunkI4F4Y3D4_js.EVENT_TYPES.READY, () => onReadyRef.current?.());
3297
3297
  element.on(
3298
- chunkYMXFVI3N_js.EVENT_TYPES.CHANGE,
3298
+ chunkI4F4Y3D4_js.EVENT_TYPES.CHANGE,
3299
3299
  (data) => onChangeRef.current?.(data)
3300
3300
  );
3301
3301
  element.on(
3302
- chunkYMXFVI3N_js.EVENT_TYPES.ERROR,
3302
+ chunkI4F4Y3D4_js.EVENT_TYPES.ERROR,
3303
3303
  (data) => onErrorRef.current?.(data)
3304
3304
  );
3305
3305
  element.mount(containerRef.current);
@@ -3458,7 +3458,7 @@ function VariantSelector({
3458
3458
  if (!variants || variants.length <= 1) {
3459
3459
  return null;
3460
3460
  }
3461
- basePrice != null ? chunk5FK7MDHS_js.parsePrice(basePrice) : 0;
3461
+ basePrice != null ? chunkPEDLCL72_js.parsePrice(basePrice) : 0;
3462
3462
  if (variantAxes && variantAxes.length > 0) {
3463
3463
  return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-variant-selector": true, className: cn("space-y-5", className, classNames?.root), children: variantAxes.map((axis) => {
3464
3464
  const labelId = `${idPrefix}-axis-${axis.id}`;
@@ -3534,7 +3534,7 @@ function VariantSelector({
3534
3534
  className: cn("divide-y divide-border", classNames?.list),
3535
3535
  children: variants.map((variant) => {
3536
3536
  const isSelected = selectedVariantId === variant.id;
3537
- const adjustment = chunk5FK7MDHS_js.parsePrice(variant.price_adjustment);
3537
+ const adjustment = chunkPEDLCL72_js.parsePrice(variant.price_adjustment);
3538
3538
  return /* @__PURE__ */ jsxRuntime.jsxs(
3539
3539
  radio.Radio.Root,
3540
3540
  {
@@ -3562,7 +3562,7 @@ function VariantSelector({
3562
3562
  {
3563
3563
  "data-cimplify-variant-name": true,
3564
3564
  className: cn("flex-1 min-w-0 text-sm", classNames?.name),
3565
- children: chunkKLRTWBDF_js.getVariantDisplayName(variant, productName)
3565
+ children: chunkIYQGGFVQ_js.getVariantDisplayName(variant, productName)
3566
3566
  }
3567
3567
  ),
3568
3568
  /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-cimplify-variant-pricing": true, className: cn("text-sm text-muted-foreground", classNames?.pricing), children: [
@@ -3800,16 +3800,16 @@ function BundleSelector({
3800
3800
  }, [components, selections, onReady]);
3801
3801
  const totalPrice = React3.useMemo(() => {
3802
3802
  if (pricingType === "fixed" && bundlePrice) {
3803
- return chunk5FK7MDHS_js.parsePrice(bundlePrice);
3803
+ return chunkPEDLCL72_js.parsePrice(bundlePrice);
3804
3804
  }
3805
3805
  const componentsTotal = components.reduce((sum, comp) => {
3806
3806
  return sum + getComponentPrice(comp, variantChoices[comp.id]) * comp.quantity;
3807
3807
  }, 0);
3808
3808
  if (pricingType === "percentage_discount" && discountValue) {
3809
- return componentsTotal * (1 - chunk5FK7MDHS_js.parsePrice(discountValue) / 100);
3809
+ return componentsTotal * (1 - chunkPEDLCL72_js.parsePrice(discountValue) / 100);
3810
3810
  }
3811
3811
  if (pricingType === "fixed_discount" && discountValue) {
3812
- return componentsTotal - chunk5FK7MDHS_js.parsePrice(discountValue);
3812
+ return componentsTotal - chunkPEDLCL72_js.parsePrice(discountValue);
3813
3813
  }
3814
3814
  return componentsTotal;
3815
3815
  }, [components, variantChoices, pricingType, bundlePrice, discountValue]);
@@ -3870,15 +3870,15 @@ function BundleSelector({
3870
3870
  }
3871
3871
  function getComponentPrice(component, selectedVariantId) {
3872
3872
  if (!selectedVariantId || component.available_variants.length === 0) {
3873
- return chunk5FK7MDHS_js.parsePrice(component.effective_price);
3873
+ return chunkPEDLCL72_js.parsePrice(component.effective_price);
3874
3874
  }
3875
3875
  if (selectedVariantId === component.variant_id) {
3876
- return chunk5FK7MDHS_js.parsePrice(component.effective_price);
3876
+ return chunkPEDLCL72_js.parsePrice(component.effective_price);
3877
3877
  }
3878
3878
  const bakedAdj = component.variant_id ? component.available_variants.find((v) => v.id === component.variant_id) : void 0;
3879
3879
  const selectedAdj = component.available_variants.find((v) => v.id === selectedVariantId);
3880
- if (!selectedAdj) return chunk5FK7MDHS_js.parsePrice(component.effective_price);
3881
- return chunk5FK7MDHS_js.parsePrice(component.effective_price) - chunk5FK7MDHS_js.parsePrice(bakedAdj?.price_adjustment ?? "0") + chunk5FK7MDHS_js.parsePrice(selectedAdj.price_adjustment);
3880
+ if (!selectedAdj) return chunkPEDLCL72_js.parsePrice(component.effective_price);
3881
+ return chunkPEDLCL72_js.parsePrice(component.effective_price) - chunkPEDLCL72_js.parsePrice(bakedAdj?.price_adjustment ?? "0") + chunkPEDLCL72_js.parsePrice(selectedAdj.price_adjustment);
3882
3882
  }
3883
3883
  function formatDuration(minutes, unit) {
3884
3884
  if (unit === "hours" || !unit && minutes >= 60 && minutes % 60 === 0) {
@@ -3991,7 +3991,7 @@ function BundleComponentCard({
3991
3991
  className: cn("mt-3 divide-y divide-border", classNames?.variantPicker),
3992
3992
  children: component.available_variants.map((variant) => {
3993
3993
  const isSelected = selectedVariantId === variant.id;
3994
- const adjustment = chunk5FK7MDHS_js.parsePrice(variant.price_adjustment);
3994
+ const adjustment = chunkPEDLCL72_js.parsePrice(variant.price_adjustment);
3995
3995
  return /* @__PURE__ */ jsxRuntime.jsxs(
3996
3996
  radio.Radio.Root,
3997
3997
  {
@@ -4437,7 +4437,7 @@ function CompositeSelector({
4437
4437
  "data-cimplify-composite-summary": true,
4438
4438
  className: cn("border-t border-border pt-4 space-y-1 text-sm", classNames?.summary),
4439
4439
  children: [
4440
- chunk5FK7MDHS_js.parsePrice(priceResult.base_price) !== 0 && /* @__PURE__ */ jsxRuntime.jsxs(
4440
+ chunkPEDLCL72_js.parsePrice(priceResult.base_price) !== 0 && /* @__PURE__ */ jsxRuntime.jsxs(
4441
4441
  "div",
4442
4442
  {
4443
4443
  "data-cimplify-composite-summary-line": true,
@@ -4448,7 +4448,7 @@ function CompositeSelector({
4448
4448
  ]
4449
4449
  }
4450
4450
  ),
4451
- chunk5FK7MDHS_js.parsePrice(priceResult.components_total) !== 0 && /* @__PURE__ */ jsxRuntime.jsxs(
4451
+ chunkPEDLCL72_js.parsePrice(priceResult.components_total) !== 0 && /* @__PURE__ */ jsxRuntime.jsxs(
4452
4452
  "div",
4453
4453
  {
4454
4454
  "data-cimplify-composite-summary-line": true,
@@ -4491,6 +4491,195 @@ function CompositeSelector({
4491
4491
  )
4492
4492
  ] });
4493
4493
  }
4494
+ var FREQUENCY_LABELS = {
4495
+ weekly: "Weekly",
4496
+ monthly: "Monthly",
4497
+ quarterly: "Quarterly",
4498
+ annually: "Annually"
4499
+ };
4500
+ function formatMarkup(plan) {
4501
+ if (!plan.markup_type || plan.markup_amount == null) return null;
4502
+ if (plan.markup_type === "percentage") return `+${plan.markup_amount}%`;
4503
+ return null;
4504
+ }
4505
+ function BillingPlanSelector({
4506
+ productId,
4507
+ plans: plansProp,
4508
+ onPlanSelect,
4509
+ selectedPlanId,
4510
+ showOneTimePurchase = false,
4511
+ oneTimePurchaseLabel = "One-time purchase",
4512
+ renderPlan,
4513
+ className,
4514
+ classNames
4515
+ }) {
4516
+ const { plans: fetched, isLoading } = useBillingPlans(productId, {
4517
+ enabled: plansProp === void 0
4518
+ });
4519
+ const plans = plansProp ?? fetched;
4520
+ if (isLoading && plans.length === 0) {
4521
+ return /* @__PURE__ */ jsxRuntime.jsx(
4522
+ "div",
4523
+ {
4524
+ "data-cimplify-billing-plan-selector": true,
4525
+ "aria-busy": "true",
4526
+ className: cn(className, classNames?.root, classNames?.loading)
4527
+ }
4528
+ );
4529
+ }
4530
+ if (plans.length === 0 && !showOneTimePurchase) {
4531
+ return null;
4532
+ }
4533
+ const isOneTimePurchaseSelected = selectedPlanId === null;
4534
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-billing-plan-selector": true, className: cn(className, classNames?.root), children: [
4535
+ showOneTimePurchase && /* @__PURE__ */ jsxRuntime.jsx(
4536
+ "button",
4537
+ {
4538
+ type: "button",
4539
+ onClick: () => onPlanSelect?.(null),
4540
+ "data-cimplify-billing-plan": true,
4541
+ "data-plan-type": "one-time",
4542
+ "data-active": isOneTimePurchaseSelected || void 0,
4543
+ "aria-pressed": isOneTimePurchaseSelected,
4544
+ className: cn(
4545
+ classNames?.plan,
4546
+ isOneTimePurchaseSelected && classNames?.activePlan
4547
+ ),
4548
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-billing-frequency": true, className: classNames?.frequency, children: oneTimePurchaseLabel })
4549
+ }
4550
+ ),
4551
+ plans.map((plan) => {
4552
+ const isActive = selectedPlanId === plan.id;
4553
+ const markup = formatMarkup(plan);
4554
+ return /* @__PURE__ */ jsxRuntime.jsx(
4555
+ "button",
4556
+ {
4557
+ type: "button",
4558
+ onClick: () => onPlanSelect?.(plan),
4559
+ "data-cimplify-billing-plan": true,
4560
+ "data-plan-type": plan.plan_type,
4561
+ "data-active": isActive || void 0,
4562
+ "aria-pressed": isActive,
4563
+ className: cn(classNames?.plan, isActive && classNames?.activePlan),
4564
+ children: renderPlan ? renderPlan(plan, isActive) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4565
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-billing-frequency": true, className: classNames?.frequency, children: FREQUENCY_LABELS[plan.frequency] }),
4566
+ markup && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-billing-markup": true, className: classNames?.price, children: markup }),
4567
+ plan.markup_type === "fixed" && plan.markup_amount != null && /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-cimplify-billing-markup": true, className: classNames?.price, children: [
4568
+ "+",
4569
+ /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: plan.markup_amount })
4570
+ ] }),
4571
+ plan.trial_days > 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-cimplify-billing-trial": true, className: classNames?.trialBadge, children: [
4572
+ plan.trial_days,
4573
+ "-day trial"
4574
+ ] }),
4575
+ plan.setup_fee > 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-cimplify-billing-setup-fee": true, className: classNames?.setupFee, children: [
4576
+ "Setup fee: ",
4577
+ /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: plan.setup_fee })
4578
+ ] }),
4579
+ plan.plan_type === "installment" && plan.installment_periods != null && /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-cimplify-billing-periods": true, children: [
4580
+ plan.installment_periods,
4581
+ " payments"
4582
+ ] })
4583
+ ] })
4584
+ },
4585
+ plan.id
4586
+ );
4587
+ })
4588
+ ] });
4589
+ }
4590
+ function formatRange(tier) {
4591
+ if (tier.max_quantity != null) {
4592
+ return `${tier.min_quantity}\u2013${tier.max_quantity} units`;
4593
+ }
4594
+ return `${tier.min_quantity}+ units`;
4595
+ }
4596
+ function isActiveTier(tier, quantity) {
4597
+ if (quantity < tier.min_quantity) return false;
4598
+ if (tier.max_quantity != null && quantity > tier.max_quantity) return false;
4599
+ return true;
4600
+ }
4601
+ function VolumePricing({
4602
+ tiers,
4603
+ currentQuantity,
4604
+ defaultOpen = false,
4605
+ className,
4606
+ classNames
4607
+ }) {
4608
+ if (tiers.length < 2) return null;
4609
+ const sorted = [...tiers].sort((a, b) => a.min_quantity - b.min_quantity);
4610
+ return /* @__PURE__ */ jsxRuntime.jsxs(
4611
+ "details",
4612
+ {
4613
+ open: defaultOpen || void 0,
4614
+ "data-cimplify-volume-pricing": true,
4615
+ className: cn("border border-border", className, classNames?.root),
4616
+ children: [
4617
+ /* @__PURE__ */ jsxRuntime.jsxs(
4618
+ "summary",
4619
+ {
4620
+ "data-cimplify-volume-pricing-trigger": true,
4621
+ className: cn(
4622
+ "flex items-center justify-between px-4 py-3 cursor-pointer select-none text-sm font-medium list-none [&::-webkit-details-marker]:hidden",
4623
+ classNames?.trigger
4624
+ ),
4625
+ children: [
4626
+ "Volume pricing",
4627
+ /* @__PURE__ */ jsxRuntime.jsx(
4628
+ "svg",
4629
+ {
4630
+ viewBox: "0 0 12 12",
4631
+ fill: "none",
4632
+ "aria-hidden": "true",
4633
+ className: cn(
4634
+ "w-3.5 h-3.5 text-muted-foreground transition-transform [[open]>&]:rotate-180",
4635
+ classNames?.triggerIcon
4636
+ ),
4637
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M2 4.5l4 4 4-4", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })
4638
+ }
4639
+ )
4640
+ ]
4641
+ }
4642
+ ),
4643
+ /* @__PURE__ */ jsxRuntime.jsx(
4644
+ "div",
4645
+ {
4646
+ "data-cimplify-volume-pricing-panel": true,
4647
+ className: cn("border-t border-border divide-y divide-border", classNames?.panel),
4648
+ children: sorted.map((tier, i) => {
4649
+ const active = currentQuantity != null && isActiveTier(tier, currentQuantity);
4650
+ return /* @__PURE__ */ jsxRuntime.jsxs(
4651
+ "div",
4652
+ {
4653
+ "data-cimplify-volume-pricing-tier": true,
4654
+ "data-active": active || void 0,
4655
+ className: cn(
4656
+ "flex items-center justify-between px-4 py-2.5 text-sm",
4657
+ active ? cn("bg-primary/5 font-medium", classNames?.tierActive) : classNames?.tier
4658
+ ),
4659
+ children: [
4660
+ /* @__PURE__ */ jsxRuntime.jsx(
4661
+ "span",
4662
+ {
4663
+ "data-cimplify-volume-pricing-range": true,
4664
+ className: cn("text-muted-foreground", classNames?.tierRange),
4665
+ children: formatRange(tier)
4666
+ }
4667
+ ),
4668
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-cimplify-volume-pricing-price": true, className: classNames?.tierPrice, children: [
4669
+ /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: tier.unit_price, prefix: "" }),
4670
+ " /ea"
4671
+ ] })
4672
+ ]
4673
+ },
4674
+ i
4675
+ );
4676
+ })
4677
+ }
4678
+ )
4679
+ ]
4680
+ }
4681
+ );
4682
+ }
4494
4683
  function ProductCustomizer({
4495
4684
  product,
4496
4685
  onAddToCart,
@@ -4498,7 +4687,7 @@ function ProductCustomizer({
4498
4687
  className,
4499
4688
  classNames
4500
4689
  }) {
4501
- const [quantity, setQuantity] = React3.useState(1);
4690
+ const [quantity, setQuantity] = React3.useState(product.min_order_quantity ?? 1);
4502
4691
  const [isAdded, setIsAdded] = React3.useState(false);
4503
4692
  const [isSubmitting, setIsSubmitting] = React3.useState(false);
4504
4693
  const [selectedVariantId, setSelectedVariantId] = React3.useState();
@@ -4510,6 +4699,7 @@ function ProductCustomizer({
4510
4699
  const [bundleSelections, setBundleSelections] = React3.useState([]);
4511
4700
  const [bundleTotalPrice, setBundleTotalPrice] = React3.useState(null);
4512
4701
  const [bundleReady, setBundleReady] = React3.useState(false);
4702
+ const [selectedBillingPlan, setSelectedBillingPlan] = React3.useState(null);
4513
4703
  const [specialInstructions, setSpecialInstructions] = React3.useState("");
4514
4704
  const cart = useCart();
4515
4705
  const productType = product.type || "product";
@@ -4521,7 +4711,7 @@ function ProductCustomizer({
4521
4711
  const hasVariants = isStandard && product.variants && product.variants.length > 0;
4522
4712
  const hasAddOns = isStandard && product.add_ons && product.add_ons.length > 0;
4523
4713
  React3.useEffect(() => {
4524
- setQuantity(1);
4714
+ setQuantity(product.min_order_quantity ?? 1);
4525
4715
  setIsAdded(false);
4526
4716
  setIsSubmitting(false);
4527
4717
  setSelectedVariantId(void 0);
@@ -4533,8 +4723,9 @@ function ProductCustomizer({
4533
4723
  setBundleSelections([]);
4534
4724
  setBundleTotalPrice(null);
4535
4725
  setBundleReady(false);
4726
+ setSelectedBillingPlan(null);
4536
4727
  setSpecialInstructions("");
4537
- }, [product.id]);
4728
+ }, [product.id, product.min_order_quantity]);
4538
4729
  const selectedAddOnOptions = React3.useMemo(() => {
4539
4730
  if (!product.add_ons) return [];
4540
4731
  const options = [];
@@ -4553,18 +4744,18 @@ function ProductCustomizer({
4553
4744
  }, [selectedAddOnOptionIds]);
4554
4745
  const localTotalPrice = React3.useMemo(() => {
4555
4746
  if (isComposite && compositePrice) {
4556
- return chunk5FK7MDHS_js.parsePrice(compositePrice.final_price) * quantity;
4747
+ return chunkPEDLCL72_js.parsePrice(compositePrice.final_price) * quantity;
4557
4748
  }
4558
4749
  if (isBundle && bundleTotalPrice != null) {
4559
4750
  return bundleTotalPrice * quantity;
4560
4751
  }
4561
- let price = chunk5FK7MDHS_js.parsePrice(product.default_price);
4752
+ let price = chunkPEDLCL72_js.parsePrice(product.default_price);
4562
4753
  if (selectedVariant?.price_adjustment) {
4563
- price += chunk5FK7MDHS_js.parsePrice(selectedVariant.price_adjustment);
4754
+ price += chunkPEDLCL72_js.parsePrice(selectedVariant.price_adjustment);
4564
4755
  }
4565
4756
  for (const option of selectedAddOnOptions) {
4566
4757
  if (option.default_price) {
4567
- price += chunk5FK7MDHS_js.parsePrice(option.default_price);
4758
+ price += chunkPEDLCL72_js.parsePrice(option.default_price);
4568
4759
  }
4569
4760
  }
4570
4761
  return price * quantity;
@@ -4605,7 +4796,7 @@ function ProductCustomizer({
4605
4796
  const priceInfo = quote.quoted_total_price_info ?? quote.final_price_info;
4606
4797
  const perUnit = priceInfo.pre_tax_price;
4607
4798
  if (perUnit === void 0 || perUnit === null) return void 0;
4608
- return chunk5FK7MDHS_js.parsePrice(perUnit) * quantity;
4799
+ return chunkPEDLCL72_js.parsePrice(perUnit) * quantity;
4609
4800
  }, [quote, quantity]);
4610
4801
  const displayTotalPrice = quotedTotalPrice ?? localTotalPrice;
4611
4802
  const handleVariantChange = React3.useCallback(
@@ -4631,6 +4822,7 @@ function ProductCustomizer({
4631
4822
  })) : void 0,
4632
4823
  compositeSelections: isComposite && compositeSelections.length > 0 ? compositeSelections : void 0,
4633
4824
  bundleSelections: isBundle && bundleSelections.length > 0 ? bundleSelections : void 0,
4825
+ billingPlanId: selectedBillingPlan?.id,
4634
4826
  specialInstructions: specialInstructions.trim() || void 0
4635
4827
  };
4636
4828
  try {
@@ -4692,12 +4884,29 @@ function ProductCustomizer({
4692
4884
  onOptionsChange: setSelectedAddOnOptionIds
4693
4885
  }
4694
4886
  ),
4887
+ product.billing_plans && product.billing_plans.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
4888
+ BillingPlanSelector,
4889
+ {
4890
+ productId: product.id,
4891
+ plans: product.billing_plans,
4892
+ onPlanSelect: setSelectedBillingPlan,
4893
+ selectedPlanId: selectedBillingPlan?.id ?? null,
4894
+ showOneTimePurchase: true
4895
+ }
4896
+ ),
4897
+ product.quantity_pricing && product.quantity_pricing.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(
4898
+ VolumePricing,
4899
+ {
4900
+ tiers: product.quantity_pricing,
4901
+ currentQuantity: quantity
4902
+ }
4903
+ ),
4695
4904
  product.deposit_type && product.deposit_type !== "none" && product.deposit_amount && /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-customizer-deposit": true, className: cn("text-sm text-muted-foreground", classNames?.depositInfo), children: product.deposit_type === "fixed" ? /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
4696
4905
  "Deposit required: ",
4697
4906
  /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: product.deposit_amount })
4698
4907
  ] }) : /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
4699
4908
  "Deposit required: ",
4700
- chunk5FK7MDHS_js.parsePrice(product.deposit_amount),
4909
+ chunkPEDLCL72_js.parsePrice(product.deposit_amount),
4701
4910
  "%"
4702
4911
  ] }) }),
4703
4912
  product.allergies && product.allergies.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-customizer-allergens": true, className: cn("flex flex-wrap gap-1.5", classNames?.allergens), children: product.allergies.map((allergen) => /* @__PURE__ */ jsxRuntime.jsx(
@@ -4745,14 +4954,24 @@ function ProductCustomizer({
4745
4954
  }
4746
4955
  ),
4747
4956
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-4", children: [
4748
- /* @__PURE__ */ jsxRuntime.jsx(
4749
- QuantitySelector,
4750
- {
4751
- value: quantity,
4752
- onChange: setQuantity,
4753
- min: 1
4754
- }
4755
- ),
4957
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
4958
+ /* @__PURE__ */ jsxRuntime.jsx(
4959
+ QuantitySelector,
4960
+ {
4961
+ value: quantity,
4962
+ onChange: setQuantity,
4963
+ min: product.min_order_quantity ?? 1
4964
+ }
4965
+ ),
4966
+ product.min_order_quantity && product.min_order_quantity > 1 && /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-cimplify-customizer-min-hint": true, className: "text-xs text-muted-foreground text-center", children: [
4967
+ "Min. ",
4968
+ product.min_order_quantity
4969
+ ] })
4970
+ ] }),
4971
+ product.quantity_pricing && product.quantity_pricing.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-customizer-unit-price": true, className: "text-sm text-muted-foreground text-right shrink-0", children: [
4972
+ /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: chunkPEDLCL72_js.getUnitPriceAtQuantity(product.quantity_pricing, quantity, chunkPEDLCL72_js.parsePrice(product.default_price)), className: "font-medium text-foreground" }),
4973
+ " ea."
4974
+ ] }),
4756
4975
  /* @__PURE__ */ jsxRuntime.jsx(
4757
4976
  button.Button,
4758
4977
  {
@@ -4876,7 +5095,7 @@ function CartLineItemRow({
4876
5095
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-cart-item": true, className: classNames?.item, children: [
4877
5096
  /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-cart-item-info": true, children: [
4878
5097
  /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-cart-item-name": true, className: classNames?.itemName, children: item.product.name }),
4879
- item.variant && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-cart-item-variant": true, children: chunkKLRTWBDF_js.getVariantDisplayName(item.variant, item.product.name) }),
5098
+ item.variant && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-cart-item-variant": true, children: chunkIYQGGFVQ_js.getVariantDisplayName(item.variant, item.product.name) }),
4880
5099
  item.addOnOptions && item.addOnOptions.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-cimplify-cart-item-addons": true, children: [
4881
5100
  "+ ",
4882
5101
  item.addOnOptions.map((opt) => opt.name).join(", ")
@@ -4998,15 +5217,15 @@ function CartSummary({
4998
5217
  ] }),
4999
5218
  /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: subtotal })
5000
5219
  ] }),
5001
- totalDiscounts != null && chunk5FK7MDHS_js.parsePrice(totalDiscounts) > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-cart-discount": true, className: classNames?.discount, children: [
5220
+ totalDiscounts != null && chunkPEDLCL72_js.parsePrice(totalDiscounts) > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-cart-discount": true, className: classNames?.discount, children: [
5002
5221
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Discount" }),
5003
5222
  /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: totalDiscounts, prefix: "-" })
5004
5223
  ] }),
5005
5224
  deliveryFee != null && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-cart-delivery-fee": true, className: classNames?.deliveryFee, children: [
5006
5225
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Delivery fee" }),
5007
- chunk5FK7MDHS_js.parsePrice(deliveryFee) > 0 ? /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: deliveryFee }) : /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Free delivery" })
5226
+ chunkPEDLCL72_js.parsePrice(deliveryFee) > 0 ? /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: deliveryFee }) : /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Free delivery" })
5008
5227
  ] }),
5009
- serviceCharge != null && chunk5FK7MDHS_js.parsePrice(serviceCharge) > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-cart-service-charge": true, className: classNames?.serviceCharge, children: [
5228
+ serviceCharge != null && chunkPEDLCL72_js.parsePrice(serviceCharge) > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-cart-service-charge": true, className: classNames?.serviceCharge, children: [
5010
5229
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Service charge" }),
5011
5230
  /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: serviceCharge })
5012
5231
  ] }),
@@ -5089,16 +5308,16 @@ function SaleBadge({
5089
5308
  className,
5090
5309
  classNames
5091
5310
  }) {
5092
- const onSale = chunk5FK7MDHS_js.isOnSale(product);
5311
+ const onSale = chunkPEDLCL72_js.isOnSale(product);
5093
5312
  const hasDeal = dealInfo !== void 0;
5094
5313
  if (!hasDeal && !onSale && !label) {
5095
5314
  return null;
5096
5315
  }
5097
5316
  let percentage = null;
5098
5317
  if (hasDeal && dealInfo.benefit_type === "percentage") {
5099
- percentage = chunk5FK7MDHS_js.parsePrice(dealInfo.value);
5318
+ percentage = chunkPEDLCL72_js.parsePrice(dealInfo.value);
5100
5319
  } else if (onSale) {
5101
- percentage = chunk5FK7MDHS_js.getDiscountPercentage(product);
5320
+ percentage = chunkPEDLCL72_js.getDiscountPercentage(product);
5102
5321
  }
5103
5322
  const badgeText = label ?? dealInfo?.label ?? (percentage != null && percentage > 0 ? `${percentage}% off` : null);
5104
5323
  if (!badgeText) {
@@ -5117,7 +5336,7 @@ function SaleBadge({
5117
5336
  "%"
5118
5337
  ] }),
5119
5338
  /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-sale-label": true, className: classNames?.label, children: badgeText }),
5120
- showOriginalPrice && onSale && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-sale-original-price": true, className: classNames?.originalPrice, children: /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: chunk5FK7MDHS_js.getBasePrice(product) }) })
5339
+ showOriginalPrice && onSale && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-sale-original-price": true, className: classNames?.originalPrice, children: /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: chunkPEDLCL72_js.getBasePrice(product) }) })
5121
5340
  ]
5122
5341
  }
5123
5342
  );
@@ -5623,7 +5842,7 @@ function SearchInput({
5623
5842
  }
5624
5843
  ),
5625
5844
  /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-search-result-name": true, className: classNames?.resultName, style: { flex: 1, textAlign: "left" }, children: product.name }),
5626
- product.default_price !== void 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-search-result-price": true, className: classNames?.resultPrice, style: { flexShrink: 0 }, children: chunk5FK7MDHS_js.formatPrice(product.default_price) })
5845
+ product.default_price !== void 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-search-result-price": true, className: classNames?.resultPrice, style: { flexShrink: 0 }, children: chunkPEDLCL72_js.formatPrice(product.default_price) })
5627
5846
  ] })
5628
5847
  },
5629
5848
  product.id
@@ -6117,19 +6336,19 @@ function OrderSummary({
6117
6336
  order.customer_notes.map((note, index) => /* @__PURE__ */ jsxRuntime.jsx("p", { "data-cimplify-order-note": true, children: note }, index))
6118
6337
  ] }),
6119
6338
  /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-order-totals": true, className: classNames?.totals, children: [
6120
- order.total_discount != null && chunk5FK7MDHS_js.parsePrice(order.total_discount) !== 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-order-discount": true, children: [
6339
+ order.total_discount != null && chunkPEDLCL72_js.parsePrice(order.total_discount) !== 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-order-discount": true, children: [
6121
6340
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Discount" }),
6122
6341
  /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: order.total_discount, prefix: "-" })
6123
6342
  ] }),
6124
- order.delivery_fee != null && chunk5FK7MDHS_js.parsePrice(order.delivery_fee) > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-order-delivery-fee": true, children: [
6343
+ order.delivery_fee != null && chunkPEDLCL72_js.parsePrice(order.delivery_fee) > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-order-delivery-fee": true, children: [
6125
6344
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Delivery fee" }),
6126
6345
  /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: order.delivery_fee })
6127
6346
  ] }),
6128
- order.service_charge != null && chunk5FK7MDHS_js.parsePrice(order.service_charge) !== 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-order-service-charge": true, children: [
6347
+ order.service_charge != null && chunkPEDLCL72_js.parsePrice(order.service_charge) !== 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-order-service-charge": true, children: [
6129
6348
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Service charge" }),
6130
6349
  /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: order.service_charge })
6131
6350
  ] }),
6132
- order.tax != null && chunk5FK7MDHS_js.parsePrice(order.tax) !== 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-order-tax": true, children: [
6351
+ order.tax != null && chunkPEDLCL72_js.parsePrice(order.tax) !== 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-order-tax": true, children: [
6133
6352
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Tax" }),
6134
6353
  /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: order.tax })
6135
6354
  ] }),
@@ -7268,84 +7487,769 @@ function useDebounce(value, delay) {
7268
7487
  }, [value, delay]);
7269
7488
  return debounced;
7270
7489
  }
7271
- function ProductPage({
7272
- productId,
7273
- product: productProp,
7274
- relatedProducts,
7275
- onAddToCart,
7276
- renderImage,
7277
- showAvailability = true,
7278
- showSaleBadge = true,
7279
- showRelated = true,
7280
- relatedTitle = "You might also like",
7281
- className,
7282
- classNames
7490
+ function TwoColumnGrid({
7491
+ left,
7492
+ right,
7493
+ className
7283
7494
  }) {
7284
- const { product: fetched, isLoading } = useProduct(productId, {
7285
- enabled: !productProp
7286
- });
7287
- const product = productProp ?? fetched;
7288
- if (isLoading && !product) {
7289
- return /* @__PURE__ */ jsxRuntime.jsx(
7290
- "div",
7495
+ return /* @__PURE__ */ jsxRuntime.jsxs(
7496
+ "div",
7497
+ {
7498
+ "data-cimplify-product-layout-grid": true,
7499
+ className: cn("grid lg:grid-cols-2 gap-8 lg:gap-12", className),
7500
+ children: [
7501
+ /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-product-layout-media": true, children: left }),
7502
+ /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-product-layout-info": true, children: right })
7503
+ ]
7504
+ }
7505
+ );
7506
+ }
7507
+ function MetadataStringList({
7508
+ items,
7509
+ label,
7510
+ icon,
7511
+ className
7512
+ }) {
7513
+ if (items.length === 0) return null;
7514
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-metadata-list": true, className: cn("space-y-2", className), children: [
7515
+ /* @__PURE__ */ jsxRuntime.jsxs("h3", { className: "flex items-center gap-2 text-sm font-medium", children: [
7516
+ icon,
7517
+ label
7518
+ ] }),
7519
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-1.5", children: items.map((item, i) => /* @__PURE__ */ jsxRuntime.jsx(
7520
+ "span",
7291
7521
  {
7292
- "data-cimplify-product-page": true,
7293
- "aria-busy": "true",
7294
- className: cn(className, classNames?.root, classNames?.loading),
7295
- children: /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-product-page-skeleton": true, style: { display: "flex", flexDirection: "column", gap: "1rem" }, children: [
7296
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { aspectRatio: "4/3", backgroundColor: "rgba(0,0,0,0.06)", borderRadius: "0.5rem" } }),
7297
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { height: "2rem", width: "60%", backgroundColor: "rgba(0,0,0,0.06)", borderRadius: "0.25rem" } }),
7298
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { height: "1rem", width: "30%", backgroundColor: "rgba(0,0,0,0.06)", borderRadius: "0.25rem" } })
7299
- ] })
7300
- }
7301
- );
7302
- }
7303
- if (!product) {
7304
- return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-product-page": true, className: cn(className, classNames?.root), children: /* @__PURE__ */ jsxRuntime.jsx("p", { children: "Product not found." }) });
7305
- }
7306
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-product-page": true, className: cn(className, classNames?.root), children: [
7307
- (showAvailability || showSaleBadge) && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-product-page-badges": true, className: classNames?.badges, children: [
7308
- showAvailability && /* @__PURE__ */ jsxRuntime.jsx(AvailabilityBadge, { product }),
7309
- showSaleBadge && /* @__PURE__ */ jsxRuntime.jsx(SaleBadge, { product })
7522
+ className: "text-xs text-muted-foreground px-2.5 py-1 bg-muted",
7523
+ children: item
7524
+ },
7525
+ `${item}-${i}`
7526
+ )) })
7527
+ ] });
7528
+ }
7529
+ function CustomAttributesTable({
7530
+ attributes,
7531
+ className
7532
+ }) {
7533
+ if (!attributes || attributes.length === 0) return null;
7534
+ const groups = /* @__PURE__ */ new Map();
7535
+ for (const attr of attributes) {
7536
+ const group = attr.group_name || "Details";
7537
+ if (!groups.has(group)) groups.set(group, []);
7538
+ groups.get(group).push(attr);
7539
+ }
7540
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-custom-attributes": true, className: cn("space-y-4", className), children: Array.from(groups.entries()).map(([groupName, attrs]) => /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
7541
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { "data-cimplify-attribute-group": true, className: "text-sm font-semibold mb-2", children: groupName }),
7542
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border border-border divide-y divide-border", children: attrs.map((attr) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-4 py-2.5 text-sm", children: [
7543
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: attr.name }),
7544
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: formatAttributeValue(attr) })
7545
+ ] }, attr.definition_id)) })
7546
+ ] }, groupName)) });
7547
+ }
7548
+ function formatAttributeValue(attr) {
7549
+ if (attr.value === null || attr.value === void 0) return "\u2014";
7550
+ if (typeof attr.value === "boolean") return attr.value ? "Yes" : "No";
7551
+ if (Array.isArray(attr.value)) return attr.value.join(", ");
7552
+ if (typeof attr.value === "object" && "value" in attr.value) {
7553
+ return `${attr.value.value}${attr.unit ? ` ${attr.unit}` : ""}`;
7554
+ }
7555
+ const str = String(attr.value);
7556
+ return attr.unit ? `${str} ${attr.unit}` : str;
7557
+ }
7558
+ function PropertiesTable({
7559
+ properties,
7560
+ className
7561
+ }) {
7562
+ if (!properties || properties.length === 0) return null;
7563
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-properties": true, className, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border border-border divide-y divide-border", children: properties.map((prop) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-4 py-2.5 text-sm", children: [
7564
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: prop.name }),
7565
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-medium", children: [
7566
+ prop.values.filter(Boolean).join(", "),
7567
+ prop.unit ? ` ${prop.unit}` : ""
7568
+ ] })
7569
+ ] }, prop.slug)) }) });
7570
+ }
7571
+ function TagPills({
7572
+ tags,
7573
+ className
7574
+ }) {
7575
+ if (!tags || tags.length === 0) return null;
7576
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-tags": true, className: cn("flex flex-wrap gap-1.5", className), children: tags.map((tag) => /* @__PURE__ */ jsxRuntime.jsx(
7577
+ "span",
7578
+ {
7579
+ className: "text-xs font-medium text-muted-foreground px-2.5 py-1 bg-muted rounded-full",
7580
+ children: tag
7581
+ },
7582
+ tag
7583
+ )) });
7584
+ }
7585
+ function InventoryBadge({
7586
+ product,
7587
+ className
7588
+ }) {
7589
+ const status = product.inventory_status;
7590
+ if (!status) return null;
7591
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-inventory-badge": true, className: cn("flex items-center gap-2 text-sm", className), children: [
7592
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn(
7593
+ "w-2 h-2 rounded-full",
7594
+ status.in_stock ? "bg-green-500" : "bg-red-500"
7595
+ ) }),
7596
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: status.in_stock ? "text-green-700 font-medium" : "text-red-700 font-medium", children: status.in_stock ? "In stock" : "Out of stock" }),
7597
+ status.in_stock && status.stock_level != null && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-muted-foreground", children: [
7598
+ "\xB7 ",
7599
+ status.stock_level.toLocaleString(),
7600
+ " available"
7310
7601
  ] }),
7311
- /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-product-page-main": true, className: classNames?.main, children: /* @__PURE__ */ jsxRuntime.jsx(
7312
- ProductSheet,
7602
+ status.low_stock && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-amber-600 font-medium", children: "\xB7 Low stock" })
7603
+ ] });
7604
+ }
7605
+ function RelatedProductsSection({
7606
+ products,
7607
+ title = "You might also like",
7608
+ renderImage,
7609
+ className
7610
+ }) {
7611
+ if (products.length === 0) return null;
7612
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-product-layout-related": true, className: cn("mt-12 pt-8 border-t border-border", className), children: [
7613
+ /* @__PURE__ */ jsxRuntime.jsx(
7614
+ "h2",
7313
7615
  {
7314
- product,
7315
- onAddToCart,
7316
- renderImage
7616
+ "data-cimplify-product-layout-related-title": true,
7617
+ className: "text-xl font-semibold mb-6",
7618
+ children: title
7317
7619
  }
7318
- ) }),
7319
- showRelated && relatedProducts && relatedProducts.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-product-page-related": true, className: classNames?.relatedSection, children: [
7320
- /* @__PURE__ */ jsxRuntime.jsx("h2", { "data-cimplify-product-page-related-title": true, className: classNames?.relatedTitle, children: relatedTitle }),
7321
- /* @__PURE__ */ jsxRuntime.jsx(
7322
- ProductGrid,
7323
- {
7324
- products: relatedProducts,
7325
- renderImage
7326
- }
7327
- )
7328
- ] })
7620
+ ),
7621
+ /* @__PURE__ */ jsxRuntime.jsx(ProductGrid, { products, renderImage })
7329
7622
  ] });
7330
7623
  }
7331
- function CartPage({
7332
- title = "Your Cart",
7333
- onCheckout,
7334
- onContinueShopping,
7335
- onDiscountApply,
7336
- onDiscountClear,
7337
- showDiscount = true,
7338
- showContinueShopping = true,
7339
- checkoutLabel = "Proceed to Checkout",
7340
- className,
7341
- classNames
7624
+ function getMetadataStringList(metadata, key) {
7625
+ const value = metadata?.[key];
7626
+ if (!Array.isArray(value)) return [];
7627
+ return value.filter((item) => typeof item === "string");
7628
+ }
7629
+ function PriceRange({ product, className }) {
7630
+ const { displayCurrency } = useCimplify();
7631
+ const range = chunkPEDLCL72_js.getPriceRange(product);
7632
+ if (!range) return null;
7633
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-price-range": true, className, children: chunkPEDLCL72_js.formatPriceRange(range.min, range.max, displayCurrency) });
7634
+ }
7635
+ function DefaultProductLayout({
7636
+ product,
7637
+ onAddToCart,
7638
+ renderBreadcrumb,
7639
+ relatedProducts,
7640
+ showRelated = true,
7641
+ className
7342
7642
  }) {
7343
- const { isEmpty, subtotal } = useCart();
7344
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-cart-page": true, className: cn(className, classNames?.root), children: [
7345
- /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-cart-page-header": true, className: classNames?.header, children: [
7346
- /* @__PURE__ */ jsxRuntime.jsx("h1", { "data-cimplify-cart-page-title": true, className: classNames?.title, children: title }),
7347
- showContinueShopping && /* @__PURE__ */ jsxRuntime.jsx(
7348
- "button",
7643
+ const images = product.images || (product.image_url ? [product.image_url] : []);
7644
+ const hasRange = product.quantity_pricing && product.quantity_pricing.length > 1 || product.variants && product.variants.length > 1;
7645
+ const onSale = chunkPEDLCL72_js.isOnSale(product);
7646
+ const hasPhysicalDetails = product.sku || product.vendor || product.material;
7647
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-product-layout": "default", className: cn("space-y-8", className), children: [
7648
+ renderBreadcrumb?.(product),
7649
+ /* @__PURE__ */ jsxRuntime.jsx(
7650
+ TwoColumnGrid,
7651
+ {
7652
+ left: /* @__PURE__ */ jsxRuntime.jsx(
7653
+ ProductImageGallery,
7654
+ {
7655
+ images,
7656
+ productName: product.name
7657
+ }
7658
+ ),
7659
+ right: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-6", children: [
7660
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
7661
+ product.vendor && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-semibold text-muted-foreground uppercase tracking-widest", children: product.vendor }),
7662
+ /* @__PURE__ */ jsxRuntime.jsx(TagPills, { tags: product.tags || [] })
7663
+ ] }),
7664
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { "data-cimplify-product-layout-name": true, className: "text-3xl lg:text-4xl font-extrabold tracking-tight", children: product.name }),
7665
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-baseline gap-3", children: hasRange ? /* @__PURE__ */ jsxRuntime.jsx(PriceRange, { product, className: "text-2xl font-extrabold" }) : onSale ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
7666
+ /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: product.default_price, className: "text-2xl font-extrabold" }),
7667
+ /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: chunkPEDLCL72_js.getBasePrice(product), className: "text-lg text-muted-foreground line-through" }),
7668
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm font-bold text-destructive bg-destructive/10 px-2 py-0.5", children: [
7669
+ "Save ",
7670
+ chunkPEDLCL72_js.getDiscountPercentage(product),
7671
+ "%"
7672
+ ] })
7673
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: product.default_price, className: "text-2xl font-semibold" }) }),
7674
+ /* @__PURE__ */ jsxRuntime.jsx(InventoryBadge, { product }),
7675
+ product.description && /* @__PURE__ */ jsxRuntime.jsx("p", { "data-cimplify-product-layout-description": true, className: "text-muted-foreground leading-relaxed", children: product.description }),
7676
+ hasPhysicalDetails && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-product-layout-details": true, className: "space-y-1 text-sm text-muted-foreground", children: [
7677
+ product.sku && /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
7678
+ "SKU: ",
7679
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono text-foreground", children: product.sku })
7680
+ ] }),
7681
+ product.barcode && /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
7682
+ "Barcode: ",
7683
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono text-foreground", children: product.barcode })
7684
+ ] }),
7685
+ product.material && /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
7686
+ "Material: ",
7687
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-foreground", children: product.material })
7688
+ ] }),
7689
+ product.vendor && /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
7690
+ "Brand: ",
7691
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-foreground", children: product.vendor })
7692
+ ] }),
7693
+ (product.length_mm || product.width_mm || product.height_mm) && /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
7694
+ "Dimensions: ",
7695
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-foreground", children: [product.length_mm, product.width_mm, product.height_mm].filter(Boolean).map((d) => `${(d / 10).toFixed(1)} cm`).join(" x ") })
7696
+ ] }),
7697
+ product.item_condition && product.item_condition !== "new" && /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
7698
+ "Condition: ",
7699
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-foreground capitalize", children: product.item_condition })
7700
+ ] })
7701
+ ] }),
7702
+ /* @__PURE__ */ jsxRuntime.jsx(CustomAttributesTable, { attributes: product.custom_attributes || [] }),
7703
+ /* @__PURE__ */ jsxRuntime.jsx(PropertiesTable, { properties: product.properties || [] }),
7704
+ /* @__PURE__ */ jsxRuntime.jsx(
7705
+ ProductCustomizer,
7706
+ {
7707
+ product,
7708
+ onAddToCart
7709
+ }
7710
+ )
7711
+ ] })
7712
+ }
7713
+ ),
7714
+ showRelated && relatedProducts && relatedProducts.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
7715
+ RelatedProductsSection,
7716
+ {
7717
+ products: relatedProducts
7718
+ }
7719
+ )
7720
+ ] });
7721
+ }
7722
+ var DIETARY_TAGS = /* @__PURE__ */ new Set([
7723
+ "vegetarian",
7724
+ "vegan",
7725
+ "gluten-free",
7726
+ "dairy-free",
7727
+ "nut-free",
7728
+ "spicy",
7729
+ "halal",
7730
+ "kosher",
7731
+ "organic",
7732
+ "sugar-free"
7733
+ ]);
7734
+ function FoodProductLayout({
7735
+ product,
7736
+ onAddToCart,
7737
+ renderBreadcrumb,
7738
+ relatedProducts,
7739
+ showRelated = true,
7740
+ className
7741
+ }) {
7742
+ const images = product.images || (product.image_url ? [product.image_url] : []);
7743
+ const allTags = product.tags || [];
7744
+ const dietaryTags = allTags.filter((t) => DIETARY_TAGS.has(t));
7745
+ const otherTags = allTags.filter((t) => !DIETARY_TAGS.has(t));
7746
+ const ingredients = getMetadataStringList(product.metadata, "ingredients");
7747
+ const pairings = getMetadataStringList(product.metadata, "pairings");
7748
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-product-layout": "food", className: cn("space-y-8", className), children: [
7749
+ renderBreadcrumb?.(product),
7750
+ /* @__PURE__ */ jsxRuntime.jsx(
7751
+ TwoColumnGrid,
7752
+ {
7753
+ left: /* @__PURE__ */ jsxRuntime.jsx(
7754
+ ProductImageGallery,
7755
+ {
7756
+ images,
7757
+ productName: product.name
7758
+ }
7759
+ ),
7760
+ right: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-6", children: [
7761
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-1.5", children: [
7762
+ dietaryTags.map((tag) => /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex items-center gap-1 px-2.5 py-1 bg-green-100 text-green-800 text-xs font-medium rounded-full", children: tag }, tag)),
7763
+ product.allergies && product.allergies.map((allergy) => /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1 px-2.5 py-1 bg-amber-100 text-amber-800 text-xs font-medium rounded-full", children: [
7764
+ "Contains ",
7765
+ allergy
7766
+ ] }, allergy))
7767
+ ] }),
7768
+ /* @__PURE__ */ jsxRuntime.jsx(TagPills, { tags: otherTags }),
7769
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
7770
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { "data-cimplify-product-layout-name": true, className: "text-3xl lg:text-4xl font-bold tracking-tight", children: product.name }),
7771
+ /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: product.default_price, className: "text-2xl font-semibold mt-2 block" })
7772
+ ] }),
7773
+ (product.calories != null || product.preparation_time_minutes != null) && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-product-layout-stats": true, className: "flex flex-wrap gap-4 py-3 border-y border-border", children: [
7774
+ product.preparation_time_minutes != null && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-1.5 text-sm text-muted-foreground", children: [
7775
+ /* @__PURE__ */ jsxRuntime.jsxs("strong", { className: "text-foreground", children: [
7776
+ product.preparation_time_minutes,
7777
+ " min"
7778
+ ] }),
7779
+ " prep time"
7780
+ ] }),
7781
+ product.calories != null && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-1.5 text-sm text-muted-foreground", children: [
7782
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { className: "text-foreground", children: product.calories }),
7783
+ " calories"
7784
+ ] })
7785
+ ] }),
7786
+ product.description && /* @__PURE__ */ jsxRuntime.jsx("p", { "data-cimplify-product-layout-description": true, className: "text-muted-foreground leading-relaxed", children: product.description }),
7787
+ (ingredients.length > 0 || pairings.length > 0) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid sm:grid-cols-2 gap-4", children: [
7788
+ /* @__PURE__ */ jsxRuntime.jsx(MetadataStringList, { items: ingredients, label: "Key Ingredients" }),
7789
+ /* @__PURE__ */ jsxRuntime.jsx(MetadataStringList, { items: pairings, label: "Pairings" })
7790
+ ] }),
7791
+ /* @__PURE__ */ jsxRuntime.jsx(CustomAttributesTable, { attributes: product.custom_attributes || [] }),
7792
+ /* @__PURE__ */ jsxRuntime.jsx(
7793
+ ProductCustomizer,
7794
+ {
7795
+ product,
7796
+ onAddToCart
7797
+ }
7798
+ )
7799
+ ] })
7800
+ }
7801
+ ),
7802
+ showRelated && relatedProducts && relatedProducts.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
7803
+ RelatedProductsSection,
7804
+ {
7805
+ products: relatedProducts,
7806
+ title: "You may also enjoy"
7807
+ }
7808
+ )
7809
+ ] });
7810
+ }
7811
+ function WholesaleProductLayout({
7812
+ product,
7813
+ onAddToCart,
7814
+ renderBreadcrumb,
7815
+ relatedProducts,
7816
+ showRelated = true,
7817
+ className
7818
+ }) {
7819
+ const images = product.images || (product.image_url ? [product.image_url] : []);
7820
+ const hasTiers = product.quantity_pricing && product.quantity_pricing.length > 1;
7821
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-product-layout": "wholesale", className: cn("space-y-8", className), children: [
7822
+ renderBreadcrumb?.(product),
7823
+ /* @__PURE__ */ jsxRuntime.jsx(
7824
+ TwoColumnGrid,
7825
+ {
7826
+ left: /* @__PURE__ */ jsxRuntime.jsx(
7827
+ ProductImageGallery,
7828
+ {
7829
+ images,
7830
+ productName: product.name
7831
+ }
7832
+ ),
7833
+ right: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-6", children: [
7834
+ /* @__PURE__ */ jsxRuntime.jsx(TagPills, { tags: product.tags || [] }),
7835
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
7836
+ product.sku && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs text-muted-foreground font-medium uppercase tracking-wider mb-1", children: [
7837
+ "SKU: ",
7838
+ product.sku
7839
+ ] }),
7840
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { "data-cimplify-product-layout-name": true, className: "text-3xl lg:text-4xl font-extrabold tracking-tight", children: product.name })
7841
+ ] }),
7842
+ /* @__PURE__ */ jsxRuntime.jsx("div", { children: hasTiers ? /* @__PURE__ */ jsxRuntime.jsx(PriceRange, { product, className: "text-2xl font-extrabold" }) : /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: product.default_price, className: "text-2xl font-semibold" }) }),
7843
+ /* @__PURE__ */ jsxRuntime.jsx(InventoryBadge, { product }),
7844
+ product.min_order_quantity != null && product.min_order_quantity > 1 && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-product-layout-moq": true, className: "flex items-center gap-3 p-3 bg-amber-50 border border-amber-200 text-sm text-amber-800", children: [
7845
+ "Minimum order quantity: ",
7846
+ /* @__PURE__ */ jsxRuntime.jsxs("strong", { children: [
7847
+ product.min_order_quantity,
7848
+ " units"
7849
+ ] })
7850
+ ] }),
7851
+ product.description && /* @__PURE__ */ jsxRuntime.jsx("p", { "data-cimplify-product-layout-description": true, className: "text-muted-foreground leading-relaxed", children: product.description }),
7852
+ hasTiers && /* @__PURE__ */ jsxRuntime.jsx(
7853
+ VolumePricing,
7854
+ {
7855
+ tiers: product.quantity_pricing,
7856
+ defaultOpen: true
7857
+ }
7858
+ ),
7859
+ (product.sku || product.barcode || product.vendor) && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-product-layout-details": true, className: "space-y-1 text-sm text-muted-foreground", children: [
7860
+ product.barcode && /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
7861
+ "Barcode: ",
7862
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono text-foreground", children: product.barcode })
7863
+ ] }),
7864
+ product.vendor && /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
7865
+ "Supplier: ",
7866
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-foreground", children: product.vendor })
7867
+ ] }),
7868
+ product.hs_code && /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
7869
+ "HS Code: ",
7870
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono text-foreground", children: product.hs_code })
7871
+ ] })
7872
+ ] }),
7873
+ /* @__PURE__ */ jsxRuntime.jsx(CustomAttributesTable, { attributes: product.custom_attributes || [] }),
7874
+ /* @__PURE__ */ jsxRuntime.jsx(PropertiesTable, { properties: product.properties || [] }),
7875
+ /* @__PURE__ */ jsxRuntime.jsx(
7876
+ ProductCustomizer,
7877
+ {
7878
+ product,
7879
+ onAddToCart
7880
+ }
7881
+ )
7882
+ ] })
7883
+ }
7884
+ ),
7885
+ showRelated && relatedProducts && relatedProducts.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
7886
+ RelatedProductsSection,
7887
+ {
7888
+ products: relatedProducts,
7889
+ title: "Related products"
7890
+ }
7891
+ )
7892
+ ] });
7893
+ }
7894
+ function formatMinutes(minutes) {
7895
+ if (minutes >= 1440) return `${Math.floor(minutes / 1440)} day${minutes >= 2880 ? "s" : ""}`;
7896
+ if (minutes >= 60) {
7897
+ const h = Math.floor(minutes / 60);
7898
+ const m = minutes % 60;
7899
+ return m > 0 ? `${h}h ${m}min` : `${h} hour${h > 1 ? "s" : ""}`;
7900
+ }
7901
+ return `${minutes} min`;
7902
+ }
7903
+ function ServiceProductLayout({
7904
+ product,
7905
+ onAddToCart,
7906
+ renderBreadcrumb,
7907
+ relatedProducts,
7908
+ showRelated = true,
7909
+ className
7910
+ }) {
7911
+ const images = product.images || (product.image_url ? [product.image_url] : []);
7912
+ const hasDeposit = product.deposit_type && product.deposit_type !== "none" && product.deposit_amount;
7913
+ const depositAmount = hasDeposit ? chunkPEDLCL72_js.parsePrice(product.deposit_amount) : 0;
7914
+ const cancellationHours = product.cancellation_window_minutes ? Math.floor(product.cancellation_window_minutes / 60) : null;
7915
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-product-layout": "service", className: cn("space-y-8", className), children: [
7916
+ renderBreadcrumb?.(product),
7917
+ /* @__PURE__ */ jsxRuntime.jsx(
7918
+ TwoColumnGrid,
7919
+ {
7920
+ left: /* @__PURE__ */ jsxRuntime.jsx(
7921
+ ProductImageGallery,
7922
+ {
7923
+ images,
7924
+ productName: product.name
7925
+ }
7926
+ ),
7927
+ right: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-6", children: [
7928
+ /* @__PURE__ */ jsxRuntime.jsx(TagPills, { tags: product.tags || [] }),
7929
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
7930
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { "data-cimplify-product-layout-name": true, className: "text-3xl lg:text-4xl font-extrabold tracking-tight", children: product.name }),
7931
+ /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: product.default_price, className: "text-2xl font-bold text-primary mt-2 block" })
7932
+ ] }),
7933
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-product-layout-service-info": true, className: "flex flex-wrap gap-2", children: [
7934
+ product.duration_minutes != null && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex items-center gap-1.5 px-3 py-1.5 bg-muted text-sm text-muted-foreground rounded-full", children: formatMinutes(product.duration_minutes) }),
7935
+ hasDeposit && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1.5 px-3 py-1.5 bg-muted text-sm text-muted-foreground rounded-full", children: [
7936
+ /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: depositAmount }),
7937
+ " deposit"
7938
+ ] }),
7939
+ product.general_service_capacity != null && product.general_service_capacity > 1 && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1.5 px-3 py-1.5 bg-muted text-sm text-muted-foreground rounded-full", children: [
7940
+ "Up to ",
7941
+ product.general_service_capacity,
7942
+ " people"
7943
+ ] }),
7944
+ product.buffer_before_minutes != null && product.buffer_before_minutes > 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1.5 px-3 py-1.5 bg-muted text-sm text-muted-foreground rounded-full", children: [
7945
+ product.buffer_before_minutes,
7946
+ " min buffer"
7947
+ ] })
7948
+ ] }),
7949
+ product.description && /* @__PURE__ */ jsxRuntime.jsx("p", { "data-cimplify-product-layout-description": true, className: "text-muted-foreground leading-relaxed", children: product.description }),
7950
+ (product.requires_specific_staff || product.requires_specific_resource) && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-product-layout-requirements": true, className: "text-sm text-muted-foreground space-y-1", children: [
7951
+ product.requires_specific_staff && /* @__PURE__ */ jsxRuntime.jsx("p", { children: "Staff selection required" }),
7952
+ product.requires_specific_resource && /* @__PURE__ */ jsxRuntime.jsx("p", { children: "Resource selection required" })
7953
+ ] }),
7954
+ /* @__PURE__ */ jsxRuntime.jsx(CustomAttributesTable, { attributes: product.custom_attributes || [] }),
7955
+ /* @__PURE__ */ jsxRuntime.jsx(
7956
+ ProductCustomizer,
7957
+ {
7958
+ product,
7959
+ onAddToCart,
7960
+ showSpecialInstructions: false
7961
+ }
7962
+ ),
7963
+ (cancellationHours != null || product.no_show_fee) && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-product-layout-cancellation": true, className: "border border-border p-4 space-y-2 text-sm", children: [
7964
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "font-semibold", children: "Cancellation Policy" }),
7965
+ cancellationHours != null && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-muted-foreground", children: [
7966
+ "Free cancellation up to ",
7967
+ /* @__PURE__ */ jsxRuntime.jsxs("strong", { className: "text-foreground", children: [
7968
+ cancellationHours,
7969
+ " hours"
7970
+ ] }),
7971
+ " before the appointment"
7972
+ ] }),
7973
+ product.no_show_fee && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-muted-foreground", children: [
7974
+ "No-show fee: ",
7975
+ /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: product.no_show_fee, className: "font-medium text-foreground" })
7976
+ ] }),
7977
+ hasDeposit && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground", children: product.deposit_type === "fixed" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
7978
+ /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: depositAmount, className: "font-medium text-foreground" }),
7979
+ " deposit charged at booking"
7980
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
7981
+ chunkPEDLCL72_js.parsePrice(product.deposit_amount),
7982
+ "% deposit charged at booking"
7983
+ ] }) })
7984
+ ] })
7985
+ ] })
7986
+ }
7987
+ ),
7988
+ showRelated && relatedProducts && relatedProducts.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
7989
+ RelatedProductsSection,
7990
+ {
7991
+ products: relatedProducts,
7992
+ title: "Other services"
7993
+ }
7994
+ )
7995
+ ] });
7996
+ }
7997
+ var DIGITAL_TYPE_LABELS = {
7998
+ download: "Digital download",
7999
+ license: "Software license",
8000
+ event_ticket: "Event ticket",
8001
+ access_pass: "Access pass",
8002
+ gift_card: "Gift card"
8003
+ };
8004
+ function DigitalProductLayout({
8005
+ product,
8006
+ onAddToCart,
8007
+ renderBreadcrumb,
8008
+ relatedProducts,
8009
+ showRelated = true,
8010
+ className
8011
+ }) {
8012
+ const images = product.images || (product.image_url ? [product.image_url] : []);
8013
+ const typeLabel = product.digital_type ? DIGITAL_TYPE_LABELS[product.digital_type] || product.digital_type : "Digital product";
8014
+ const isTicket = product.digital_type === "event_ticket";
8015
+ const isAccessPass = product.digital_type === "access_pass";
8016
+ const isDownload = product.digital_type === "download" || product.digital_type === "license";
8017
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-product-layout": "digital", className: cn("space-y-8", className), children: [
8018
+ renderBreadcrumb?.(product),
8019
+ /* @__PURE__ */ jsxRuntime.jsx(
8020
+ TwoColumnGrid,
8021
+ {
8022
+ left: /* @__PURE__ */ jsxRuntime.jsx(
8023
+ ProductImageGallery,
8024
+ {
8025
+ images,
8026
+ productName: product.name
8027
+ }
8028
+ ),
8029
+ right: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-6", children: [
8030
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
8031
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-product-layout-badge": true, className: "text-xs font-semibold uppercase tracking-wider text-primary bg-primary/10 px-2.5 py-1 rounded-full", children: typeLabel }),
8032
+ /* @__PURE__ */ jsxRuntime.jsx(TagPills, { tags: product.tags || [] })
8033
+ ] }),
8034
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
8035
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { "data-cimplify-product-layout-name": true, className: "text-3xl lg:text-4xl font-extrabold tracking-tight", children: product.name }),
8036
+ /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: product.default_price, className: "text-2xl font-bold mt-2 block" })
8037
+ ] }),
8038
+ product.description && /* @__PURE__ */ jsxRuntime.jsx("p", { "data-cimplify-product-layout-description": true, className: "text-muted-foreground leading-relaxed", children: product.description }),
8039
+ isDownload && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-product-layout-delivery": true, className: "flex items-center gap-3 px-4 py-3 bg-muted rounded-lg", children: [
8040
+ /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-5 h-5 text-primary shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M13 10V3L4 14h7v7l9-11h-7z" }) }),
8041
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
8042
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium", children: "Instant delivery" }),
8043
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: "Download immediately after purchase" })
8044
+ ] })
8045
+ ] }),
8046
+ isTicket && (product.event_date || product.venue) && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-product-layout-event": true, className: "border border-border p-4 space-y-2", children: [
8047
+ product.event_date && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-sm", children: [
8048
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "Date:" }),
8049
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: new Date(product.event_date).toLocaleDateString(void 0, { weekday: "long", year: "numeric", month: "long", day: "numeric" }) })
8050
+ ] }),
8051
+ product.venue && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-sm", children: [
8052
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "Venue:" }),
8053
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: product.venue })
8054
+ ] }),
8055
+ product.ticket_type && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-sm", children: [
8056
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "Type:" }),
8057
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium capitalize", children: product.ticket_type })
8058
+ ] })
8059
+ ] }),
8060
+ isAccessPass && (product.access_type || product.access_duration_days) && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-product-layout-access": true, className: "border border-border p-4 space-y-2", children: [
8061
+ product.access_type && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-sm", children: [
8062
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "Access:" }),
8063
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium capitalize", children: product.access_type })
8064
+ ] }),
8065
+ product.access_level && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-sm", children: [
8066
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "Level:" }),
8067
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium capitalize", children: product.access_level })
8068
+ ] }),
8069
+ product.access_duration_days && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-sm", children: [
8070
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "Duration:" }),
8071
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-medium", children: [
8072
+ product.access_duration_days,
8073
+ " days"
8074
+ ] })
8075
+ ] })
8076
+ ] }),
8077
+ isDownload && (product.file_size_mb || product.file_type || product.version || product.max_downloads) && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-product-layout-file-details": true, className: "grid grid-cols-2 gap-3", children: [
8078
+ product.file_type && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-3 py-2 bg-muted text-center", children: [
8079
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: "Format" }),
8080
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold", children: product.file_type.toUpperCase() })
8081
+ ] }),
8082
+ product.file_size_mb != null && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-3 py-2 bg-muted text-center", children: [
8083
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: "Size" }),
8084
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold", children: product.file_size_mb >= 1024 ? `${(product.file_size_mb / 1024).toFixed(1)} GB` : `${product.file_size_mb} MB` })
8085
+ ] }),
8086
+ product.max_downloads != null && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-3 py-2 bg-muted text-center", children: [
8087
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: "Downloads" }),
8088
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold", children: product.max_downloads })
8089
+ ] }),
8090
+ product.version && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-3 py-2 bg-muted text-center", children: [
8091
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: "Version" }),
8092
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm font-semibold", children: [
8093
+ "v",
8094
+ product.version
8095
+ ] })
8096
+ ] }),
8097
+ product.download_expires_days != null && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-3 py-2 bg-muted text-center", children: [
8098
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: "Expires" }),
8099
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm font-semibold", children: [
8100
+ product.download_expires_days,
8101
+ " days"
8102
+ ] })
8103
+ ] }),
8104
+ product.max_activations != null && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-3 py-2 bg-muted text-center", children: [
8105
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: "Activations" }),
8106
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold", children: product.max_activations })
8107
+ ] })
8108
+ ] }),
8109
+ /* @__PURE__ */ jsxRuntime.jsx(CustomAttributesTable, { attributes: product.custom_attributes || [] }),
8110
+ /* @__PURE__ */ jsxRuntime.jsx(
8111
+ ProductCustomizer,
8112
+ {
8113
+ product,
8114
+ onAddToCart,
8115
+ showSpecialInstructions: false
8116
+ }
8117
+ )
8118
+ ] })
8119
+ }
8120
+ ),
8121
+ showRelated && relatedProducts && relatedProducts.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
8122
+ RelatedProductsSection,
8123
+ {
8124
+ products: relatedProducts,
8125
+ title: "More digital products"
8126
+ }
8127
+ )
8128
+ ] });
8129
+ }
8130
+ var ProductTemplate = /* @__PURE__ */ ((ProductTemplate2) => {
8131
+ ProductTemplate2["Default"] = "default";
8132
+ ProductTemplate2["Food"] = "food";
8133
+ ProductTemplate2["Wholesale"] = "wholesale";
8134
+ ProductTemplate2["Service"] = "service";
8135
+ ProductTemplate2["Digital"] = "digital";
8136
+ ProductTemplate2["Physical"] = "physical";
8137
+ return ProductTemplate2;
8138
+ })(ProductTemplate || {});
8139
+ var BUILT_IN_LAYOUTS = {
8140
+ ["food" /* Food */]: FoodProductLayout,
8141
+ ["wholesale" /* Wholesale */]: WholesaleProductLayout,
8142
+ ["service" /* Service */]: ServiceProductLayout,
8143
+ ["digital" /* Digital */]: DigitalProductLayout,
8144
+ ["default" /* Default */]: DefaultProductLayout
8145
+ };
8146
+ function resolveTemplateKey(product) {
8147
+ const metaTemplate = product.metadata?.page_template;
8148
+ if (typeof metaTemplate === "string" && metaTemplate.trim()) {
8149
+ return metaTemplate.trim();
8150
+ }
8151
+ if (product.quantity_pricing && product.quantity_pricing.length > 1) {
8152
+ return "wholesale" /* Wholesale */;
8153
+ }
8154
+ if (product.type === "service") {
8155
+ return "service" /* Service */;
8156
+ }
8157
+ if (product.type === "digital") {
8158
+ return "digital" /* Digital */;
8159
+ }
8160
+ if (product.render_hint === "food") {
8161
+ return "food" /* Food */;
8162
+ }
8163
+ if (product.render_hint === "physical") {
8164
+ return "physical" /* Physical */;
8165
+ }
8166
+ return "default" /* Default */;
8167
+ }
8168
+ function resolveLayout(product, pages, templates) {
8169
+ if (pages?.[product.slug]) {
8170
+ return pages[product.slug];
8171
+ }
8172
+ const key = resolveTemplateKey(product);
8173
+ if (templates?.[key]) {
8174
+ return templates[key];
8175
+ }
8176
+ if (BUILT_IN_LAYOUTS[key]) {
8177
+ return BUILT_IN_LAYOUTS[key];
8178
+ }
8179
+ return DefaultProductLayout;
8180
+ }
8181
+ function ProductPage({
8182
+ productId,
8183
+ product: productProp,
8184
+ pages,
8185
+ templates,
8186
+ onAddToCart,
8187
+ renderImage,
8188
+ renderBreadcrumb,
8189
+ relatedProducts,
8190
+ showRelated = true,
8191
+ className,
8192
+ classNames
8193
+ }) {
8194
+ const resolvedId = productId || productProp?.slug || productProp?.id || "";
8195
+ const { product: fetched, isLoading } = useProduct(resolvedId, {
8196
+ enabled: !productProp && resolvedId.length > 0
8197
+ });
8198
+ const product = productProp ?? fetched;
8199
+ if (isLoading && !product) {
8200
+ return /* @__PURE__ */ jsxRuntime.jsx(
8201
+ "div",
8202
+ {
8203
+ "data-cimplify-product-page": true,
8204
+ "aria-busy": "true",
8205
+ className: cn(className, classNames?.root, classNames?.loading),
8206
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid lg:grid-cols-2 gap-8 lg:gap-12 animate-pulse", children: [
8207
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "aspect-square bg-muted" }),
8208
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4 py-4", children: [
8209
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-8 w-3/5 bg-muted" }),
8210
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-6 w-2/5 bg-muted" }),
8211
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-4 w-4/5 bg-muted" }),
8212
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-4 w-3/5 bg-muted" }),
8213
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-14 w-full bg-muted mt-8" })
8214
+ ] })
8215
+ ] })
8216
+ }
8217
+ );
8218
+ }
8219
+ if (!product) {
8220
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-product-page": true, className: cn(className, classNames?.root), children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground", children: "Product not found." }) });
8221
+ }
8222
+ const Layout = resolveLayout(product, pages, templates);
8223
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-product-page": true, className: cn(className, classNames?.root), children: /* @__PURE__ */ jsxRuntime.jsx(
8224
+ Layout,
8225
+ {
8226
+ product,
8227
+ onAddToCart,
8228
+ renderImage,
8229
+ renderBreadcrumb,
8230
+ relatedProducts,
8231
+ showRelated
8232
+ }
8233
+ ) });
8234
+ }
8235
+ function CartPage({
8236
+ title = "Your Cart",
8237
+ onCheckout,
8238
+ onContinueShopping,
8239
+ onDiscountApply,
8240
+ onDiscountClear,
8241
+ showDiscount = true,
8242
+ showContinueShopping = true,
8243
+ checkoutLabel = "Proceed to Checkout",
8244
+ className,
8245
+ classNames
8246
+ }) {
8247
+ const { isEmpty, subtotal } = useCart();
8248
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-cart-page": true, className: cn(className, classNames?.root), children: [
8249
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-cart-page-header": true, className: classNames?.header, children: [
8250
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { "data-cimplify-cart-page-title": true, className: classNames?.title, children: title }),
8251
+ showContinueShopping && /* @__PURE__ */ jsxRuntime.jsx(
8252
+ "button",
7349
8253
  {
7350
8254
  type: "button",
7351
8255
  onClick: onContinueShopping,
@@ -7825,7 +8729,7 @@ function BookingPage({
7825
8729
  const hasStaffStep = staff && staff.length > 0;
7826
8730
  const depositType = product?.deposit_type;
7827
8731
  const depositAmount = product?.deposit_amount;
7828
- const hasDeposit = depositType !== void 0 && depositType !== "none" && depositAmount !== void 0 && chunk5FK7MDHS_js.parsePrice(depositAmount) !== 0;
8732
+ const hasDeposit = depositType !== void 0 && depositType !== "none" && depositAmount !== void 0 && chunkPEDLCL72_js.parsePrice(depositAmount) !== 0;
7829
8733
  const cancellationMinutes = product?.cancellation_window_minutes;
7830
8734
  const noShowFee = product?.no_show_fee;
7831
8735
  const handleSlotSelect = React3.useCallback(
@@ -7957,14 +8861,14 @@ function BookingPage({
7957
8861
  service.price && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-booking-service-price": true, children: /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: service.price }) }),
7958
8862
  hasDeposit && /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-cimplify-booking-deposit-info": true, className: classNames?.depositInfo, children: [
7959
8863
  "Deposit: ",
7960
- depositType === "percentage" ? `${chunk5FK7MDHS_js.parsePrice(depositAmount)}%` : /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: depositAmount })
8864
+ depositType === "percentage" ? `${chunkPEDLCL72_js.parsePrice(depositAmount)}%` : /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: depositAmount })
7961
8865
  ] }),
7962
8866
  cancellationMinutes !== void 0 && cancellationMinutes > 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-cimplify-booking-cancellation-policy": true, className: classNames?.cancellationPolicy, children: [
7963
8867
  "Free cancellation up to ",
7964
8868
  cancellationMinutes >= 60 ? `${Math.floor(cancellationMinutes / 60)} hour${Math.floor(cancellationMinutes / 60) !== 1 ? "s" : ""}` : `${cancellationMinutes} minute${cancellationMinutes !== 1 ? "s" : ""}`,
7965
8869
  " before"
7966
8870
  ] }),
7967
- noShowFee !== void 0 && chunk5FK7MDHS_js.parsePrice(noShowFee) !== 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-cimplify-booking-no-show-fee": true, className: classNames?.cancellationPolicy, children: [
8871
+ noShowFee !== void 0 && chunkPEDLCL72_js.parsePrice(noShowFee) !== 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-cimplify-booking-no-show-fee": true, className: classNames?.cancellationPolicy, children: [
7968
8872
  "No-show fee: ",
7969
8873
  /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: noShowFee })
7970
8874
  ] })
@@ -8041,7 +8945,7 @@ function BookingPage({
8041
8945
  ] }),
8042
8946
  hasDeposit && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-booking-summary-row": true, className: cn(classNames?.summaryRow, classNames?.depositInfo), children: [
8043
8947
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Deposit" }),
8044
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: depositType === "percentage" ? `${chunk5FK7MDHS_js.parsePrice(depositAmount)}%` : /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: depositAmount }) })
8948
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: depositType === "percentage" ? `${chunkPEDLCL72_js.parsePrice(depositAmount)}%` : /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: depositAmount }) })
8045
8949
  ] })
8046
8950
  ] }),
8047
8951
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -8356,102 +9260,6 @@ function RecentlyViewed({
8356
9260
  product.product_id
8357
9261
  )) });
8358
9262
  }
8359
- var FREQUENCY_LABELS = {
8360
- weekly: "Weekly",
8361
- monthly: "Monthly",
8362
- quarterly: "Quarterly",
8363
- annually: "Annually"
8364
- };
8365
- function formatMarkup(plan) {
8366
- if (!plan.markup_type || plan.markup_amount == null) return null;
8367
- if (plan.markup_type === "percentage") return `+${plan.markup_amount}%`;
8368
- return null;
8369
- }
8370
- function BillingPlanSelector({
8371
- productId,
8372
- plans: plansProp,
8373
- onPlanSelect,
8374
- selectedPlanId,
8375
- showOneTimePurchase = false,
8376
- oneTimePurchaseLabel = "One-time purchase",
8377
- renderPlan,
8378
- className,
8379
- classNames
8380
- }) {
8381
- const { plans: fetched, isLoading } = useBillingPlans(productId, {
8382
- enabled: plansProp === void 0
8383
- });
8384
- const plans = plansProp ?? fetched;
8385
- if (isLoading && plans.length === 0) {
8386
- return /* @__PURE__ */ jsxRuntime.jsx(
8387
- "div",
8388
- {
8389
- "data-cimplify-billing-plan-selector": true,
8390
- "aria-busy": "true",
8391
- className: cn(className, classNames?.root, classNames?.loading)
8392
- }
8393
- );
8394
- }
8395
- if (plans.length === 0 && !showOneTimePurchase) {
8396
- return null;
8397
- }
8398
- const isOneTimePurchaseSelected = selectedPlanId === null;
8399
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-billing-plan-selector": true, className: cn(className, classNames?.root), children: [
8400
- showOneTimePurchase && /* @__PURE__ */ jsxRuntime.jsx(
8401
- "button",
8402
- {
8403
- type: "button",
8404
- onClick: () => onPlanSelect?.(null),
8405
- "data-cimplify-billing-plan": true,
8406
- "data-plan-type": "one-time",
8407
- "data-active": isOneTimePurchaseSelected || void 0,
8408
- "aria-pressed": isOneTimePurchaseSelected,
8409
- className: cn(
8410
- classNames?.plan,
8411
- isOneTimePurchaseSelected && classNames?.activePlan
8412
- ),
8413
- children: /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-billing-frequency": true, className: classNames?.frequency, children: oneTimePurchaseLabel })
8414
- }
8415
- ),
8416
- plans.map((plan) => {
8417
- const isActive = selectedPlanId === plan.id;
8418
- const markup = formatMarkup(plan);
8419
- return /* @__PURE__ */ jsxRuntime.jsx(
8420
- "button",
8421
- {
8422
- type: "button",
8423
- onClick: () => onPlanSelect?.(plan),
8424
- "data-cimplify-billing-plan": true,
8425
- "data-plan-type": plan.plan_type,
8426
- "data-active": isActive || void 0,
8427
- "aria-pressed": isActive,
8428
- className: cn(classNames?.plan, isActive && classNames?.activePlan),
8429
- children: renderPlan ? renderPlan(plan, isActive) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
8430
- /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-billing-frequency": true, className: classNames?.frequency, children: FREQUENCY_LABELS[plan.frequency] }),
8431
- markup && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-billing-markup": true, className: classNames?.price, children: markup }),
8432
- plan.markup_type === "fixed" && plan.markup_amount != null && /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-cimplify-billing-markup": true, className: classNames?.price, children: [
8433
- "+",
8434
- /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: plan.markup_amount })
8435
- ] }),
8436
- plan.trial_days > 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-cimplify-billing-trial": true, className: classNames?.trialBadge, children: [
8437
- plan.trial_days,
8438
- "-day trial"
8439
- ] }),
8440
- plan.setup_fee > 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-cimplify-billing-setup-fee": true, className: classNames?.setupFee, children: [
8441
- "Setup fee: ",
8442
- /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: plan.setup_fee })
8443
- ] }),
8444
- plan.plan_type === "installment" && plan.installment_periods != null && /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-cimplify-billing-periods": true, children: [
8445
- plan.installment_periods,
8446
- " payments"
8447
- ] })
8448
- ] })
8449
- },
8450
- plan.id
8451
- );
8452
- })
8453
- ] });
8454
- }
8455
9263
  function DeliveryEstimate({
8456
9264
  latitude,
8457
9265
  longitude,
@@ -8601,7 +9409,7 @@ function CurrencySelector({
8601
9409
 
8602
9410
  Object.defineProperty(exports, "getVariantDisplayName", {
8603
9411
  enumerable: true,
8604
- get: function () { return chunkKLRTWBDF_js.getVariantDisplayName; }
9412
+ get: function () { return chunkIYQGGFVQ_js.getVariantDisplayName; }
8605
9413
  });
8606
9414
  exports.Ad = Ad;
8607
9415
  exports.AdProvider = AdProvider;
@@ -8626,39 +9434,54 @@ exports.CimplifyProvider = CimplifyProvider;
8626
9434
  exports.CollectionPage = CollectionPage;
8627
9435
  exports.CompositeSelector = CompositeSelector;
8628
9436
  exports.CurrencySelector = CurrencySelector;
9437
+ exports.CustomAttributesTable = CustomAttributesTable;
8629
9438
  exports.DateSlotPicker = DateSlotPicker;
8630
9439
  exports.DealBanner = DealBanner;
8631
9440
  exports.DealsPage = DealsPage;
9441
+ exports.DefaultProductLayout = DefaultProductLayout;
8632
9442
  exports.DeliveryEstimate = DeliveryEstimate;
9443
+ exports.DigitalProductLayout = DigitalProductLayout;
8633
9444
  exports.DiscountInput = DiscountInput;
8634
9445
  exports.ElementsProvider = ElementsProvider;
9446
+ exports.FoodProductLayout = FoodProductLayout;
9447
+ exports.InventoryBadge = InventoryBadge;
8635
9448
  exports.LocationPicker = LocationPicker;
9449
+ exports.MetadataStringList = MetadataStringList;
8636
9450
  exports.OrderDetailPage = OrderDetailPage;
8637
9451
  exports.OrderHistory = OrderHistory;
8638
9452
  exports.OrderHistoryPage = OrderHistoryPage;
8639
9453
  exports.OrderSummary = OrderSummary;
8640
9454
  exports.PaymentElement = PaymentElement;
8641
9455
  exports.Price = Price;
9456
+ exports.PriceRange = PriceRange;
8642
9457
  exports.ProductCard = ProductCard;
8643
9458
  exports.ProductCustomizer = ProductCustomizer;
8644
9459
  exports.ProductGrid = ProductGrid;
8645
9460
  exports.ProductImageGallery = ProductImageGallery;
8646
9461
  exports.ProductPage = ProductPage;
8647
9462
  exports.ProductSheet = ProductSheet;
9463
+ exports.ProductTemplate = ProductTemplate;
9464
+ exports.PropertiesTable = PropertiesTable;
8648
9465
  exports.QuantitySelector = QuantitySelector;
8649
9466
  exports.RecentlyViewed = RecentlyViewed;
8650
9467
  exports.RecommendationCarousel = RecommendationCarousel;
9468
+ exports.RelatedProductsSection = RelatedProductsSection;
8651
9469
  exports.ResourcePicker = ResourcePicker;
8652
9470
  exports.SaleBadge = SaleBadge;
8653
9471
  exports.SearchInput = SearchInput;
8654
9472
  exports.SearchPage = SearchPage;
8655
9473
  exports.ServiceCard = ServiceCard;
8656
9474
  exports.ServiceGrid = ServiceGrid;
9475
+ exports.ServiceProductLayout = ServiceProductLayout;
8657
9476
  exports.SessionMessageBanner = SessionMessageBanner;
8658
9477
  exports.SlotPicker = SlotPicker;
8659
9478
  exports.StaffPicker = StaffPicker;
8660
9479
  exports.StoreNav = StoreNav;
9480
+ exports.TagPills = TagPills;
9481
+ exports.TwoColumnGrid = TwoColumnGrid;
8661
9482
  exports.VariantSelector = VariantSelector;
9483
+ exports.VolumePricing = VolumePricing;
9484
+ exports.WholesaleProductLayout = WholesaleProductLayout;
8662
9485
  exports.cn = cn;
8663
9486
  exports.roomToResource = roomToResource;
8664
9487
  exports.useActivityState = useActivityState;