@mohasinac/appkit 4.3.0 → 4.3.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.
Files changed (41) hide show
  1. package/dist/_internal/client/features/layout/navActive.d.ts +17 -0
  2. package/dist/_internal/client/features/layout/navActive.js +33 -0
  3. package/dist/_internal/server/features/products/service.d.ts +1 -1
  4. package/dist/_internal/server/features/products/service.js +3 -3
  5. package/dist/_internal/server/jobs/core/prizeDrawExpiryReveal.js +1 -1
  6. package/dist/_internal/server/jobs/core/prizeDrawSoldOutReveal.js +1 -1
  7. package/dist/features/account/components/UserSidebar.js +21 -9
  8. package/dist/features/admin/components/AdminGuideHubView.js +15 -1
  9. package/dist/features/admin/components/AdminPaymentsGuideView.d.ts +2 -0
  10. package/dist/features/admin/components/AdminPaymentsGuideView.js +36 -0
  11. package/dist/features/admin/components/AdminSidebar.js +18 -9
  12. package/dist/features/admin/components/AdminWhatsAppGuideView.d.ts +2 -0
  13. package/dist/features/admin/components/AdminWhatsAppGuideView.js +35 -0
  14. package/dist/features/auctions/components/CollapsibleBidHistory.d.ts +10 -10
  15. package/dist/features/auctions/components/CollapsibleBidHistory.js +3 -2
  16. package/dist/features/events/components/EventCard.js +2 -2
  17. package/dist/features/homepage/components/SectionCarousel.js +1 -1
  18. package/dist/features/layout/AppLayoutShell.js +43 -9
  19. package/dist/features/pre-orders/components/MarketplacePreorderCard.js +1 -1
  20. package/dist/features/products/components/MarketplaceBundleCard.js +1 -1
  21. package/dist/features/products/components/ProductGalleryClient.js +2 -2
  22. package/dist/features/products/constants/action-defs.d.ts +1 -2
  23. package/dist/features/products/constants/action-defs.js +0 -3
  24. package/dist/features/products/schemas/firestore.d.ts +4 -3
  25. package/dist/features/seller/components/SellerSidebar.js +20 -9
  26. package/dist/features/stores/components/StoreGuideHubView.js +7 -1
  27. package/dist/features/stores/components/StoreNavTabs.js +4 -3
  28. package/dist/features/stores/components/StoreWhatsAppGuideView.d.ts +3 -0
  29. package/dist/features/stores/components/StoreWhatsAppGuideView.js +12 -0
  30. package/dist/features/stores/components/index.d.ts +2 -0
  31. package/dist/features/stores/components/index.js +1 -0
  32. package/dist/features/tester/seed-data/products-tester-seed-data.js +4 -3
  33. package/dist/features/tester/seed-data/tester-checklist-seed-data.js +8 -6
  34. package/dist/index.d.ts +4 -0
  35. package/dist/index.js +6 -0
  36. package/dist/next/routing/route-map.d.ts +7 -2
  37. package/dist/next/routing/route-map.js +3 -1
  38. package/dist/seed/products-standard-seed-data.js +2 -4
  39. package/dist/styles.css +1 -1
  40. package/dist/tailwind-utilities.css +1 -1
  41. package/package.json +1 -1
@@ -64,5 +64,5 @@ export function MarketplacePreorderCard({ product, className = "", variant = "gr
64
64
  /* ── Compact list layout ── */
65
65
  _jsxs(_Fragment, { children: [_jsxs(Row, { className: "min-w-0", align: "start", justify: "between", gap: "sm", children: [_jsx(TextLink, { href: detailHref, className: "min-w-0 flex-1", children: _jsx(Text, { size: "sm", weight: "medium", color: "primary", truncate: 2, children: product.title }) }), wishlistActions && (_jsx(Button, { type: "button", variant: "ghost", size: "sm", className: `shrink-0 p-[0.25rem] leading-none ${inWishlist ? "text-primary" : "text-[var(--appkit-color-text-faint)]"}`, onClick: handleWishlist, "aria-label": inWishlist ? mergedLabels.removeFromWishlist : mergedLabels.addToWishlist, children: inWishlist ? "♥" : "♡" }))] }), _jsxs(Row, { align: "center", gap: "sm", wrap: true, children: [_jsx(Text, { className: "text-primary", size: "sm", weight: "bold", children: formatCurrency(product.price, getDefaultCurrency()) }), shipDate && _jsx(PreorderBadge, { shipDate: shipDate })] }), _jsx(Button, { type: "button", variant: "primary", size: "sm", textSize: "xs", className: "self-start mt-0.5", onClick: handleNavigate, children: mergedLabels.reserveNow })] })) : (
66
66
  /* ── Full grid layout ── */
67
- _jsxs(_Fragment, { children: [_jsx(TextLink, { href: detailHref, children: _jsx(Text, { size: "sm", weight: "medium", color: "primary", truncate: 2, children: product.title }) }), product.description ? (_jsx(RichText, { html: normalizeRichTextHtml(product.description), proseClass: "prose prose-sm max-w-none dark:prose-invert prose-p:my-0", className: "line-clamp-2 text-[length:var(--appkit-text-xs)] text-[var(--appkit-color-text-muted)]" })) : null, _jsxs(Row, { justify: "between", className: "mt-1", gap: "sm", children: [_jsx(Text, { size: "sm", weight: "semibold", color: "primary", children: formatCurrency(product.price, getDefaultCurrency()) }), shipDate && _jsx(PreorderBadge, { shipDate: shipDate })] }), _jsxs(Row, { justify: "between", className: "mt-auto pt-2", gap: "sm", children: [_jsx(Button, { type: "button", variant: "primary", size: "sm", textSize: "xs", className: "flex-1", onClick: handleNavigate, children: mergedLabels.reserveNow }), onAddToCart ? (_jsx(Button, { type: "button", variant: "outline", size: "sm", textSize: "xs", className: "flex-1", onClick: (e) => { e.stopPropagation(); onAddToCart(product); }, children: mergedLabels.addToCart })) : null, wishlistActions ? (_jsx(Button, { type: "button", variant: "ghost", size: "sm", className: `${inWishlist ? "text-primary" : "text-[var(--appkit-color-text-muted)]"}`, onClick: handleWishlist, "aria-label": inWishlist ? mergedLabels.removeFromWishlist : mergedLabels.addToWishlist, children: inWishlist ? "♥" : "♡" })) : null] })] })) })] }));
67
+ _jsxs(_Fragment, { children: [_jsx(TextLink, { href: detailHref, children: _jsx(Text, { size: "sm", weight: "medium", color: "primary", truncate: 2, children: product.title }) }), product.description ? (_jsx(RichText, { html: normalizeRichTextHtml(product.description), proseClass: "prose prose-sm max-w-none dark:prose-invert prose-p:my-0", className: "line-clamp-2 text-[length:var(--appkit-text-xs)] text-[var(--appkit-color-text-muted)]" })) : null, _jsxs(Row, { justify: "between", className: "mt-1", gap: "sm", children: [_jsx(Text, { size: "sm", weight: "semibold", color: "primary", children: formatCurrency(product.price, getDefaultCurrency()) }), shipDate && _jsx(PreorderBadge, { shipDate: shipDate })] }), _jsxs(Row, { justify: "between", className: "mt-auto pt-[var(--appkit-space-2)]", gap: "sm", children: [_jsx(Button, { type: "button", variant: "primary", size: "sm", textSize: "xs", className: "flex-1", onClick: handleNavigate, children: mergedLabels.reserveNow }), onAddToCart ? (_jsx(Button, { type: "button", variant: "outline", size: "sm", textSize: "xs", className: "flex-1", onClick: (e) => { e.stopPropagation(); onAddToCart(product); }, children: mergedLabels.addToCart })) : null, wishlistActions ? (_jsx(Button, { type: "button", variant: "ghost", size: "sm", className: `${inWishlist ? "text-primary" : "text-[var(--appkit-color-text-muted)]"}`, onClick: handleWishlist, "aria-label": inWishlist ? mergedLabels.removeFromWishlist : mergedLabels.addToWishlist, children: inWishlist ? "♥" : "♡" })) : null] })] })) })] }));
68
68
  }
@@ -49,7 +49,7 @@ export function MarketplaceBundleCard({ bundle, className = "", variant = "grid"
49
49
  }
50
50
  router.push(String(detailHref));
51
51
  }, [detailHref, onNavigate, router]);
52
- return (_jsxs(BaseListingCard, { isSelected: isSelected, variant: variant, className: className, onMouseDown: !isSelected ? longPress.onMouseDown : undefined, onMouseUp: !isSelected ? longPress.onMouseUp : undefined, onMouseLeave: !isSelected ? longPress.onMouseLeave : undefined, onTouchStart: !isSelected ? longPress.onTouchStart : undefined, onTouchEnd: !isSelected ? longPress.onTouchEnd : undefined, onTouchCancel: !isSelected ? longPress.onTouchCancel : undefined, children: [_jsxs(BaseListingCard.Hero, { aspect: "square", variant: variant, children: [_jsx(TextLink, { href: String(detailHref), className: "absolute inset-0 block", children: showCollage ? (_jsx(Div, { layout: "grid", className: `h-full w-full gap-[0.125rem] bg-[var(--appkit-color-surface-muted)] ${collageTiles.length === 2 ? "grid-cols-2 grid-rows-1" : "grid-cols-2 grid-rows-2"}`, children: collageTiles.map((tile, i) => (_jsxs(Div, { className: "relative overflow-hidden bg-[var(--appkit-color-surface-muted)]", children: [_jsx(MediaImage, { src: tile.imageURL, alt: tile.title ?? `${bundle.name} item ${i + 1}`, size: "card" }), i === collageTiles.length - 1 && overflow > 0 && (_jsxs(Row, { textWeight: "semibold", textSize: "sm", surface: "overlay-md", className: "absolute inset-0 text-white", align: "center", justify: "center", children: ["+", overflow] }))] }, `${tile.productId}-${i}`))) })) : cover ? (_jsx(Div, { className: "absolute inset-0 bg-[var(--appkit-color-surface-muted)]", children: _jsx(MediaImage, { src: cover, alt: bundle.name, size: "card" }) })) : (_jsx(Row, { className: "absolute inset-0 bg-[var(--appkit-color-surface-muted)]", align: "center", justify: "center", children: _jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", size: "xs", children: "No image" }) })) }), discount && (_jsx(Span, { size: "xs", weight: "bold", color: "inverse", className: "absolute left-2 top-2 bg-success-surface", rounded: "full", padding: "pill-xs", children: BUNDLE_COPY.detail.discountBadge(discount.percent) })), _jsxs(Stack, { className: "absolute right-2 top-2", align: "end", gap: "xs", children: [_jsx(Span, { size: "xs", weight: "medium", className: CLS_BUNDLE_PILL, children: mergedLabels.bundleBadge }), _jsx(Span, { layout: "inline-flex", color: "inverse", className: `${stock === "out_of_stock" ? "bg-neutral-500 " : CLS_STOCK_OK}`, rounded: "full", padding: "pill-xs", size: "xs", weight: "medium", children: stock === "out_of_stock" ? mergedLabels.outOfStockBadge : mergedLabels.inStockBadge })] }), stock === "out_of_stock" && (_jsx(Row, { surface: "overlay-xs", className: "absolute inset-0", align: "center", justify: "center", children: _jsx(Span, { color: "inverse", size: "xs", weight: "bold", className: "bg-neutral-900/80 tracking-wider", rounded: "default", padding: "pill-md", transform: "uppercase", children: mergedLabels.outOfStockBadge }) })), onSelect && (_jsx(BaseListingCard.Checkbox, { selected: isSelected, onSelect: (event) => {
52
+ return (_jsxs(BaseListingCard, { isSelected: isSelected, variant: variant, className: className, onMouseDown: !isSelected ? longPress.onMouseDown : undefined, onMouseUp: !isSelected ? longPress.onMouseUp : undefined, onMouseLeave: !isSelected ? longPress.onMouseLeave : undefined, onTouchStart: !isSelected ? longPress.onTouchStart : undefined, onTouchEnd: !isSelected ? longPress.onTouchEnd : undefined, onTouchCancel: !isSelected ? longPress.onTouchCancel : undefined, children: [_jsxs(BaseListingCard.Hero, { aspect: "square", variant: variant, children: [_jsx(TextLink, { href: String(detailHref), className: "absolute inset-0 block", children: showCollage ? (_jsx(Div, { layout: "grid", className: `h-full w-full gap-[0.125rem] bg-[var(--appkit-color-surface-muted)] ${collageTiles.length === 2 ? "grid-cols-2 grid-rows-1" : "grid-cols-2 grid-rows-2"}`, children: collageTiles.map((tile, i) => (_jsxs(Div, { className: "relative overflow-hidden bg-[var(--appkit-color-surface-muted)]", children: [_jsx(MediaImage, { src: tile.imageURL, alt: tile.title ?? `${bundle.name} item ${i + 1}`, size: "card" }), i === collageTiles.length - 1 && overflow > 0 && (_jsxs(Row, { textWeight: "semibold", textSize: "sm", surface: "overlay-md", className: "absolute inset-0 text-white", align: "center", justify: "center", children: ["+", overflow] }))] }, `${tile.productId}-${i}`))) })) : cover ? (_jsx(Div, { className: "absolute inset-0 bg-[var(--appkit-color-surface-muted)]", children: _jsx(MediaImage, { src: cover, alt: bundle.name, size: "card" }) })) : (_jsx(Row, { className: "absolute inset-0 bg-[var(--appkit-color-surface-muted)]", align: "center", justify: "center", children: _jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", size: "xs", children: "No image" }) })) }), discount && (_jsx(Span, { size: "xs", weight: "bold", color: "inverse", surface: "success-surface", className: "absolute left-2 top-2", rounded: "full", padding: "pill-xs", children: BUNDLE_COPY.detail.discountBadge(discount.percent) })), _jsxs(Stack, { className: "absolute right-2 top-2", align: "end", gap: "xs", children: [_jsx(Span, { size: "xs", weight: "medium", className: CLS_BUNDLE_PILL, children: mergedLabels.bundleBadge }), _jsx(Span, { layout: "inline-flex", color: "inverse", className: `${stock === "out_of_stock" ? "bg-neutral-500 " : CLS_STOCK_OK}`, rounded: "full", padding: "pill-xs", size: "xs", weight: "medium", children: stock === "out_of_stock" ? mergedLabels.outOfStockBadge : mergedLabels.inStockBadge })] }), stock === "out_of_stock" && (_jsx(Row, { surface: "overlay-xs", className: "absolute inset-0", align: "center", justify: "center", children: _jsx(Span, { color: "inverse", size: "xs", weight: "bold", className: "bg-neutral-900/80 tracking-wider", rounded: "default", padding: "pill-md", transform: "uppercase", children: mergedLabels.outOfStockBadge }) })), onSelect && (_jsx(BaseListingCard.Checkbox, { selected: isSelected, onSelect: (event) => {
53
53
  event.stopPropagation();
54
54
  onSelect(bundle.id, !isSelected);
55
55
  }, className: selectable || isSelected
@@ -42,9 +42,9 @@ export function ProductGalleryClient({ images, video, productName }) {
42
42
  : "Product video"
43
43
  : productName
44
44
  ? `${productName} — image ${activeIndex + 1}`
45
- : `Product image ${activeIndex + 1}`, size: "gallery", className: "transition-transform duration-300 hover:scale-105" }), activeSlide.kind === "video" && (_jsx(Row, { className: "absolute inset-0 pointer-events-none", align: "center", justify: "center", children: _jsx(Row, { className: "h-16 w-16 rounded-full bg-black/50 text-white", align: "center", justify: "center", children: _jsx(Play, { className: "h-7 w-7 fill-current", "aria-hidden": "true" }) }) }))] }), slides.length > 1 && (_jsx(Div, { layout: "flex", gap: "2", className: `${__O.xAuto}`, padding: "b-2xs", children: slides.map((slide, i) => (_jsxs(Button, { variant: "ghost", type: "button", onClick: () => setActiveIndex(i), rounded: "lg", paddingX: "none", paddingY: "none", className: `relative flex-shrink-0 h-16 w-16 overflow-hidden border-2 transition-all${i === activeIndex
45
+ : `Product image ${activeIndex + 1}`, size: "gallery", className: "transition-transform duration-300 hover:scale-105" }), activeSlide.kind === "video" && (_jsx(Row, { className: "absolute inset-0 pointer-events-none", align: "center", justify: "center", children: _jsx(Row, { surface: "overlay-sm", rounded: "full", className: "h-16 w-16 text-white", align: "center", justify: "center", children: _jsx(Play, { className: "h-7 w-7 fill-current", "aria-hidden": "true" }) }) }))] }), slides.length > 1 && (_jsx(Div, { layout: "flex", gap: "2", className: `${__O.xAuto}`, padding: "b-2xs", children: slides.map((slide, i) => (_jsxs(Button, { variant: "ghost", type: "button", onClick: () => setActiveIndex(i), rounded: "lg", paddingX: "none", paddingY: "none", className: `relative flex-shrink-0 h-16 w-16 overflow-hidden border-2 transition-all${i === activeIndex
46
46
  ? " border-primary-500"
47
- : " border-transparent opacity-60 hover:opacity-100"}`, "aria-label": slide.kind === "video" ? "View video" : `View image ${i + 1}`, "aria-current": i === activeIndex ? "true" : undefined, children: [_jsx(MediaImage, { src: slide.kind === "video" ? slide.poster : slide.src, alt: slide.kind === "video" ? "Video thumbnail" : `Thumbnail ${i + 1}`, size: "thumbnail" }), slide.kind === "video" && (_jsx(Row, { className: "absolute inset-0 pointer-events-none bg-black/25", align: "center", justify: "center", children: _jsx(Play, { className: "h-5 w-5 text-white fill-current", "aria-hidden": "true" }) }))] }, i))) })), slides.length > 1 && (
47
+ : " border-transparent opacity-60 hover:opacity-100"}`, "aria-label": slide.kind === "video" ? "View video" : `View image ${i + 1}`, "aria-current": i === activeIndex ? "true" : undefined, children: [_jsx(MediaImage, { src: slide.kind === "video" ? slide.poster : slide.src, alt: slide.kind === "video" ? "Video thumbnail" : `Thumbnail ${i + 1}`, size: "thumbnail" }), slide.kind === "video" && (_jsx(Row, { surface: "overlay-xs", className: "absolute inset-0 pointer-events-none", align: "center", justify: "center", children: _jsx(Play, { className: "h-5 w-5 text-white fill-current", "aria-hidden": "true" }) }))] }, i))) })), slides.length > 1 && (
48
48
  // audit-content-alignment-ok: functional image-counter label under the gallery, not page content
49
49
  _jsxs(Text, { size: "xs", align: "center", color: "faint", children: [activeIndex + 1, " / ", slides.length] })), _jsx(ImageLightbox, { images: lightboxImages, activeIndex: lightboxIndex, onClose: () => setLightboxIndex(null), onNavigate: (i) => setLightboxIndex(i) })] }));
50
50
  }
@@ -286,7 +286,6 @@ export declare const DASHBOARD_QUICK_ACTION_ID: {
286
286
  readonly ADMIN_EVENTS: "dqa-admin-events";
287
287
  readonly ADMIN_SUPPORT: "dqa-admin-support";
288
288
  readonly ADMIN_MODERATION: "dqa-admin-moderation";
289
- readonly ADMIN_INTEGRATION_GUIDES: "dqa-admin-integration-guides";
290
289
  readonly ADMIN_USERS: "dqa-admin-users";
291
290
  readonly ADMIN_CATEGORIES: "dqa-admin-categories";
292
291
  readonly ADMIN_REVIEWS: "dqa-admin-reviews";
@@ -333,7 +332,7 @@ export interface DashboardQuickActionMeta {
333
332
  }
334
333
  export declare const DASHBOARD_QUICK_ACTION_META: Record<DashboardQuickActionId, DashboardQuickActionMeta>;
335
334
  export declare const DASHBOARD_QUICK_ACTIONS: {
336
- readonly admin: readonly ["dqa-admin-add-product", "dqa-admin-add-user", "dqa-admin-add-store", "dqa-admin-add-coupon", "dqa-admin-add-event", "dqa-admin-add-blog", "dqa-admin-users", "dqa-admin-stores", "dqa-admin-orders", "dqa-admin-payouts", "dqa-admin-analytics", "dqa-admin-categories", "dqa-admin-reviews", "dqa-admin-events", "dqa-admin-faqs", "dqa-admin-carousel", "dqa-admin-sections", "dqa-admin-support", "dqa-admin-moderation", "dqa-admin-integration-guides", "dqa-admin-settings"];
335
+ readonly admin: readonly ["dqa-admin-add-product", "dqa-admin-add-user", "dqa-admin-add-store", "dqa-admin-add-coupon", "dqa-admin-add-event", "dqa-admin-add-blog", "dqa-admin-users", "dqa-admin-stores", "dqa-admin-orders", "dqa-admin-payouts", "dqa-admin-analytics", "dqa-admin-categories", "dqa-admin-reviews", "dqa-admin-events", "dqa-admin-faqs", "dqa-admin-carousel", "dqa-admin-sections", "dqa-admin-support", "dqa-admin-moderation", "dqa-admin-settings"];
337
336
  readonly seller: readonly ["dqa-seller-add-product", "dqa-seller-products", "dqa-seller-view-orders", "dqa-seller-analytics", "dqa-seller-add-coupon", "dqa-seller-auctions", "dqa-seller-payout-request", "dqa-seller-shipping", "dqa-seller-messages", "dqa-seller-whatsapp", "dqa-seller-reviews", "dqa-seller-storefront", "dqa-seller-settings"];
338
337
  readonly user: readonly ["dqa-user-view-orders", "dqa-user-view-wishlist", "dqa-user-edit-profile", "dqa-user-add-address", "dqa-user-recently-viewed", "dqa-user-my-catalogue", "dqa-user-my-coupons"];
339
338
  };
@@ -356,7 +356,6 @@ export const DASHBOARD_QUICK_ACTION_ID = {
356
356
  ADMIN_EVENTS: "dqa-admin-events",
357
357
  ADMIN_SUPPORT: "dqa-admin-support",
358
358
  ADMIN_MODERATION: "dqa-admin-moderation",
359
- ADMIN_INTEGRATION_GUIDES: "dqa-admin-integration-guides",
360
359
  ADMIN_USERS: "dqa-admin-users",
361
360
  ADMIN_CATEGORIES: "dqa-admin-categories",
362
361
  ADMIN_REVIEWS: "dqa-admin-reviews",
@@ -402,7 +401,6 @@ export const DASHBOARD_QUICK_ACTION_META = {
402
401
  [DASHBOARD_QUICK_ACTION_ID.ADMIN_EVENTS]: { id: DASHBOARD_QUICK_ACTION_ID.ADMIN_EVENTS, label: "Events", variant: "outline", iconName: "Calendar", requiresAuth: true, requiredRole: "admin", requiredPermission: "events.read" },
403
402
  [DASHBOARD_QUICK_ACTION_ID.ADMIN_SUPPORT]: { id: DASHBOARD_QUICK_ACTION_ID.ADMIN_SUPPORT, label: "Support Tickets", variant: "outline", iconName: "LifeBuoy", requiresAuth: true, requiredRole: "admin", requiredPermission: "support.read" },
404
403
  [DASHBOARD_QUICK_ACTION_ID.ADMIN_MODERATION]: { id: DASHBOARD_QUICK_ACTION_ID.ADMIN_MODERATION, label: "Moderation", variant: "outline", iconName: "ShieldAlert", requiresAuth: true, requiredRole: "admin", requiredPermission: "moderation.read" },
405
- [DASHBOARD_QUICK_ACTION_ID.ADMIN_INTEGRATION_GUIDES]: { id: DASHBOARD_QUICK_ACTION_ID.ADMIN_INTEGRATION_GUIDES, label: "Integration Guides", variant: "ghost", iconName: "BookOpen", requiresAuth: true, requiredRole: "admin", requiredPermission: "admin:site:read" },
406
404
  [DASHBOARD_QUICK_ACTION_ID.ADMIN_USERS]: { id: DASHBOARD_QUICK_ACTION_ID.ADMIN_USERS, label: "Users", variant: "outline", iconName: "Users", requiresAuth: true, requiredRole: "admin", requiredPermission: "admin.users.read" },
407
405
  [DASHBOARD_QUICK_ACTION_ID.ADMIN_CATEGORIES]: { id: DASHBOARD_QUICK_ACTION_ID.ADMIN_CATEGORIES, label: "Categories", variant: "outline", iconName: "Tag", requiresAuth: true, requiredRole: "admin", requiredPermission: "categories.read" },
408
406
  [DASHBOARD_QUICK_ACTION_ID.ADMIN_REVIEWS]: { id: DASHBOARD_QUICK_ACTION_ID.ADMIN_REVIEWS, label: "Reviews", variant: "outline", iconName: "Star", requiresAuth: true, requiredRole: "admin", requiredPermission: "reviews.read" },
@@ -452,7 +450,6 @@ export const DASHBOARD_QUICK_ACTIONS = {
452
450
  DASHBOARD_QUICK_ACTION_ID.ADMIN_SECTIONS,
453
451
  DASHBOARD_QUICK_ACTION_ID.ADMIN_SUPPORT,
454
452
  DASHBOARD_QUICK_ACTION_ID.ADMIN_MODERATION,
455
- DASHBOARD_QUICK_ACTION_ID.ADMIN_INTEGRATION_GUIDES,
456
453
  DASHBOARD_QUICK_ACTION_ID.ADMIN_SETTINGS,
457
454
  ],
458
455
  seller: [
@@ -241,7 +241,7 @@ export interface ProductDocument extends BaseDocument {
241
241
  sublistingIcon?: string;
242
242
  /**
243
243
  * Required since Phase 4 dropped the legacy `isAuction` / `isPreOrder`
244
- * booleans. Every product document carries this; queries route through
244
+ * booleans. Every product document carries this queries route through
245
245
  * `where("listingType", "==", X)` against the `listingType+...` composite
246
246
  * indexes in `appkit/firebase/base/firestore.indexes.json`.
247
247
  * SB-UNI-F — extended with classified | digital-code | live.
@@ -272,9 +272,10 @@ export interface ProductDocument extends BaseDocument {
272
272
  prizeRevealWindowEnd?: Date;
273
273
  /**
274
274
  * "pending" is legacy-only (no longer written by new listings — reveal is
275
- * fully automatic, there's no seller-facing delayed-start concept anymore;
275
+ * fully automatic, there's no seller-facing delayed-start concept anymore
276
276
  * draft→published is how a seller holds a draw back). New listings go
277
- * straight to "open"; "closed" once every eligible order has been revealed.
277
+ * straight to "open", flipping to "closed" once every eligible order has
278
+ * been revealed.
278
279
  */
279
280
  prizeRevealStatus?: "pending" | "open" | "closed";
280
281
  /**
@@ -8,6 +8,7 @@ import { MediaImage } from "../../media/MediaImage";
8
8
  import { BottomSheet } from "../../layout/BottomSheet";
9
9
  import { SidebarCollapseToggle } from "../../../_internal/client/features/layout/SidebarCollapseToggle";
10
10
  import { useSidebarSearch } from "../../../_internal/client/features/layout/useSidebarSearch";
11
+ import { findActiveNavGroup, findActiveNavItem } from "../../../_internal/client/features/layout/navActive";
11
12
  const __O = {
12
13
  hidden: "overflow-hidden",
13
14
  yAuto: "overflow-y-auto",
@@ -18,26 +19,36 @@ const CLS_STORE_NAME = "text-[length:var(--appkit-text-sm)] font-semibold text-[
18
19
  const CLS_NAV_ACTIVE = "bg-warning-surface dark:bg-warning-surface text-warning dark:text-warning";
19
20
  const CLS_NAV_BADGE = "shrink-0 rounded-full bg-warning-surface px-[var(--appkit-space-1-5)] py-[var(--appkit-space-0-5)] text-[10px] text-white leading-none";
20
21
  const CLS_NAV_ICON_ACTIVE = "text-warning dark:text-warning";
21
- function isNavItemActive(item, activeHref) {
22
- return activeHref === item.href;
23
- }
24
22
  function NavLink({ item, isActive, onClick }) {
25
23
  return (_jsxs(Link, { href: item.href, onClick: onClick, className: `flex items-center justify-end gap-[var(--appkit-space-2-5)] rounded-lg px-[var(--appkit-space-3)] py-[var(--appkit-space-2)] text-[0.8125rem] font-medium leading-tight transition-colors ${isActive
26
24
  ? CLS_NAV_ACTIVE
27
25
  : "text-[var(--appkit-color-text-muted)] hover:bg-zinc-50 hover:bg-[var(--appkit-color-surface-elevated)]/60 hover:text-zinc-800 hover:text-[var(--appkit-color-text-muted)]"}`, children: [item.icon && _jsx(Span, { size: "base", className: "shrink-0 opacity-60", children: item.icon }), _jsx(Span, { className: "truncate", children: item.label }), item.badge != null && item.badge > 0 && (_jsx(Span, { weight: "bold", className: CLS_NAV_BADGE, children: item.badge }))] }));
28
26
  }
29
27
  function FlatContent({ items, activeHref, storeName, storeLogoURL, onItemClick, }) {
28
+ const activeItem = findActiveNavItem(items, activeHref);
30
29
  return (_jsxs(_Fragment, { children: [storeName && (_jsxs(Row, { border: "bottom-subtle", gap: "3", padding: "inline", children: [storeLogoURL ? (_jsx(Div, { className: CLS_STORE_AVATAR, children: _jsx(MediaImage, { src: storeLogoURL, alt: storeName, size: "thumbnail" }) })) : (_jsx(Div, { className: CLS_STORE_FALLBACK, children: storeName[0]?.toUpperCase() })), _jsx(Text, { className: CLS_STORE_NAME, children: storeName })] })), _jsx(Nav, { "aria-label": "Store navigation", padding: "y-sm", children: _jsx(Ul, { paddingX: "x-sm", spacing: "2xs", children: items.map((item) => {
31
- const isActive = activeHref === item.href;
30
+ const isActive = activeItem?.href === item.href;
32
31
  return (_jsx(Li, { children: _jsx(NavLink, { item: item, isActive: isActive, onClick: onItemClick }) }, item.href));
33
32
  }) }) })] }));
34
33
  }
35
34
  function GroupsContent({ groups, activeHref, storeName, storeLogoURL, onItemClick, }) {
36
- // Accordion — only one group open at a time.
35
+ // Accordion — only one group open at a time. Initial pick: the group
36
+ // containing the active path, else the first group with defaultOpen.
37
37
  const [openGroup, setOpenGroup] = useState(() => {
38
- const match = groups.find((g) => g.defaultOpen ?? g.items.some((i) => activeHref === i.href));
39
- return match?.title ?? null;
38
+ const active = findActiveNavGroup(groups, activeHref);
39
+ if (active)
40
+ return active.title;
41
+ return groups.find((g) => g.defaultOpen)?.title ?? null;
40
42
  });
43
+ // Re-sync whenever the route changes — the sidebar stays mounted across
44
+ // client-side navigation, so the lazy initializer above only fires once.
45
+ useEffect(() => {
46
+ const active = findActiveNavGroup(groups, activeHref);
47
+ if (active)
48
+ setOpenGroup(active.title);
49
+ // eslint-disable-next-line react-hooks/exhaustive-deps
50
+ }, [activeHref]);
51
+ const activeItem = findActiveNavItem(groups.flatMap((g) => g.items), activeHref);
41
52
  const { query, setQuery, isSearching, filteredGroups } = useSidebarSearch(groups);
42
53
  const toggle = useCallback((title) => {
43
54
  if (isSearching)
@@ -46,10 +57,10 @@ function GroupsContent({ groups, activeHref, storeName, storeLogoURL, onItemClic
46
57
  }, [isSearching]);
47
58
  return (_jsxs(_Fragment, { children: [storeName && (_jsxs(Row, { border: "bottom-subtle", gap: "3", padding: "inline", children: [storeLogoURL ? (_jsx(Div, { className: CLS_STORE_AVATAR, children: _jsx(MediaImage, { src: storeLogoURL, alt: storeName, size: "thumbnail" }) })) : (_jsx(Div, { className: CLS_STORE_FALLBACK, children: storeName[0]?.toUpperCase() })), _jsx(Text, { className: CLS_STORE_NAME, children: storeName })] })), _jsxs(Nav, { "aria-label": "Store navigation", padding: "y-xs", children: [_jsx(Div, { padding: "x-md", paddingY: "y-sm", children: _jsx(Input, { value: query, onChange: (e) => setQuery(e.target.value), placeholder: "Search navigation\u2026", "aria-label": "Search navigation" }) }), isSearching && filteredGroups.length === 0 && (_jsx(Div, { padding: "x-md", paddingY: "y-sm", children: _jsxs(Span, { size: "xs", color: "muted", children: ["No matches for \u201C", query, "\u201D."] }) })), filteredGroups.map((group) => {
48
59
  const isOpen = isSearching || openGroup === group.title;
49
- const hasActive = group.items.some((i) => activeHref === i.href);
60
+ const hasActive = !!findActiveNavItem(group.items, activeHref);
50
61
  return (_jsxs(Div, { className: "mb-0.5", children: [_jsx(Button, { type: "button", variant: "ghost", onClick: () => toggle(group.title), paddingX: "md", paddingY: "sm", weight: "semibold", rounded: "none", className: `w-full text-[0.6875rem] uppercase tracking-widest transition-colors ${hasActive && !isOpen
51
62
  ? CLS_NAV_ICON_ACTIVE
52
- : "text-[var(--appkit-color-text-faint)] hover:text-[var(--appkit-color-text-muted)]"}`, children: _jsxs(Row, { align: "center", justify: "between", className: "w-full", children: [_jsx(Span, { children: group.title }), _jsx("svg", { className: `w-3 h-3 transition-transform duration-150 ${isOpen ? "rotate-180" : ""}`, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2.5, d: "M19 9l-7 7-7-7" }) })] }) }), isOpen && (_jsx(Ul, { paddingX: "x-sm", paddingY: "y-bottom-xs", spacing: "2xs", children: group.items.map((item) => (_jsx(Li, { children: _jsx(NavLink, { item: item, isActive: isNavItemActive(item, activeHref), onClick: onItemClick }) }, item.href))) }))] }, group.title));
63
+ : "text-[var(--appkit-color-text-faint)] hover:text-[var(--appkit-color-text-muted)]"}`, children: _jsxs(Row, { align: "center", justify: "between", className: "w-full", children: [_jsx(Span, { children: group.title }), _jsx("svg", { className: `w-3 h-3 transition-transform duration-150 ${isOpen ? "rotate-180" : ""}`, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2.5, d: "M19 9l-7 7-7-7" }) })] }) }), isOpen && (_jsx(Ul, { paddingX: "x-sm", paddingY: "y-bottom-xs", spacing: "2xs", children: group.items.map((item) => (_jsx(Li, { children: _jsx(NavLink, { item: item, isActive: activeItem?.href === item.href, onClick: onItemClick }) }, item.href))) }))] }, group.title));
53
64
  })] })] }));
54
65
  }
55
66
  function DrawerPanel({ title, onClose, children }) {
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Package, ShoppingBag, Wallet, Settings, Shield, Headphones, CheckCircle2, Circle, BookOpen, } from "lucide-react";
2
+ import { Package, ShoppingBag, Wallet, Settings, Shield, Headphones, CheckCircle2, Circle, BookOpen, MessageSquare, } from "lucide-react";
3
3
  import { Div, Heading, Progress, Row, Section, Stack, Text, TextLink } from "../../../ui";
4
4
  import { ROUTES } from "../../../next/routing/route-map";
5
5
  const CLS_CHECK_ICON = "w-5 h-5 flex-shrink-0 text-emerald-500";
@@ -36,6 +36,12 @@ const GUIDE_CARDS = [
36
36
  description: "Admin-granted feature flags — auctions, pre-orders, lower commissions, and more.",
37
37
  href: String(ROUTES.STORE.GUIDE_CAPABILITIES),
38
38
  },
39
+ {
40
+ Icon: MessageSquare,
41
+ title: "WhatsApp Catalog Sync",
42
+ description: "Push your product catalog to Meta Commerce Manager for WhatsApp, Facebook, and Instagram Shops.",
43
+ href: String(ROUTES.STORE.GUIDE_WHATSAPP),
44
+ },
39
45
  {
40
46
  Icon: Headphones,
41
47
  title: "Support",
@@ -2,6 +2,7 @@
2
2
  import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useRouter } from "next/navigation";
4
4
  import { Button, Div, Select, TextLink } from "../../../ui";
5
+ const CLS_ACTIVE_TAB = "border-primary text-primary";
5
6
  export function StoreNavTabs({ tabs, dropdownTabs = [], dropdownPlaceholder = "Browse listings", activeValue, onTabChange, renderTabBar, className = "", }) {
6
7
  const router = useRouter();
7
8
  const handleChange = (v) => onTabChange?.(v);
@@ -17,9 +18,9 @@ export function StoreNavTabs({ tabs, dropdownTabs = [], dropdownPlaceholder = "B
17
18
  router.push(tab.href);
18
19
  handleChange(tab.value);
19
20
  };
20
- return (_jsxs(Div, { layout: "flex", gap: "2", role: "tablist", border: "bottom", className: `items-center overflow-x-auto ${className}`, children: [dropdownTabs.length > 0 && (_jsx(Select, { bare: true, "aria-label": dropdownPlaceholder, options: dropdownTabs.map((tab) => ({ value: tab.value, label: tab.label })), value: activeDropdownTab?.value ?? "", placeholder: activeDropdownTab ? undefined : dropdownPlaceholder, onValueChange: handleDropdownChange, className: `max-w-[12rem] flex-shrink-0 whitespace-nowrap ${activeDropdownTab ? "border-primary text-primary" : ""}` })), tabs.map((tab) => tab.href ? (_jsx(TextLink, { variant: "bare", href: tab.href, role: "tab", "aria-selected": activeValue === tab.value, paddingX: "md", paddingY: "xs", size: "sm", weight: "medium", className: `whitespace-nowrap border-b-2 -mb-px transition-colors ${activeValue === tab.value
21
- ? "border-primary text-primary"
21
+ return (_jsxs(Div, { layout: "flex", gap: "2", align: "center", role: "tablist", border: "bottom", className: `overflow-x-auto ${className}`, children: [dropdownTabs.length > 0 && (_jsx(Select, { bare: true, "aria-label": dropdownPlaceholder, options: dropdownTabs.map((tab) => ({ value: tab.value, label: tab.label })), value: activeDropdownTab?.value ?? "", placeholder: activeDropdownTab ? undefined : dropdownPlaceholder, onValueChange: handleDropdownChange, className: `max-w-[12rem] flex-shrink-0 whitespace-nowrap ${activeDropdownTab ? CLS_ACTIVE_TAB : ""}` })), tabs.map((tab) => tab.href ? (_jsx(TextLink, { variant: "bare", href: tab.href, role: "tab", "aria-selected": activeValue === tab.value, paddingX: "md", paddingY: "xs", size: "sm", weight: "medium", className: `whitespace-nowrap border-b-2 -mb-px transition-colors ${activeValue === tab.value
22
+ ? CLS_ACTIVE_TAB
22
23
  : "border-transparent text-[var(--appkit-color-text-muted)] text-[var(--appkit-color-text-muted)] hover:text-neutral-800 hover:text-[var(--appkit-color-text-muted)]"}`, children: tab.label }, tab.value)) : (_jsx(Button, { variant: "ghost", type: "button", role: "tab", "aria-selected": activeValue === tab.value, onClick: () => handleChange(tab.value), paddingX: "md", paddingY: "sm", textSize: "sm", weight: "medium", rounded: "none", className: `whitespace-nowrap border-b-2 -mb-px transition-colors ${activeValue === tab.value
23
- ? "border-primary text-primary"
24
+ ? CLS_ACTIVE_TAB
24
25
  : "border-transparent text-[var(--appkit-color-text-muted)] text-[var(--appkit-color-text-muted)] hover:text-neutral-800 hover:text-[var(--appkit-color-text-muted)]"}`, children: tab.label }, tab.value)))] }));
25
26
  }
@@ -0,0 +1,3 @@
1
+ import React from "react";
2
+ export type StoreWhatsAppGuideViewProps = Record<string, never>;
3
+ export declare function StoreWhatsAppGuideView(_props: StoreWhatsAppGuideViewProps): React.JSX.Element;
@@ -0,0 +1,12 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { ArrowLeft } from "lucide-react";
3
+ import { Alert, Code, Div, Heading, Li, Section, Span, Stack, Text, TextLink, Ul } from "../../../ui";
4
+ import { ROUTES } from "../../../next/routing/route-map";
5
+ function GuideSection({ title, children, }) {
6
+ return (_jsxs(Section, { className: "border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)]", rounded: "xl", shadow: "sm", padding: "lg", children: [_jsx(Heading, { level: 2, className: "mb-4 text-[var(--appkit-color-text)]", size: "lg", weight: "semibold", children: title }), children] }));
7
+ }
8
+ const LIST_DISC = "list-disc leading-relaxed";
9
+ const TEXT_MUTED = "leading-relaxed text-[var(--appkit-color-text-muted)]";
10
+ export function StoreWhatsAppGuideView(_props) {
11
+ return (_jsxs(Stack, { gap: "lg", padding: "b-2xl", children: [_jsxs(TextLink, { variant: "bare", href: String(ROUTES.STORE.GUIDE), size: "sm", layout: "inline-flex", align: "center", gap: "sm", className: "text-[var(--appkit-color-text-muted)] hover:text-[var(--appkit-color-text)] transition-colors", children: [_jsx(ArrowLeft, { className: "h-4 w-4" }), "Back to Seller Guide"] }), _jsxs(Div, { children: [_jsx(Heading, { level: 1, className: "text-[var(--appkit-color-text)]", size: "2xl", weight: "bold", children: "WhatsApp Catalog Sync" }), _jsx(Text, { className: "mt-1 text-[var(--appkit-color-text-muted)]", size: "sm", children: "Push your product catalog to Meta's Commerce Manager for WhatsApp catalog messages and Facebook/Instagram Shops \u2014 and import products back the other way." })] }), _jsx(GuideSection, { title: "1. Create a Commerce Manager catalog", children: _jsxs(Ul, { spacing: "tight", indent: "lg", children: [_jsxs(Li, { className: LIST_DISC, textSize: "sm", color: "muted", children: ["At ", _jsx(Span, { weight: "bold", children: "business.facebook.com/commerce" }), ", create a new catalog for the store (or use an existing one)."] }), _jsxs(Li, { className: LIST_DISC, textSize: "sm", color: "muted", children: ["Note the ", _jsx(Span, { weight: "bold", children: "Catalog ID" }), " shown in the catalog's settings."] })] }) }), _jsx(GuideSection, { title: "2. Generate a catalog-scoped access token", children: _jsxs(Text, { className: TEXT_MUTED, size: "sm", children: ["You need a Meta access token with ", _jsx(Code, { size: "xs", padding: "xs", rounded: "default", surface: "subtle", children: "catalog_management" }), " permission, scoped to that catalog. This is generated the same way as the platform-level WhatsApp System User token (ask your admin \u2014 Admin Guide \u2192 WhatsApp Integration, step 3) but assigned to the ", _jsx(Span, { weight: "bold", children: "catalog" }), " asset instead of the WhatsApp Business Account asset."] }) }), _jsxs(GuideSection, { title: "3. Enter credentials in the seller dashboard", children: [_jsxs(Text, { className: "mb-2 leading-relaxed text-[var(--appkit-color-text-muted)]", size: "sm", children: [_jsx(Span, { weight: "bold", children: "Store \u2192 WhatsApp" }), " settings page:"] }), _jsxs(Ul, { spacing: "tight", indent: "lg", children: [_jsx(Li, { className: LIST_DISC, textSize: "sm", color: "muted", children: "Catalog ID" }), _jsx(Li, { className: LIST_DISC, textSize: "sm", color: "muted", children: "Access Token" })] }), _jsxs(Text, { className: "mt-3 leading-relaxed text-[var(--appkit-color-text-muted)]", size: "sm", children: ["This is a store capability \u2014 it must be enabled for the store (", _jsx(Code, { size: "xs", padding: "xs", rounded: "default", surface: "subtle", children: "whatsapp_catalog_sync" }), " capability) before the settings page and sync actions are available."] })] }), _jsx(GuideSection, { title: "4. Push products to the catalog", children: _jsxs(Text, { className: TEXT_MUTED, size: "sm", children: ["Once connected, trigger a sync that batches published ", _jsx(Code, { size: "xs", padding: "xs", rounded: "default", surface: "subtle", children: "standard" }), "-listing products (up to 50 per API call) to the Meta catalog via the Commerce API ", _jsx(Code, { size: "xs", padding: "xs", rounded: "default", surface: "subtle", children: "items_batch" }), " endpoint \u2014 title, description, price, image, availability, and condition."] }) }), _jsx(GuideSection, { title: "5. Import products from the catalog", children: _jsxs(Text, { className: TEXT_MUTED, size: "sm", children: ["The reverse flow fetches products already in the Meta catalog and creates them as local ", _jsx(Span, { weight: "bold", children: "draft" }), " listings, deduplicating against existing products by slug/retailer-id matching."] }) }), _jsxs(Alert, { variant: "info", children: ["This is unrelated to the platform-level WhatsApp order-notification credentials \u2014 those are for sending order-status messages to buyers, not catalog sync. Only published ", _jsx(Span, { weight: "bold", children: "standard" }), " listings sync \u2014 auctions, pre-orders, and other listing types are not included."] })] }));
12
+ }
@@ -47,3 +47,5 @@ export { StoreCapabilitiesGuideView } from "./StoreCapabilitiesGuideView";
47
47
  export type { StoreCapabilitiesGuideViewProps } from "./StoreCapabilitiesGuideView";
48
48
  export { StoreSettingsGuideView } from "./StoreSettingsGuideView";
49
49
  export type { StoreSettingsGuideViewProps } from "./StoreSettingsGuideView";
50
+ export { StoreWhatsAppGuideView } from "./StoreWhatsAppGuideView";
51
+ export type { StoreWhatsAppGuideViewProps } from "./StoreWhatsAppGuideView";
@@ -20,3 +20,4 @@ export { StoreOrdersGuideView } from "./StoreOrdersGuideView";
20
20
  export { StoreFinanceGuideView } from "./StoreFinanceGuideView";
21
21
  export { StoreCapabilitiesGuideView } from "./StoreCapabilitiesGuideView";
22
22
  export { StoreSettingsGuideView } from "./StoreSettingsGuideView";
23
+ export { StoreWhatsAppGuideView } from "./StoreWhatsAppGuideView";
@@ -25,6 +25,7 @@ import { seedExtMedia } from "../../../seed/_helpers/media";
25
25
  import { testDataExpiresAt } from "./tester-ttl";
26
26
  const TESTER_STORE_ID = "store-tester-sandbox";
27
27
  const TESTER_STORE_NAME = "Tester Sandbox Store";
28
+ const TESTER_GROUP_TITLE = "Tester Sandbox Bundle";
28
29
  const GADGETS_CATEGORY_SLUGS = ["category-tester-gadgets", "category-tester-sandbox"];
29
30
  const GADGETS_CATEGORY_NAMES = ["Test Gadgets", "Tester Sandbox"];
30
31
  const COLLECTIBLES_CATEGORY_SLUGS = ["category-tester-collectibles", "category-tester-sandbox"];
@@ -71,7 +72,7 @@ export const productsTesterSeedData = [
71
72
  // resolvable and ShowGroupSection renders nothing (members.length <= 1).
72
73
  groupId: "group-tester-sandbox-bundle",
73
74
  groupParentSlug: "group-tester-sandbox-bundle",
74
- groupTitle: "Tester Sandbox Bundle",
75
+ groupTitle: TESTER_GROUP_TITLE,
75
76
  createdAt: new Date(),
76
77
  updatedAt: new Date(),
77
78
  }),
@@ -100,7 +101,7 @@ export const productsTesterSeedData = [
100
101
  isOnSale: false,
101
102
  groupId: "group-tester-sandbox-bundle",
102
103
  groupParentSlug: "group-tester-sandbox-bundle",
103
- groupTitle: "Tester Sandbox Bundle",
104
+ groupTitle: TESTER_GROUP_TITLE,
104
105
  createdAt: new Date(),
105
106
  updatedAt: new Date(),
106
107
  }),
@@ -492,7 +493,7 @@ export const productsTesterSeedData = [
492
493
  isOnSale: false,
493
494
  isGroupParent: true,
494
495
  groupId: "group-tester-sandbox-bundle",
495
- groupTitle: "Tester Sandbox Bundle",
496
+ groupTitle: TESTER_GROUP_TITLE,
496
497
  groupChildSlugs: ["product-tester-standard-1", "product-tester-standard-2"],
497
498
  createdAt: new Date(),
498
499
  updatedAt: new Date(),
@@ -18,6 +18,8 @@
18
18
  * @tag sideEffects:none
19
19
  */
20
20
  import { assignDefaultPhases } from "../utils/phases";
21
+ const ADMIN_TESTING_GROUP_LABEL = "Admin (Testing)";
22
+ const BUG_HUNTER_REWARDS_PAGE_LABEL = "Bug Hunter Rewards";
21
23
  function group(groupKey, groupLabel, pages, opts) {
22
24
  const items = [];
23
25
  pages.forEach((page, pageIdx) => {
@@ -676,7 +678,7 @@ const rawTesterChecklistItems = [
676
678
  ],
677
679
  },
678
680
  ]),
679
- ...group("admin", "Admin (Testing)", [
681
+ ...group("admin", ADMIN_TESTING_GROUP_LABEL, [
680
682
  {
681
683
  pageKey: "catalog-listings",
682
684
  pageLabel: "Catalog & Listings",
@@ -853,7 +855,7 @@ const rawTesterChecklistItems = [
853
855
  },
854
856
  {
855
857
  pageKey: "bug-hunter-rewards",
856
- pageLabel: "Bug Hunter Rewards",
858
+ pageLabel: BUG_HUNTER_REWARDS_PAGE_LABEL,
857
859
  cases: [
858
860
  {
859
861
  key: "confirm-bug",
@@ -888,9 +890,9 @@ const rawTesterChecklistItems = [
888
890
  {
889
891
  id: "checklist-admin-bug-hunter-rewards-demo-fixture",
890
892
  groupKey: "admin",
891
- groupLabel: "Admin (Testing)",
893
+ groupLabel: ADMIN_TESTING_GROUP_LABEL,
892
894
  pageKey: "bug-hunter-rewards",
893
- pageLabel: "Bug Hunter Rewards",
895
+ pageLabel: BUG_HUNTER_REWARDS_PAGE_LABEL,
894
896
  label: "Demo fixture — reported bug, already confirmed and reopened (v1, disabled)",
895
897
  description: "Seed-only fixture demonstrating a confirmed bug: this v1 case is disabled (isActive:false) and credited to \"Mock User 18\". Its retest is \"Demo fixture — reported bug, already confirmed and reopened (v2, active)\" in this same page.",
896
898
  order: 100,
@@ -906,9 +908,9 @@ const rawTesterChecklistItems = [
906
908
  {
907
909
  id: "checklist-admin-bug-hunter-rewards-demo-fixture-v2",
908
910
  groupKey: "admin",
909
- groupLabel: "Admin (Testing)",
911
+ groupLabel: ADMIN_TESTING_GROUP_LABEL,
910
912
  pageKey: "bug-hunter-rewards",
911
- pageLabel: "Bug Hunter Rewards",
913
+ pageLabel: BUG_HUNTER_REWARDS_PAGE_LABEL,
912
914
  label: "Demo fixture — reported bug, already confirmed and reopened (v2, active)",
913
915
  description: "Seed-only fixture — the retest version reopened from the disabled v1 case in this same page. Active and answerable again; a fresh \"No\" answer here can be used to try Mark as Bug end-to-end.",
914
916
  order: 101,
package/dist/index.d.ts CHANGED
@@ -2900,6 +2900,8 @@ export { AdminSiteConfigGuideView } from "./features/admin/components/AdminSiteC
2900
2900
  export { AdminTeamGuideView } from "./features/admin/components/AdminTeamGuideView";
2901
2901
  export { AdminAnalyticsGuideView } from "./features/admin/components/AdminAnalyticsGuideView";
2902
2902
  export { AdminTrustGuideView } from "./features/admin/components/AdminTrustGuideView";
2903
+ export { AdminWhatsAppGuideView } from "./features/admin/components/AdminWhatsAppGuideView";
2904
+ export { AdminPaymentsGuideView } from "./features/admin/components/AdminPaymentsGuideView";
2903
2905
  export { BuyerShoppingGuideView } from "./features/account/components/BuyerShoppingGuideView";
2904
2906
  export { BuyerAuctionsGuideView } from "./features/account/components/BuyerAuctionsGuideView";
2905
2907
  export { BuyerOrdersGuideView } from "./features/account/components/BuyerOrdersGuideView";
@@ -2916,6 +2918,8 @@ export { StoreCapabilitiesGuideView } from "./features/stores/components/StoreCa
2916
2918
  export type { StoreCapabilitiesGuideViewProps } from "./features/stores/components/StoreCapabilitiesGuideView";
2917
2919
  export { StoreSettingsGuideView } from "./features/stores/components/StoreSettingsGuideView";
2918
2920
  export type { StoreSettingsGuideViewProps } from "./features/stores/components/StoreSettingsGuideView";
2921
+ export { StoreWhatsAppGuideView } from "./features/stores/components/StoreWhatsAppGuideView";
2922
+ export type { StoreWhatsAppGuideViewProps } from "./features/stores/components/StoreWhatsAppGuideView";
2919
2923
  export { StorePreOrdersListing } from "./features/stores/components/StorePreOrdersListing";
2920
2924
  export type { StorePreOrdersListingProps } from "./features/stores/components/StorePreOrdersListing";
2921
2925
  export { buildStoreColumns } from "./features/stores/index";
package/dist/index.js CHANGED
@@ -5218,6 +5218,10 @@ export { AdminTeamGuideView } from "./features/admin/components/AdminTeamGuideVi
5218
5218
  export { AdminAnalyticsGuideView } from "./features/admin/components/AdminAnalyticsGuideView";
5219
5219
  // [CLIENT-SSR]-Admin trust & safety guide — static view, no firebase-admin.
5220
5220
  export { AdminTrustGuideView } from "./features/admin/components/AdminTrustGuideView";
5221
+ // [CLIENT-SSR]-Admin WhatsApp integration guide — static view, no firebase-admin.
5222
+ export { AdminWhatsAppGuideView } from "./features/admin/components/AdminWhatsAppGuideView";
5223
+ // [CLIENT-SSR]-Admin payments (Razorpay) guide — static view, no firebase-admin.
5224
+ export { AdminPaymentsGuideView } from "./features/admin/components/AdminPaymentsGuideView";
5221
5225
  // [CLIENT-SSR]-Buyer shopping guide — static view, no firebase-admin.
5222
5226
  export { BuyerShoppingGuideView } from "./features/account/components/BuyerShoppingGuideView";
5223
5227
  // [CLIENT-SSR]-Buyer auctions & pre-orders guide — static view, no firebase-admin.
@@ -5238,6 +5242,8 @@ export { StoreFinanceGuideView } from "./features/stores/components/StoreFinance
5238
5242
  export { StoreCapabilitiesGuideView } from "./features/stores/components/StoreCapabilitiesGuideView";
5239
5243
  // [CLIENT-SSR]-Store settings guide — static view, no firebase-admin.
5240
5244
  export { StoreSettingsGuideView } from "./features/stores/components/StoreSettingsGuideView";
5245
+ // [CLIENT-SSR]-Store WhatsApp catalog sync guide — static view, no firebase-admin.
5246
+ export { StoreWhatsAppGuideView } from "./features/stores/components/StoreWhatsAppGuideView";
5241
5247
  export { StorePreOrdersListing } from "./features/stores/components/StorePreOrdersListing";
5242
5248
  // [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
5243
5249
  // buildStoreColumns - Helper for build store columns.
@@ -238,6 +238,7 @@ export declare const DEFAULT_ROUTE_MAP: {
238
238
  readonly GUIDE_FINANCE: "/store/guide/finance";
239
239
  readonly GUIDE_CAPABILITIES: "/store/guide/capabilities";
240
240
  readonly GUIDE_SETTINGS: "/store/guide/settings";
241
+ readonly GUIDE_WHATSAPP: "/store/guide/whatsapp";
241
242
  };
242
243
  readonly ADMIN: {
243
244
  readonly DASHBOARD: "/admin/dashboard";
@@ -249,7 +250,6 @@ export declare const DEFAULT_ROUTE_MAP: {
249
250
  readonly CATALOGUE_APPROVALS: "/admin/catalogue-approvals";
250
251
  readonly USERS: "/admin/users";
251
252
  readonly SITE: "/admin/site";
252
- readonly INTEGRATION_GUIDES: "/admin/integration-guides";
253
253
  readonly CAROUSEL: "/admin/carousel";
254
254
  readonly CAROUSEL_NEW: "/admin/carousel/new";
255
255
  readonly CAROUSEL_EDIT: (id: string) => string;
@@ -360,6 +360,8 @@ export declare const DEFAULT_ROUTE_MAP: {
360
360
  readonly GUIDE_TEAM: "/admin/guide/team";
361
361
  readonly GUIDE_ANALYTICS: "/admin/guide/analytics";
362
362
  readonly GUIDE_TRUST: "/admin/guide/trust";
363
+ readonly GUIDE_WHATSAPP: "/admin/guide/whatsapp";
364
+ readonly GUIDE_PAYMENTS: "/admin/guide/payments";
363
365
  readonly BANNED_ADDRESSES: "/admin/banned-addresses";
364
366
  readonly ADDRESS_CLUSTERS: "/admin/address-clusters";
365
367
  readonly PAYMENT_METHODS: "/admin/payment-methods";
@@ -599,6 +601,7 @@ export declare const ROUTES: {
599
601
  readonly GUIDE_FINANCE: "/store/guide/finance";
600
602
  readonly GUIDE_CAPABILITIES: "/store/guide/capabilities";
601
603
  readonly GUIDE_SETTINGS: "/store/guide/settings";
604
+ readonly GUIDE_WHATSAPP: "/store/guide/whatsapp";
602
605
  };
603
606
  readonly ADMIN: {
604
607
  readonly DASHBOARD: "/admin/dashboard";
@@ -610,7 +613,6 @@ export declare const ROUTES: {
610
613
  readonly CATALOGUE_APPROVALS: "/admin/catalogue-approvals";
611
614
  readonly USERS: "/admin/users";
612
615
  readonly SITE: "/admin/site";
613
- readonly INTEGRATION_GUIDES: "/admin/integration-guides";
614
616
  readonly CAROUSEL: "/admin/carousel";
615
617
  readonly CAROUSEL_NEW: "/admin/carousel/new";
616
618
  readonly CAROUSEL_EDIT: (id: string) => string;
@@ -721,6 +723,8 @@ export declare const ROUTES: {
721
723
  readonly GUIDE_TEAM: "/admin/guide/team";
722
724
  readonly GUIDE_ANALYTICS: "/admin/guide/analytics";
723
725
  readonly GUIDE_TRUST: "/admin/guide/trust";
726
+ readonly GUIDE_WHATSAPP: "/admin/guide/whatsapp";
727
+ readonly GUIDE_PAYMENTS: "/admin/guide/payments";
724
728
  readonly BANNED_ADDRESSES: "/admin/banned-addresses";
725
729
  readonly ADDRESS_CLUSTERS: "/admin/address-clusters";
726
730
  readonly PAYMENT_METHODS: "/admin/payment-methods";
@@ -815,6 +819,7 @@ export declare const SELLER_ROUTES: {
815
819
  readonly GUIDE_FINANCE: "/store/guide/finance";
816
820
  readonly GUIDE_CAPABILITIES: "/store/guide/capabilities";
817
821
  readonly GUIDE_SETTINGS: "/store/guide/settings";
822
+ readonly GUIDE_WHATSAPP: "/store/guide/whatsapp";
818
823
  };
819
824
  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"];
820
825
  export declare const PROTECTED_ROUTES: readonly [string, string, string, string, string, string, string];
@@ -237,6 +237,7 @@ export const DEFAULT_ROUTE_MAP = {
237
237
  GUIDE_FINANCE: "/store/guide/finance",
238
238
  GUIDE_CAPABILITIES: "/store/guide/capabilities",
239
239
  GUIDE_SETTINGS: "/store/guide/settings",
240
+ GUIDE_WHATSAPP: "/store/guide/whatsapp",
240
241
  },
241
242
  ADMIN: {
242
243
  DASHBOARD: "/admin/dashboard",
@@ -248,7 +249,6 @@ export const DEFAULT_ROUTE_MAP = {
248
249
  CATALOGUE_APPROVALS: "/admin/catalogue-approvals",
249
250
  USERS: "/admin/users",
250
251
  SITE: "/admin/site",
251
- INTEGRATION_GUIDES: "/admin/integration-guides",
252
252
  CAROUSEL: "/admin/carousel",
253
253
  CAROUSEL_NEW: "/admin/carousel/new",
254
254
  CAROUSEL_EDIT: (id) => `/admin/carousel/${id}/edit`,
@@ -364,6 +364,8 @@ export const DEFAULT_ROUTE_MAP = {
364
364
  GUIDE_TEAM: "/admin/guide/team",
365
365
  GUIDE_ANALYTICS: "/admin/guide/analytics",
366
366
  GUIDE_TRUST: "/admin/guide/trust",
367
+ GUIDE_WHATSAPP: "/admin/guide/whatsapp",
368
+ GUIDE_PAYMENTS: "/admin/guide/payments",
367
369
  BANNED_ADDRESSES: "/admin/banned-addresses",
368
370
  ADDRESS_CLUSTERS: "/admin/address-clusters",
369
371
  PAYMENT_METHODS: "/admin/payment-methods",
@@ -290,8 +290,7 @@ const _rawProductsStandardSeedData = [
290
290
  seedExtMedia("https://picsum.photos/seed/product-image-beyblade-original-dragoon-f-video-demo-2-20260819/900/900"),
291
291
  ],
292
292
  video: {
293
- // audit-seed-external-url-ok: raw <video> src, /api/media/ext is image-only (Root Cause #27)
294
- url: "https://storage.googleapis.com/gtv-videos-bucket/sample/ForBiggerBlazes.mp4",
293
+ url: "https://storage.googleapis.com/gtv-videos-bucket/sample/ForBiggerBlazes.mp4", // audit-seed-external-url-ok: raw <video> src, /api/media/ext is image-only (Root Cause #27)
295
294
  thumbnailUrl: seedExtMedia("https://picsum.photos/seed/product-video-thumb-beyblade-original-dragoon-f-video-demo-20260819/800/450"),
296
295
  duration: 15,
297
296
  },
@@ -324,8 +323,7 @@ const _rawProductsStandardSeedData = [
324
323
  seedExtMedia("https://picsum.photos/seed/product-image-beyblade-x-dran-sword-video-demo-2-20260819/900/900"),
325
324
  ],
326
325
  video: {
327
- // audit-seed-external-url-ok: raw <video> src, /api/media/ext is image-only (Root Cause #27)
328
- url: "https://storage.googleapis.com/gtv-videos-bucket/sample/ElephantsDream.mp4",
326
+ url: "https://storage.googleapis.com/gtv-videos-bucket/sample/ElephantsDream.mp4", // audit-seed-external-url-ok: raw <video> src, /api/media/ext is image-only (Root Cause #27)
329
327
  thumbnailUrl: seedExtMedia("https://picsum.photos/seed/product-video-thumb-beyblade-x-dran-sword-video-demo-20260819/800/450"),
330
328
  duration: 20,
331
329
  },