@sprintup-cms/sdk 1.8.14 → 1.8.16

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.
@@ -491,18 +491,19 @@ function ProductListBlock({ block }) {
491
491
  title && /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-2xl md:text-3xl font-semibold tracking-tight", children: title }),
492
492
  subtitle && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground mt-2", children: subtitle })
493
493
  ] }),
494
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: `grid gap-6 grid-cols-1 ${gridCols}`, children: products.map((product) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border rounded-lg overflow-hidden group hover:shadow-md transition-shadow", children: [
495
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "aspect-square relative bg-muted overflow-hidden", children: [
496
- product.image ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: product.image, alt: product.name, className: "w-full h-full object-cover group-hover:scale-105 transition-transform duration-300" }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full flex items-center justify-center text-muted-foreground/30", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-12 h-12", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M16 11V7a4 4 0 00-8 0v4M5 9h14l1 12H4L5 9z" }) }) }),
497
- product.badge && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute top-3 left-3 text-xs px-2 py-1 rounded bg-primary text-primary-foreground", children: product.badge })
498
- ] }),
494
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: `grid gap-6 grid-cols-1 ${gridCols}`, children: products.map((product) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border rounded-lg overflow-hidden group hover:shadow-md transition-shadow bg-card", children: [
495
+ product.image && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "aspect-video relative bg-muted overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx("img", { src: product.image, alt: product.name, className: "w-full h-full object-cover group-hover:scale-105 transition-transform duration-300" }) }),
499
496
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-4 space-y-2", children: [
500
- product.category && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground uppercase tracking-wide", children: product.category }),
501
- /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "font-medium text-sm line-clamp-2", children: product.name }),
497
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [
498
+ product.category && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs px-2 py-0.5 rounded-full bg-primary/10 text-primary font-medium", children: product.category }),
499
+ product.badge && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs px-2 py-0.5 rounded-full bg-muted text-muted-foreground", children: product.badge })
500
+ ] }),
501
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "font-semibold text-base line-clamp-2", children: product.name }),
502
502
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between pt-1", children: [
503
- showPrice && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-semibold", children: [
504
- currency,
505
- typeof product.price === "number" ? product.price.toFixed(2) : product.price
503
+ showPrice && product.price > 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-bold text-lg", children: [
504
+ typeof product.price === "number" ? product.price.toFixed(2) : product.price,
505
+ " ",
506
+ currency
506
507
  ] }),
507
508
  showRating && product.rating && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 text-sm text-muted-foreground", children: [
508
509
  /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-3.5 h-3.5 fill-yellow-400 text-yellow-400", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z" }) }),
@@ -620,15 +621,13 @@ function CMSBlocks({ blocks, pageType, className = "", custom = {} }) {
620
621
  }) });
621
622
  }
622
623
  function normaliseProductServer(raw) {
623
- if (raw.id !== void 0 && raw.price !== void 0) return raw;
624
624
  const firstPlan = Array.isArray(raw.plans) && raw.plans.length > 0 ? raw.plans[0] : null;
625
625
  const courseCount = Array.isArray(raw.courses) ? raw.courses.length : void 0;
626
- const image = raw.image && !raw.image.startsWith("data:") ? raw.image : raw.thumbnail ?? void 0;
627
626
  return {
628
627
  id: raw._id ?? raw.id ?? String(Math.random()),
629
628
  name: raw.name ?? "Unnamed",
630
629
  price: firstPlan?.price ?? raw.price ?? 0,
631
- image,
630
+ color: raw.primaryColor ?? raw.color ?? void 0,
632
631
  rating: raw.rating ?? void 0,
633
632
  category: raw.type ? raw.type.replace(/-/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()) : void 0,
634
633
  badge: courseCount ? `${courseCount} course${courseCount !== 1 ? "s" : ""}` : raw.duration ? `${raw.duration} min` : void 0
@@ -639,7 +638,7 @@ function ServerProductListBlock({ block }) {
639
638
  const { title, subtitle, columns = 3, showPrice = true, showRating = true, limit = 6, currency = "$" } = cfg;
640
639
  const cols = parseInt(String(columns), 10);
641
640
  const gridCols = cols === 2 ? "sm:grid-cols-2" : cols === 4 ? "sm:grid-cols-2 lg:grid-cols-4" : "sm:grid-cols-2 lg:grid-cols-3";
642
- const rawProducts = Array.isArray(cfg.prefetchedProducts) ? cfg.prefetchedProducts : [];
641
+ const rawProducts = Array.isArray(block._resolvedProducts) ? block._resolvedProducts : Array.isArray(cfg.prefetchedProducts) ? cfg.prefetchedProducts : [];
643
642
  const products = rawProducts.map(normaliseProductServer).slice(0, Number(limit));
644
643
  if (products.length === 0) {
645
644
  return /* @__PURE__ */ jsxRuntime.jsx("section", { className: "py-12", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-6xl mx-auto px-4", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-center py-12 border border-dashed border-border rounded-lg bg-muted/10", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: "No products available" }) }) }) });
@@ -649,18 +648,32 @@ function ServerProductListBlock({ block }) {
649
648
  title && /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-2xl md:text-3xl font-semibold tracking-tight", children: title }),
650
649
  subtitle && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground mt-2", children: subtitle })
651
650
  ] }),
652
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: `grid gap-6 grid-cols-1 ${gridCols}`, children: products.map((product) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border rounded-lg overflow-hidden group hover:shadow-md transition-shadow", children: [
653
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "aspect-square relative bg-muted overflow-hidden", children: [
654
- product.image ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: product.image, alt: product.name, className: "w-full h-full object-cover group-hover:scale-105 transition-transform duration-300" }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full flex items-center justify-center text-muted-foreground/30", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-12 h-12", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M16 11V7a4 4 0 00-8 0v4M5 9h14l1 12H4L5 9z" }) }) }),
655
- product.badge && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute top-3 left-3 text-xs px-2 py-1 rounded bg-primary text-primary-foreground", children: product.badge })
656
- ] }),
657
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-4 space-y-2", children: [
658
- product.category && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground uppercase tracking-wide", children: product.category }),
659
- /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "font-medium text-sm line-clamp-2", children: product.name }),
660
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between pt-1", children: [
661
- showPrice && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-semibold", children: [
662
- currency,
663
- typeof product.price === "number" ? product.price.toFixed(2) : product.price
651
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: `grid gap-6 grid-cols-1 ${gridCols}`, children: products.map((product) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border rounded-xl overflow-hidden group hover:shadow-lg transition-shadow bg-card flex flex-col", children: [
652
+ /* @__PURE__ */ jsxRuntime.jsx(
653
+ "div",
654
+ {
655
+ className: "h-2 w-full",
656
+ style: { backgroundColor: product.color ?? "#6366f1" }
657
+ }
658
+ ),
659
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-5 flex flex-col gap-3 flex-1", children: [
660
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [
661
+ product.category && /* @__PURE__ */ jsxRuntime.jsx(
662
+ "span",
663
+ {
664
+ className: "text-xs px-2 py-0.5 rounded-full font-medium text-white",
665
+ style: { backgroundColor: product.color ?? "#6366f1" },
666
+ children: product.category
667
+ }
668
+ ),
669
+ product.badge && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs px-2 py-0.5 rounded-full bg-muted text-muted-foreground", children: product.badge })
670
+ ] }),
671
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "font-semibold text-base line-clamp-2 flex-1", children: product.name }),
672
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mt-auto pt-2 border-t border-border", children: [
673
+ showPrice && product.price > 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-bold text-lg", children: [
674
+ typeof product.price === "number" ? product.price.toFixed(2) : product.price,
675
+ " ",
676
+ currency
664
677
  ] }),
665
678
  showRating && product.rating && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 text-sm text-muted-foreground", children: [
666
679
  /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-3.5 h-3.5 fill-yellow-400 text-yellow-400", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z" }) }),
@@ -688,6 +701,27 @@ async function generateMetadata({ params }) {
688
701
  }
689
702
  };
690
703
  }
704
+ async function resolveProductListBlocks(blocks) {
705
+ return Promise.all(blocks.map(async (block) => {
706
+ if (block.type !== "product-list") return block;
707
+ const cfg = block.content ?? block.data ?? {};
708
+ if (Array.isArray(cfg.prefetchedProducts) && cfg.prefetchedProducts.length > 0) return block;
709
+ const endpoint = cfg.endpoint;
710
+ if (!endpoint) return block;
711
+ try {
712
+ const headers = { "Accept": "application/json" };
713
+ const token = cfg.token ?? cfg.apiToken;
714
+ if (token) headers["Authorization"] = `Bearer ${token}`;
715
+ const res = await fetch(endpoint, { headers, next: { revalidate: cfg.refreshInterval || 300 } });
716
+ if (!res.ok) return block;
717
+ const json = await res.json();
718
+ const items = Array.isArray(json) ? json : json.products ?? json.data ?? json.items ?? json.result ?? [];
719
+ return { ...block, _resolvedProducts: items };
720
+ } catch {
721
+ return block;
722
+ }
723
+ }));
724
+ }
691
725
  async function CMSCatchAllPage({ params }) {
692
726
  const { slug } = await params;
693
727
  const slugStr = slug.join("/");
@@ -710,6 +744,7 @@ async function CMSCatchAllPage({ params }) {
710
744
  if (page.pageTypeId) {
711
745
  pageType = await client.getPageType(page.pageTypeId);
712
746
  }
747
+ const resolvedBlocks = await resolveProductListBlocks(page.blocks ?? []);
713
748
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-h-screen bg-background", children: [
714
749
  isPreview && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sticky top-0 z-50 flex items-center justify-between px-4 py-2.5 bg-amber-500 text-white text-sm font-medium shadow", children: [
715
750
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
@@ -731,11 +766,11 @@ async function CMSCatchAllPage({ params }) {
731
766
  }
732
767
  )
733
768
  ] }),
734
- /* @__PURE__ */ jsxRuntime.jsx("article", { className: "max-w-5xl mx-auto px-6 py-12", children: page.blocks?.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
735
- page.blocks.map(
769
+ /* @__PURE__ */ jsxRuntime.jsx("article", { className: "max-w-5xl mx-auto px-6 py-12", children: resolvedBlocks.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
770
+ resolvedBlocks.map(
736
771
  (block, idx) => block.type === "product-list" ? /* @__PURE__ */ jsxRuntime.jsx(ServerProductListBlock, { block }, block.id ?? idx) : null
737
772
  ),
738
- /* @__PURE__ */ jsxRuntime.jsx(CMSBlocks, { blocks: page.blocks.filter((b) => b.type !== "product-list"), pageType })
773
+ /* @__PURE__ */ jsxRuntime.jsx(CMSBlocks, { blocks: resolvedBlocks.filter((b) => b.type !== "product-list"), pageType })
739
774
  ] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center py-24 text-muted-foreground border-2 border-dashed border-border rounded-xl", children: [
740
775
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm", children: "No content added yet." }),
741
776
  isPreview && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs mt-1 opacity-60", children: "Add blocks in the CMS editor to see them here." })