@nextblock-cms/ecom 0.11.1 → 0.11.2

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.
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const r=require("react/jsx-runtime"),S=require("./AddToCartButton.cjs.js"),l=require("@nextblock-cms/utils"),v=require("next/link"),w=require("../CurrencyProvider.cjs.js"),n=require("../currency.cjs.js"),q=require("../trials.cjs.js"),A=require("../variation-utils.cjs.js"),T=({product:e,className:b})=>{const{activeCurrencyCode:a,currencies:c}=w.useCurrency(),i=n.resolvePriceRangeForCurrency({entries:e.variants?.length?e.variants:e.product_variants?.length?e.product_variants:[],currencyCode:a,currencies:c}),u=!!(e.has_variants&&i),t=n.resolveEffectivePriceForCurrency({prices:e.prices,salePrices:e.sale_prices,fallbackPrice:e.price,fallbackSalePrice:e.sale_price,saleStartAt:e.sale_start_at,saleEndAt:e.sale_end_at,scheduledPrice:e.scheduled_price,scheduledPrices:e.scheduled_prices,scheduledPriceAt:e.scheduled_price_at,currencyCode:a,currencies:c}),P=u&&i?i.min===i.max?l.formatPrice(i.min,a):`${l.formatPrice(i.min,a)} - ${l.formatPrice(i.max,a)}`:l.formatPrice(t.sale_price??t.price,a),j=e.variants?.length?e.variants:e.product_variants?.length?e.product_variants:[],y=u?j.some(s=>n.resolveEffectivePriceForCurrency({prices:s.prices,salePrices:s.sale_prices,fallbackPrice:s.price,fallbackSalePrice:s.sale_price,saleStartAt:s.sale_start_at,saleEndAt:s.sale_end_at,scheduledPrice:s.scheduled_price,scheduledPrices:s.scheduled_prices,scheduledPriceAt:s.scheduled_price_at,currencyCode:a,currencies:c}).sale_price!=null):t.sale_price!=null,{t:x,lang:N}=l.useTranslations(),p=x("ecommerce.on_sale"),C=p==="ecommerce.on_sale"?"On Sale":p,f=q.getTrialSummary(e),o=e.freemius_plans?.[0]?.freemius_pricing?.[0],d=c.find(s=>s.is_default)?.code||"USD",_=o?.override_monthly_price??o?.api_monthly_price,g=o?.override_annual_price??o?.api_annual_price,m=typeof _=="number"?n.resolvePriceForCurrency({prices:{[d]:l.majorUnitAmountToMinor(_,d)},currencyCode:a,currencies:c}):null,h=typeof g=="number"?n.resolvePriceForCurrency({prices:{[d]:l.majorUnitAmountToMinor(g,d)},currencyCode:a,currencies:c}):null;return r.jsxs("div",{className:l.cn("group relative flex flex-col overflow-hidden rounded-lg border bg-card text-card-foreground shadow-sm transition-all hover:shadow-md",b),children:[r.jsxs(v,{href:`/product/${e.slug}`,className:"relative aspect-square overflow-hidden bg-muted",children:[y&&r.jsx("span",{className:"absolute left-3 top-3 z-10 rounded-full bg-destructive px-2.5 py-1 text-[10px] font-bold uppercase tracking-wider text-destructive-foreground shadow-sm",children:C}),e.image_url?r.jsx("img",{src:e.image_url,alt:e.title,className:"h-full w-full object-cover object-center transition-transform duration-300 group-hover:scale-105"}):r.jsx("div",{className:"flex h-full items-center justify-center text-muted-foreground",children:"No Image"})]}),r.jsxs("div",{className:"flex flex-1 flex-col p-4",children:[e.categories&&e.categories.length>0&&r.jsx("div",{className:"text-[10px] font-bold uppercase tracking-widest text-amber-600 dark:text-amber-400 mb-1",children:e.categories.map(s=>A.resolveTranslatedText(s.name,s.name_translations,N)).join(" • ")}),r.jsx(v,{href:`/product/${e.slug}`,className:"mb-2",children:r.jsx("h3",{className:"line-clamp-1 text-lg font-medium text-foreground group-hover:underline",children:e.title})}),r.jsx("div",{className:"mb-4",children:e.product_type==="digital"&&(m||h)?r.jsxs("div",{className:"flex flex-wrap items-baseline gap-x-3 gap-y-1",children:[m&&r.jsxs("div",{className:"flex items-baseline gap-0.5",children:[r.jsx("span",{className:"text-xl font-bold text-primary",children:l.formatPrice(m.price,a)}),r.jsxs("span",{className:"text-xs font-medium text-muted-foreground lowercase",children:["/ ",x("ecommerce.month")]})]}),h&&r.jsxs("div",{className:"flex items-baseline gap-0.5",children:[r.jsx("span",{className:l.cn("font-bold text-primary",m?"text-lg":"text-xl"),children:l.formatPrice(h.price,a)}),r.jsxs("span",{className:"text-xs font-medium text-muted-foreground lowercase",children:["/ ",x("ecommerce.year")]})]})]}):r.jsxs("div",{className:"flex items-baseline gap-2",children:[r.jsx("span",{className:"text-xl font-bold text-primary",children:P}),!u&&t.sale_price&&r.jsx("span",{className:"text-sm text-muted-foreground line-through",children:l.formatPrice(t.price,a)})]})}),f&&r.jsxs("div",{className:"mb-4 rounded-md border border-emerald-200 bg-emerald-50 px-3 py-2 text-xs text-emerald-900",children:[r.jsx("div",{className:"font-semibold",children:f.label}),r.jsx("div",{className:"text-emerald-700",children:f.paymentRequirementLabel})]}),r.jsx("div",{className:"mt-auto",children:r.jsx(S.AddToCartButton,{product:{...e,price:e.price,prices:e.prices,sale_price:e.sale_price,sale_prices:e.sale_prices},className:"w-full"})})]})]})};exports.ProductCard=T;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const r=require("react/jsx-runtime"),k=require("./AddToCartButton.cjs.js"),a=require("@nextblock-cms/utils"),b=require("next/link"),A=require("../CurrencyProvider.cjs.js"),c=require("../currency.cjs.js"),q=require("../trials.cjs.js"),R=require("../variation-utils.cjs.js"),T=({product:e,className:j})=>{const{activeCurrencyCode:l,currencies:i}=A.useCurrency(),t=c.resolvePriceRangeForCurrency({entries:e.variants?.length?e.variants:e.product_variants?.length?e.product_variants:[],currencyCode:l,currencies:i}),u=!!(e.has_variants&&t),n=c.resolveEffectivePriceForCurrency({prices:e.prices,salePrices:e.sale_prices,fallbackPrice:e.price,fallbackSalePrice:e.sale_price,saleStartAt:e.sale_start_at,saleEndAt:e.sale_end_at,scheduledPrice:e.scheduled_price,scheduledPrices:e.scheduled_prices,scheduledPriceAt:e.scheduled_price_at,currencyCode:l,currencies:i}),P=u&&t?t.min===t.max?a.formatPrice(t.min,l):`${a.formatPrice(t.min,l)} - ${a.formatPrice(t.max,l)}`:a.formatPrice(n.sale_price??n.price,l),y=e.variants?.length?e.variants:e.product_variants?.length?e.product_variants:[],N=u?y.some(s=>c.resolveEffectivePriceForCurrency({prices:s.prices,salePrices:s.sale_prices,fallbackPrice:s.price,fallbackSalePrice:s.sale_price,saleStartAt:s.sale_start_at,saleEndAt:s.sale_end_at,scheduledPrice:s.scheduled_price,scheduledPrices:s.scheduled_prices,scheduledPriceAt:s.scheduled_price_at,currencyCode:l,currencies:i}).sale_price!=null):n.sale_price!=null,{t:o,lang:C}=a.useTranslations(),g=o("ecommerce.on_sale"),w=g==="ecommerce.on_sale"?"On Sale":g,h=q.getTrialSummary(e),m=e.freemius_plans?.[0]?.freemius_pricing?.[0],d=i.find(s=>s.is_default)?.code||"USD",_=m?.override_monthly_price??m?.api_monthly_price,p=m?.override_annual_price??m?.api_annual_price,x=typeof _=="number"?c.resolvePriceForCurrency({prices:{[d]:a.majorUnitAmountToMinor(_,d)},currencyCode:l,currencies:i}):null,f=typeof p=="number"?c.resolvePriceForCurrency({prices:{[d]:a.majorUnitAmountToMinor(p,d)},currencyCode:l,currencies:i}):null;return r.jsxs("div",{className:a.cn("group relative flex flex-col overflow-hidden rounded-lg border bg-card text-card-foreground shadow-sm transition-all hover:shadow-md",j),children:[r.jsxs(b,{href:`/product/${e.slug}`,className:"relative aspect-square overflow-hidden bg-muted",children:[N&&r.jsx("span",{className:"absolute left-3 top-3 z-10 rounded-full bg-destructive px-2.5 py-1 text-[10px] font-bold uppercase tracking-wider text-destructive-foreground shadow-sm",children:w}),e.image_url?r.jsx("img",{src:e.image_url,alt:e.title,className:"h-full w-full object-cover object-center transition-transform duration-300 group-hover:scale-105"}):r.jsx("div",{className:"flex h-full items-center justify-center text-muted-foreground",children:"No Image"})]}),r.jsxs("div",{className:"flex flex-1 flex-col p-4",children:[e.categories&&e.categories.length>0&&r.jsx("div",{className:"text-[10px] font-bold uppercase tracking-widest text-amber-600 dark:text-amber-400 mb-1",children:e.categories.map(s=>R.resolveTranslatedText(s.name,s.name_translations,C)).join(" • ")}),r.jsx(b,{href:`/product/${e.slug}`,className:"mb-2",children:r.jsx("h3",{className:"line-clamp-1 text-lg font-medium text-foreground group-hover:underline",children:e.title})}),r.jsx("div",{className:"flex items-center gap-1 mb-2 mt-0.5 text-xs text-muted-foreground min-h-[1.25rem] select-none","aria-label":`Rating: ${e.average_rating??0} out of 5 stars`,children:e.total_reviews&&e.total_reviews>0?r.jsxs(r.Fragment,{children:[r.jsx("div",{className:"flex items-center text-amber-500 mr-1",children:Array.from({length:5}).map((s,v)=>{const S=e.average_rating??0;return r.jsx("svg",{className:a.cn("h-3.5 w-3.5 fill-current",v<Math.round(S)?"text-amber-500":"text-slate-200 dark:text-slate-800"),viewBox:"0 0 20 20",fill:"currentColor",children:r.jsx("path",{d:"M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"})},v)})}),r.jsx("span",{className:"font-semibold text-slate-700 dark:text-slate-300",children:Number(e.average_rating).toFixed(1)}),r.jsxs("span",{className:"ml-0.5",children:["(",e.total_reviews,")"]})]}):r.jsx("span",{className:"text-slate-400 dark:text-slate-600",children:o("reviews.no_reviews")})}),r.jsx("div",{className:"mb-4",children:e.product_type==="digital"&&(x||f)?r.jsxs("div",{className:"flex flex-wrap items-baseline gap-x-3 gap-y-1",children:[x&&r.jsxs("div",{className:"flex items-baseline gap-0.5",children:[r.jsx("span",{className:"text-xl font-bold text-primary",children:a.formatPrice(x.price,l)}),r.jsxs("span",{className:"text-xs font-medium text-muted-foreground lowercase",children:["/ ",o("ecommerce.month")]})]}),f&&r.jsxs("div",{className:"flex items-baseline gap-0.5",children:[r.jsx("span",{className:a.cn("font-bold text-primary",x?"text-lg":"text-xl"),children:a.formatPrice(f.price,l)}),r.jsxs("span",{className:"text-xs font-medium text-muted-foreground lowercase",children:["/ ",o("ecommerce.year")]})]})]}):r.jsxs("div",{className:"flex items-baseline gap-2",children:[r.jsx("span",{className:"text-xl font-bold text-primary",children:P}),!u&&n.sale_price&&r.jsx("span",{className:"text-sm text-muted-foreground line-through",children:a.formatPrice(n.price,l)})]})}),h&&r.jsxs("div",{className:"mb-4 rounded-md border border-emerald-200 bg-emerald-50 px-3 py-2 text-xs text-emerald-900",children:[r.jsx("div",{className:"font-semibold",children:h.label}),r.jsx("div",{className:"text-emerald-700",children:h.paymentRequirementLabel})]}),r.jsx("div",{className:"mt-auto",children:r.jsx(k.AddToCartButton,{product:{...e,price:e.price,prices:e.prices,sale_price:e.sale_price,sale_prices:e.sale_prices},className:"w-full"})})]})]})};exports.ProductCard=T;
@@ -1,18 +1,18 @@
1
1
  'use client';
2
- import { jsxs as s, jsx as r } from "react/jsx-runtime";
3
- import { AddToCartButton as R } from "./AddToCartButton.es.js";
4
- import { formatPrice as c, useTranslations as T, majorUnitAmountToMinor as b, cn as v } from "@nextblock-cms/utils";
2
+ import { jsxs as s, jsx as a, Fragment as T } from "react/jsx-runtime";
3
+ import { AddToCartButton as F } from "./AddToCartButton.es.js";
4
+ import { formatPrice as i, useTranslations as M, majorUnitAmountToMinor as N, cn as p } from "@nextblock-cms/utils";
5
5
  import y from "next/link";
6
- import { useCurrency as L } from "../CurrencyProvider.es.js";
7
- import { resolvePriceRangeForCurrency as E, resolveEffectivePriceForCurrency as N, resolvePriceForCurrency as P } from "../currency.es.js";
8
- import { getTrialSummary as $ } from "../trials.es.js";
9
- import { resolveTranslatedText as F } from "../variation-utils.es.js";
10
- const G = ({ product: e, className: C }) => {
11
- const { activeCurrencyCode: l, currencies: n } = L(), i = E({
6
+ import { useCurrency as $ } from "../CurrencyProvider.es.js";
7
+ import { resolvePriceRangeForCurrency as E, resolveEffectivePriceForCurrency as P, resolvePriceForCurrency as w } from "../currency.es.js";
8
+ import { getTrialSummary as B } from "../trials.es.js";
9
+ import { resolveTranslatedText as q } from "../variation-utils.es.js";
10
+ const K = ({ product: e, className: C }) => {
11
+ const { activeCurrencyCode: l, currencies: n } = $(), t = E({
12
12
  entries: e.variants?.length ? e.variants : e.product_variants?.length ? e.product_variants : [],
13
13
  currencyCode: l,
14
14
  currencies: n
15
- }), f = !!(e.has_variants && i), t = N({
15
+ }), f = !!(e.has_variants && t), c = P({
16
16
  prices: e.prices,
17
17
  salePrices: e.sale_prices,
18
18
  fallbackPrice: e.price,
@@ -24,82 +24,106 @@ const G = ({ product: e, className: C }) => {
24
24
  scheduledPriceAt: e.scheduled_price_at,
25
25
  currencyCode: l,
26
26
  currencies: n
27
- }), w = f && i ? i.min === i.max ? c(i.min, l) : `${c(i.min, l)} - ${c(
28
- i.max,
27
+ }), S = f && t ? t.min === t.max ? i(t.min, l) : `${i(t.min, l)} - ${i(
28
+ t.max,
29
29
  l
30
- )}` : c(t.sale_price ?? t.price, l), S = e.variants?.length ? e.variants : e.product_variants?.length ? e.product_variants : [], j = f ? S.some(
31
- (a) => N({
32
- prices: a.prices,
33
- salePrices: a.sale_prices,
34
- fallbackPrice: a.price,
35
- fallbackSalePrice: a.sale_price,
36
- saleStartAt: a.sale_start_at,
37
- saleEndAt: a.sale_end_at,
38
- scheduledPrice: a.scheduled_price,
39
- scheduledPrices: a.scheduled_prices,
40
- scheduledPriceAt: a.scheduled_price_at,
30
+ )}` : i(c.sale_price ?? c.price, l), k = e.variants?.length ? e.variants : e.product_variants?.length ? e.product_variants : [], j = f ? k.some(
31
+ (r) => P({
32
+ prices: r.prices,
33
+ salePrices: r.sale_prices,
34
+ fallbackPrice: r.price,
35
+ fallbackSalePrice: r.sale_price,
36
+ saleStartAt: r.sale_start_at,
37
+ saleEndAt: r.sale_end_at,
38
+ scheduledPrice: r.scheduled_price,
39
+ scheduledPrices: r.scheduled_prices,
40
+ scheduledPriceAt: r.scheduled_price_at,
41
41
  currencyCode: l,
42
42
  currencies: n
43
43
  }).sale_price != null
44
- ) : t.sale_price != null, { t: p, lang: k } = T(), x = p("ecommerce.on_sale"), A = x === "ecommerce.on_sale" ? "On Sale" : x, h = $(e), o = e.freemius_plans?.[0]?.freemius_pricing?.[0], m = n.find((a) => a.is_default)?.code || "USD", _ = o?.override_monthly_price ?? o?.api_monthly_price, g = o?.override_annual_price ?? o?.api_annual_price, d = typeof _ == "number" ? P({
44
+ ) : c.sale_price != null, { t: o, lang: A } = M(), g = o("ecommerce.on_sale"), R = g === "ecommerce.on_sale" ? "On Sale" : g, x = B(e), m = e.freemius_plans?.[0]?.freemius_pricing?.[0], d = n.find((r) => r.is_default)?.code || "USD", _ = m?.override_monthly_price ?? m?.api_monthly_price, v = m?.override_annual_price ?? m?.api_annual_price, h = typeof _ == "number" ? w({
45
45
  prices: {
46
- [m]: b(
46
+ [d]: N(
47
47
  _,
48
- m
48
+ d
49
49
  )
50
50
  },
51
51
  currencyCode: l,
52
52
  currencies: n
53
- }) : null, u = typeof g == "number" ? P({
53
+ }) : null, u = typeof v == "number" ? w({
54
54
  prices: {
55
- [m]: b(
56
- g,
57
- m
55
+ [d]: N(
56
+ v,
57
+ d
58
58
  )
59
59
  },
60
60
  currencyCode: l,
61
61
  currencies: n
62
62
  }) : null;
63
- return /* @__PURE__ */ s("div", { className: v("group relative flex flex-col overflow-hidden rounded-lg border bg-card text-card-foreground shadow-sm transition-all hover:shadow-md", C), children: [
63
+ return /* @__PURE__ */ s("div", { className: p("group relative flex flex-col overflow-hidden rounded-lg border bg-card text-card-foreground shadow-sm transition-all hover:shadow-md", C), children: [
64
64
  /* @__PURE__ */ s(y, { href: `/product/${e.slug}`, className: "relative aspect-square overflow-hidden bg-muted", children: [
65
- j && /* @__PURE__ */ r("span", { className: "absolute left-3 top-3 z-10 rounded-full bg-destructive px-2.5 py-1 text-[10px] font-bold uppercase tracking-wider text-destructive-foreground shadow-sm", children: A }),
66
- e.image_url ? /* @__PURE__ */ r(
65
+ j && /* @__PURE__ */ a("span", { className: "absolute left-3 top-3 z-10 rounded-full bg-destructive px-2.5 py-1 text-[10px] font-bold uppercase tracking-wider text-destructive-foreground shadow-sm", children: R }),
66
+ e.image_url ? /* @__PURE__ */ a(
67
67
  "img",
68
68
  {
69
69
  src: e.image_url,
70
70
  alt: e.title,
71
71
  className: "h-full w-full object-cover object-center transition-transform duration-300 group-hover:scale-105"
72
72
  }
73
- ) : /* @__PURE__ */ r("div", { className: "flex h-full items-center justify-center text-muted-foreground", children: "No Image" })
73
+ ) : /* @__PURE__ */ a("div", { className: "flex h-full items-center justify-center text-muted-foreground", children: "No Image" })
74
74
  ] }),
75
75
  /* @__PURE__ */ s("div", { className: "flex flex-1 flex-col p-4", children: [
76
- e.categories && e.categories.length > 0 && /* @__PURE__ */ r("div", { className: "text-[10px] font-bold uppercase tracking-widest text-amber-600 dark:text-amber-400 mb-1", children: e.categories.map((a) => F(a.name, a.name_translations, k)).join(" • ") }),
77
- /* @__PURE__ */ r(y, { href: `/product/${e.slug}`, className: "mb-2", children: /* @__PURE__ */ r("h3", { className: "line-clamp-1 text-lg font-medium text-foreground group-hover:underline", children: e.title }) }),
78
- /* @__PURE__ */ r("div", { className: "mb-4", children: e.product_type === "digital" && (d || u) ? /* @__PURE__ */ s("div", { className: "flex flex-wrap items-baseline gap-x-3 gap-y-1", children: [
79
- d && /* @__PURE__ */ s("div", { className: "flex items-baseline gap-0.5", children: [
80
- /* @__PURE__ */ r("span", { className: "text-xl font-bold text-primary", children: c(d.price, l) }),
76
+ e.categories && e.categories.length > 0 && /* @__PURE__ */ a("div", { className: "text-[10px] font-bold uppercase tracking-widest text-amber-600 dark:text-amber-400 mb-1", children: e.categories.map((r) => q(r.name, r.name_translations, A)).join(" • ") }),
77
+ /* @__PURE__ */ a(y, { href: `/product/${e.slug}`, className: "mb-2", children: /* @__PURE__ */ a("h3", { className: "line-clamp-1 text-lg font-medium text-foreground group-hover:underline", children: e.title }) }),
78
+ /* @__PURE__ */ a("div", { className: "flex items-center gap-1 mb-2 mt-0.5 text-xs text-muted-foreground min-h-[1.25rem] select-none", "aria-label": `Rating: ${e.average_rating ?? 0} out of 5 stars`, children: e.total_reviews && e.total_reviews > 0 ? /* @__PURE__ */ s(T, { children: [
79
+ /* @__PURE__ */ a("div", { className: "flex items-center text-amber-500 mr-1", children: Array.from({ length: 5 }).map((r, b) => {
80
+ const L = e.average_rating ?? 0;
81
+ return /* @__PURE__ */ a(
82
+ "svg",
83
+ {
84
+ className: p(
85
+ "h-3.5 w-3.5 fill-current",
86
+ b < Math.round(L) ? "text-amber-500" : "text-slate-200 dark:text-slate-800"
87
+ ),
88
+ viewBox: "0 0 20 20",
89
+ fill: "currentColor",
90
+ children: /* @__PURE__ */ a("path", { d: "M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z" })
91
+ },
92
+ b
93
+ );
94
+ }) }),
95
+ /* @__PURE__ */ a("span", { className: "font-semibold text-slate-700 dark:text-slate-300", children: Number(e.average_rating).toFixed(1) }),
96
+ /* @__PURE__ */ s("span", { className: "ml-0.5", children: [
97
+ "(",
98
+ e.total_reviews,
99
+ ")"
100
+ ] })
101
+ ] }) : /* @__PURE__ */ a("span", { className: "text-slate-400 dark:text-slate-600", children: o("reviews.no_reviews") }) }),
102
+ /* @__PURE__ */ a("div", { className: "mb-4", children: e.product_type === "digital" && (h || u) ? /* @__PURE__ */ s("div", { className: "flex flex-wrap items-baseline gap-x-3 gap-y-1", children: [
103
+ h && /* @__PURE__ */ s("div", { className: "flex items-baseline gap-0.5", children: [
104
+ /* @__PURE__ */ a("span", { className: "text-xl font-bold text-primary", children: i(h.price, l) }),
81
105
  /* @__PURE__ */ s("span", { className: "text-xs font-medium text-muted-foreground lowercase", children: [
82
106
  "/ ",
83
- p("ecommerce.month")
107
+ o("ecommerce.month")
84
108
  ] })
85
109
  ] }),
86
110
  u && /* @__PURE__ */ s("div", { className: "flex items-baseline gap-0.5", children: [
87
- /* @__PURE__ */ r("span", { className: v("font-bold text-primary", d ? "text-lg" : "text-xl"), children: c(u.price, l) }),
111
+ /* @__PURE__ */ a("span", { className: p("font-bold text-primary", h ? "text-lg" : "text-xl"), children: i(u.price, l) }),
88
112
  /* @__PURE__ */ s("span", { className: "text-xs font-medium text-muted-foreground lowercase", children: [
89
113
  "/ ",
90
- p("ecommerce.year")
114
+ o("ecommerce.year")
91
115
  ] })
92
116
  ] })
93
117
  ] }) : /* @__PURE__ */ s("div", { className: "flex items-baseline gap-2", children: [
94
- /* @__PURE__ */ r("span", { className: "text-xl font-bold text-primary", children: w }),
95
- !f && t.sale_price && /* @__PURE__ */ r("span", { className: "text-sm text-muted-foreground line-through", children: c(t.price, l) })
118
+ /* @__PURE__ */ a("span", { className: "text-xl font-bold text-primary", children: S }),
119
+ !f && c.sale_price && /* @__PURE__ */ a("span", { className: "text-sm text-muted-foreground line-through", children: i(c.price, l) })
96
120
  ] }) }),
97
- h && /* @__PURE__ */ s("div", { className: "mb-4 rounded-md border border-emerald-200 bg-emerald-50 px-3 py-2 text-xs text-emerald-900", children: [
98
- /* @__PURE__ */ r("div", { className: "font-semibold", children: h.label }),
99
- /* @__PURE__ */ r("div", { className: "text-emerald-700", children: h.paymentRequirementLabel })
121
+ x && /* @__PURE__ */ s("div", { className: "mb-4 rounded-md border border-emerald-200 bg-emerald-50 px-3 py-2 text-xs text-emerald-900", children: [
122
+ /* @__PURE__ */ a("div", { className: "font-semibold", children: x.label }),
123
+ /* @__PURE__ */ a("div", { className: "text-emerald-700", children: x.paymentRequirementLabel })
100
124
  ] }),
101
- /* @__PURE__ */ r("div", { className: "mt-auto", children: /* @__PURE__ */ r(
102
- R,
125
+ /* @__PURE__ */ a("div", { className: "mt-auto", children: /* @__PURE__ */ a(
126
+ F,
103
127
  {
104
128
  product: {
105
129
  ...e,
@@ -115,5 +139,5 @@ const G = ({ product: e, className: C }) => {
115
139
  ] });
116
140
  };
117
141
  export {
118
- G as ProductCard
142
+ K as ProductCard
119
143
  };
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),m=require("react"),R=require("lucide-react"),T=require("@nextblock-cms/ui/badge"),z=require("@nextblock-cms/ui/button"),W=require("@nextblock-cms/ui/label"),H=require("@nextblock-cms/ui/separator"),q=require("@nextblock-cms/utils"),Q=require("../product-context.cjs.js"),Y=require("./ProductGallery.cjs.js"),Z=require("./AddToCartButton.cjs.js"),ee=require("./SubscriptionSelector.cjs.js"),te=require("./SimpleTiptapRenderer.cjs.js"),h=require("../variation-utils.cjs.js"),se=require("../CurrencyProvider.cjs.js"),$=require("../currency.cjs.js"),re=require("../types.cjs.js"),ae=require("../trials.cjs.js");function I(l,v,t,o){const y={kind:"product-field",field:v,input:t,label:o},p=typeof window<"u"?window.location.origin:process.env.NEXT_PUBLIC_URL||process.env.TARGET_URL||(process.env.VERCEL_URL?`https://${process.env.VERCEL_URL}`:"")||"http://localhost:3000";let x=(typeof window<"u"?window.location.origin:process.env.NEXT_PUBLIC_URL||process.env.TARGET_URL||(process.env.VERCEL_URL?`https://${process.env.VERCEL_URL}`:"")||"http://localhost:3000").replace(/\/+$/,"");try{(x.startsWith("http://")||x.startsWith("https://"))&&(x=new URL(x).hostname)}catch{}const k=process.env.NEXTBLOCK_VERCEL_PROJECT_ID||process.env.VERCEL_PROJECT_ID,w=process.env.NEXTBLOCK_VERCEL_WORKSPACE_ID||process.env.VERCEL_ORG_ID,n={origin:x,editUrl:`${p}/cms/products/${l.id}/edit`,data:{parentType:"product",parentId:l.id,slug:l.slug,languageId:l.language_id,draftId:null,target:y}};return k&&(n.projectId=k),w&&(n.workspaceId=w),{"data-vercel-edit-info":JSON.stringify(n),"data-vercel-edit-target":JSON.stringify(y),"data-nextblock-visual-edit":`product:${v}`}}const ie=({visualEditingEnabled:l=!1,descriptionNode:v})=>{const t=Q.useProduct(),{t:o,lang:y}=q.useTranslations(),{activeCurrencyCode:p,currencies:P}=se.useCurrency(),x=l?I(t,"title","plain-text","Product title"):void 0,k=l?I(t,"short_description","plain-text","Short description"):void 0,w=l?I(t,"description_json","tiptap","Product description"):void 0,n=(r,u,i)=>{const B=o(r,i);return B===r?u:B},C=t.images&&t.images.length>0?t.images:t.image_url?[{url:t.image_url,alt:t.title}]:[],b=t.custom_props?.provider==="freemius"||re.isDigitalProduct(t),A=ae.getTrialSummary(t),a=!b&&!!(t.has_variants&&t.attributes?.length&&t.variants?.length),g=t.attributes||[],d=t.variants||[],[_,E]=m.useState(()=>h.chooseInitialVariantSelections(g,d)),[S,L]=m.useState(1);m.useEffect(()=>{L(1)},[t.id]),m.useEffect(()=>{a&&E(h.chooseInitialVariantSelections(g,d))},[g,a,t.id,d]);const f=m.useMemo(()=>a?h.normalizeSelectionsToAvailableVariants(g,d,_):_,[g,a,_,d]);m.useEffect(()=>{JSON.stringify(f)!==JSON.stringify(_)&&E(f)},[f,_]);const s=m.useMemo(()=>a?h.findMatchingVariant(d,f):null,[a,f,d]),V=$.resolveEffectivePriceForCurrency({prices:t.prices,salePrices:t.sale_prices,fallbackPrice:t.price,fallbackSalePrice:t.sale_price,saleStartAt:t.sale_start_at,saleEndAt:t.sale_end_at,scheduledPrice:t.scheduled_price,scheduledPrices:t.scheduled_prices,scheduledPriceAt:t.scheduled_price_at,currencyCode:p,currencies:P}),O=a&&s?$.resolveEffectivePriceForCurrency({prices:s.prices,salePrices:s.sale_prices,fallbackPrice:s.price,fallbackSalePrice:s.sale_price,saleStartAt:s.sale_start_at,saleEndAt:s.sale_end_at,scheduledPrice:s.scheduled_price,scheduledPrices:s.scheduled_prices,scheduledPriceAt:s.scheduled_price_at,currencyCode:p,currencies:P}):null,j=O?.price??V.price,N=O?.sale_price??V.sale_price,c=a?s?.stock_quantity??0:t.stock??0,D=m.useMemo(()=>{if(!s?.image_url)return C;const r={url:s.image_url,alt:`${t.title} ${s.label}`},u=C.filter(i=>i.url!==s.image_url);return[r,...u]},[C,t.title,s]),M=typeof N=="number"&&j>0?Math.round((j-N)/j*100):0,F=a&&s?{...t,sku:s.sku,price:s.price,prices:s.prices,sale_price:typeof s.sale_price=="number"?s.sale_price:null,sale_prices:s.sale_prices,image_url:s.image_url||t.image_url,stock:s.stock_quantity,variant_id:s.id,variant_label:s.label,selected_options:s.selected_options,currency_code:p}:{...t,currency_code:p},J=(r,u)=>{E(i=>h.normalizeSelectionsToAvailableVariants(g,d,{...i,[r]:u}))},G=n("ecommerce.in_stock",`${c} in stock`,{count:String(c)}),U=n("ecommerce.out_of_stock","Out of stock"),K=n("ecommerce.select_options","Select Options"),X=n("ecommerce.variant_selection_required","Select one term from every dropdown to resolve a variation.");return e.jsxs("div",{className:"w-full animate-in fade-in slide-in-from-bottom-4 duration-700 ease-out",children:[e.jsx("div",{className:"container mx-auto px-4 md:px-6 py-12",children:e.jsxs("div",{className:"grid gap-12 lg:grid-cols-[2fr_3fr] items-start",children:[e.jsx("div",{className:"w-full max-w-2xl mx-auto lg:max-w-none",children:e.jsx(Y.ProductGallery,{images:D,className:"w-full"})}),e.jsxs("div",{className:"flex flex-col gap-4 pb-2 max-w-xl mx-auto lg:mx-0 lg:max-w-none",children:[e.jsx("div",{className:"space-y-6",children:e.jsxs("div",{className:"space-y-4",children:[e.jsx("h1",{className:"text-3xl sm:text-4xl lg:text-5xl font-extrabold tracking-tight text-foreground leading-[1.1] lg:mt-0",...x,children:t.title}),t.categories&&t.categories.length>0&&e.jsx("div",{className:"flex flex-wrap items-center gap-1.5 text-xs font-bold uppercase tracking-widest text-amber-600 dark:text-amber-400",children:t.categories.map((r,u)=>{const i=h.resolveTranslatedText(r.name,r.name_translations,y);return e.jsxs(m.Fragment,{children:[u>0&&e.jsx("span",{className:"text-muted-foreground/30",children:"•"}),e.jsx("span",{children:i})]},r.id)})}),e.jsx("div",{className:"prose prose-neutral dark:prose-invert max-w-none text-muted-foreground leading-relaxed text-left",...k,children:t.short_description?e.jsx("div",{className:"text-lg mb-4 leading-relaxed",dangerouslySetInnerHTML:{__html:t.short_description}}):l?e.jsx("p",{className:"text-lg mb-4 italic text-muted-foreground",children:"Add a short product description."}):null}),e.jsxs("div",{className:"flex items-center gap-3",children:[typeof N=="number"&&e.jsx(T.Badge,{variant:"destructive",className:"px-2.5 py-1 text-xs font-bold uppercase tracking-wide animate-pulse shadow-sm",children:o("ecommerce.sale_badge",{percent:String(M)})}),!b&&c>0&&c<10&&e.jsx(T.Badge,{variant:"outline",className:"text-amber-600 border-amber-200 bg-amber-50",children:o("ecommerce.low_stock",{count:String(c)})}),A&&e.jsx(T.Badge,{variant:"secondary",className:"border border-emerald-200 bg-emerald-50 text-emerald-800",children:A.label})]})]})}),e.jsxs("div",{className:"p-5 rounded-2xl bg-card/60 border border-border/80 shadow-md backdrop-blur-md space-y-4",children:[b?e.jsx(ee.SubscriptionSelector,{product:t}):e.jsxs("div",{className:"space-y-3.5",children:[e.jsxs("div",{className:"flex items-center justify-between gap-4",children:[e.jsxs("div",{className:"space-y-1",children:[e.jsx("span",{className:"text-[10px] font-bold text-muted-foreground uppercase tracking-widest",children:n("ecommerce.price","Price")}),e.jsxs("div",{className:"flex items-baseline gap-2.5",children:[e.jsx("span",{className:"text-3xl font-extrabold text-foreground",children:q.formatPrice(N??j,p)}),typeof N=="number"&&e.jsx("span",{className:"text-lg text-muted-foreground line-through decoration-destructive/20 decoration-1",children:q.formatPrice(j,p)})]})]}),!b&&(s||!a)&&e.jsxs("div",{className:"text-right space-y-1",children:[e.jsxs("span",{className:"text-[10px] font-bold text-muted-foreground uppercase tracking-widest block",children:[!a&&t.sku&&e.jsxs("span",{className:"mr-2 font-normal lowercase normal-case text-muted-foreground/70",children:["SKU: ",t.sku]}),n("ecommerce.status","Status")]}),e.jsx("div",{className:(c??0)>0?"text-emerald-600 dark:text-emerald-400 font-semibold text-sm":"text-destructive font-semibold text-sm",children:(c??0)>0?G:U})]})]}),a&&e.jsx("div",{className:"space-y-3",children:e.jsx("div",{className:"grid gap-3 sm:grid-cols-2",children:g.map(r=>{const u=h.getAvailableTermIdsForAttribute(d,r.id,f);return e.jsxs("div",{className:"space-y-1",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(W.Label,{htmlFor:`attribute-${r.id}`,className:"text-[11px] font-semibold text-muted-foreground uppercase tracking-wider",children:r.name}),s?.sku&&e.jsx("span",{className:"text-[10px] text-muted-foreground font-mono",children:s.sku})]}),e.jsx("select",{id:`attribute-${r.id}`,className:"flex h-9 w-full rounded-md border border-input bg-background px-3 py-1 text-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",value:f[r.id]||"",onChange:i=>J(r.id,i.target.value),children:r.terms.map(i=>e.jsx("option",{value:i.id,disabled:!u.has(i.id),children:i.value},i.id))})]},r.id)})})}),a&&!s&&e.jsx("p",{className:"text-xs text-muted-foreground italic pt-1",children:X}),e.jsxs("div",{className:"flex items-center gap-3 pt-1",children:[!b&&(c??0)>0&&e.jsxs("div",{className:"flex items-center border rounded-lg h-12 bg-background border-input select-none",children:[e.jsx("button",{type:"button",onClick:()=>L(r=>Math.max(1,r-1)),className:"px-3 h-full flex items-center justify-center text-muted-foreground hover:text-foreground active:scale-95 transition-all text-lg font-medium",disabled:S<=1,children:"-"}),e.jsx("span",{className:"w-8 text-center text-sm font-semibold",children:S}),e.jsx("button",{type:"button",onClick:()=>L(r=>c!==null&&r>=c?r:r+1),className:"px-3 h-full flex items-center justify-center text-muted-foreground hover:text-foreground active:scale-95 transition-all text-lg font-medium",disabled:c!==null&&S>=c,children:"+"})]}),a&&(!s||(c??0)<=0)?e.jsx(z.Button,{disabled:!0,className:"flex-1 h-12 text-md font-bold shadow-md",children:s?U:K}):e.jsx(Z.AddToCartButton,{product:F,quantity:S,className:"flex-1 h-12 text-md font-bold shadow-md transition-all hover:shadow-lg active:scale-[0.98]"})]})]}),e.jsx(H.Separator,{className:"opacity-60 my-0.5"}),e.jsxs("div",{className:"grid grid-cols-2 gap-4 text-center text-[11px] font-medium text-muted-foreground pt-1",children:[e.jsx("div",{className:"flex items-center justify-center gap-2",children:b?e.jsxs("span",{className:"inline-flex items-center gap-1.5",children:[e.jsx(R.Download,{className:"h-3.5 w-3.5"}),o("ecommerce.instant_digital_delivery")]}):e.jsxs("span",{className:"inline-flex items-center gap-1.5",children:[e.jsx(R.Package,{className:"h-3.5 w-3.5"}),o("ecommerce.free_shipping")]})}),e.jsx("div",{className:"flex items-center justify-center gap-2",children:e.jsxs("span",{className:"inline-flex items-center gap-1.5",children:[e.jsx(R.ShieldCheck,{className:"h-3.5 w-3.5"}),o("ecommerce.secure_checkout")]})})]})]})]})]})}),e.jsx("div",{className:"min-w-0 w-full",...v?void 0:w,children:v||(t.description_json?e.jsx("div",{className:"container mx-auto px-4 md:px-6 pb-12 prose prose-neutral dark:prose-invert max-w-none leading-relaxed",children:e.jsx(te.SimpleTiptapRenderer,{content:t.description_json})}):e.jsx("div",{className:"container mx-auto px-4 md:px-6 pb-12",children:e.jsx("p",{className:"italic text-sm text-muted-foreground",children:o("ecommerce.no_description")})}))})]})};exports.ProductDetailsLayout=ie;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),u=require("react"),q=require("lucide-react"),A=require("@nextblock-cms/ui/badge"),W=require("@nextblock-cms/ui/button"),H=require("@nextblock-cms/ui/label"),Q=require("@nextblock-cms/ui/separator"),C=require("@nextblock-cms/utils"),Y=require("../product-context.cjs.js"),Z=require("./ProductGallery.cjs.js"),ee=require("./AddToCartButton.cjs.js"),te=require("./SubscriptionSelector.cjs.js"),se=require("./SimpleTiptapRenderer.cjs.js"),h=require("../variation-utils.cjs.js"),re=require("../CurrencyProvider.cjs.js"),M=require("../currency.cjs.js"),ae=require("../types.cjs.js"),ie=require("../trials.cjs.js");function I(o,f,w,t){const c={kind:"product-field",field:f,input:w,label:t},E=typeof window<"u"?window.location.origin:process.env.NEXT_PUBLIC_URL||process.env.TARGET_URL||(process.env.VERCEL_URL?`https://${process.env.VERCEL_URL}`:"")||"http://localhost:3000";let m=(typeof window<"u"?window.location.origin:process.env.NEXT_PUBLIC_URL||process.env.TARGET_URL||(process.env.VERCEL_URL?`https://${process.env.VERCEL_URL}`:"")||"http://localhost:3000").replace(/\/+$/,"");try{(m.startsWith("http://")||m.startsWith("https://"))&&(m=new URL(m).hostname)}catch{}const k=process.env.NEXTBLOCK_VERCEL_PROJECT_ID||process.env.VERCEL_PROJECT_ID,S=process.env.NEXTBLOCK_VERCEL_WORKSPACE_ID||process.env.VERCEL_ORG_ID,b={origin:m,editUrl:`${E}/cms/products/${o.id}/edit`,data:{parentType:"product",parentId:o.id,slug:o.slug,languageId:o.language_id,draftId:null,target:c}};return k&&(b.projectId=k),S&&(b.workspaceId=S),{"data-vercel-edit-info":JSON.stringify(b),"data-vercel-edit-target":JSON.stringify(c),"data-nextblock-visual-edit":`product:${f}`}}const ce=({visualEditingEnabled:o=!1,descriptionNode:f,reviewsNode:w})=>{const t=Y.useProduct(),{t:c,lang:E}=C.useTranslations(),{activeCurrencyCode:p,currencies:m}=re.useCurrency(),k=o?I(t,"title","plain-text","Product title"):void 0,S=o?I(t,"short_description","plain-text","Short description"):void 0,b=o?I(t,"description_json","tiptap","Product description"):void 0,v=(r,l,i)=>{const $=c(r,i);return $===r?l:$},L=t.images&&t.images.length>0?t.images:t.image_url?[{url:t.image_url,alt:t.title}]:[],_=t.custom_props?.provider==="freemius"||ae.isDigitalProduct(t),V=ie.getTrialSummary(t),a=!_&&!!(t.has_variants&&t.attributes?.length&&t.variants?.length),x=t.attributes||[],d=t.variants||[],[j,R]=u.useState(()=>h.chooseInitialVariantSelections(x,d)),[P,T]=u.useState(1);u.useEffect(()=>{T(1)},[t.id]),u.useEffect(()=>{a&&R(h.chooseInitialVariantSelections(x,d))},[x,a,t.id,d]);const g=u.useMemo(()=>a?h.normalizeSelectionsToAvailableVariants(x,d,j):j,[x,a,j,d]);u.useEffect(()=>{JSON.stringify(g)!==JSON.stringify(j)&&R(g)},[g,j]);const s=u.useMemo(()=>a?h.findMatchingVariant(d,g):null,[a,g,d]),O=M.resolveEffectivePriceForCurrency({prices:t.prices,salePrices:t.sale_prices,fallbackPrice:t.price,fallbackSalePrice:t.sale_price,saleStartAt:t.sale_start_at,saleEndAt:t.sale_end_at,scheduledPrice:t.scheduled_price,scheduledPrices:t.scheduled_prices,scheduledPriceAt:t.scheduled_price_at,currencyCode:p,currencies:m}),U=a&&s?M.resolveEffectivePriceForCurrency({prices:s.prices,salePrices:s.sale_prices,fallbackPrice:s.price,fallbackSalePrice:s.sale_price,saleStartAt:s.sale_start_at,saleEndAt:s.sale_end_at,scheduledPrice:s.scheduled_price,scheduledPrices:s.scheduled_prices,scheduledPriceAt:s.scheduled_price_at,currencyCode:p,currencies:m}):null,N=U?.price??O.price,y=U?.sale_price??O.sale_price,n=a?s?.stock_quantity??0:t.stock??0,D=u.useMemo(()=>{if(!s?.image_url)return L;const r={url:s.image_url,alt:`${t.title} ${s.label}`},l=L.filter(i=>i.url!==s.image_url);return[r,...l]},[L,t.title,s]),F=typeof y=="number"&&N>0?Math.round((N-y)/N*100):0,J=a&&s?{...t,sku:s.sku,price:s.price,prices:s.prices,sale_price:typeof s.sale_price=="number"?s.sale_price:null,sale_prices:s.sale_prices,image_url:s.image_url||t.image_url,stock:s.stock_quantity,variant_id:s.id,variant_label:s.label,selected_options:s.selected_options,currency_code:p}:{...t,currency_code:p},G=(r,l)=>{R(i=>h.normalizeSelectionsToAvailableVariants(x,d,{...i,[r]:l}))},z=v("ecommerce.in_stock",`${n} in stock`,{count:String(n)}),B=v("ecommerce.out_of_stock","Out of stock"),K=v("ecommerce.select_options","Select Options"),X=v("ecommerce.variant_selection_required","Select one term from every dropdown to resolve a variation.");return e.jsxs("div",{className:"w-full animate-in fade-in slide-in-from-bottom-4 duration-700 ease-out",children:[e.jsx("div",{className:"container mx-auto px-4 md:px-6 py-12",children:e.jsxs("div",{className:"grid gap-12 lg:grid-cols-[2fr_3fr] items-start",children:[e.jsx("div",{className:"w-full max-w-2xl mx-auto lg:max-w-none",children:e.jsx(Z.ProductGallery,{images:D,className:"w-full"})}),e.jsxs("div",{className:"flex flex-col gap-4 pb-2 max-w-xl mx-auto lg:mx-0 lg:max-w-none",children:[e.jsx("div",{className:"space-y-6",children:e.jsxs("div",{className:"space-y-4",children:[e.jsx("h1",{className:"text-3xl sm:text-4xl lg:text-5xl font-extrabold tracking-tight text-foreground leading-[1.1] lg:mt-0",...k,children:t.title}),e.jsx("div",{className:"flex items-center gap-2 mt-2",children:e.jsxs("a",{href:"#reviews-section",className:"flex items-center gap-1.5 group hover:opacity-85 transition-opacity",children:[e.jsx("div",{className:"flex items-center text-amber-500",children:Array.from({length:5}).map((r,l)=>e.jsx("svg",{className:C.cn("h-4 w-4 fill-current",l<Math.round(t.average_rating||0)?"text-amber-500":"text-slate-300 dark:text-slate-700"),viewBox:"0 0 20 20",fill:"currentColor",children:e.jsx("path",{d:"M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"})},l))}),t.total_reviews&&t.total_reviews>0?e.jsxs(e.Fragment,{children:[e.jsx("span",{className:"text-sm font-semibold text-slate-700 dark:text-slate-300",children:t.average_rating?.toFixed(1)}),e.jsxs("span",{className:"text-sm text-muted-foreground underline decoration-dotted group-hover:text-primary",children:["(",t.total_reviews===1?c("reviews.review_count_one",{count:t.total_reviews}):c("reviews.review_count_other",{count:t.total_reviews}),")"]})]}):e.jsx("span",{className:"text-xs text-muted-foreground group-hover:text-primary underline decoration-dotted",children:c("reviews.be_the_first")})]})}),t.categories&&t.categories.length>0&&e.jsx("div",{className:"flex flex-wrap items-center gap-1.5 text-xs font-bold uppercase tracking-widest text-amber-600 dark:text-amber-400",children:t.categories.map((r,l)=>{const i=h.resolveTranslatedText(r.name,r.name_translations,E);return e.jsxs(u.Fragment,{children:[l>0&&e.jsx("span",{className:"text-muted-foreground/30",children:"•"}),e.jsx("span",{children:i})]},r.id)})}),e.jsx("div",{className:"prose prose-neutral dark:prose-invert max-w-none text-muted-foreground leading-relaxed text-left",...S,children:t.short_description?e.jsx("div",{className:"text-lg mb-4 leading-relaxed",dangerouslySetInnerHTML:{__html:t.short_description}}):o?e.jsx("p",{className:"text-lg mb-4 italic text-muted-foreground",children:"Add a short product description."}):null}),e.jsxs("div",{className:"flex items-center gap-3",children:[typeof y=="number"&&e.jsx(A.Badge,{variant:"destructive",className:"px-2.5 py-1 text-xs font-bold uppercase tracking-wide animate-pulse shadow-sm",children:c("ecommerce.sale_badge",{percent:String(F)})}),!_&&n>0&&n<10&&e.jsx(A.Badge,{variant:"outline",className:"text-amber-600 border-amber-200 bg-amber-50",children:c("ecommerce.low_stock",{count:String(n)})}),V&&e.jsx(A.Badge,{variant:"secondary",className:"border border-emerald-200 bg-emerald-50 text-emerald-800",children:V.label})]})]})}),e.jsxs("div",{className:"p-5 rounded-2xl bg-card/60 border border-border/80 shadow-md backdrop-blur-md space-y-4",children:[_?e.jsx(te.SubscriptionSelector,{product:t}):e.jsxs("div",{className:"space-y-3.5",children:[e.jsxs("div",{className:"flex items-center justify-between gap-4",children:[e.jsxs("div",{className:"space-y-1",children:[e.jsx("span",{className:"text-[10px] font-bold text-muted-foreground uppercase tracking-widest",children:v("ecommerce.price","Price")}),e.jsxs("div",{className:"flex items-baseline gap-2.5",children:[e.jsx("span",{className:"text-3xl font-extrabold text-foreground",children:C.formatPrice(y??N,p)}),typeof y=="number"&&e.jsx("span",{className:"text-lg text-muted-foreground line-through decoration-destructive/20 decoration-1",children:C.formatPrice(N,p)})]})]}),!_&&(s||!a)&&e.jsxs("div",{className:"text-right space-y-1",children:[e.jsxs("span",{className:"text-[10px] font-bold text-muted-foreground uppercase tracking-widest block",children:[!a&&t.sku&&e.jsxs("span",{className:"mr-2 font-normal lowercase normal-case text-muted-foreground/70",children:["SKU: ",t.sku]}),v("ecommerce.status","Status")]}),e.jsx("div",{className:(n??0)>0?"text-emerald-600 dark:text-emerald-400 font-semibold text-sm":"text-destructive font-semibold text-sm",children:(n??0)>0?z:B})]})]}),a&&e.jsx("div",{className:"space-y-3",children:e.jsx("div",{className:"grid gap-3 sm:grid-cols-2",children:x.map(r=>{const l=h.getAvailableTermIdsForAttribute(d,r.id,g);return e.jsxs("div",{className:"space-y-1",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(H.Label,{htmlFor:`attribute-${r.id}`,className:"text-[11px] font-semibold text-muted-foreground uppercase tracking-wider",children:r.name}),s?.sku&&e.jsx("span",{className:"text-[10px] text-muted-foreground font-mono",children:s.sku})]}),e.jsx("select",{id:`attribute-${r.id}`,className:"flex h-9 w-full rounded-md border border-input bg-background px-3 py-1 text-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",value:g[r.id]||"",onChange:i=>G(r.id,i.target.value),children:r.terms.map(i=>e.jsx("option",{value:i.id,disabled:!l.has(i.id),children:i.value},i.id))})]},r.id)})})}),a&&!s&&e.jsx("p",{className:"text-xs text-muted-foreground italic pt-1",children:X}),e.jsxs("div",{className:"flex items-center gap-3 pt-1",children:[!_&&(n??0)>0&&e.jsxs("div",{className:"flex items-center border rounded-lg h-12 bg-background border-input select-none",children:[e.jsx("button",{type:"button",onClick:()=>T(r=>Math.max(1,r-1)),className:"px-3 h-full flex items-center justify-center text-muted-foreground hover:text-foreground active:scale-95 transition-all text-lg font-medium",disabled:P<=1,children:"-"}),e.jsx("span",{className:"w-8 text-center text-sm font-semibold",children:P}),e.jsx("button",{type:"button",onClick:()=>T(r=>n!==null&&r>=n?r:r+1),className:"px-3 h-full flex items-center justify-center text-muted-foreground hover:text-foreground active:scale-95 transition-all text-lg font-medium",disabled:n!==null&&P>=n,children:"+"})]}),a&&(!s||(n??0)<=0)?e.jsx(W.Button,{disabled:!0,className:"flex-1 h-12 text-md font-bold shadow-md",children:s?B:K}):e.jsx(ee.AddToCartButton,{product:J,quantity:P,className:"flex-1 h-12 text-md font-bold shadow-md transition-all hover:shadow-lg active:scale-[0.98]"})]})]}),e.jsx(Q.Separator,{className:"opacity-60 my-0.5"}),e.jsxs("div",{className:"grid grid-cols-2 gap-4 text-center text-[11px] font-medium text-muted-foreground pt-1",children:[e.jsx("div",{className:"flex items-center justify-center gap-2",children:_?e.jsxs("span",{className:"inline-flex items-center gap-1.5",children:[e.jsx(q.Download,{className:"h-3.5 w-3.5"}),c("ecommerce.instant_digital_delivery")]}):e.jsxs("span",{className:"inline-flex items-center gap-1.5",children:[e.jsx(q.Package,{className:"h-3.5 w-3.5"}),c("ecommerce.free_shipping")]})}),e.jsx("div",{className:"flex items-center justify-center gap-2",children:e.jsxs("span",{className:"inline-flex items-center gap-1.5",children:[e.jsx(q.ShieldCheck,{className:"h-3.5 w-3.5"}),c("ecommerce.secure_checkout")]})})]})]})]})]})}),e.jsx("div",{className:"min-w-0 w-full",...f?void 0:b,children:f||(t.description_json?e.jsx("div",{className:"container mx-auto px-4 md:px-6 pb-12 prose prose-neutral dark:prose-invert max-w-none leading-relaxed",children:e.jsx(se.SimpleTiptapRenderer,{content:t.description_json})}):e.jsx("div",{className:"container mx-auto px-4 md:px-6 pb-12",children:e.jsx("p",{className:"italic text-sm text-muted-foreground",children:c("ecommerce.no_description")})}))}),w&&e.jsx("div",{id:"reviews-section",className:"border-t border-border mt-12 pt-12",children:w})]})};exports.ProductDetailsLayout=ce;
@@ -2,6 +2,7 @@ import { default as React } from 'react';
2
2
  interface ProductDetailsLayoutProps {
3
3
  visualEditingEnabled?: boolean;
4
4
  descriptionNode?: React.ReactNode;
5
+ reviewsNode?: React.ReactNode;
5
6
  }
6
7
  export declare const ProductDetailsLayout: React.FC<ProductDetailsLayoutProps>;
7
8
  export {};
@@ -1,89 +1,90 @@
1
1
  'use client';
2
- import { jsxs as a, jsx as t } from "react/jsx-runtime";
3
- import Q, { useState as B, useEffect as R, useMemo as T } from "react";
4
- import { Download as Y, Package as Z, ShieldCheck as ee } from "lucide-react";
5
- import { Badge as I } from "@nextblock-cms/ui/badge";
6
- import { Button as te } from "@nextblock-cms/ui/button";
7
- import { Label as re } from "@nextblock-cms/ui/label";
8
- import { Separator as se } from "@nextblock-cms/ui/separator";
9
- import { useTranslations as ae, formatPrice as D } from "@nextblock-cms/utils";
10
- import { useProduct as ie } from "../product-context.es.js";
11
- import { ProductGallery as ce } from "./ProductGallery.es.js";
12
- import { AddToCartButton as ne } from "./AddToCartButton.es.js";
13
- import { SubscriptionSelector as le } from "./SubscriptionSelector.es.js";
14
- import { SimpleTiptapRenderer as oe } from "./SimpleTiptapRenderer.es.js";
15
- import { chooseInitialVariantSelections as F, normalizeSelectionsToAvailableVariants as J, findMatchingVariant as de, resolveTranslatedText as me, getAvailableTermIdsForAttribute as pe } from "../variation-utils.es.js";
16
- import { useCurrency as ue } from "../CurrencyProvider.es.js";
17
- import { resolveEffectivePriceForCurrency as M } from "../currency.es.js";
18
- import { isDigitalProduct as fe } from "../types.es.js";
19
- import { getTrialSummary as ge } from "../trials.es.js";
20
- function A(o, x, e, d) {
21
- const y = {
2
+ import { jsxs as a, jsx as t, Fragment as Y } from "react/jsx-runtime";
3
+ import Z, { useState as D, useEffect as T, useMemo as I } from "react";
4
+ import { Download as ee, Package as te, ShieldCheck as re } from "lucide-react";
5
+ import { Badge as A } from "@nextblock-cms/ui/badge";
6
+ import { Button as se } from "@nextblock-cms/ui/button";
7
+ import { Label as ae } from "@nextblock-cms/ui/label";
8
+ import { Separator as ie } from "@nextblock-cms/ui/separator";
9
+ import { useTranslations as ce, cn as le, formatPrice as F } from "@nextblock-cms/utils";
10
+ import { useProduct as ne } from "../product-context.es.js";
11
+ import { ProductGallery as oe } from "./ProductGallery.es.js";
12
+ import { AddToCartButton as de } from "./AddToCartButton.es.js";
13
+ import { SubscriptionSelector as me } from "./SubscriptionSelector.es.js";
14
+ import { SimpleTiptapRenderer as pe } from "./SimpleTiptapRenderer.es.js";
15
+ import { chooseInitialVariantSelections as M, normalizeSelectionsToAvailableVariants as J, findMatchingVariant as ue, resolveTranslatedText as fe, getAvailableTermIdsForAttribute as he } from "../variation-utils.es.js";
16
+ import { useCurrency as ge } from "../CurrencyProvider.es.js";
17
+ import { resolveEffectivePriceForCurrency as G } from "../currency.es.js";
18
+ import { isDigitalProduct as xe } from "../types.es.js";
19
+ import { getTrialSummary as ve } from "../trials.es.js";
20
+ function V(d, g, w, e) {
21
+ const l = {
22
22
  kind: "product-field",
23
- field: x,
24
- input: e,
25
- label: d
26
- }, u = typeof window < "u" ? window.location.origin : process.env.NEXT_PUBLIC_URL || process.env.TARGET_URL || (process.env.VERCEL_URL ? `https://${process.env.VERCEL_URL}` : "") || "http://localhost:3000";
27
- let f = (typeof window < "u" ? window.location.origin : process.env.NEXT_PUBLIC_URL || process.env.TARGET_URL || (process.env.VERCEL_URL ? `https://${process.env.VERCEL_URL}` : "") || "http://localhost:3000").replace(/\/+$/, "");
23
+ field: g,
24
+ input: w,
25
+ label: e
26
+ }, C = typeof window < "u" ? window.location.origin : process.env.NEXT_PUBLIC_URL || process.env.TARGET_URL || (process.env.VERCEL_URL ? `https://${process.env.VERCEL_URL}` : "") || "http://localhost:3000";
27
+ let p = (typeof window < "u" ? window.location.origin : process.env.NEXT_PUBLIC_URL || process.env.TARGET_URL || (process.env.VERCEL_URL ? `https://${process.env.VERCEL_URL}` : "") || "http://localhost:3000").replace(/\/+$/, "");
28
28
  try {
29
- (f.startsWith("http://") || f.startsWith("https://")) && (f = new URL(f).hostname);
29
+ (p.startsWith("http://") || p.startsWith("https://")) && (p = new URL(p).hostname);
30
30
  } catch {
31
31
  }
32
- const k = process.env.NEXTBLOCK_VERCEL_PROJECT_ID || process.env.VERCEL_PROJECT_ID, w = process.env.NEXTBLOCK_VERCEL_WORKSPACE_ID || process.env.VERCEL_ORG_ID, l = {
33
- origin: f,
34
- editUrl: `${u}/cms/products/${o.id}/edit`,
32
+ const k = process.env.NEXTBLOCK_VERCEL_PROJECT_ID || process.env.VERCEL_PROJECT_ID, S = process.env.NEXTBLOCK_VERCEL_WORKSPACE_ID || process.env.VERCEL_ORG_ID, _ = {
33
+ origin: p,
34
+ editUrl: `${C}/cms/products/${d.id}/edit`,
35
35
  data: {
36
36
  parentType: "product",
37
- parentId: o.id,
38
- slug: o.slug,
39
- languageId: o.language_id,
37
+ parentId: d.id,
38
+ slug: d.slug,
39
+ languageId: d.language_id,
40
40
  draftId: null,
41
- target: y
41
+ target: l
42
42
  }
43
43
  };
44
- return k && (l.projectId = k), w && (l.workspaceId = w), {
45
- "data-vercel-edit-info": JSON.stringify(l),
46
- "data-vercel-edit-target": JSON.stringify(y),
47
- "data-nextblock-visual-edit": `product:${x}`
44
+ return k && (_.projectId = k), S && (_.workspaceId = S), {
45
+ "data-vercel-edit-info": JSON.stringify(_),
46
+ "data-vercel-edit-target": JSON.stringify(l),
47
+ "data-nextblock-visual-edit": `product:${g}`
48
48
  };
49
49
  }
50
- const Ve = ({
51
- visualEditingEnabled: o = !1,
52
- descriptionNode: x
50
+ const je = ({
51
+ visualEditingEnabled: d = !1,
52
+ descriptionNode: g,
53
+ reviewsNode: w
53
54
  }) => {
54
- const e = ie(), { t: d, lang: y } = ae(), { activeCurrencyCode: u, currencies: P } = ue(), f = o ? A(
55
+ const e = ne(), { t: l, lang: C } = ce(), { activeCurrencyCode: u, currencies: p } = ge(), k = d ? V(
55
56
  e,
56
57
  "title",
57
58
  "plain-text",
58
59
  "Product title"
59
- ) : void 0, k = o ? A(
60
+ ) : void 0, S = d ? V(
60
61
  e,
61
62
  "short_description",
62
63
  "plain-text",
63
64
  "Short description"
64
- ) : void 0, w = o ? A(
65
+ ) : void 0, _ = d ? V(
65
66
  e,
66
67
  "description_json",
67
68
  "tiptap",
68
69
  "Product description"
69
- ) : void 0, l = (s, p, c) => {
70
- const $ = d(s, c);
71
- return $ === s ? p : $;
72
- }, C = e.images && e.images.length > 0 ? e.images : e.image_url ? [{ url: e.image_url, alt: e.title }] : [], v = e.custom_props?.provider === "freemius" || fe(e), V = ge(e), i = !v && !!(e.has_variants && e.attributes?.length && e.variants?.length), g = e.attributes || [], m = e.variants || [], [_, L] = B(() => F(g, m)), [S, E] = B(1);
73
- R(() => {
74
- E(1);
75
- }, [e.id]), R(() => {
76
- i && L(F(g, m));
77
- }, [g, i, e.id, m]);
78
- const h = T(() => i ? J(
79
- g,
70
+ ) : void 0, x = (s, o, c) => {
71
+ const B = l(s, c);
72
+ return B === s ? o : B;
73
+ }, L = e.images && e.images.length > 0 ? e.images : e.image_url ? [{ url: e.image_url, alt: e.title }] : [], v = e.custom_props?.provider === "freemius" || xe(e), O = ve(e), i = !v && !!(e.has_variants && e.attributes?.length && e.variants?.length), f = e.attributes || [], m = e.variants || [], [b, E] = D(() => M(f, m)), [P, R] = D(1);
74
+ T(() => {
75
+ R(1);
76
+ }, [e.id]), T(() => {
77
+ i && E(M(f, m));
78
+ }, [f, i, e.id, m]);
79
+ const h = I(() => i ? J(
80
+ f,
80
81
  m,
81
- _
82
- ) : _, [g, i, _, m]);
83
- R(() => {
84
- JSON.stringify(h) !== JSON.stringify(_) && L(h);
85
- }, [h, _]);
86
- const r = T(() => i ? de(m, h) : null, [i, h, m]), O = M({
82
+ b
83
+ ) : b, [f, i, b, m]);
84
+ T(() => {
85
+ JSON.stringify(h) !== JSON.stringify(b) && E(h);
86
+ }, [h, b]);
87
+ const r = I(() => i ? ue(m, h) : null, [i, h, m]), U = G({
87
88
  prices: e.prices,
88
89
  salePrices: e.sale_prices,
89
90
  fallbackPrice: e.price,
@@ -94,8 +95,8 @@ const Ve = ({
94
95
  scheduledPrices: e.scheduled_prices,
95
96
  scheduledPriceAt: e.scheduled_price_at,
96
97
  currencyCode: u,
97
- currencies: P
98
- }), U = i && r ? M({
98
+ currencies: p
99
+ }), j = i && r ? G({
99
100
  prices: r.prices,
100
101
  salePrices: r.sale_prices,
101
102
  fallbackPrice: r.price,
@@ -106,20 +107,20 @@ const Ve = ({
106
107
  scheduledPrices: r.scheduled_prices,
107
108
  scheduledPriceAt: r.scheduled_price_at,
108
109
  currencyCode: u,
109
- currencies: P
110
- }) : null, b = U?.price ?? O.price, N = U?.sale_price ?? O.sale_price, n = i ? r?.stock_quantity ?? 0 : e.stock ?? 0, G = T(() => {
110
+ currencies: p
111
+ }) : null, N = j?.price ?? U.price, y = j?.sale_price ?? U.sale_price, n = i ? r?.stock_quantity ?? 0 : e.stock ?? 0, K = I(() => {
111
112
  if (!r?.image_url)
112
- return C;
113
+ return L;
113
114
  const s = {
114
115
  url: r.image_url,
115
116
  alt: `${e.title} ${r.label}`
116
- }, p = C.filter(
117
+ }, o = L.filter(
117
118
  (c) => c.url !== r.image_url
118
119
  );
119
- return [s, ...p];
120
- }, [C, e.title, r]), K = typeof N == "number" && b > 0 ? Math.round(
121
- (b - N) / b * 100
122
- ) : 0, X = i && r ? {
120
+ return [s, ...o];
121
+ }, [L, e.title, r]), X = typeof y == "number" && N > 0 ? Math.round(
122
+ (N - y) / N * 100
123
+ ) : 0, q = i && r ? {
123
124
  ...e,
124
125
  sku: r.sku,
125
126
  price: r.price,
@@ -135,48 +136,78 @@ const Ve = ({
135
136
  } : {
136
137
  ...e,
137
138
  currency_code: u
138
- }, q = (s, p) => {
139
- L(
140
- (c) => J(g, m, {
139
+ }, z = (s, o) => {
140
+ E(
141
+ (c) => J(f, m, {
141
142
  ...c,
142
- [s]: p
143
+ [s]: o
143
144
  })
144
145
  );
145
- }, W = l(
146
+ }, W = x(
146
147
  "ecommerce.in_stock",
147
148
  `${n} in stock`,
148
149
  { count: String(n) }
149
- ), j = l(
150
+ ), $ = x(
150
151
  "ecommerce.out_of_stock",
151
152
  "Out of stock"
152
- ), z = l(
153
+ ), H = x(
153
154
  "ecommerce.select_options",
154
155
  "Select Options"
155
- ), H = l(
156
+ ), Q = x(
156
157
  "ecommerce.variant_selection_required",
157
158
  "Select one term from every dropdown to resolve a variation."
158
159
  );
159
160
  return /* @__PURE__ */ a("div", { className: "w-full animate-in fade-in slide-in-from-bottom-4 duration-700 ease-out", children: [
160
161
  /* @__PURE__ */ t("div", { className: "container mx-auto px-4 md:px-6 py-12", children: /* @__PURE__ */ a("div", { className: "grid gap-12 lg:grid-cols-[2fr_3fr] items-start", children: [
161
- /* @__PURE__ */ t("div", { className: "w-full max-w-2xl mx-auto lg:max-w-none", children: /* @__PURE__ */ t(ce, { images: G, className: "w-full" }) }),
162
+ /* @__PURE__ */ t("div", { className: "w-full max-w-2xl mx-auto lg:max-w-none", children: /* @__PURE__ */ t(oe, { images: K, className: "w-full" }) }),
162
163
  /* @__PURE__ */ a("div", { className: "flex flex-col gap-4 pb-2 max-w-xl mx-auto lg:mx-0 lg:max-w-none", children: [
163
164
  /* @__PURE__ */ t("div", { className: "space-y-6", children: /* @__PURE__ */ a("div", { className: "space-y-4", children: [
164
165
  /* @__PURE__ */ t(
165
166
  "h1",
166
167
  {
167
168
  className: "text-3xl sm:text-4xl lg:text-5xl font-extrabold tracking-tight text-foreground leading-[1.1] lg:mt-0",
168
- ...f,
169
+ ...k,
169
170
  children: e.title
170
171
  }
171
172
  ),
172
- e.categories && e.categories.length > 0 && /* @__PURE__ */ t("div", { className: "flex flex-wrap items-center gap-1.5 text-xs font-bold uppercase tracking-widest text-amber-600 dark:text-amber-400", children: e.categories.map((s, p) => {
173
- const c = me(
173
+ /* @__PURE__ */ t("div", { className: "flex items-center gap-2 mt-2", children: /* @__PURE__ */ a(
174
+ "a",
175
+ {
176
+ href: "#reviews-section",
177
+ className: "flex items-center gap-1.5 group hover:opacity-85 transition-opacity",
178
+ children: [
179
+ /* @__PURE__ */ t("div", { className: "flex items-center text-amber-500", children: Array.from({ length: 5 }).map((s, o) => /* @__PURE__ */ t(
180
+ "svg",
181
+ {
182
+ className: le(
183
+ "h-4 w-4 fill-current",
184
+ o < Math.round(e.average_rating || 0) ? "text-amber-500" : "text-slate-300 dark:text-slate-700"
185
+ ),
186
+ viewBox: "0 0 20 20",
187
+ fill: "currentColor",
188
+ children: /* @__PURE__ */ t("path", { d: "M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z" })
189
+ },
190
+ o
191
+ )) }),
192
+ e.total_reviews && e.total_reviews > 0 ? /* @__PURE__ */ a(Y, { children: [
193
+ /* @__PURE__ */ t("span", { className: "text-sm font-semibold text-slate-700 dark:text-slate-300", children: e.average_rating?.toFixed(1) }),
194
+ /* @__PURE__ */ a("span", { className: "text-sm text-muted-foreground underline decoration-dotted group-hover:text-primary", children: [
195
+ "(",
196
+ e.total_reviews === 1 ? l("reviews.review_count_one", { count: e.total_reviews }) : l("reviews.review_count_other", { count: e.total_reviews }),
197
+ ")"
198
+ ] })
199
+ ] }) : /* @__PURE__ */ t("span", { className: "text-xs text-muted-foreground group-hover:text-primary underline decoration-dotted", children: l("reviews.be_the_first") })
200
+ ]
201
+ }
202
+ ) }),
203
+ e.categories && e.categories.length > 0 && /* @__PURE__ */ t("div", { className: "flex flex-wrap items-center gap-1.5 text-xs font-bold uppercase tracking-widest text-amber-600 dark:text-amber-400", children: e.categories.map((s, o) => {
204
+ const c = fe(
174
205
  s.name,
175
206
  s.name_translations,
176
- y
207
+ C
177
208
  );
178
- return /* @__PURE__ */ a(Q.Fragment, { children: [
179
- p > 0 && /* @__PURE__ */ t("span", { className: "text-muted-foreground/30", children: "•" }),
209
+ return /* @__PURE__ */ a(Z.Fragment, { children: [
210
+ o > 0 && /* @__PURE__ */ t("span", { className: "text-muted-foreground/30", children: "•" }),
180
211
  /* @__PURE__ */ t("span", { children: c })
181
212
  ] }, s.id);
182
213
  }) }),
@@ -184,7 +215,7 @@ const Ve = ({
184
215
  "div",
185
216
  {
186
217
  className: "prose prose-neutral dark:prose-invert max-w-none text-muted-foreground leading-relaxed text-left",
187
- ...k,
218
+ ...S,
188
219
  children: e.short_description ? /* @__PURE__ */ t(
189
220
  "div",
190
221
  {
@@ -193,51 +224,51 @@ const Ve = ({
193
224
  __html: e.short_description
194
225
  }
195
226
  }
196
- ) : o ? /* @__PURE__ */ t("p", { className: "text-lg mb-4 italic text-muted-foreground", children: "Add a short product description." }) : null
227
+ ) : d ? /* @__PURE__ */ t("p", { className: "text-lg mb-4 italic text-muted-foreground", children: "Add a short product description." }) : null
197
228
  }
198
229
  ),
199
230
  /* @__PURE__ */ a("div", { className: "flex items-center gap-3", children: [
200
- typeof N == "number" && /* @__PURE__ */ t(
201
- I,
231
+ typeof y == "number" && /* @__PURE__ */ t(
232
+ A,
202
233
  {
203
234
  variant: "destructive",
204
235
  className: "px-2.5 py-1 text-xs font-bold uppercase tracking-wide animate-pulse shadow-sm",
205
- children: d("ecommerce.sale_badge", {
206
- percent: String(K)
236
+ children: l("ecommerce.sale_badge", {
237
+ percent: String(X)
207
238
  })
208
239
  }
209
240
  ),
210
241
  !v && n > 0 && n < 10 && /* @__PURE__ */ t(
211
- I,
242
+ A,
212
243
  {
213
244
  variant: "outline",
214
245
  className: "text-amber-600 border-amber-200 bg-amber-50",
215
- children: d("ecommerce.low_stock", {
246
+ children: l("ecommerce.low_stock", {
216
247
  count: String(n)
217
248
  })
218
249
  }
219
250
  ),
220
- V && /* @__PURE__ */ t(
221
- I,
251
+ O && /* @__PURE__ */ t(
252
+ A,
222
253
  {
223
254
  variant: "secondary",
224
255
  className: "border border-emerald-200 bg-emerald-50 text-emerald-800",
225
- children: V.label
256
+ children: O.label
226
257
  }
227
258
  )
228
259
  ] })
229
260
  ] }) }),
230
261
  /* @__PURE__ */ a("div", { className: "p-5 rounded-2xl bg-card/60 border border-border/80 shadow-md backdrop-blur-md space-y-4", children: [
231
- v ? /* @__PURE__ */ t(le, { product: e }) : /* @__PURE__ */ a("div", { className: "space-y-3.5", children: [
262
+ v ? /* @__PURE__ */ t(me, { product: e }) : /* @__PURE__ */ a("div", { className: "space-y-3.5", children: [
232
263
  /* @__PURE__ */ a("div", { className: "flex items-center justify-between gap-4", children: [
233
264
  /* @__PURE__ */ a("div", { className: "space-y-1", children: [
234
- /* @__PURE__ */ t("span", { className: "text-[10px] font-bold text-muted-foreground uppercase tracking-widest", children: l("ecommerce.price", "Price") }),
265
+ /* @__PURE__ */ t("span", { className: "text-[10px] font-bold text-muted-foreground uppercase tracking-widest", children: x("ecommerce.price", "Price") }),
235
266
  /* @__PURE__ */ a("div", { className: "flex items-baseline gap-2.5", children: [
236
- /* @__PURE__ */ t("span", { className: "text-3xl font-extrabold text-foreground", children: D(
237
- N ?? b,
267
+ /* @__PURE__ */ t("span", { className: "text-3xl font-extrabold text-foreground", children: F(
268
+ y ?? N,
238
269
  u
239
270
  ) }),
240
- typeof N == "number" && /* @__PURE__ */ t("span", { className: "text-lg text-muted-foreground line-through decoration-destructive/20 decoration-1", children: D(b, u) })
271
+ typeof y == "number" && /* @__PURE__ */ t("span", { className: "text-lg text-muted-foreground line-through decoration-destructive/20 decoration-1", children: F(N, u) })
241
272
  ] })
242
273
  ] }),
243
274
  !v && (r || !i) && /* @__PURE__ */ a("div", { className: "text-right space-y-1", children: [
@@ -246,13 +277,13 @@ const Ve = ({
246
277
  "SKU: ",
247
278
  e.sku
248
279
  ] }),
249
- l("ecommerce.status", "Status")
280
+ x("ecommerce.status", "Status")
250
281
  ] }),
251
- /* @__PURE__ */ t("div", { className: (n ?? 0) > 0 ? "text-emerald-600 dark:text-emerald-400 font-semibold text-sm" : "text-destructive font-semibold text-sm", children: (n ?? 0) > 0 ? W : j })
282
+ /* @__PURE__ */ t("div", { className: (n ?? 0) > 0 ? "text-emerald-600 dark:text-emerald-400 font-semibold text-sm" : "text-destructive font-semibold text-sm", children: (n ?? 0) > 0 ? W : $ })
252
283
  ] })
253
284
  ] }),
254
- i && /* @__PURE__ */ t("div", { className: "space-y-3", children: /* @__PURE__ */ t("div", { className: "grid gap-3 sm:grid-cols-2", children: g.map((s) => {
255
- const p = pe(
285
+ i && /* @__PURE__ */ t("div", { className: "space-y-3", children: /* @__PURE__ */ t("div", { className: "grid gap-3 sm:grid-cols-2", children: f.map((s) => {
286
+ const o = he(
256
287
  m,
257
288
  s.id,
258
289
  h
@@ -260,7 +291,7 @@ const Ve = ({
260
291
  return /* @__PURE__ */ a("div", { className: "space-y-1", children: [
261
292
  /* @__PURE__ */ a("div", { className: "flex items-center justify-between", children: [
262
293
  /* @__PURE__ */ t(
263
- re,
294
+ ae,
264
295
  {
265
296
  htmlFor: `attribute-${s.id}`,
266
297
  className: "text-[11px] font-semibold text-muted-foreground uppercase tracking-wider",
@@ -275,7 +306,7 @@ const Ve = ({
275
306
  id: `attribute-${s.id}`,
276
307
  className: "flex h-9 w-full rounded-md border border-input bg-background px-3 py-1 text-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
277
308
  value: h[s.id] || "",
278
- onChange: (c) => q(
309
+ onChange: (c) => z(
279
310
  s.id,
280
311
  c.target.value
281
312
  ),
@@ -283,7 +314,7 @@ const Ve = ({
283
314
  "option",
284
315
  {
285
316
  value: c.id,
286
- disabled: !p.has(c.id),
317
+ disabled: !o.has(c.id),
287
318
  children: c.value
288
319
  },
289
320
  c.id
@@ -292,70 +323,71 @@ const Ve = ({
292
323
  )
293
324
  ] }, s.id);
294
325
  }) }) }),
295
- i && !r && /* @__PURE__ */ t("p", { className: "text-xs text-muted-foreground italic pt-1", children: H }),
326
+ i && !r && /* @__PURE__ */ t("p", { className: "text-xs text-muted-foreground italic pt-1", children: Q }),
296
327
  /* @__PURE__ */ a("div", { className: "flex items-center gap-3 pt-1", children: [
297
328
  !v && (n ?? 0) > 0 && /* @__PURE__ */ a("div", { className: "flex items-center border rounded-lg h-12 bg-background border-input select-none", children: [
298
329
  /* @__PURE__ */ t(
299
330
  "button",
300
331
  {
301
332
  type: "button",
302
- onClick: () => E((s) => Math.max(1, s - 1)),
333
+ onClick: () => R((s) => Math.max(1, s - 1)),
303
334
  className: "px-3 h-full flex items-center justify-center text-muted-foreground hover:text-foreground active:scale-95 transition-all text-lg font-medium",
304
- disabled: S <= 1,
335
+ disabled: P <= 1,
305
336
  children: "-"
306
337
  }
307
338
  ),
308
- /* @__PURE__ */ t("span", { className: "w-8 text-center text-sm font-semibold", children: S }),
339
+ /* @__PURE__ */ t("span", { className: "w-8 text-center text-sm font-semibold", children: P }),
309
340
  /* @__PURE__ */ t(
310
341
  "button",
311
342
  {
312
343
  type: "button",
313
- onClick: () => E(
344
+ onClick: () => R(
314
345
  (s) => n !== null && s >= n ? s : s + 1
315
346
  ),
316
347
  className: "px-3 h-full flex items-center justify-center text-muted-foreground hover:text-foreground active:scale-95 transition-all text-lg font-medium",
317
- disabled: n !== null && S >= n,
348
+ disabled: n !== null && P >= n,
318
349
  children: "+"
319
350
  }
320
351
  )
321
352
  ] }),
322
353
  i && (!r || (n ?? 0) <= 0) ? /* @__PURE__ */ t(
323
- te,
354
+ se,
324
355
  {
325
356
  disabled: !0,
326
357
  className: "flex-1 h-12 text-md font-bold shadow-md",
327
- children: r ? j : z
358
+ children: r ? $ : H
328
359
  }
329
360
  ) : /* @__PURE__ */ t(
330
- ne,
361
+ de,
331
362
  {
332
- product: X,
333
- quantity: S,
363
+ product: q,
364
+ quantity: P,
334
365
  className: "flex-1 h-12 text-md font-bold shadow-md transition-all hover:shadow-lg active:scale-[0.98]"
335
366
  }
336
367
  )
337
368
  ] })
338
369
  ] }),
339
- /* @__PURE__ */ t(se, { className: "opacity-60 my-0.5" }),
370
+ /* @__PURE__ */ t(ie, { className: "opacity-60 my-0.5" }),
340
371
  /* @__PURE__ */ a("div", { className: "grid grid-cols-2 gap-4 text-center text-[11px] font-medium text-muted-foreground pt-1", children: [
341
372
  /* @__PURE__ */ t("div", { className: "flex items-center justify-center gap-2", children: v ? /* @__PURE__ */ a("span", { className: "inline-flex items-center gap-1.5", children: [
342
- /* @__PURE__ */ t(Y, { className: "h-3.5 w-3.5" }),
343
- d("ecommerce.instant_digital_delivery")
373
+ /* @__PURE__ */ t(ee, { className: "h-3.5 w-3.5" }),
374
+ l("ecommerce.instant_digital_delivery")
344
375
  ] }) : /* @__PURE__ */ a("span", { className: "inline-flex items-center gap-1.5", children: [
345
- /* @__PURE__ */ t(Z, { className: "h-3.5 w-3.5" }),
346
- d("ecommerce.free_shipping")
376
+ /* @__PURE__ */ t(te, { className: "h-3.5 w-3.5" }),
377
+ l("ecommerce.free_shipping")
347
378
  ] }) }),
348
379
  /* @__PURE__ */ t("div", { className: "flex items-center justify-center gap-2", children: /* @__PURE__ */ a("span", { className: "inline-flex items-center gap-1.5", children: [
349
- /* @__PURE__ */ t(ee, { className: "h-3.5 w-3.5" }),
350
- d("ecommerce.secure_checkout")
380
+ /* @__PURE__ */ t(re, { className: "h-3.5 w-3.5" }),
381
+ l("ecommerce.secure_checkout")
351
382
  ] }) })
352
383
  ] })
353
384
  ] })
354
385
  ] })
355
386
  ] }) }),
356
- /* @__PURE__ */ t("div", { className: "min-w-0 w-full", ...x ? void 0 : w, children: x || (e.description_json ? /* @__PURE__ */ t("div", { className: "container mx-auto px-4 md:px-6 pb-12 prose prose-neutral dark:prose-invert max-w-none leading-relaxed", children: /* @__PURE__ */ t(oe, { content: e.description_json }) }) : /* @__PURE__ */ t("div", { className: "container mx-auto px-4 md:px-6 pb-12", children: /* @__PURE__ */ t("p", { className: "italic text-sm text-muted-foreground", children: d("ecommerce.no_description") }) })) })
387
+ /* @__PURE__ */ t("div", { className: "min-w-0 w-full", ...g ? void 0 : _, children: g || (e.description_json ? /* @__PURE__ */ t("div", { className: "container mx-auto px-4 md:px-6 pb-12 prose prose-neutral dark:prose-invert max-w-none leading-relaxed", children: /* @__PURE__ */ t(pe, { content: e.description_json }) }) : /* @__PURE__ */ t("div", { className: "container mx-auto px-4 md:px-6 pb-12", children: /* @__PURE__ */ t("p", { className: "italic text-sm text-muted-foreground", children: l("ecommerce.no_description") }) })) }),
388
+ w && /* @__PURE__ */ t("div", { id: "reviews-section", className: "border-t border-border mt-12 pt-12", children: w })
357
389
  ] });
358
390
  };
359
391
  export {
360
- Ve as ProductDetailsLayout
392
+ je as ProductDetailsLayout
361
393
  };
@@ -7,6 +7,8 @@ export declare function getProducts(options?: {
7
7
  data: never[] | {
8
8
  id: string;
9
9
  title: string;
10
+ average_rating: number;
11
+ total_reviews: number;
10
12
  sku: string;
11
13
  upc: string | null;
12
14
  price: number;
@@ -79,6 +81,7 @@ export declare function getProducts(options?: {
79
81
  count: number | null;
80
82
  }>;
81
83
  export declare function getProduct(id: string): Promise<{
84
+ average_rating: number;
82
85
  created_at: string | null;
83
86
  description_json: import('../../../../../../db/src/index.ts').Json | null;
84
87
  freemius_plan_id: string | null;
@@ -106,6 +109,7 @@ export declare function getProduct(id: string): Promise<{
106
109
  status: string;
107
110
  stock: number | null;
108
111
  title: string;
112
+ total_reviews: number;
109
113
  translation_group_id: string;
110
114
  trial_period_days: number;
111
115
  trial_requires_payment_method: boolean;
@@ -1,4 +1,4 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const F=require("@nextblock-cms/utils/server"),P=require("./shared-inventory.cjs.js"),b=require("@nextblock-cms/utils"),g=e=>Math.round(e*100);function y(e){return Object.entries(e||{}).reduce((t,[r,i])=>(typeof i=="number"&&Number.isFinite(i)&&i>=0&&(t[b.normalizeCurrencyCode(r)]=g(i)),t),{})}function E(e){return(e||[]).map(t=>({id:t.id,sku:t.sku,upc:t.upc??null,price:g(t.price),sale_price:typeof t.sale_price=="number"&&!isNaN(t.sale_price)?g(t.sale_price):null,prices:y(t.prices),sale_prices:y(t.sale_prices),sale_start_at:t.sale_start_at??null,sale_end_at:t.sale_end_at??null,stock_quantity:t.stock_quantity,main_media_id:t.main_media_id??null,attribute_term_ids:t.attribute_term_ids}))}function j(e,t){const i=e.product_type==="digital"&&e.payment_provider==="freemius"?Math.max(0,Number(e.trial_period_days??0)):0;return{id:t,product_type:e.product_type,payment_provider:e.payment_provider,title:e.title,slug:e.slug,sku:e.sku,upc:e.upc??null,stock:e.stock,status:e.status,short_description:e.short_description??null,description_json:e.description_json??null,metadata:{},price:g(e.price),sale_price:typeof e.sale_price=="number"&&!isNaN(e.sale_price)?g(e.sale_price):null,prices:y(e.prices),sale_prices:y(e.sale_prices),sale_start_at:e.sale_start_at??null,sale_end_at:e.sale_end_at??null,freemius_plan_id:e.freemius_plan_id??null,freemius_product_id:e.freemius_product_id??null,trial_period_days:i,trial_requires_payment_method:i>0?e.trial_requires_payment_method??!1:!1,is_taxable:e.is_taxable,language_id:e.language_id,translation_group_id:e.translation_group_id||void 0,variants:E(e.variants)}}async function S(e,t,r){const{error:i}=await e.from("products").update({is_taxable:r,updated_at:new Date().toISOString()}).eq("id",t);if(i)throw i}async function x(e,t,r){const i=new Date().toISOString(),{data:c}=await e.from("products").select("sku, sale_price, sale_prices").eq("id",t).maybeSingle(),s=c?.sku??r.sku,{data:a}=await e.from("products").select("id").eq("sku",s),d=(a??[]).map(o=>o.id);d.length===0&&d.push(t);const{error:n}=await e.from("products").update({sale_price:c?.sale_price??null,sale_prices:c?.sale_prices??null,sale_start_at:r.sale_start_at??null,sale_end_at:r.sale_end_at??null,updated_at:i}).in("id",d);if(n)throw n;const _=r.variants??[];if(_.length===0)return;const{data:l}=await e.from("product_variants").select("sku, sale_price, sale_prices").eq("product_id",t),u=new Map((l??[]).map(o=>[o.sku,o]));for(const o of _){const p=u.get(o.sku);if(!p)continue;const{error:m}=await e.from("product_variants").update({sale_price:p.sale_price??null,sale_prices:p.sale_prices??null,sale_start_at:o.sale_start_at??null,sale_end_at:o.sale_end_at??null,updated_at:i}).eq("sku",o.sku).in("product_id",d);if(m)throw m}}async function C(e,{page:t=1,limit:r=10,search:i="",languageId:c,categoryId:s}={}){const a=(t-1)*r,d=a+r-1;let n=e.from("products").select("id, title, sku, upc, price, prices, sale_price, sale_prices, sale_start_at, sale_end_at, scheduled_price, scheduled_prices, scheduled_price_at, is_taxable, product_type, payment_provider, short_description, stock, status, slug, language_id, translation_group_id, freemius_product_id, freemius_plan_id, trial_period_days, trial_requires_payment_method, product_media(media(file_path, object_key)), product_variants(id, price, prices, sale_price, sale_prices, sale_start_at, sale_end_at, scheduled_price, scheduled_prices, scheduled_price_at), freemius_plans(id, name, title, freemius_pricing(id, license_quota, api_monthly_price, api_annual_price, api_lifetime_price, override_monthly_price, override_annual_price, override_lifetime_price, is_active)), product_categories(category:categories(id, name, slug, description, name_translations, description_translations))",{count:"exact"}).range(a,d).order("created_at",{ascending:!1});if(c&&(n=n.eq("language_id",c)),s){const{data:_,error:l}=await e.from("product_categories").select("product_id").eq("category_id",s);if(l)return{data:[],error:l,count:0};const u=(_||[]).map(o=>o.product_id).filter(Boolean);if(u.length===0)return{data:[],error:null,count:0};n=n.in("id",u)}return i&&(n=n.or(`title.ilike.%${i}%,sku.ilike.%${i}%`)),n}async function M(e,t){return e.from("products").select(`
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const F=require("@nextblock-cms/utils/server"),P=require("./shared-inventory.cjs.js"),b=require("@nextblock-cms/utils/utils"),g=e=>Math.round(e*100);function y(e){return Object.entries(e||{}).reduce((t,[r,i])=>(typeof i=="number"&&Number.isFinite(i)&&i>=0&&(t[b.normalizeCurrencyCode(r)]=g(i)),t),{})}function E(e){return(e||[]).map(t=>({id:t.id,sku:t.sku,upc:t.upc??null,price:g(t.price),sale_price:typeof t.sale_price=="number"&&!isNaN(t.sale_price)?g(t.sale_price):null,prices:y(t.prices),sale_prices:y(t.sale_prices),sale_start_at:t.sale_start_at??null,sale_end_at:t.sale_end_at??null,stock_quantity:t.stock_quantity,main_media_id:t.main_media_id??null,attribute_term_ids:t.attribute_term_ids}))}function j(e,t){const i=e.product_type==="digital"&&e.payment_provider==="freemius"?Math.max(0,Number(e.trial_period_days??0)):0;return{id:t,product_type:e.product_type,payment_provider:e.payment_provider,title:e.title,slug:e.slug,sku:e.sku,upc:e.upc??null,stock:e.stock,status:e.status,short_description:e.short_description??null,description_json:e.description_json??null,metadata:{},price:g(e.price),sale_price:typeof e.sale_price=="number"&&!isNaN(e.sale_price)?g(e.sale_price):null,prices:y(e.prices),sale_prices:y(e.sale_prices),sale_start_at:e.sale_start_at??null,sale_end_at:e.sale_end_at??null,freemius_plan_id:e.freemius_plan_id??null,freemius_product_id:e.freemius_product_id??null,trial_period_days:i,trial_requires_payment_method:i>0?e.trial_requires_payment_method??!1:!1,is_taxable:e.is_taxable,language_id:e.language_id,translation_group_id:e.translation_group_id||void 0,variants:E(e.variants)}}async function S(e,t,r){const{error:i}=await e.from("products").update({is_taxable:r,updated_at:new Date().toISOString()}).eq("id",t);if(i)throw i}async function x(e,t,r){const i=new Date().toISOString(),{data:c}=await e.from("products").select("sku, sale_price, sale_prices").eq("id",t).maybeSingle(),s=c?.sku??r.sku,{data:a}=await e.from("products").select("id").eq("sku",s),d=(a??[]).map(o=>o.id);d.length===0&&d.push(t);const{error:n}=await e.from("products").update({sale_price:c?.sale_price??null,sale_prices:c?.sale_prices??null,sale_start_at:r.sale_start_at??null,sale_end_at:r.sale_end_at??null,updated_at:i}).in("id",d);if(n)throw n;const _=r.variants??[];if(_.length===0)return;const{data:l}=await e.from("product_variants").select("sku, sale_price, sale_prices").eq("product_id",t),u=new Map((l??[]).map(o=>[o.sku,o]));for(const o of _){const p=u.get(o.sku);if(!p)continue;const{error:m}=await e.from("product_variants").update({sale_price:p.sale_price??null,sale_prices:p.sale_prices??null,sale_start_at:o.sale_start_at??null,sale_end_at:o.sale_end_at??null,updated_at:i}).eq("sku",o.sku).in("product_id",d);if(m)throw m}}async function C(e,{page:t=1,limit:r=10,search:i="",languageId:c,categoryId:s}={}){const a=(t-1)*r,d=a+r-1;let n=e.from("products").select("id, title, average_rating, total_reviews, sku, upc, price, prices, sale_price, sale_prices, sale_start_at, sale_end_at, scheduled_price, scheduled_prices, scheduled_price_at, is_taxable, product_type, payment_provider, short_description, stock, status, slug, language_id, translation_group_id, freemius_product_id, freemius_plan_id, trial_period_days, trial_requires_payment_method, product_media(media(file_path, object_key)), product_variants(id, price, prices, sale_price, sale_prices, sale_start_at, sale_end_at, scheduled_price, scheduled_prices, scheduled_price_at), freemius_plans(id, name, title, freemius_pricing(id, license_quota, api_monthly_price, api_annual_price, api_lifetime_price, override_monthly_price, override_annual_price, override_lifetime_price, is_active)), product_categories(category:categories(id, name, slug, description, name_translations, description_translations))",{count:"exact"}).range(a,d).order("created_at",{ascending:!1});if(c&&(n=n.eq("language_id",c)),s){const{data:_,error:l}=await e.from("product_categories").select("product_id").eq("category_id",s);if(l)return{data:[],error:l,count:0};const u=(_||[]).map(o=>o.product_id).filter(Boolean);if(u.length===0)return{data:[],error:null,count:0};n=n.in("id",u)}return i&&(n=n.or(`title.ilike.%${i}%,sku.ilike.%${i}%`)),n}async function M(e,t){return e.from("products").select(`
2
2
  *,
3
3
  languages (
4
4
  code
@@ -166,7 +166,7 @@
166
166
  description_translations
167
167
  )
168
168
  )
169
- `).eq("slug",t);if(c)return{data:null,error:c};if(!i||i.length===0)return{data:null,error:{message:"Product not found",code:"PGRST116"}};let s=null;return r&&(s=i.find(a=>(Array.isArray(a.languages)?a.languages[0]:a.languages)?.code===r)),s||(s=i.find(a=>(Array.isArray(a.languages)?a.languages[0]:a.languages)?.is_default)),s||(s=i.find(a=>(Array.isArray(a.languages)?a.languages[0]:a.languages)?.code==="en")),s||(s=i[0]),{data:s,error:null}}async function A(e,t){const{data:r,error:i}=await e.rpc("upsert_product_with_variants",{product_payload:j(t)});if(i||!r)throw i||new Error("Failed to create product");if(t.product_media&&t.product_media.length>0){const s=t.product_media.map((a,d)=>({product_id:r,media_id:a.media_id,sort_order:d}));await e.from("product_media").insert(s)}else t.media_id&&await e.from("product_media").insert({product_id:r,media_id:t.media_id,sort_order:0});await S(e,r,t.is_taxable),await x(e,r,t),await P.syncSharedInventoryForSavedProduct(r,t),t.category_ids!==void 0&&await q(e,r,t.category_ids);const{data:c}=await e.from("products").select("*").eq("id",r).single();return c}async function R(e,t,r){const{data:i}=await e.from("product_media").select("media_id").eq("product_id",t),c=i?.map(o=>o.media_id)||[],{data:s,error:a}=await e.rpc("upsert_product_with_variants",{product_payload:j(r,t)});if(a||!s)throw a||new Error("Failed to update product");if(r.product_media){if(await e.from("product_media").delete().eq("product_id",t),r.product_media.length>0){const o=r.product_media.map((p,m)=>({product_id:t,media_id:p.media_id,sort_order:m}));await e.from("product_media").insert(o)}}else r.media_id&&(await e.from("product_media").delete().eq("product_id",t),await e.from("product_media").insert({product_id:t,media_id:r.media_id,sort_order:0}));await S(e,s,r.is_taxable),await x(e,s,r);const d=r.product_media?r.product_media.map(o=>o.media_id):r.media_id?[r.media_id]:[],n=r.explicitly_removed_media_ids||[],_=c.filter(o=>!d.includes(o)),l=Array.from(new Set([..._,...n]));if(l.length>0)for(const o of l){const{count:p}=await e.from("product_media").select("*",{count:"exact",head:!0}).eq("media_id",o);if(p&&p>0)continue;const{count:m}=await e.from("posts").select("*",{count:"exact",head:!0}).eq("feature_image_id",o);if(m&&m>0)continue;const{count:h}=await e.from("logos").select("*",{count:"exact",head:!0}).eq("media_id",o);if(h&&h>0)continue;const{count:w}=await e.from("product_variants").select("*",{count:"exact",head:!0}).eq("main_media_id",o);if(w&&w>0)continue;const{data:f}=await e.from("media").select("object_key, variants").eq("id",o).single();if(f){const v=[f.object_key];f.variants&&Array.isArray(f.variants)&&f.variants.forEach(k=>{k.objectKey&&v.push(k.objectKey)}),await F.deleteMediaFiles(v),await e.from("media").delete().eq("id",o)}}await P.syncSharedInventoryForSavedProduct(s,r),r.category_ids!==void 0&&await q(e,t,r.category_ids);const{data:u}=await e.from("products").select("*").eq("id",s).single();return u}async function I(e,t){const{error:r}=await e.from("products").delete().eq("id",t);if(r)throw r;return!0}async function N(e,t,r){const{data:i,error:c}=await e.from("products").select("*").eq("id",r).single();if(c||!i)throw new Error(c?.message||"Source product not found");const{data:s,error:a}=await e.from("products").select("language_id").eq("id",t).single();if(a||!s)throw new Error(a?.message||"Target product not found");const{error:d}=await e.from("products").update({title:i.title,short_description:i.short_description,description_json:i.description_json}).eq("id",t);if(d)throw d;const{data:n,error:_}=await e.from("blocks").select("*").eq("product_id",r).order("order",{ascending:!0});if(_)throw _;if(await e.from("blocks").delete().eq("product_id",t),n&&n.length>0){const u=n.map(p=>{const{id:m,created_at:h,updated_at:w,...f}=p;return{...f,product_id:t,language_id:s.language_id}}),{error:o}=await e.from("blocks").insert(u);if(o)throw o}await e.from("product_drafts").delete().eq("product_id",t),await e.from("product_media").delete().eq("product_id",t);const{data:l}=await e.from("product_media").select("media_id, sort_order").eq("product_id",r);if(l&&l.length>0){const u=l.map(o=>({product_id:t,media_id:o.media_id,sort_order:o.sort_order}));await e.from("product_media").insert(u)}return{success:!0}}async function $(e,t,r,i=[],c=[]){const{data:s}=await e.from("languages").select("id").eq("code",r).single();if(!s)return{data:[],error:"Language not found"};const a=[];t.length>0&&a.push(`translation_group_id.in.(${t.join(",")})`),i.length>0&&a.push(`sku.in.(${i.map(_=>`"${_}"`).join(",")})`),c.length>0&&a.push(`id.in.(${c.join(",")})`);let d=e.from("products").select(`
169
+ `).eq("slug",t);if(c)return{data:null,error:c};if(!i||i.length===0)return{data:null,error:{message:"Product not found",code:"PGRST116"}};let s=null;return r&&(s=i.find(a=>(Array.isArray(a.languages)?a.languages[0]:a.languages)?.code===r)),s||(s=i.find(a=>(Array.isArray(a.languages)?a.languages[0]:a.languages)?.is_default)),s||(s=i.find(a=>(Array.isArray(a.languages)?a.languages[0]:a.languages)?.code==="en")),s||(s=i[0]),{data:s,error:null}}async function A(e,t){const{data:r,error:i}=await e.rpc("upsert_product_with_variants",{product_payload:j(t)});if(i||!r)throw i||new Error("Failed to create product");if(t.product_media&&t.product_media.length>0){const s=t.product_media.map((a,d)=>({product_id:r,media_id:a.media_id,sort_order:d}));await e.from("product_media").insert(s)}else t.media_id&&await e.from("product_media").insert({product_id:r,media_id:t.media_id,sort_order:0});await S(e,r,t.is_taxable),await x(e,r,t),await P.syncSharedInventoryForSavedProduct(r,t),t.category_ids!==void 0&&await v(e,r,t.category_ids);const{data:c}=await e.from("products").select("*").eq("id",r).single();return c}async function R(e,t,r){const{data:i}=await e.from("product_media").select("media_id").eq("product_id",t),c=i?.map(o=>o.media_id)||[],{data:s,error:a}=await e.rpc("upsert_product_with_variants",{product_payload:j(r,t)});if(a||!s)throw a||new Error("Failed to update product");if(r.product_media){if(await e.from("product_media").delete().eq("product_id",t),r.product_media.length>0){const o=r.product_media.map((p,m)=>({product_id:t,media_id:p.media_id,sort_order:m}));await e.from("product_media").insert(o)}}else r.media_id&&(await e.from("product_media").delete().eq("product_id",t),await e.from("product_media").insert({product_id:t,media_id:r.media_id,sort_order:0}));await S(e,s,r.is_taxable),await x(e,s,r);const d=r.product_media?r.product_media.map(o=>o.media_id):r.media_id?[r.media_id]:[],n=r.explicitly_removed_media_ids||[],_=c.filter(o=>!d.includes(o)),l=Array.from(new Set([..._,...n]));if(l.length>0)for(const o of l){const{count:p}=await e.from("product_media").select("*",{count:"exact",head:!0}).eq("media_id",o);if(p&&p>0)continue;const{count:m}=await e.from("posts").select("*",{count:"exact",head:!0}).eq("feature_image_id",o);if(m&&m>0)continue;const{count:h}=await e.from("logos").select("*",{count:"exact",head:!0}).eq("media_id",o);if(h&&h>0)continue;const{count:w}=await e.from("product_variants").select("*",{count:"exact",head:!0}).eq("main_media_id",o);if(w&&w>0)continue;const{data:f}=await e.from("media").select("object_key, variants").eq("id",o).single();if(f){const q=[f.object_key];f.variants&&Array.isArray(f.variants)&&f.variants.forEach(k=>{k.objectKey&&q.push(k.objectKey)}),await F.deleteMediaFiles(q),await e.from("media").delete().eq("id",o)}}await P.syncSharedInventoryForSavedProduct(s,r),r.category_ids!==void 0&&await v(e,t,r.category_ids);const{data:u}=await e.from("products").select("*").eq("id",s).single();return u}async function I(e,t){const{error:r}=await e.from("products").delete().eq("id",t);if(r)throw r;return!0}async function N(e,t,r){const{data:i,error:c}=await e.from("products").select("*").eq("id",r).single();if(c||!i)throw new Error(c?.message||"Source product not found");const{data:s,error:a}=await e.from("products").select("language_id").eq("id",t).single();if(a||!s)throw new Error(a?.message||"Target product not found");const{error:d}=await e.from("products").update({title:i.title,short_description:i.short_description,description_json:i.description_json}).eq("id",t);if(d)throw d;const{data:n,error:_}=await e.from("blocks").select("*").eq("product_id",r).order("order",{ascending:!0});if(_)throw _;if(await e.from("blocks").delete().eq("product_id",t),n&&n.length>0){const u=n.map(p=>{const{id:m,created_at:h,updated_at:w,...f}=p;return{...f,product_id:t,language_id:s.language_id}}),{error:o}=await e.from("blocks").insert(u);if(o)throw o}await e.from("product_drafts").delete().eq("product_id",t),await e.from("product_media").delete().eq("product_id",t);const{data:l}=await e.from("product_media").select("media_id, sort_order").eq("product_id",r);if(l&&l.length>0){const u=l.map(o=>({product_id:t,media_id:o.media_id,sort_order:o.sort_order}));await e.from("product_media").insert(u)}return{success:!0}}async function $(e,t,r,i=[],c=[]){const{data:s}=await e.from("languages").select("id").eq("code",r).single();if(!s)return{data:[],error:"Language not found"};const a=[];t.length>0&&a.push(`translation_group_id.in.(${t.join(",")})`),i.length>0&&a.push(`sku.in.(${i.map(_=>`"${_}"`).join(",")})`),c.length>0&&a.push(`id.in.(${c.join(",")})`);let d=e.from("products").select(`
170
170
  id,
171
171
  title,
172
172
  sku,
@@ -234,4 +234,4 @@
234
234
  )
235
235
  ),
236
236
  translation_group_id
237
- `).eq("language_id",s.id).eq("status","active");return a.length>0&&(d=d.or(a.join(","))),await d.order("id")}async function q(e,t,r){const{data:i}=await e.from("products").select("translation_group_id").eq("id",t).single();if(!i||!i.translation_group_id){if(await e.from("product_categories").delete().eq("product_id",t),r.length>0){const a=r.map(d=>({product_id:t,category_id:d}));await e.from("product_categories").insert(a)}return}const{data:c}=await e.from("products").select("id").eq("translation_group_id",i.translation_group_id),s=c&&c.length>0?c.map(a=>a.id):[t];if(await e.from("product_categories").delete().in("product_id",s),r.length>0){const a=[];for(const d of s)for(const n of r)a.push({product_id:d,category_id:n});await e.from("product_categories").insert(a)}}exports.copyProductFromLanguage=N;exports.createProduct=A;exports.deleteProduct=I;exports.fetchTranslatedProductsForCartInternal=$;exports.getProduct=M;exports.getProductBySlug=T;exports.getProducts=C;exports.syncCategoriesForTranslationGroup=q;exports.updateProduct=R;
237
+ `).eq("language_id",s.id).eq("status","active");return a.length>0&&(d=d.or(a.join(","))),await d.order("id")}async function v(e,t,r){const{data:i}=await e.from("products").select("translation_group_id").eq("id",t).single();if(!i||!i.translation_group_id){if(await e.from("product_categories").delete().eq("product_id",t),r.length>0){const a=r.map(d=>({product_id:t,category_id:d}));await e.from("product_categories").insert(a)}return}const{data:c}=await e.from("products").select("id").eq("translation_group_id",i.translation_group_id),s=c&&c.length>0?c.map(a=>a.id):[t];if(await e.from("product_categories").delete().in("product_id",s),r.length>0){const a=[];for(const d of s)for(const n of r)a.push({product_id:d,category_id:n});await e.from("product_categories").insert(a)}}exports.copyProductFromLanguage=N;exports.createProduct=A;exports.deleteProduct=I;exports.fetchTranslatedProductsForCartInternal=$;exports.getProduct=M;exports.getProductBySlug=T;exports.getProducts=C;exports.syncCategoriesForTranslationGroup=v;exports.updateProduct=R;
@@ -1,5 +1,5 @@
1
1
  import { SupabaseClient } from '@supabase/supabase-js';
2
- import { Database } from '../../../db/src/index.ts';
2
+ import { Database } from '../../../db/src/lib/supabase/types.ts';
3
3
  import { ProductFormValues } from './product-schema';
4
4
  export declare function getProducts(supabase: SupabaseClient<Database>, { page, limit, search, languageId, categoryId, }?: {
5
5
  page?: number;
@@ -10,6 +10,8 @@ export declare function getProducts(supabase: SupabaseClient<Database>, { page,
10
10
  }): Promise<import('@supabase/postgrest-js').PostgrestResponseFailure | import('@supabase/postgrest-js').PostgrestResponseSuccess<{
11
11
  id: string;
12
12
  title: string;
13
+ average_rating: number;
14
+ total_reviews: number;
13
15
  sku: string;
14
16
  upc: string | null;
15
17
  price: number;
@@ -88,6 +90,7 @@ export declare function getProducts(supabase: SupabaseClient<Database>, { page,
88
90
  count: number;
89
91
  }>;
90
92
  export declare function getProduct(supabase: SupabaseClient<Database>, id: string): Promise<import('@supabase/postgrest-js').PostgrestSingleResponse<{
93
+ average_rating: number;
91
94
  created_at: string | null;
92
95
  description_json: import('../../../db/src/index.ts').Json | null;
93
96
  freemius_plan_id: string | null;
@@ -115,6 +118,7 @@ export declare function getProduct(supabase: SupabaseClient<Database>, id: strin
115
118
  status: string;
116
119
  stock: number | null;
117
120
  title: string;
121
+ total_reviews: number;
118
122
  translation_group_id: string;
119
123
  trial_period_days: number;
120
124
  trial_requires_payment_method: boolean;
@@ -210,6 +214,7 @@ export declare function getProductBySlug(supabase: SupabaseClient<Database>, slu
210
214
  error: null;
211
215
  }>;
212
216
  export declare function createProduct(supabase: SupabaseClient<Database>, data: ProductFormValues): Promise<{
217
+ average_rating: number;
213
218
  created_at: string | null;
214
219
  description_json: import('../../../db/src/index.ts').Json | null;
215
220
  freemius_plan_id: string | null;
@@ -237,6 +242,7 @@ export declare function createProduct(supabase: SupabaseClient<Database>, data:
237
242
  status: string;
238
243
  stock: number | null;
239
244
  title: string;
245
+ total_reviews: number;
240
246
  translation_group_id: string;
241
247
  trial_period_days: number;
242
248
  trial_requires_payment_method: boolean;
@@ -244,6 +250,7 @@ export declare function createProduct(supabase: SupabaseClient<Database>, data:
244
250
  updated_at: string | null;
245
251
  } | null>;
246
252
  export declare function updateProduct(supabase: SupabaseClient<Database>, id: string, data: ProductFormValues): Promise<{
253
+ average_rating: number;
247
254
  created_at: string | null;
248
255
  description_json: import('../../../db/src/index.ts').Json | null;
249
256
  freemius_plan_id: string | null;
@@ -271,6 +278,7 @@ export declare function updateProduct(supabase: SupabaseClient<Database>, id: st
271
278
  status: string;
272
279
  stock: number | null;
273
280
  title: string;
281
+ total_reviews: number;
274
282
  translation_group_id: string;
275
283
  trial_period_days: number;
276
284
  trial_requires_payment_method: boolean;
@@ -1,6 +1,6 @@
1
1
  import { deleteMediaFiles as b } from "@nextblock-cms/utils/server";
2
- import { syncSharedInventoryForSavedProduct as v } from "./shared-inventory.es.js";
3
- import { normalizeCurrencyCode as E } from "@nextblock-cms/utils";
2
+ import { syncSharedInventoryForSavedProduct as k } from "./shared-inventory.es.js";
3
+ import { normalizeCurrencyCode as E } from "@nextblock-cms/utils/utils";
4
4
  const g = (e) => Math.round(e * 100);
5
5
  function h(e) {
6
6
  return Object.entries(e || {}).reduce(
@@ -105,7 +105,7 @@ async function R(e, {
105
105
  } = {}) {
106
106
  const a = (t - 1) * i, d = a + i - 1;
107
107
  let n = e.from("products").select(
108
- "id, title, sku, upc, price, prices, sale_price, sale_prices, sale_start_at, sale_end_at, scheduled_price, scheduled_prices, scheduled_price_at, is_taxable, product_type, payment_provider, short_description, stock, status, slug, language_id, translation_group_id, freemius_product_id, freemius_plan_id, trial_period_days, trial_requires_payment_method, product_media(media(file_path, object_key)), product_variants(id, price, prices, sale_price, sale_prices, sale_start_at, sale_end_at, scheduled_price, scheduled_prices, scheduled_price_at), freemius_plans(id, name, title, freemius_pricing(id, license_quota, api_monthly_price, api_annual_price, api_lifetime_price, override_monthly_price, override_annual_price, override_lifetime_price, is_active)), product_categories(category:categories(id, name, slug, description, name_translations, description_translations))",
108
+ "id, title, average_rating, total_reviews, sku, upc, price, prices, sale_price, sale_prices, sale_start_at, sale_end_at, scheduled_price, scheduled_prices, scheduled_price_at, is_taxable, product_type, payment_provider, short_description, stock, status, slug, language_id, translation_group_id, freemius_product_id, freemius_plan_id, trial_period_days, trial_requires_payment_method, product_media(media(file_path, object_key)), product_variants(id, price, prices, sale_price, sale_prices, sale_start_at, sale_end_at, scheduled_price, scheduled_prices, scheduled_price_at), freemius_plans(id, name, title, freemius_pricing(id, license_quota, api_monthly_price, api_annual_price, api_lifetime_price, override_monthly_price, override_annual_price, override_lifetime_price, is_active)), product_categories(category:categories(id, name, slug, description, name_translations, description_translations))",
109
109
  { count: "exact" }
110
110
  ).range(a, d).order("created_at", { ascending: !1 });
111
111
  if (c && (n = n.eq("language_id", c)), s) {
@@ -320,7 +320,7 @@ async function $(e, t) {
320
320
  media_id: t.media_id,
321
321
  sort_order: 0
322
322
  });
323
- await x(e, i, t.is_taxable), await P(e, i, t), await v(i, t), t.category_ids !== void 0 && await S(e, i, t.category_ids);
323
+ await x(e, i, t.is_taxable), await P(e, i, t), await k(i, t), t.category_ids !== void 0 && await S(e, i, t.category_ids);
324
324
  const { data: c } = await e.from("products").select("*").eq("id", i).single();
325
325
  return c;
326
326
  }
@@ -358,12 +358,12 @@ async function D(e, t, i) {
358
358
  const { data: f } = await e.from("media").select("object_key, variants").eq("id", o).single();
359
359
  if (f) {
360
360
  const q = [f.object_key];
361
- f.variants && Array.isArray(f.variants) && f.variants.forEach((k) => {
362
- k.objectKey && q.push(k.objectKey);
361
+ f.variants && Array.isArray(f.variants) && f.variants.forEach((v) => {
362
+ v.objectKey && q.push(v.objectKey);
363
363
  }), await b(q), await e.from("media").delete().eq("id", o);
364
364
  }
365
365
  }
366
- await v(s, i), i.category_ids !== void 0 && await S(e, t, i.category_ids);
366
+ await k(s, i), i.category_ids !== void 0 && await S(e, t, i.category_ids);
367
367
  const { data: u } = await e.from("products").select("*").eq("id", s).single();
368
368
  return u;
369
369
  }
@@ -1,5 +1,5 @@
1
1
  import { SupabaseClient } from '@supabase/supabase-js';
2
- import { Database } from '../../../db/src/index.ts';
2
+ import { Database } from '../../../db/src/lib/supabase/types.ts';
3
3
  import { ProductFormValues } from './product-schema';
4
4
  export type InventoryUsageType = 'product' | 'variant' | 'mixed';
5
5
  export interface InventoryItem {
package/lib/types.d.ts CHANGED
@@ -66,6 +66,8 @@ export interface Product {
66
66
  id: string;
67
67
  title: string;
68
68
  slug: string;
69
+ average_rating?: number;
70
+ total_reviews?: number;
69
71
  categories?: Category[];
70
72
  sku: string;
71
73
  upc?: string | null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nextblock-cms/ecom",
3
- "version": "0.11.1",
3
+ "version": "0.11.2",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -10,9 +10,9 @@
10
10
  },
11
11
  "type": "module",
12
12
  "dependencies": {
13
- "@nextblock-cms/db": "^0.11.1",
14
- "@nextblock-cms/ui": "^0.11.1",
15
- "@nextblock-cms/utils": "^0.11.1",
13
+ "@nextblock-cms/db": "^0.11.2",
14
+ "@nextblock-cms/ui": "^0.11.2",
15
+ "@nextblock-cms/utils": "^0.11.2",
16
16
  "@freemius/checkout": "^1.4.1",
17
17
  "@freemius/sdk": "^0.3.0",
18
18
  "@hookform/resolvers": "^5.2.2",