@mohasinac/appkit 2.4.5 → 2.4.6

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.
@@ -20,6 +20,7 @@ import { MarketplaceAuctionGrid } from "./MarketplaceAuctionGrid";
20
20
  import { listReviewsBySeller } from "../../reviews/actions/review-actions";
21
21
  import { PlaceBidFormClient } from "./PlaceBidFormClient";
22
22
  import { CollapsibleBidHistory } from "./CollapsibleBidHistory";
23
+ import { SublistingCarouselSection } from "../../products/components/SublistingCarouselSection";
23
24
  function toDescriptionHtml(raw) {
24
25
  if (!raw)
25
26
  return "";
@@ -90,6 +91,7 @@ export async function AuctionDetailPageView({ id, onPlaceBid }) {
90
91
  ? p.customSections
91
92
  : [];
92
93
  const descriptionHtml = toDescriptionHtml(p.description);
94
+ const sublistingCategoryId = typeof p.sublistingCategoryId === "string" ? p.sublistingCategoryId : null;
93
95
  const relatedDocs = await productRepository
94
96
  .findByCategory(String(p.category ?? ""))
95
97
  .catch(() => []);
@@ -107,7 +109,9 @@ export async function AuctionDetailPageView({ id, onPlaceBid }) {
107
109
  codAvailable: "Cash on Delivery",
108
110
  wishlistCount: (n) => `${n} wishlisted`,
109
111
  categoryProductCount: (n, cat) => `${n} in ${cat}`,
110
- } }), (categoryName || category || brand) && (_jsxs(Row, { align: "center", gap: "xs", className: "text-xs text-zinc-400 dark:text-zinc-500 flex-wrap", children: [category ? (_jsx(Link, { href: String(ROUTES.PUBLIC.CATEGORY_DETAIL(category)), className: "hover:text-primary-600 dark:hover:text-primary-400 transition-colors", children: categoryName || category })) : categoryName ? (_jsx(Span, { children: categoryName })) : null, (category || categoryName) && brand && _jsx(Span, { children: "\u203A" }), brand && (brandSlug ? (_jsx(Link, { href: String(ROUTES.PUBLIC.BRAND_DETAIL(brandSlug)), className: "font-medium text-zinc-600 dark:text-zinc-300 hover:text-primary-600 dark:hover:text-primary-400 transition-colors", children: brand })) : (_jsx(Span, { className: "font-medium text-zinc-600 dark:text-zinc-300", children: brand })))] })), features.length > 0 && (_jsxs(Div, { className: "rounded-xl border border-zinc-100 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-900/60 px-4 py-3", children: [_jsx(Text, { className: "mb-2 text-xs font-semibold uppercase tracking-wide text-zinc-500 dark:text-zinc-400", children: "About this item" }), _jsx("ul", { className: "space-y-1.5", children: features.map((f, i) => (_jsxs("li", { className: "flex items-start gap-2 text-sm text-zinc-700 dark:text-zinc-300", children: [_jsx(Span, { className: "mt-0.5 flex-shrink-0 text-primary-500", children: "\u2022" }), f] }, i))) })] })), descriptionHtml && (_jsx(RichText, { html: descriptionHtml, proseClass: "prose prose-sm max-w-none dark:prose-invert prose-p:my-0", className: "text-sm leading-relaxed text-zinc-600 dark:text-zinc-400 line-clamp-4" })), safeSeller && (_jsx(Div, { className: "rounded-xl border border-zinc-100 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-900/60 p-3", children: _jsxs(Row, { justify: "between", align: "center", children: [_jsxs(Div, { children: [_jsx(Text, { className: "text-[10px] uppercase tracking-wide text-zinc-400 dark:text-zinc-500 mb-0.5", children: "Listed by" }), _jsx(Text, { className: "text-sm font-semibold text-zinc-800 dark:text-zinc-200", children: safeSeller })] }), storeHref && (_jsx(Link, { href: storeHref, className: "shrink-0 rounded-lg bg-primary/10 dark:bg-primary/20 px-3 py-1.5 text-xs font-semibold text-primary-700 dark:text-primary-300 hover:bg-primary/20 dark:hover:bg-primary/30 transition-colors", children: "Visit Store \u2192" }))] }) }))] })), renderBidForm: () => onPlaceBid ? (_jsx(Div, { id: "auction-bid-form", children: _jsx(PlaceBidFormClient, { productId: String(product.id), currentBid: currentBid, startingBid: startingBid, minBidIncrement: minBidIncrement, currency: currency, isEnded: isEnded, buyNowPrice: buyNowPrice, bidCount: bidCount, tags: tags, onPlaceBid: onPlaceBid }) })) : (_jsxs(Div, { className: "rounded-xl border border-zinc-100 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-900/60 p-5 space-y-4", children: [_jsxs(Div, { className: "space-y-1", children: [_jsxs(Row, { justify: "between", align: "center", children: [_jsx(Text, { className: "text-xs text-zinc-500", children: "Current bid" }), _jsx(Text, { className: "text-xs text-zinc-500", children: "Starting bid" })] }), _jsxs(Row, { justify: "between", align: "baseline", children: [_jsx(Span, { className: "text-xl font-bold text-primary-600 dark:text-primary-400", children: formatCurrency(currentBid, currency) }), _jsx(Span, { className: "text-sm text-zinc-500", children: formatCurrency(startingBid, currency) })] }), _jsxs(Text, { className: "text-xs text-zinc-400 dark:text-zinc-500", children: [bidCount, " ", bidCount === 1 ? "bid" : "bids", " \u00B7 min increment ", formatCurrency(minBidIncrement, currency)] })] }), _jsxs(Stack, { gap: "sm", children: [_jsx(Input, { type: "number", placeholder: `At least ${formatCurrency(currentBid + minBidIncrement, currency)}`, min: currentBid + minBidIncrement, "aria-label": "Your bid amount", disabled: isEnded }), _jsx(Button, { variant: "primary", size: "md", className: "w-full", disabled: isEnded, children: isEnded ? "Auction Ended" : "Place Bid" }), buyNowPrice !== null && !isEnded && (_jsxs(Button, { variant: "secondary", size: "md", className: "w-full", children: ["Buy Now \u2014 ", formatCurrency(buyNowPrice, currency)] }))] }), tags.length > 0 && (_jsx(Div, { className: "border-t border-zinc-200 dark:border-zinc-700 pt-4", children: _jsx(Row, { wrap: true, gap: "xs", children: tags.map((tag) => (_jsx(Span, { className: "rounded-full bg-zinc-100 dark:bg-zinc-800 px-2.5 py-1 text-xs text-zinc-600 dark:text-zinc-300", children: tag }, tag))) }) }))] })), renderMobileBidForm: () => !isEnded && onPlaceBid ? (_jsx(Div, { className: "lg:hidden", children: _jsx(PlaceBidFormClient, { productId: String(product.id), currentBid: currentBid, startingBid: startingBid, minBidIncrement: minBidIncrement, currency: currency, isEnded: isEnded, buyNowPrice: buyNowPrice, bidCount: bidCount, tags: tags, onPlaceBid: onPlaceBid }) })) : !isEnded ? (_jsxs(Div, { className: "rounded-xl border border-zinc-100 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-900/60 p-4 lg:hidden", children: [_jsxs(Row, { align: "center", gap: "sm", className: "mb-3", children: [_jsx(Span, { className: "text-base font-bold text-primary-600 dark:text-primary-400", children: formatCurrency(currentBid, currency) }), _jsxs(Span, { className: "text-xs text-zinc-500", children: [bidCount, " bids"] })] }), _jsx(Button, { variant: "primary", size: "md", className: "w-full", children: "Place Bid" })] })) : null, renderTabs: () => (_jsx(ProductTabsShell, { descriptionContent: descriptionHtml ? (_jsx(RichText, { html: descriptionHtml, proseClass: "prose prose-sm sm:prose max-w-none dark:prose-invert", className: "text-zinc-700 dark:text-zinc-300" })) : undefined, specsContent: specs.length > 0 ? (_jsx("dl", { className: "divide-y divide-zinc-100 dark:divide-zinc-800 rounded-xl border border-zinc-100 dark:border-zinc-800 overflow-hidden text-sm", children: specs.map((s, i) => (_jsxs("div", { className: "flex gap-4 px-4 py-3 bg-white dark:bg-zinc-900 even:bg-zinc-50 dark:even:bg-zinc-800/50", children: [_jsx("dt", { className: "w-36 flex-shrink-0 font-medium text-zinc-700 dark:text-zinc-300", children: s.name }), _jsxs("dd", { className: "flex-1 text-zinc-600 dark:text-zinc-400", children: [s.value, s.unit ? ` ${s.unit}` : ""] })] }, i))) })) : undefined, customTabs: customSections.map((s) => ({
112
+ } }), (categoryName || category || brand) && (_jsxs(Row, { align: "center", gap: "xs", className: "text-xs text-zinc-400 dark:text-zinc-500 flex-wrap", children: [category ? (_jsx(Link, { href: String(ROUTES.PUBLIC.CATEGORY_DETAIL(category)), className: "hover:text-primary-600 dark:hover:text-primary-400 transition-colors", children: categoryName || category })) : categoryName ? (_jsx(Span, { children: categoryName })) : null, (category || categoryName) && brand && _jsx(Span, { children: "\u203A" }), brand && (brandSlug ? (_jsx(Link, { href: String(ROUTES.PUBLIC.BRAND_DETAIL(brandSlug)), className: "font-medium text-zinc-600 dark:text-zinc-300 hover:text-primary-600 dark:hover:text-primary-400 transition-colors", children: brand })) : (_jsx(Span, { className: "font-medium text-zinc-600 dark:text-zinc-300", children: brand })))] })), features.length > 0 && (_jsxs(Div, { className: "rounded-xl border border-zinc-100 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-900/60 px-4 py-3", children: [_jsx(Text, { className: "mb-2 text-xs font-semibold uppercase tracking-wide text-zinc-500 dark:text-zinc-400", children: "About this item" }), _jsx("ul", { className: "space-y-1.5", children: features.map((f, i) => (_jsxs("li", { className: "flex items-start gap-2 text-sm text-zinc-700 dark:text-zinc-300", children: [_jsx(Span, { className: "mt-0.5 flex-shrink-0 text-primary-500", children: "\u2022" }), f] }, i))) })] })), descriptionHtml && (_jsx(RichText, { html: descriptionHtml, proseClass: "prose prose-sm max-w-none dark:prose-invert prose-p:my-0", className: "text-sm leading-relaxed text-zinc-600 dark:text-zinc-400 line-clamp-4" })), safeSeller && (_jsx(Div, { className: "rounded-xl border border-zinc-100 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-900/60 p-3", children: _jsxs(Row, { justify: "between", align: "center", children: [_jsxs(Div, { children: [_jsx(Text, { className: "text-[10px] uppercase tracking-wide text-zinc-400 dark:text-zinc-500 mb-0.5", children: "Listed by" }), _jsx(Text, { className: "text-sm font-semibold text-zinc-800 dark:text-zinc-200", children: safeSeller })] }), storeHref && (_jsx(Link, { href: storeHref, className: "shrink-0 rounded-lg bg-primary/10 dark:bg-primary/20 px-3 py-1.5 text-xs font-semibold text-primary-700 dark:text-primary-300 hover:bg-primary/20 dark:hover:bg-primary/30 transition-colors", children: "Visit Store \u2192" }))] }) }))] })), renderBidForm: () => onPlaceBid ? (_jsx(Div, { id: "auction-bid-form", children: _jsx(PlaceBidFormClient, { productId: String(product.id), currentBid: currentBid, startingBid: startingBid, minBidIncrement: minBidIncrement, currency: currency, isEnded: isEnded, buyNowPrice: buyNowPrice, bidCount: bidCount, tags: tags, onPlaceBid: onPlaceBid }) })) : (_jsxs(Div, { className: "rounded-xl border border-zinc-100 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-900/60 p-5 space-y-4", children: [_jsxs(Div, { className: "space-y-1", children: [_jsxs(Row, { justify: "between", align: "center", children: [_jsx(Text, { className: "text-xs text-zinc-500", children: "Current bid" }), _jsx(Text, { className: "text-xs text-zinc-500", children: "Starting bid" })] }), _jsxs(Row, { justify: "between", align: "baseline", children: [_jsx(Span, { className: "text-xl font-bold text-primary-600 dark:text-primary-400", children: formatCurrency(currentBid, currency) }), _jsx(Span, { className: "text-sm text-zinc-500", children: formatCurrency(startingBid, currency) })] }), _jsxs(Text, { className: "text-xs text-zinc-400 dark:text-zinc-500", children: [bidCount, " ", bidCount === 1 ? "bid" : "bids", " \u00B7 min increment ", formatCurrency(minBidIncrement, currency)] })] }), _jsxs(Stack, { gap: "sm", children: [_jsx(Input, { type: "number", placeholder: `At least ${formatCurrency(currentBid + minBidIncrement, currency)}`, min: currentBid + minBidIncrement, "aria-label": "Your bid amount", disabled: isEnded }), _jsx(Button, { variant: "primary", size: "md", className: "w-full", disabled: isEnded, children: isEnded ? "Auction Ended" : "Place Bid" }), buyNowPrice !== null && !isEnded && (_jsxs(Button, { variant: "secondary", size: "md", className: "w-full", children: ["Buy Now \u2014 ", formatCurrency(buyNowPrice, currency)] }))] }), tags.length > 0 && (_jsx(Div, { className: "border-t border-zinc-200 dark:border-zinc-700 pt-4", children: _jsx(Row, { wrap: true, gap: "xs", children: tags.map((tag) => (_jsx(Span, { className: "rounded-full bg-zinc-100 dark:bg-zinc-800 px-2.5 py-1 text-xs text-zinc-600 dark:text-zinc-300", children: tag }, tag))) }) }))] })), renderMobileBidForm: () => !isEnded && onPlaceBid ? (_jsx(Div, { className: "lg:hidden", children: _jsx(PlaceBidFormClient, { productId: String(product.id), currentBid: currentBid, startingBid: startingBid, minBidIncrement: minBidIncrement, currency: currency, isEnded: isEnded, buyNowPrice: buyNowPrice, bidCount: bidCount, tags: tags, onPlaceBid: onPlaceBid }) })) : !isEnded ? (_jsxs(Div, { className: "rounded-xl border border-zinc-100 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-900/60 p-4 lg:hidden", children: [_jsxs(Row, { align: "center", gap: "sm", className: "mb-3", children: [_jsx(Span, { className: "text-base font-bold text-primary-600 dark:text-primary-400", children: formatCurrency(currentBid, currency) }), _jsxs(Span, { className: "text-xs text-zinc-500", children: [bidCount, " bids"] })] }), _jsx(Button, { variant: "primary", size: "md", className: "w-full", children: "Place Bid" })] })) : null, renderSublistingSection: sublistingCategoryId
113
+ ? () => (_jsx(SublistingCarouselSection, { sublistingCategoryId: sublistingCategoryId, currentListingId: String(product.id) }))
114
+ : undefined, renderTabs: () => (_jsx(ProductTabsShell, { descriptionContent: descriptionHtml ? (_jsx(RichText, { html: descriptionHtml, proseClass: "prose prose-sm sm:prose max-w-none dark:prose-invert", className: "text-zinc-700 dark:text-zinc-300" })) : undefined, specsContent: specs.length > 0 ? (_jsx("dl", { className: "divide-y divide-zinc-100 dark:divide-zinc-800 rounded-xl border border-zinc-100 dark:border-zinc-800 overflow-hidden text-sm", children: specs.map((s, i) => (_jsxs("div", { className: "flex gap-4 px-4 py-3 bg-white dark:bg-zinc-900 even:bg-zinc-50 dark:even:bg-zinc-800/50", children: [_jsx("dt", { className: "w-36 flex-shrink-0 font-medium text-zinc-700 dark:text-zinc-300", children: s.name }), _jsxs("dd", { className: "flex-1 text-zinc-600 dark:text-zinc-400", children: [s.value, s.unit ? ` ${s.unit}` : ""] })] }, i))) })) : undefined, customTabs: customSections.map((s) => ({
111
115
  id: s.id,
112
116
  label: s.title,
113
117
  content: _jsx(CustomSectionTabContent, { section: s }),
@@ -15,6 +15,7 @@ import { PreOrderActionsClient } from "./PreOrderActionsClient";
15
15
  import { ProductGalleryClient } from "../../products/components/ProductGalleryClient";
16
16
  import { ProductFeatureBadges } from "../../products/components/ProductFeatureBadges";
17
17
  import { ShareButton } from "../../products/components/ShareButton";
18
+ import { SublistingCarouselSection } from "../../products/components/SublistingCarouselSection";
18
19
  function toDescriptionHtml(raw) {
19
20
  if (!raw)
20
21
  return "";
@@ -95,6 +96,7 @@ export async function PreOrderDetailPageView({ id, onReserveNow }) {
95
96
  ? p.customSections
96
97
  : [];
97
98
  const descriptionHtml = toDescriptionHtml(p.description);
99
+ const sublistingCategoryId = typeof p.sublistingCategoryId === "string" ? p.sublistingCategoryId : null;
98
100
  return (_jsx(Main, { children: _jsxs(Container, { size: "xl", className: "px-4 py-6", children: [_jsxs("div", { className: "mb-4 flex items-center justify-between flex-wrap gap-2", children: [_jsxs("nav", { "aria-label": "Breadcrumb", className: "flex items-center gap-1.5 text-xs text-zinc-500 dark:text-zinc-400 flex-wrap", children: [_jsx(Link, { href: String(ROUTES.HOME), className: "hover:text-primary-600 transition-colors", children: "Home" }), _jsx(Span, { "aria-hidden": true, children: "/" }), _jsx(Link, { href: String(ROUTES.PUBLIC.PRE_ORDERS), className: "hover:text-primary-600 transition-colors", children: "Pre-Orders" }), category && (_jsxs(_Fragment, { children: [_jsx(Span, { "aria-hidden": true, children: "/" }), _jsx(Link, { href: String(ROUTES.PUBLIC.CATEGORY_DETAIL(category)), className: "hover:text-primary-600 transition-colors", children: categoryName || category })] })), _jsx(Span, { "aria-hidden": true, children: "/" }), _jsx(Span, { className: "text-zinc-700 dark:text-zinc-300 truncate max-w-[200px]", children: title })] }), _jsx(ShareButton, { title: title })] }), _jsx(PreOrderDetailView, { renderGallery: () => (_jsx(ProductGalleryClient, { images: images, productName: title })), renderInfo: () => (_jsxs(Stack, { gap: "sm", children: [_jsxs(Div, { children: [_jsxs(Row, { gap: "xs", className: "mb-1.5 flex-wrap", children: [_jsx(Span, { className: "inline-block rounded-full bg-indigo-100 dark:bg-indigo-900/30 px-2.5 py-0.5 text-xs font-semibold text-indigo-700 dark:text-indigo-300", children: "Pre-Order" }), productionStatus && (_jsx(Span, { className: "inline-block rounded-full bg-zinc-100 dark:bg-zinc-800 px-2.5 py-0.5 text-xs font-medium text-zinc-600 dark:text-zinc-300", children: PRODUCTION_STATUS_LABELS[productionStatus] ?? productionStatus }))] }), _jsx(Heading, { level: 1, className: "text-xl font-bold leading-snug text-zinc-900 dark:text-zinc-50 sm:text-2xl", children: title })] }), price !== null && (_jsx(Span, { className: "text-2xl font-bold text-zinc-900 dark:text-zinc-50", children: formatCurrency(price, currency) })), deliveryDate && (_jsxs(Row, { align: "center", gap: "xs", className: "text-sm text-zinc-600 dark:text-zinc-400", children: [_jsx(Span, { children: "\uD83D\uDCC5" }), _jsx(Span, { children: "Estimated delivery:" }), _jsx(Span, { className: "font-medium", children: deliveryDate.toLocaleDateString(undefined, { year: "numeric", month: "long" }) })] })), _jsx(ProductFeatureBadges, { featured: featured, freeShipping: freeShipping, condition: condition ?? undefined, returnable: isCancellable, labels: {
99
101
  featured: "Featured",
100
102
  fasterDelivery: "Faster Delivery",
@@ -109,7 +111,9 @@ export async function PreOrderDetailPageView({ id, onReserveNow }) {
109
111
  codAvailable: "Cash on Delivery",
110
112
  wishlistCount: (n) => `${n} wishlisted`,
111
113
  categoryProductCount: (n, cat) => `${n} in ${cat}`,
112
- } }), (categoryName || category || brand) && (_jsxs(Row, { align: "center", gap: "xs", className: "text-xs text-zinc-400 dark:text-zinc-500 flex-wrap", children: [category ? (_jsx(Link, { href: String(ROUTES.PUBLIC.CATEGORY_DETAIL(category)), className: "hover:text-primary-600 dark:hover:text-primary-400 transition-colors", children: categoryName || category })) : (categoryName ? _jsx(Span, { children: categoryName }) : null), brand && (categoryName || category) && (_jsx(Span, { className: "text-zinc-300 dark:text-zinc-600", children: "\u00B7" })), brand && (brandSlug ? (_jsx(Link, { href: String(ROUTES.PUBLIC.BRAND_DETAIL(brandSlug)), className: "hover:text-primary-600 dark:hover:text-primary-400 transition-colors", children: brand })) : (_jsx(Span, { children: brand })))] })), features.length > 0 && (_jsxs(Div, { className: "rounded-xl border border-zinc-100 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-900/60 px-4 py-3", children: [_jsx(Text, { className: "mb-2 text-xs font-semibold uppercase tracking-wide text-zinc-500 dark:text-zinc-400", children: "About this product" }), _jsx("ul", { className: "space-y-1.5", children: features.map((f, i) => (_jsxs("li", { className: "flex items-start gap-2 text-sm text-zinc-700 dark:text-zinc-300", children: [_jsx(Span, { className: "mt-0.5 flex-shrink-0 text-primary-500", children: "\u2022" }), f] }, i))) })] })), descriptionHtml && (_jsx(RichText, { html: descriptionHtml, proseClass: "prose prose-sm max-w-none dark:prose-invert prose-p:my-0", className: "text-sm leading-relaxed text-zinc-600 dark:text-zinc-400 line-clamp-4" })), safeSeller && (_jsx(Div, { className: "rounded-xl border border-zinc-100 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-900/60 p-3", children: _jsxs(Row, { justify: "between", align: "center", children: [_jsxs(Div, { children: [_jsx(Text, { className: "text-[10px] uppercase tracking-wide text-zinc-400 dark:text-zinc-500 mb-0.5", children: "Sold by" }), _jsx(Text, { className: "text-sm font-semibold text-zinc-800 dark:text-zinc-200", children: safeSeller })] }), storeHref && (_jsx(Link, { href: storeHref, className: "shrink-0 rounded-lg bg-primary/10 dark:bg-primary/20 px-3 py-1.5 text-xs font-semibold text-primary-700 dark:text-primary-300 hover:bg-primary/20 dark:hover:bg-primary/30 transition-colors", children: "Visit Store \u2192" }))] }) }))] })), renderTabs: () => (_jsx(ProductTabsShell, { descriptionContent: descriptionHtml ? (_jsx(RichText, { html: descriptionHtml, proseClass: "prose prose-sm sm:prose max-w-none dark:prose-invert", className: "text-zinc-700 dark:text-zinc-300" })) : undefined, specsContent: specs.length > 0 ? (_jsx("dl", { className: "divide-y divide-zinc-100 dark:divide-zinc-800 rounded-xl border border-zinc-100 dark:border-zinc-800 overflow-hidden text-sm", children: specs.map((s, i) => (_jsxs("div", { className: "flex gap-4 px-4 py-3 bg-white dark:bg-zinc-900 even:bg-zinc-50 dark:even:bg-zinc-800/50", children: [_jsx("dt", { className: "w-36 flex-shrink-0 font-medium text-zinc-700 dark:text-zinc-300", children: s.name }), _jsxs("dd", { className: "flex-1 text-zinc-600 dark:text-zinc-400", children: [s.value, s.unit ? ` ${s.unit}` : ""] })] }, i))) })) : undefined, customTabs: customSections.map((s) => ({
114
+ } }), (categoryName || category || brand) && (_jsxs(Row, { align: "center", gap: "xs", className: "text-xs text-zinc-400 dark:text-zinc-500 flex-wrap", children: [category ? (_jsx(Link, { href: String(ROUTES.PUBLIC.CATEGORY_DETAIL(category)), className: "hover:text-primary-600 dark:hover:text-primary-400 transition-colors", children: categoryName || category })) : (categoryName ? _jsx(Span, { children: categoryName }) : null), brand && (categoryName || category) && (_jsx(Span, { className: "text-zinc-300 dark:text-zinc-600", children: "\u00B7" })), brand && (brandSlug ? (_jsx(Link, { href: String(ROUTES.PUBLIC.BRAND_DETAIL(brandSlug)), className: "hover:text-primary-600 dark:hover:text-primary-400 transition-colors", children: brand })) : (_jsx(Span, { children: brand })))] })), features.length > 0 && (_jsxs(Div, { className: "rounded-xl border border-zinc-100 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-900/60 px-4 py-3", children: [_jsx(Text, { className: "mb-2 text-xs font-semibold uppercase tracking-wide text-zinc-500 dark:text-zinc-400", children: "About this product" }), _jsx("ul", { className: "space-y-1.5", children: features.map((f, i) => (_jsxs("li", { className: "flex items-start gap-2 text-sm text-zinc-700 dark:text-zinc-300", children: [_jsx(Span, { className: "mt-0.5 flex-shrink-0 text-primary-500", children: "\u2022" }), f] }, i))) })] })), descriptionHtml && (_jsx(RichText, { html: descriptionHtml, proseClass: "prose prose-sm max-w-none dark:prose-invert prose-p:my-0", className: "text-sm leading-relaxed text-zinc-600 dark:text-zinc-400 line-clamp-4" })), safeSeller && (_jsx(Div, { className: "rounded-xl border border-zinc-100 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-900/60 p-3", children: _jsxs(Row, { justify: "between", align: "center", children: [_jsxs(Div, { children: [_jsx(Text, { className: "text-[10px] uppercase tracking-wide text-zinc-400 dark:text-zinc-500 mb-0.5", children: "Sold by" }), _jsx(Text, { className: "text-sm font-semibold text-zinc-800 dark:text-zinc-200", children: safeSeller })] }), storeHref && (_jsx(Link, { href: storeHref, className: "shrink-0 rounded-lg bg-primary/10 dark:bg-primary/20 px-3 py-1.5 text-xs font-semibold text-primary-700 dark:text-primary-300 hover:bg-primary/20 dark:hover:bg-primary/30 transition-colors", children: "Visit Store \u2192" }))] }) }))] })), renderSublistingSection: sublistingCategoryId
115
+ ? () => (_jsx(SublistingCarouselSection, { sublistingCategoryId: sublistingCategoryId, currentListingId: String(product.id) }))
116
+ : undefined, renderTabs: () => (_jsx(ProductTabsShell, { descriptionContent: descriptionHtml ? (_jsx(RichText, { html: descriptionHtml, proseClass: "prose prose-sm sm:prose max-w-none dark:prose-invert", className: "text-zinc-700 dark:text-zinc-300" })) : undefined, specsContent: specs.length > 0 ? (_jsx("dl", { className: "divide-y divide-zinc-100 dark:divide-zinc-800 rounded-xl border border-zinc-100 dark:border-zinc-800 overflow-hidden text-sm", children: specs.map((s, i) => (_jsxs("div", { className: "flex gap-4 px-4 py-3 bg-white dark:bg-zinc-900 even:bg-zinc-50 dark:even:bg-zinc-800/50", children: [_jsx("dt", { className: "w-36 flex-shrink-0 font-medium text-zinc-700 dark:text-zinc-300", children: s.name }), _jsxs("dd", { className: "flex-1 text-zinc-600 dark:text-zinc-400", children: [s.value, s.unit ? ` ${s.unit}` : ""] })] }, i))) })) : undefined, customTabs: customSections.map((s) => ({
113
117
  id: s.id,
114
118
  label: s.title,
115
119
  content: _jsx(CustomSectionTabContent, { section: s }),
@@ -7,8 +7,10 @@ export interface AuctionDetailViewProps extends Omit<DetailViewShellProps, "main
7
7
  renderBidForm?: () => React.ReactNode;
8
8
  /** Mobile bid form shown below the grid on small screens */
9
9
  renderMobileBidForm?: () => React.ReactNode;
10
+ /** Rendered between the main grid and the below-fold tabs (e.g. sub-listing carousel). */
11
+ renderSublistingSection?: () => React.ReactNode;
10
12
  renderTabs?: () => React.ReactNode;
11
13
  renderBidHistory?: () => React.ReactNode;
12
14
  renderRelated?: () => React.ReactNode;
13
15
  }
14
- export declare function AuctionDetailView({ renderGallery, renderInfo, renderBidForm, renderMobileBidForm, renderTabs, renderBidHistory, renderRelated, isLoading, ...rest }: AuctionDetailViewProps): import("react/jsx-runtime").JSX.Element;
16
+ export declare function AuctionDetailView({ renderGallery, renderInfo, renderBidForm, renderMobileBidForm, renderSublistingSection, renderTabs, renderBidHistory, renderRelated, isLoading, ...rest }: AuctionDetailViewProps): import("react/jsx-runtime").JSX.Element;
@@ -1,9 +1,12 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
1
+ import { Fragment as _Fragment, jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
2
  import { DetailViewShell, Div } from "../../../ui";
3
- export function AuctionDetailView({ renderGallery, renderInfo, renderBidForm, renderMobileBidForm, renderTabs, renderBidHistory, renderRelated, isLoading = false, ...rest }) {
3
+ export function AuctionDetailView({ renderGallery, renderInfo, renderBidForm, renderMobileBidForm, renderSublistingSection, renderTabs, renderBidHistory, renderRelated, isLoading = false, ...rest }) {
4
+ const mobileBid = renderMobileBidForm?.();
5
+ const sublistingSection = renderSublistingSection?.();
6
+ const afterMainContent = (mobileBid || sublistingSection) ? (_jsxs(_Fragment, { children: [mobileBid, sublistingSection] })) : undefined;
4
7
  return (_jsx(DetailViewShell, { portal: "public", ...rest, layout: "grid-3", isLoading: isLoading, mainSlots: [
5
8
  renderGallery?.(isLoading),
6
9
  renderInfo?.(isLoading),
7
10
  _jsx(Div, { className: "hidden lg:block", children: renderBidForm?.() }, "bid"),
8
- ], afterMain: renderMobileBidForm?.(), belowFold: [renderTabs?.(), renderBidHistory?.(), renderRelated?.()] }));
11
+ ], afterMain: afterMainContent, belowFold: [renderTabs?.(), renderBidHistory?.(), renderRelated?.()] }));
9
12
  }
@@ -4,11 +4,13 @@ import type { DetailViewShellProps } from "../../../ui";
4
4
  * PreOrderDetailView — shell for pre-order product detail pages.
5
5
  * Uses grid-2 layout (gallery | info+buyBar).
6
6
  */
7
- export interface PreOrderDetailViewProps extends Omit<DetailViewShellProps, "mainSlots" | "belowFold" | "layout"> {
7
+ export interface PreOrderDetailViewProps extends Omit<DetailViewShellProps, "mainSlots" | "belowFold" | "layout" | "afterMain"> {
8
8
  renderGallery?: (isLoading: boolean) => React.ReactNode;
9
9
  renderInfo?: (isLoading: boolean) => React.ReactNode;
10
10
  renderBuyBar?: () => React.ReactNode;
11
+ /** Rendered between the main grid and the below-fold tabs (e.g. sub-listing carousel). */
12
+ renderSublistingSection?: () => React.ReactNode;
11
13
  renderTabs?: () => React.ReactNode;
12
14
  renderRelated?: () => React.ReactNode;
13
15
  }
14
- export declare function PreOrderDetailView({ renderGallery, renderInfo, renderBuyBar, renderTabs, renderRelated, isLoading, ...rest }: PreOrderDetailViewProps): import("react/jsx-runtime").JSX.Element;
16
+ export declare function PreOrderDetailView({ renderGallery, renderInfo, renderBuyBar, renderSublistingSection, renderTabs, renderRelated, isLoading, ...rest }: PreOrderDetailViewProps): import("react/jsx-runtime").JSX.Element;
@@ -1,9 +1,9 @@
1
1
  import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
2
  import React from "react";
3
3
  import { DetailViewShell } from "../../../ui";
4
- export function PreOrderDetailView({ renderGallery, renderInfo, renderBuyBar, renderTabs, renderRelated, isLoading = false, ...rest }) {
4
+ export function PreOrderDetailView({ renderGallery, renderInfo, renderBuyBar, renderSublistingSection, renderTabs, renderRelated, isLoading = false, ...rest }) {
5
5
  return (_jsx(DetailViewShell, { portal: "public", ...rest, layout: "grid-2", isLoading: isLoading, mainSlots: [
6
6
  renderGallery?.(isLoading),
7
7
  _jsxs(React.Fragment, { children: [renderInfo?.(isLoading), renderBuyBar?.()] }, "info"),
8
- ], belowFold: [renderTabs?.(), renderRelated?.()] }));
8
+ ], afterMain: renderSublistingSection?.(), belowFold: [renderTabs?.(), renderRelated?.()] }));
9
9
  }
@@ -16,6 +16,7 @@ import { RelatedProductsCarousel } from "./RelatedProductsCarousel";
16
16
  import { BuyBar } from "./BuyBar";
17
17
  import { ShareButton } from "./ShareButton";
18
18
  import { CustomSectionTabContent } from "./CustomSectionTabContent";
19
+ import { SublistingCarouselSection } from "./SublistingCarouselSection";
19
20
  // ---------------------------------------------------------------------------
20
21
  // Helpers
21
22
  // ---------------------------------------------------------------------------
@@ -155,6 +156,7 @@ export async function ProductDetailPageView({ slug, renderOfferAction, }) {
155
156
  ? String(ROUTES.PUBLIC.SELLER_DETAIL(sellerId))
156
157
  : null;
157
158
  const descriptionHtml = toDescriptionHtml(p.description);
159
+ const sublistingCategoryId = typeof p.sublistingCategoryId === "string" ? p.sublistingCategoryId : null;
158
160
  // -- Fetch reviews + related in parallel ------------------------------------
159
161
  const [reviewDocs, relatedDocs] = await Promise.all([
160
162
  reviewRepository
@@ -210,7 +212,9 @@ export async function ProductDetailPageView({ slug, renderOfferAction, }) {
210
212
  { icon: "🔒", label: "Secure\nPayment" },
211
213
  { icon: "✓", label: "Verified\nSeller" },
212
214
  { icon: "⭐", label: "Quality\nGuarantee" },
213
- ].map(({ icon, label }) => (_jsxs(Div, { className: "flex flex-col items-center gap-1 text-xs text-zinc-500 dark:text-zinc-400 min-w-[60px]", children: [_jsx(Span, { className: "text-base", children: icon }), _jsx(Span, { className: "whitespace-pre-line leading-tight", children: label })] }, label))) }) })] })), renderTabs: () => (_jsx(ProductTabsShell, { descriptionContent: descriptionHtml ? (_jsx(RichText, { html: descriptionHtml, proseClass: "prose prose-sm sm:prose max-w-none dark:prose-invert", className: "text-zinc-700 dark:text-zinc-300" })) : undefined, specsContent: specs.length > 0 ? (_jsx("dl", { className: "divide-y divide-zinc-100 dark:divide-zinc-800 rounded-xl border border-zinc-100 dark:border-zinc-800 overflow-hidden text-sm", children: specs.map((s, i) => (_jsxs("div", { className: "flex gap-4 px-4 py-3 bg-white dark:bg-zinc-900 even:bg-zinc-50 dark:even:bg-zinc-800/50", children: [_jsx("dt", { className: "w-36 flex-shrink-0 font-medium text-zinc-700 dark:text-zinc-300", children: s.name }), _jsxs("dd", { className: "flex-1 text-zinc-600 dark:text-zinc-400", children: [s.value, s.unit ? ` ${s.unit}` : ""] })] }, i))) })) : undefined, ingredientsContent: ingredients.length > 0 ? (_jsx("ul", { className: "space-y-2", children: ingredients.map((item, i) => (_jsxs("li", { className: "flex items-start gap-2 text-sm text-zinc-700 dark:text-zinc-300", children: [_jsx(Span, { className: "mt-1 flex-shrink-0 h-1.5 w-1.5 rounded-full bg-primary-400" }), item] }, i))) })) : undefined, howToUseContent: howToUse.length > 0 ? (_jsx("ol", { className: "space-y-3", children: howToUse.map((step, i) => (_jsxs("li", { className: "flex items-start gap-3 text-sm text-zinc-700 dark:text-zinc-300", children: [_jsx(Span, { className: "flex-shrink-0 flex h-6 w-6 items-center justify-center rounded-full bg-primary-100 dark:bg-primary-900/30 text-xs font-bold text-primary-700 dark:text-primary-300", children: i + 1 }), step] }, i))) })) : undefined, reviewsContent: _jsx(ReviewsList, { reviews: reviews, emptyLabel: "No reviews yet \u2014 be the first to review this product." }), customTabs: customSections.map((s) => ({
215
+ ].map(({ icon, label }) => (_jsxs(Div, { className: "flex flex-col items-center gap-1 text-xs text-zinc-500 dark:text-zinc-400 min-w-[60px]", children: [_jsx(Span, { className: "text-base", children: icon }), _jsx(Span, { className: "whitespace-pre-line leading-tight", children: label })] }, label))) }) })] })), renderSublistingSection: sublistingCategoryId
216
+ ? () => (_jsx(SublistingCarouselSection, { sublistingCategoryId: sublistingCategoryId, currentListingId: String(product.id) }))
217
+ : undefined, renderTabs: () => (_jsx(ProductTabsShell, { descriptionContent: descriptionHtml ? (_jsx(RichText, { html: descriptionHtml, proseClass: "prose prose-sm sm:prose max-w-none dark:prose-invert", className: "text-zinc-700 dark:text-zinc-300" })) : undefined, specsContent: specs.length > 0 ? (_jsx("dl", { className: "divide-y divide-zinc-100 dark:divide-zinc-800 rounded-xl border border-zinc-100 dark:border-zinc-800 overflow-hidden text-sm", children: specs.map((s, i) => (_jsxs("div", { className: "flex gap-4 px-4 py-3 bg-white dark:bg-zinc-900 even:bg-zinc-50 dark:even:bg-zinc-800/50", children: [_jsx("dt", { className: "w-36 flex-shrink-0 font-medium text-zinc-700 dark:text-zinc-300", children: s.name }), _jsxs("dd", { className: "flex-1 text-zinc-600 dark:text-zinc-400", children: [s.value, s.unit ? ` ${s.unit}` : ""] })] }, i))) })) : undefined, ingredientsContent: ingredients.length > 0 ? (_jsx("ul", { className: "space-y-2", children: ingredients.map((item, i) => (_jsxs("li", { className: "flex items-start gap-2 text-sm text-zinc-700 dark:text-zinc-300", children: [_jsx(Span, { className: "mt-1 flex-shrink-0 h-1.5 w-1.5 rounded-full bg-primary-400" }), item] }, i))) })) : undefined, howToUseContent: howToUse.length > 0 ? (_jsx("ol", { className: "space-y-3", children: howToUse.map((step, i) => (_jsxs("li", { className: "flex items-start gap-3 text-sm text-zinc-700 dark:text-zinc-300", children: [_jsx(Span, { className: "flex-shrink-0 flex h-6 w-6 items-center justify-center rounded-full bg-primary-100 dark:bg-primary-900/30 text-xs font-bold text-primary-700 dark:text-primary-300", children: i + 1 }), step] }, i))) })) : undefined, reviewsContent: _jsx(ReviewsList, { reviews: reviews, emptyLabel: "No reviews yet \u2014 be the first to review this product." }), customTabs: customSections.map((s) => ({
214
218
  id: s.id,
215
219
  label: s.title,
216
220
  content: _jsx(CustomSectionTabContent, { section: s }),
@@ -1,6 +1,6 @@
1
1
  import React from "react";
2
2
  import type { DetailViewShellProps } from "../../../ui";
3
- export interface ProductDetailViewProps extends Omit<DetailViewShellProps, "mainSlots" | "belowFold" | "layout"> {
3
+ export interface ProductDetailViewProps extends Omit<DetailViewShellProps, "mainSlots" | "belowFold" | "layout" | "afterMain"> {
4
4
  renderGallery?: (isLoading: boolean) => React.ReactNode;
5
5
  renderInfo?: (isLoading: boolean) => React.ReactNode;
6
6
  /**
@@ -8,6 +8,8 @@ export interface ProductDetailViewProps extends Omit<DetailViewShellProps, "main
8
8
  * `useBottomActions` in the consumer to also register mobile bottom actions.
9
9
  */
10
10
  renderActions?: () => React.ReactNode;
11
+ /** Rendered between the main grid and the below-fold tabs (e.g. sub-listing carousel). */
12
+ renderSublistingSection?: () => React.ReactNode;
11
13
  renderTabs?: () => React.ReactNode;
12
14
  renderRelated?: () => React.ReactNode;
13
15
  /**
@@ -21,4 +23,4 @@ export interface ProductDetailViewProps extends Omit<DetailViewShellProps, "main
21
23
  */
22
24
  stickyRailOffset?: string;
23
25
  }
24
- export declare function ProductDetailView({ renderGallery, renderInfo, renderActions, renderTabs, renderRelated, isLoading, stickyActionRail, stickyRailOffset, ...rest }: ProductDetailViewProps): import("react/jsx-runtime").JSX.Element;
26
+ export declare function ProductDetailView({ renderGallery, renderInfo, renderActions, renderSublistingSection, renderTabs, renderRelated, isLoading, stickyActionRail, stickyRailOffset, ...rest }: ProductDetailViewProps): import("react/jsx-runtime").JSX.Element;
@@ -1,9 +1,9 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { DetailViewShell } from "../../../ui";
3
- export function ProductDetailView({ renderGallery, renderInfo, renderActions, renderTabs, renderRelated, isLoading = false, stickyActionRail = true, stickyRailOffset = "top-20", ...rest }) {
3
+ export function ProductDetailView({ renderGallery, renderInfo, renderActions, renderSublistingSection, renderTabs, renderRelated, isLoading = false, stickyActionRail = true, stickyRailOffset = "top-20", ...rest }) {
4
4
  return (_jsx(DetailViewShell, { portal: "public", ...rest, layout: "grid-3", isLoading: isLoading, stickyActionRail: stickyActionRail, stickyRailOffset: stickyRailOffset, mainSlots: [
5
5
  renderGallery?.(isLoading),
6
6
  renderInfo?.(isLoading),
7
7
  renderActions?.(),
8
- ], belowFold: [renderTabs?.(), renderRelated?.()] }));
8
+ ], afterMain: renderSublistingSection?.(), belowFold: [renderTabs?.(), renderRelated?.()] }));
9
9
  }
@@ -44,3 +44,5 @@ export { CustomSectionsEditor } from "./CustomSectionsEditor";
44
44
  export type { CustomSectionsEditorProps } from "./CustomSectionsEditor";
45
45
  export { CustomSectionTabContent } from "./CustomSectionTabContent";
46
46
  export { RelatedProductsCarousel } from "./RelatedProductsCarousel";
47
+ export { SublistingCategorySelect } from "./SublistingCategorySelect";
48
+ export { SublistingCarouselSection } from "./SublistingCarouselSection";
@@ -23,3 +23,5 @@ export { CustomFieldsEditor } from "./CustomFieldsEditor";
23
23
  export { CustomSectionsEditor } from "./CustomSectionsEditor";
24
24
  export { CustomSectionTabContent } from "./CustomSectionTabContent";
25
25
  export { RelatedProductsCarousel } from "./RelatedProductsCarousel";
26
+ export { SublistingCategorySelect } from "./SublistingCategorySelect";
27
+ export { SublistingCarouselSection } from "./SublistingCarouselSection";
@@ -134,6 +134,9 @@ export declare const DEFAULT_ROUTE_MAP: {
134
134
  readonly WHATSAPP: "/store/whatsapp";
135
135
  readonly REVIEWS: "/store/reviews";
136
136
  readonly BIDS: "/store/bids";
137
+ readonly SUBLISTING_CATEGORIES: "/store/sublisting-categories";
138
+ readonly SUBLISTING_CATEGORIES_NEW: "/store/sublisting-categories/new";
139
+ readonly SUBLISTING_CATEGORIES_EDIT: (id: string) => string;
137
140
  };
138
141
  readonly ADMIN: {
139
142
  readonly DASHBOARD: "/admin/dashboard";
@@ -326,6 +329,9 @@ export declare const ROUTES: {
326
329
  readonly WHATSAPP: "/store/whatsapp";
327
330
  readonly REVIEWS: "/store/reviews";
328
331
  readonly BIDS: "/store/bids";
332
+ readonly SUBLISTING_CATEGORIES: "/store/sublisting-categories";
333
+ readonly SUBLISTING_CATEGORIES_NEW: "/store/sublisting-categories/new";
334
+ readonly SUBLISTING_CATEGORIES_EDIT: (id: string) => string;
329
335
  };
330
336
  readonly ADMIN: {
331
337
  readonly DASHBOARD: "/admin/dashboard";
@@ -424,6 +430,9 @@ export declare const SELLER_ROUTES: {
424
430
  readonly WHATSAPP: "/store/whatsapp";
425
431
  readonly REVIEWS: "/store/reviews";
426
432
  readonly BIDS: "/store/bids";
433
+ readonly SUBLISTING_CATEGORIES: "/store/sublisting-categories";
434
+ readonly SUBLISTING_CATEGORIES_NEW: "/store/sublisting-categories/new";
435
+ readonly SUBLISTING_CATEGORIES_EDIT: (id: string) => string;
427
436
  };
428
437
  export declare const PUBLIC_ROUTES: readonly ["/", string, string, string, string, string, string, string, string, string, string, string, string, string, string, string, "/unauthorized", "/auth/login", "/auth/register", "/auth/forgot-password", "/auth/reset-password", "/auth/verify-email"];
429
438
  export declare const PROTECTED_ROUTES: readonly [string, string, string, string, string, string, string];
@@ -121,6 +121,9 @@ export const DEFAULT_ROUTE_MAP = {
121
121
  WHATSAPP: "/store/whatsapp",
122
122
  REVIEWS: "/store/reviews",
123
123
  BIDS: "/store/bids",
124
+ SUBLISTING_CATEGORIES: "/store/sublisting-categories",
125
+ SUBLISTING_CATEGORIES_NEW: "/store/sublisting-categories/new",
126
+ SUBLISTING_CATEGORIES_EDIT: (id) => `/store/sublisting-categories/${id}/edit`,
124
127
  },
125
128
  ADMIN: {
126
129
  DASHBOARD: "/admin/dashboard",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mohasinac/appkit",
3
- "version": "2.4.5",
3
+ "version": "2.4.6",
4
4
  "license": "MIT",
5
5
  "publishConfig": {
6
6
  "access": "public"