@mohasinac/appkit 3.3.5 → 3.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (160) hide show
  1. package/dist/_internal/client/features/classified/ClassifiedDetailView.js +2 -1
  2. package/dist/_internal/client/features/digital-code/DigitalCodeDetailView.js +2 -1
  3. package/dist/_internal/client/features/live/LiveItemDetailView.js +2 -1
  4. package/dist/_internal/client/features/lottery/LotteryAdminEditView.js +1 -1
  5. package/dist/_internal/client/features/lottery/LotteryDetailView.js +2 -1
  6. package/dist/_internal/client/features/lottery/LotteryListView.js +2 -1
  7. package/dist/_internal/client/features/lottery/PrizeDrawLotteryDetailView.js +2 -1
  8. package/dist/_internal/server/features/checkout/actions.js +0 -1
  9. package/dist/_internal/server/features/lottery/actions.js +0 -2
  10. package/dist/_internal/server/features/reviews/actions.js +1 -1
  11. package/dist/features/about/components/AboutView.js +1 -1
  12. package/dist/features/about/components/FAQPageView.js +0 -2
  13. package/dist/features/about/components/FeesView.js +13 -1
  14. package/dist/features/about/components/HowCheckoutWorksView.js +17 -3
  15. package/dist/features/about/components/HowEmiWorksView.d.ts +3 -0
  16. package/dist/features/about/components/HowEmiWorksView.js +117 -0
  17. package/dist/features/about/components/PublicProfileView.js +1 -4
  18. package/dist/features/about/components/TrackOrderView.js +1 -1
  19. package/dist/features/about/index.d.ts +2 -0
  20. package/dist/features/about/index.js +1 -0
  21. package/dist/features/account/components/AddressesIndexListing.js +1 -1
  22. package/dist/features/account/components/BecomeSellerView.d.ts +1 -1
  23. package/dist/features/account/components/BecomeSellerView.js +1 -1
  24. package/dist/features/account/components/NotificationBell.js +1 -2
  25. package/dist/features/account/components/UserSupportView.js +0 -1
  26. package/dist/features/admin/components/AdminAdsView.js +3 -3
  27. package/dist/features/admin/components/AdminBlogEditorView.js +2 -2
  28. package/dist/features/admin/components/AdminBundleEditorView.js +0 -4
  29. package/dist/features/admin/components/AdminCarouselEditorView.js +3 -3
  30. package/dist/features/admin/components/AdminCarouselView.js +3 -2
  31. package/dist/features/admin/components/AdminGuideHubView.js +2 -2
  32. package/dist/features/admin/components/AdminMediaView.js +2 -4
  33. package/dist/features/admin/components/AdminProductsView.js +2 -2
  34. package/dist/features/admin/components/AdminSiteSettingsView.js +1 -1
  35. package/dist/features/admin/components/AdminUserEditorView.d.ts +1 -1
  36. package/dist/features/admin/components/AdminUserEditorView.js +1 -1
  37. package/dist/features/admin/components/QuickActionsPanel.js +2 -2
  38. package/dist/features/auctions/components/AuctionBidsTable.js +1 -1
  39. package/dist/features/auctions/components/AuctionDetailPageView.js +1 -1
  40. package/dist/features/blog/components/BlogFeaturedCard.js +2 -1
  41. package/dist/features/blog/components/BlogIndexListing.js +1 -1
  42. package/dist/features/blog/components/BlogListView.js +2 -1
  43. package/dist/features/blog/components/BlogPostForm.js +1 -1
  44. package/dist/features/blog/components/BlogPostView.js +2 -1
  45. package/dist/features/cart/components/CartDrawer.js +2 -1
  46. package/dist/features/categories/components/BrandDetailPageView.js +2 -1
  47. package/dist/features/categories/components/BundleCollage.js +2 -3
  48. package/dist/features/categories/components/CategoriesIndexListing.js +1 -5
  49. package/dist/features/categories/components/CategoryDetailPageView.js +2 -2
  50. package/dist/features/categories/components/CategoryGrid.js +2 -1
  51. package/dist/features/categories/components/CategoryProductsView.d.ts +1 -1
  52. package/dist/features/categories/components/CategoryProductsView.js +1 -1
  53. package/dist/features/categories/components/ConcernCard.js +2 -1
  54. package/dist/features/collections/components/CollectionCard.js +2 -1
  55. package/dist/features/consultation/components/ConsultationForm.js +0 -1
  56. package/dist/features/contact/components/ContactInfoSidebar.js +2 -2
  57. package/dist/features/copilot/components/AdminCopilotView.js +0 -9
  58. package/dist/features/events/components/EventFormDrawer.d.ts +1 -1
  59. package/dist/features/events/components/EventFormDrawer.js +1 -1
  60. package/dist/features/events/components/EventLeaderboard.js +1 -1
  61. package/dist/features/events/components/EventPollWidget.js +2 -2
  62. package/dist/features/events/components/EventsIndexListing.js +1 -1
  63. package/dist/features/faq/actions/faq-actions.d.ts +2 -10
  64. package/dist/features/faq/actions/faq-actions.js +0 -4
  65. package/dist/features/forms/Slider.js +1 -1
  66. package/dist/features/homepage/components/AdSlot.js +2 -1
  67. package/dist/features/homepage/components/BeforeAfterCard.js +1 -1
  68. package/dist/features/homepage/components/CustomCardsSection.js +2 -3
  69. package/dist/features/homepage/components/FeaturedBundlesSection.js +2 -3
  70. package/dist/features/homepage/components/GoogleReviewsSection.js +4 -3
  71. package/dist/features/homepage/components/HeroBanner.js +0 -1
  72. package/dist/features/homepage/components/HowItWorksInfoView.js +1 -1
  73. package/dist/features/homepage/components/SectionCarousel.d.ts +1 -1
  74. package/dist/features/homepage/components/SectionCarousel.js +1 -2
  75. package/dist/features/homepage/components/SiteFeaturesSection.js +1 -1
  76. package/dist/features/homepage/components/SocialFeedSection.js +2 -5
  77. package/dist/features/homepage/components/SocialPostCard.js +4 -3
  78. package/dist/features/homepage/components/TrustIndicatorsSection.js +1 -1
  79. package/dist/features/media/MediaPickerModal.js +2 -3
  80. package/dist/features/media/upload/MediaUploadList.js +2 -2
  81. package/dist/features/orders/components/MarketplaceOrderCard.js +7 -4
  82. package/dist/features/orders/components/OrdersList.js +2 -1
  83. package/dist/features/pre-orders/components/PreOrderDetailPageView.js +1 -0
  84. package/dist/features/products/api/route.js +1 -2
  85. package/dist/features/products/components/BidHistory.js +1 -1
  86. package/dist/features/products/components/CompareOverlay.js +2 -3
  87. package/dist/features/products/components/CustomSectionTabContent.js +2 -2
  88. package/dist/features/products/components/FeatureBadge.js +0 -6
  89. package/dist/features/products/components/GroupSettingsPanel.js +2 -3
  90. package/dist/features/products/components/MarketplaceBundleCard.js +2 -1
  91. package/dist/features/products/components/MarketplacePrizeDrawCard.js +2 -3
  92. package/dist/features/products/components/PrizeDrawCollage.js +2 -3
  93. package/dist/features/products/components/PrizeDrawEntryActions.d.ts +1 -1
  94. package/dist/features/products/components/PrizeDrawEntryActions.js +3 -3
  95. package/dist/features/products/components/PrizeRevealModal.js +3 -4
  96. package/dist/features/products/components/ProductDetailActions.d.ts +1 -1
  97. package/dist/features/products/components/ProductDetailActions.js +1 -1
  98. package/dist/features/products/components/ProductDetailPageView.d.ts +3 -1
  99. package/dist/features/products/components/ProductDetailPageView.js +3 -2
  100. package/dist/features/products/components/ProductFeatureBadges.d.ts +7 -1
  101. package/dist/features/products/components/ProductFeatureBadges.js +16 -3
  102. package/dist/features/products/components/ProductGalleryClient.js +1 -1
  103. package/dist/features/products/components/ProductGradingTab.js +2 -2
  104. package/dist/features/products/components/ProductsIndexPageView.js +2 -2
  105. package/dist/features/products/components/ShowGroupSection.js +1 -1
  106. package/dist/features/products/components/SublistingCarouselSection.js +3 -4
  107. package/dist/features/promotions/components/CouponsIndexListing.d.ts +1 -1
  108. package/dist/features/promotions/components/CouponsIndexListing.js +1 -1
  109. package/dist/features/reviews/components/ReviewDetailShell.js +4 -3
  110. package/dist/features/reviews/components/ReviewModal.js +2 -1
  111. package/dist/features/reviews/components/ReviewsIndexListing.js +1 -1
  112. package/dist/features/reviews/components/ReviewsList.js +2 -1
  113. package/dist/features/scams/components/ScamAwarenessModal.js +2 -2
  114. package/dist/features/search/components/Search.js +1 -1
  115. package/dist/features/search/components/SearchView.d.ts +1 -1
  116. package/dist/features/search/components/SearchView.js +1 -1
  117. package/dist/features/seller/components/SellerAddressesView.js +1 -5
  118. package/dist/features/seller/components/SellerGoogleReviewsView.js +1 -1
  119. package/dist/features/seller/components/SellerPayoutMethodsView.js +1 -1
  120. package/dist/features/seller/components/SellerPreOrdersView.js +3 -2
  121. package/dist/features/shell/QuickFormDrawer.js +1 -1
  122. package/dist/features/shell/StepForm.js +1 -1
  123. package/dist/features/stores/components/InteractiveStoreCard.js +1 -2
  124. package/dist/features/stores/components/StoreAboutView.js +2 -2
  125. package/dist/features/stores/components/StoreCapabilitiesGuideView.js +2 -2
  126. package/dist/features/stores/components/StoreFinanceGuideView.js +2 -2
  127. package/dist/features/stores/components/StoreGuideHubView.js +2 -2
  128. package/dist/features/stores/components/StoreListingsGuideView.js +2 -2
  129. package/dist/features/stores/components/StoreNavTabs.js +2 -2
  130. package/dist/features/stores/components/StoreOrdersGuideView.js +2 -2
  131. package/dist/features/stores/components/StoreSettingsGuideView.js +3 -3
  132. package/dist/features/wishlist/components/WishlistView.js +0 -7
  133. package/dist/index.d.ts +2 -0
  134. package/dist/index.js +3 -0
  135. package/dist/next/ErrorBoundary.js +2 -2
  136. package/dist/next/routing/route-map.d.ts +2 -0
  137. package/dist/next/routing/route-map.js +1 -0
  138. package/dist/seed/factories/product.factory.js +0 -32
  139. package/dist/seed/faq-seed-data.js +23 -4
  140. package/dist/styles.css +1 -1
  141. package/dist/tailwind-utilities.css +1 -1
  142. package/dist/tokens/index.js +6 -458
  143. package/dist/ui/DataTable.js +0 -21
  144. package/dist/ui/components/Anchor.d.ts +12 -3
  145. package/dist/ui/components/Anchor.js +18 -2
  146. package/dist/ui/components/Breadcrumb.js +2 -1
  147. package/dist/ui/components/Div.d.ts +1 -1
  148. package/dist/ui/components/Div.js +2 -0
  149. package/dist/ui/components/FormActionBar.js +2 -1
  150. package/dist/ui/components/ListingLayout.d.ts +1 -1
  151. package/dist/ui/components/ListingLayout.js +1 -1
  152. package/dist/ui/components/Motion.js +1 -1
  153. package/dist/ui/components/QuickCreateModal.js +2 -1
  154. package/dist/ui/components/SlottedListingView.d.ts +1 -1
  155. package/dist/ui/components/SlottedListingView.js +1 -2
  156. package/dist/ui/components/Typography.d.ts +1 -1
  157. package/dist/ui/components/Typography.js +1 -0
  158. package/dist/ui/components/surface-tokens.d.ts +1 -1
  159. package/dist/ui/components/surface-tokens.js +4 -0
  160. package/package.json +1 -1
@@ -15,7 +15,8 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
15
15
  * nor LetItRip admins can influence the outcome.
16
16
  */
17
17
  import { useCallback, useEffect, useRef, useState } from "react";
18
- import { Button, Div, Heading, LoginRequiredModal, Modal, Span, Stack, Text, useToast } from "../../../ui";
18
+ import { Anchor, Button, Div, Heading, LoginRequiredModal, Modal, Span, Stack, Text, useToast } from "../../../ui";
19
+ import { MediaImage } from "../../media/MediaImage";
19
20
  import { isAuthError } from "../../../utils/auth-error";
20
21
  import { PrizeDrawCollage } from "./PrizeDrawCollage";
21
22
  import { normalizeError } from "../../../errors/normalize";
@@ -149,8 +150,6 @@ export function PrizeRevealModal({ open, onClose, items, orderId, productId, onR
149
150
  }, REVEAL_DURATION_MS);
150
151
  }, [onReveal, orderId, phase, productId, startAnimation]);
151
152
  const winnerImg = winner?.images?.[0];
152
- return (_jsxs(Modal, { isOpen: open, onClose: onClose, title: "Prize Reveal", size: "lg", children: [_jsx(LoginRequiredModal, { isOpen: showLoginModal, onClose: () => setShowLoginModal(false), message: "You need to be signed in to reveal your prize. Please log in or create an account to continue." }), _jsxs(Stack, { gap: "md", children: [phase === "refunded" ? (_jsxs(Div, { className: CLS_REFUND_NOTE, children: [_jsx(Heading, { level: 3, className: "mb-1", children: "Pool exhausted \u2014 you've been refunded" }), _jsx(Text, { size: "sm", children: "Every prize in this draw was already claimed by the time your entry rolled. Your order has been marked refunded automatically." })] })) : null, phase === "error" ? (_jsxs(Div, { className: "border border-error/40", color: "error", surface: "danger-surface", padding: "inline", rounded: "default", children: [_jsx(Text, { size: "sm", weight: "semibold", children: "Something went wrong" }), _jsx(Text, { size: "sm", children: errorMessage })] })) : null, _jsx(PrizeDrawCollage, { items: items, hideWonState: true, highlightItemNumber: highlight }), phase === "idle" ? (_jsx(Button, { type: "button", variant: "primary", size: "lg", onClick: handleRevealClick, children: "\u2728 Reveal my prize" })) : null, phase === "revealing" ? (_jsxs(Div, { className: `bg-[var(--appkit-color-surface-muted)] ${__P.p4} text-center`, rounded: "default", children: [_jsx(Text, { size: "lg", weight: "semibold", children: "Rolling\u2026" }), _jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", size: "sm", children: "The winner was locked by the server before this animation started. Hang tight \u2014 we're just making it look pretty." })] })) : null, phase === "won" && winner ? (_jsxs(Div, { className: `border-2 border-[var(--appkit-color-primary)] bg-[var(--appkit-color-surface)] ${__P.p4} text-center`, rounded: "lg", children: [_jsx(Text, { className: "tracking-wider text-[var(--appkit-color-text-muted)]", size: "xs", transform: "uppercase", children: "You won" }), _jsxs(Heading, { level: 2, className: "my-2", children: ["#", winner.itemNumber, " \u2014 ", winner.title] }), winnerImg ? (
153
- /* eslint-disable-next-line @next/next/no-img-element */
154
- _jsx("img", { src: winnerImg, alt: winner.title, className: "mx-auto max-h-64 rounded" })) : null, winner.estimatedValue != null ? (_jsxs(Text, { className: "mt-2 text-[var(--appkit-color-text-muted)]", size: "sm", children: ["Estimated value: \u20B9", (winner.estimatedValue / 100).toLocaleString("en-IN")] })) : null] })) : null, _jsxs(Div, { textSize: "xs", className: "border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface-muted)] text-[var(--appkit-color-text-muted)]", padding: "inlineSm", rounded: "default", children: [_jsx(Span, { weight: "bold", children: "Fairness guarantee:" }), " ", "Winners are picked by ", _jsx("code", { children: "crypto.randomInt" }), " running on LetItRip's server before the animation starts. The animation is theatrical \u2014 neither the store nor LetItRip staff can influence the outcome.", " ", effectiveRngUrl ? (_jsx("a", { href: effectiveRngUrl, target: "_blank", rel: "noreferrer noopener", className: "underline", children: "View RNG source code \u2192" })) : null] })] })] }));
153
+ return (_jsxs(Modal, { isOpen: open, onClose: onClose, title: "Prize Reveal", size: "lg", children: [_jsx(LoginRequiredModal, { isOpen: showLoginModal, onClose: () => setShowLoginModal(false), message: "You need to be signed in to reveal your prize. Please log in or create an account to continue." }), _jsxs(Stack, { gap: "md", children: [phase === "refunded" ? (_jsxs(Div, { className: CLS_REFUND_NOTE, children: [_jsx(Heading, { level: 3, className: "mb-1", children: "Pool exhausted \u2014 you've been refunded" }), _jsx(Text, { size: "sm", children: "Every prize in this draw was already claimed by the time your entry rolled. Your order has been marked refunded automatically." })] })) : null, phase === "error" ? (_jsxs(Div, { className: "border border-error/40", color: "error", surface: "danger-surface", padding: "inline", rounded: "default", children: [_jsx(Text, { size: "sm", weight: "semibold", children: "Something went wrong" }), _jsx(Text, { size: "sm", children: errorMessage })] })) : null, _jsx(PrizeDrawCollage, { items: items, hideWonState: true, highlightItemNumber: highlight }), phase === "idle" ? (_jsx(Button, { type: "button", variant: "primary", size: "lg", onClick: handleRevealClick, children: "\u2728 Reveal my prize" })) : null, phase === "revealing" ? (_jsxs(Div, { className: `bg-[var(--appkit-color-surface-muted)] ${__P.p4} text-center`, rounded: "default", children: [_jsx(Text, { size: "lg", weight: "semibold", children: "Rolling\u2026" }), _jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", size: "sm", children: "The winner was locked by the server before this animation started. Hang tight \u2014 we're just making it look pretty." })] })) : null, phase === "won" && winner ? (_jsxs(Div, { className: `border-2 border-[var(--appkit-color-primary)] bg-[var(--appkit-color-surface)] ${__P.p4} text-center`, rounded: "lg", children: [_jsx(Text, { className: "tracking-wider text-[var(--appkit-color-text-muted)]", size: "xs", transform: "uppercase", children: "You won" }), _jsxs(Heading, { level: 2, className: "my-2", children: ["#", winner.itemNumber, " \u2014 ", winner.title] }), winnerImg ? (_jsx(Div, { className: "relative mx-auto h-64 w-64 max-w-full overflow-hidden", rounded: "md", children: _jsx(MediaImage, { src: winnerImg, alt: winner.title, size: "hero", objectFit: "contain" }) })) : null, winner.estimatedValue != null ? (_jsxs(Text, { className: "mt-2 text-[var(--appkit-color-text-muted)]", size: "sm", children: ["Estimated value: \u20B9", (winner.estimatedValue / 100).toLocaleString("en-IN")] })) : null] })) : null, _jsxs(Div, { textSize: "xs", className: "border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface-muted)] text-[var(--appkit-color-text-muted)]", padding: "inlineSm", rounded: "default", children: [_jsx(Span, { weight: "bold", children: "Fairness guarantee:" }), " ", "Winners are picked by ", _jsx("code", { children: "crypto.randomInt" }), " running on LetItRip's server before the animation starts. The animation is theatrical \u2014 neither the store nor LetItRip staff can influence the outcome.", " ", effectiveRngUrl ? (_jsx(Anchor, { href: effectiveRngUrl, tone: "none", underline: "always", children: "View RNG source code \u2192" })) : null] })] })] }));
155
154
  }
156
155
  export default PrizeRevealModal;
@@ -22,4 +22,4 @@ export interface ProductDetailActionsProps {
22
22
  * to the server APIs with guest-fallback. Replaces the previously-unwired
23
23
  * placeholder buttons inside ProductDetailPageView.
24
24
  */
25
- export declare function ProductDetailActions({ productId, productSlug, productTitle, productImage, price, currency, storeId, storeName, inStock, variant, }: ProductDetailActionsProps): import("react").JSX.Element;
25
+ export declare function ProductDetailActions({ productId, productSlug: _productSlug, productTitle, productImage, price, currency, storeId, storeName, inStock, variant, }: ProductDetailActionsProps): import("react").JSX.Element;
@@ -18,7 +18,7 @@ import { normalizeError } from "../../../errors/normalize";
18
18
  * to the server APIs with guest-fallback. Replaces the previously-unwired
19
19
  * placeholder buttons inside ProductDetailPageView.
20
20
  */
21
- export function ProductDetailActions({ productId, productSlug, productTitle, productImage, price, currency, storeId, storeName, inStock, variant = "desktop", }) {
21
+ export function ProductDetailActions({ productId, productSlug: _productSlug, productTitle, productImage, price, currency, storeId, storeName, inStock, variant = "desktop", }) {
22
22
  const router = useRouter();
23
23
  const { showToast } = useToast();
24
24
  const { requireAuth, modalOpen, modalMessage, closeModal } = useAuthGate();
@@ -44,5 +44,7 @@ export interface ProductDetailPageViewProps {
44
44
  productFeatures?: ProductFeatureDocument[];
45
45
  /** Site-wide COD availability (`siteSettings.payment.codEnabled`), threaded from the page's data layer. Drives the "Cash on Delivery" feature badge. */
46
46
  codEnabled?: boolean;
47
+ /** Site-wide EMI availability (`siteSettings.emi.enabled`), threaded from the page's data layer. Drives the "EMI Available" feature badge. */
48
+ emiEnabled?: boolean;
47
49
  }
48
- export declare function ProductDetailPageView({ slug, initialProduct, renderOfferAction, renderPrimaryActions, productFeatures, codEnabled, }: ProductDetailPageViewProps): Promise<import("react").JSX.Element>;
50
+ export declare function ProductDetailPageView({ slug, initialProduct, renderOfferAction, renderPrimaryActions, productFeatures, codEnabled, emiEnabled, }: ProductDetailPageViewProps): Promise<import("react").JSX.Element>;
@@ -106,7 +106,7 @@ function StarRating({ value }) {
106
106
  // ---------------------------------------------------------------------------
107
107
  // Component
108
108
  // ---------------------------------------------------------------------------
109
- export async function ProductDetailPageView({ slug, initialProduct, renderOfferAction, renderPrimaryActions, productFeatures, codEnabled, }) {
109
+ export async function ProductDetailPageView({ slug, initialProduct, renderOfferAction, renderPrimaryActions, productFeatures, codEnabled, emiEnabled, }) {
110
110
  // Use pre-fetched data when available to avoid a redundant repository call.
111
111
  // The page layer wraps getProductForDetail in React.cache(), so both
112
112
  // generateMetadata() and this component share the same in-flight promise.
@@ -262,7 +262,7 @@ export async function ProductDetailPageView({ slug, initialProduct, renderOfferA
262
262
  ? ` — only ${effectiveStock} left`
263
263
  : ""] })] })) : (_jsxs(Span, { layout: "inline-flex", gap: "xs", className: `w-fit .5 ${inStock ? CLS_STOCK_IN : CLS_STOCK_OUT}`, rounded: "full", padding: "pill-md", size: "xs", weight: "medium", children: [inStock ? "✓ In Stock" : "✗ Out of Stock", inStock && effectiveStock !== null && effectiveStock <= 10
264
264
  ? ` — only ${effectiveStock} left`
265
- : ""] })), (categorySlugs.length > 0 || subcategory || brand) && (_jsxs(Row, { gap: "sm", wrap: true, children: [categorySlugs.map((slug, i) => (_jsx(Link, { href: String(ROUTES.PUBLIC.CATEGORY_DETAIL(slug)), className: "inline-flex items-center rounded-full border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] px-2.5 py-1 text-xs font-medium text-[var(--appkit-color-text-muted)] transition-colors hover:border-primary-300 hover:bg-primary-50 hover:text-primary-700 dark:hover:border-primary-700/60 dark:hover:bg-primary-900/20 dark:hover:text-primary-400", children: categoryNames[i] ?? slug }, slug))), subcategory && (_jsx(Span, { layout: "inline-flex", size: "xs", weight: "medium", border: "subtle", rounded: "full", padding: "pill-sm-tall", surface: "muted", color: "muted", transform: "capitalize", children: subcategory })), brand && brandSlug && (_jsx(Link, { href: String(ROUTES.PUBLIC.BRAND_DETAIL(brandSlug)), className: "inline-flex items-center rounded-full border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] px-2.5 py-1 text-xs font-medium text-[var(--appkit-color-text-muted)] transition-colors hover:border-primary-300 hover:bg-primary-50 hover:text-primary-700 dark:hover:border-primary-700/60 dark:hover:bg-primary-900/20 dark:hover:text-primary-400", children: brand })), brand && !brandSlug && (_jsx(Span, { layout: "inline-flex", size: "xs", weight: "medium", border: "subtle", rounded: "full", padding: "pill-sm-tall", surface: "muted", color: "muted", children: brand }))] })), bundleMemberships.length > 0 && (_jsx(Row, { gap: "sm", wrap: true, children: bundleMemberships.map((b) => (_jsxs(Link, { href: String(ROUTES.PUBLIC.BUNDLE_DETAIL(b.id)), className: CLS_BUNDLE_PILL, children: [_jsx(Span, { "aria-hidden": "true", children: "\uD83D\uDCE6" }), "In bundle: ", b.title] }, b.id))) })), _jsx(ProductFeatureBadges, { featured: featured, freeShipping: freeShipping, codAvailable: codEnabled === true, condition: condition ?? undefined, returnable: returnPolicy != null && returnPolicy.length > 0, labels: {
265
+ : ""] })), (categorySlugs.length > 0 || subcategory || brand) && (_jsxs(Row, { gap: "sm", wrap: true, children: [categorySlugs.map((slug, i) => (_jsx(Link, { href: String(ROUTES.PUBLIC.CATEGORY_DETAIL(slug)), className: "inline-flex items-center rounded-full border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] px-2.5 py-1 text-xs font-medium text-[var(--appkit-color-text-muted)] transition-colors hover:border-primary-300 hover:bg-primary-50 hover:text-primary-700 dark:hover:border-primary-700/60 dark:hover:bg-primary-900/20 dark:hover:text-primary-400", children: categoryNames[i] ?? slug }, slug))), subcategory && (_jsx(Span, { layout: "inline-flex", size: "xs", weight: "medium", border: "subtle", rounded: "full", padding: "pill-sm-tall", surface: "muted", color: "muted", transform: "capitalize", children: subcategory })), brand && brandSlug && (_jsx(Link, { href: String(ROUTES.PUBLIC.BRAND_DETAIL(brandSlug)), className: "inline-flex items-center rounded-full border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] px-2.5 py-1 text-xs font-medium text-[var(--appkit-color-text-muted)] transition-colors hover:border-primary-300 hover:bg-primary-50 hover:text-primary-700 dark:hover:border-primary-700/60 dark:hover:bg-primary-900/20 dark:hover:text-primary-400", children: brand })), brand && !brandSlug && (_jsx(Span, { layout: "inline-flex", size: "xs", weight: "medium", border: "subtle", rounded: "full", padding: "pill-sm-tall", surface: "muted", color: "muted", children: brand }))] })), bundleMemberships.length > 0 && (_jsx(Row, { gap: "sm", wrap: true, children: bundleMemberships.map((b) => (_jsxs(Link, { href: String(ROUTES.PUBLIC.BUNDLE_DETAIL(b.id)), className: CLS_BUNDLE_PILL, children: [_jsx(Span, { "aria-hidden": "true", children: "\uD83D\uDCE6" }), "In bundle: ", b.title] }, b.id))) })), _jsx(ProductFeatureBadges, { featured: featured, freeShipping: freeShipping, codAvailable: codEnabled === true, codHref: String(ROUTES.PUBLIC.HOW_CHECKOUT_WORKS), emiAvailable: emiEnabled === true, emiHref: String(ROUTES.PUBLIC.HOW_EMI_WORKS), condition: condition ?? undefined, returnable: returnPolicy != null && returnPolicy.length > 0, labels: {
266
266
  featured: "Featured",
267
267
  fasterDelivery: "Faster Delivery",
268
268
  ratedSeller: "Rated Seller",
@@ -274,6 +274,7 @@ export async function ProductDetailPageView({ slug, initialProduct, renderOfferA
274
274
  returnable: "Returnable",
275
275
  freeShipping: "Free Shipping",
276
276
  codAvailable: "Cash on Delivery",
277
+ emiAvailable: "EMI Available",
277
278
  wishlistCount: (n) => `${n} wishlisted`,
278
279
  categoryProductCount: (n, cat) => `${n} in ${cat}`,
279
280
  } }), productFeatures && features.length > 0 && (_jsx(FeatureBadgeList, { productFeatureIds: features, features: productFeatures })), !productFeatures && features.length > 0 && (_jsxs(Div, { border: "subtle", surface: "muted", padding: "inline", rounded: "xl", children: [_jsx(Text, { className: "mb-2 tracking-wide", color: "muted", size: "xs", weight: "semibold", transform: "uppercase", children: "About this product" }), _jsx(Ul, { spacing: "comfortable", size: "sm", color: "primary", children: features.map((f, i) => (_jsxs(Li, { layout: "flex-start", gap: "2", 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-[var(--appkit-color-text-muted)] line-clamp-4" })), safeSeller && (_jsx(Div, { className: `${__P.p3}`, border: "subtle", rounded: "xl", surface: "muted", children: _jsxs(Row, { justify: "between", align: "center", children: [_jsxs(Div, { children: [_jsx(Text, { className: "text-[10px] tracking-wide mb-0.5", color: "faint", transform: "uppercase", children: "Sold by" }), _jsx(Text, { size: "sm", weight: "semibold", color: "primary", children: safeSeller }), typeof p.storeRating === "number" && p.storeRating > 0 && (_jsx(Row, { gap: "xs", align: "center", className: "mt-0.5", children: _jsxs(Text, { size: "xs", color: "muted", children: [_jsx(Span, { className: "text-warning", "aria-hidden": "true", children: "\u2605" }), " ", p.storeRating.toFixed(1), typeof p.storeReviewCount === "number" &&
@@ -10,6 +10,7 @@ interface ProductFeatureBadgeLabels {
10
10
  returnable: string;
11
11
  freeShipping: string;
12
12
  codAvailable: string;
13
+ emiAvailable: string;
13
14
  wishlistCount: (count: number) => string;
14
15
  categoryProductCount: (count: string, category: string) => string;
15
16
  }
@@ -24,9 +25,14 @@ interface ProductFeatureBadgesProps {
24
25
  categoryProductCount?: number;
25
26
  categoryName?: string;
26
27
  codAvailable?: boolean;
28
+ /** When set, the COD badge links here (e.g. the "How Checkout Works" policy page). */
29
+ codHref?: string;
30
+ emiAvailable?: boolean;
31
+ /** When set, the EMI badge links here (e.g. the "How EMI Works" policy page). */
32
+ emiHref?: string;
27
33
  labels: ProductFeatureBadgeLabels;
28
34
  formatCount?: (value: number) => string;
29
35
  categoryBadgeClassName?: string;
30
36
  }
31
- export declare function ProductFeatureBadges({ featured, fasterDelivery, ratedSeller, condition, returnable, freeShipping, wishlistCount, categoryProductCount, categoryName, codAvailable, labels, formatCount, categoryBadgeClassName, }: ProductFeatureBadgesProps): import("react").JSX.Element | null;
37
+ export declare function ProductFeatureBadges({ featured, fasterDelivery, ratedSeller, condition, returnable, freeShipping, wishlistCount, categoryProductCount, categoryName, codAvailable, codHref, emiAvailable, emiHref, labels, formatCount, categoryBadgeClassName, }: ProductFeatureBadgesProps): import("react").JSX.Element | null;
32
38
  export {};
@@ -1,6 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Row, Span } from "../../../ui";
3
- export function ProductFeatureBadges({ featured, fasterDelivery, ratedSeller, condition, returnable, freeShipping, wishlistCount, categoryProductCount, categoryName, codAvailable, labels, formatCount, categoryBadgeClassName, }) {
2
+ import { Fragment } from "react";
3
+ import { Row, Span, TextLink } from "../../../ui";
4
+ export function ProductFeatureBadges({ featured, fasterDelivery, ratedSeller, condition, returnable, freeShipping, wishlistCount, categoryProductCount, categoryName, codAvailable, codHref, emiAvailable, emiHref, labels, formatCount, categoryBadgeClassName, }) {
4
5
  const badges = [];
5
6
  if (featured) {
6
7
  badges.push({
@@ -72,6 +73,17 @@ export function ProductFeatureBadges({ featured, fasterDelivery, ratedSeller, co
72
73
  label: labels.codAvailable,
73
74
  colorClass: "text-purple-700 dark:text-purple-300",
74
75
  bgClass: "bg-purple-50 dark:bg-purple-900/30 border-purple-200 dark:border-purple-800",
76
+ href: codHref,
77
+ });
78
+ }
79
+ if (emiAvailable) {
80
+ badges.push({
81
+ key: "emi",
82
+ icon: _jsx(Span, { size: "xs", children: "\uD83D\uDCC5" }),
83
+ label: labels.emiAvailable,
84
+ colorClass: "text-indigo-700 dark:text-indigo-300",
85
+ bgClass: "bg-indigo-50 dark:bg-indigo-900/30 border-indigo-200 dark:border-indigo-800",
86
+ href: emiHref,
75
87
  });
76
88
  }
77
89
  if (wishlistCount && wishlistCount > 0) {
@@ -98,5 +110,6 @@ export function ProductFeatureBadges({ featured, fasterDelivery, ratedSeller, co
98
110
  }
99
111
  if (badges.length === 0)
100
112
  return null;
101
- return (_jsx(Row, { wrap: true, gap: "sm", children: badges.map((badge) => (_jsxs(Span, { layout: "inline-flex", gap: "xs", className: `.5 border py-[0.375rem] ${badge.bgClass} ${badge.colorClass}`, rounded: "lg", padding: "x-sm", size: "xs", weight: "medium", children: [_jsx(Span, { "aria-hidden": "true", children: badge.icon }), badge.label] }, badge.key))) }));
113
+ const renderPill = (badge) => (_jsxs(Span, { layout: "inline-flex", gap: "xs", className: `.5 border py-[0.375rem] ${badge.bgClass} ${badge.colorClass}`, rounded: "lg", padding: "x-sm", size: "xs", weight: "medium", children: [_jsx(Span, { "aria-hidden": "true", children: badge.icon }), badge.label] }));
114
+ return (_jsx(Row, { wrap: true, gap: "sm", children: badges.map((badge) => badge.href ? (_jsx(TextLink, { href: badge.href, className: "no-underline", children: renderPill(badge) }, badge.key)) : (_jsx(Fragment, { children: renderPill(badge) }, badge.key))) }));
102
115
  }
@@ -20,7 +20,7 @@ export function ProductGalleryClient({ images, productName }) {
20
20
  return (_jsx(Div, { className: `${__O.hidden}`, border: "subtle", rounded: "xl", surface: "muted", children: _jsx(Row, { className: "aspect-square text-[var(--appkit-color-border)] dark:text-[var(--appkit-color-border-subtle)]", align: "center", justify: "center", children: _jsx(PlaceholderSvg, {}) }) }));
21
21
  }
22
22
  const mainImage = images[activeIndex] ?? images[0];
23
- return (_jsxs(Stack, { gap: "3", children: [_jsx(Div, { className: "overflow-hidden rounded-xl border border-[var(--appkit-color-border-subtle)] cursor-zoom-in aspect-square w-full", onClick: () => setLightboxIndex(activeIndex), role: "button", tabIndex: 0, onKeyDown: (e) => {
23
+ return (_jsxs(Stack, { gap: "3", children: [_jsx(Div, { rounded: "xl", className: "overflow-hidden border border-[var(--appkit-color-border-subtle)] cursor-zoom-in aspect-square w-full", onClick: () => setLightboxIndex(activeIndex), role: "button", tabIndex: 0, onKeyDown: (e) => {
24
24
  if (e.key === "Enter" || e.key === " ")
25
25
  setLightboxIndex(activeIndex);
26
26
  }, "aria-label": `View ${productName ?? "product"} image in full screen`, children: _jsx(MediaImage, { src: mainImage, alt: productName ? `${productName} — image ${activeIndex + 1}` : `Product image ${activeIndex + 1}`, size: "gallery", className: "transition-transform duration-300 hover:scale-105" }) }), images.length > 1 && (_jsx(Div, { layout: "flex", gap: "2", className: `${__O.xAuto}`, padding: "b-2xs", children: images.map((src, i) => (_jsx("button", { type: "button", onClick: () => setActiveIndex(i), className: `flex-shrink-0 h-16 w-16 overflow-hidden rounded-lg border-2 transition-all${i === activeIndex
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
- import { Div, Heading, Row, Stack, Text } from "../../../ui";
3
+ import { Anchor, Div, Heading, Row, Stack, Text } from "../../../ui";
4
4
  import { Badge } from "../../../ui/components/Badge";
5
5
  import { MediaImage } from "../../media/MediaImage";
6
6
  const __O = {
@@ -25,5 +25,5 @@ function buildCertLookupUrl(service, certNumber) {
25
25
  */
26
26
  export function ProductGradingTab({ grading, slabImageUrl }) {
27
27
  const lookupUrl = buildCertLookupUrl(grading.service, grading.certNumber);
28
- return (_jsxs(Stack, { gap: "lg", children: [_jsxs(Row, { align: "center", gap: "md", children: [_jsxs(Stack, { justify: "center", className: "border-2 border-[var(--appkit-color-primary)] min-w-[120px]", padding: "inlineLg", align: "center", rounded: "2xl", children: [_jsx(Text, { className: "tracking-wide", color: "muted", size: "xs", weight: "bold", transform: "uppercase", children: grading.service }), _jsx(Text, { className: "font-extrabold", size: "4xl", children: grading.grade })] }), _jsxs(Stack, { gap: "xs", className: "flex-1", children: [_jsxs(Heading, { level: 3, size: "base", weight: "semibold", children: ["Graded by ", grading.service] }), grading.certNumber ? (_jsxs(Text, { size: "sm", color: "muted", children: ["Cert #", grading.certNumber, lookupUrl ? (_jsxs(_Fragment, { children: [" — ", _jsx("a", { href: lookupUrl, target: "_blank", rel: "noopener noreferrer", className: "text-[var(--appkit-color-primary)] hover:underline", children: "Verify" })] })) : null] })) : null] })] }), slabImageUrl ? (_jsx(Div, { className: `${__O.hidden} aspect-[4/3] w-full`, rounded: "2xl", border: "default", children: _jsx(MediaImage, { src: slabImageUrl, alt: "Slab certificate image", size: "gallery", objectFit: "contain" }) })) : null, grading.attributes && Object.keys(grading.attributes).length > 0 ? (_jsxs(Stack, { gap: "sm", children: [_jsx(Heading, { level: 3, className: "tracking-wide", color: "muted", size: "sm", weight: "semibold", transform: "uppercase", children: "Subgrades & attributes" }), _jsx(Row, { wrap: true, gap: "sm", children: Object.entries(grading.attributes).map(([key, value]) => (_jsxs(Badge, { variant: "default", children: [key, ": ", value] }, key))) })] })) : null] }));
28
+ return (_jsxs(Stack, { gap: "lg", children: [_jsxs(Row, { align: "center", gap: "md", children: [_jsxs(Stack, { justify: "center", className: "border-2 border-[var(--appkit-color-primary)] min-w-[120px]", padding: "inlineLg", align: "center", rounded: "2xl", children: [_jsx(Text, { className: "tracking-wide", color: "muted", size: "xs", weight: "bold", transform: "uppercase", children: grading.service }), _jsx(Text, { className: "font-extrabold", size: "4xl", children: grading.grade })] }), _jsxs(Stack, { gap: "xs", className: "flex-1", children: [_jsxs(Heading, { level: 3, size: "base", weight: "semibold", children: ["Graded by ", grading.service] }), grading.certNumber ? (_jsxs(Text, { size: "sm", color: "muted", children: ["Cert #", grading.certNumber, lookupUrl ? (_jsxs(_Fragment, { children: [" — ", _jsx(Anchor, { href: lookupUrl, tone: "none", underline: "hover", className: "text-[var(--appkit-color-primary)]", children: "Verify" })] })) : null] })) : null] })] }), slabImageUrl ? (_jsx(Div, { className: `${__O.hidden} aspect-[4/3] w-full`, rounded: "2xl", border: "default", children: _jsx(MediaImage, { src: slabImageUrl, alt: "Slab certificate image", size: "gallery", objectFit: "contain" }) })) : null, grading.attributes && Object.keys(grading.attributes).length > 0 ? (_jsxs(Stack, { gap: "sm", children: [_jsx(Heading, { level: 3, className: "tracking-wide", color: "muted", size: "sm", weight: "semibold", transform: "uppercase", children: "Subgrades & attributes" }), _jsx(Row, { wrap: true, gap: "sm", children: Object.entries(grading.attributes).map(([key, value]) => (_jsxs(Badge, { variant: "default", children: [key, ": ", value] }, key))) })] })) : null] }));
29
29
  }
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { productRepository } from "../../../repositories";
3
3
  import { ROUTES } from "../../../constants";
4
- import { Container, Div, Heading, Main, Section, Text } from "../../../ui";
4
+ import { Container, Div, Heading, Main, Section, Text, TextLink } from "../../../ui";
5
5
  import { AdSlot } from "../../homepage/components/AdSlot";
6
6
  import { parseListingSearchParams } from "../../../utils/listing-params";
7
7
  import { ProductsIndexListing } from "./ProductsIndexListing";
@@ -59,5 +59,5 @@ export async function ProductsIndexPageView({ searchParams = {} }) {
59
59
  })
60
60
  .catch(() => null);
61
61
  const products = result ?? null;
62
- return (_jsxs(Main, { children: [_jsx(Section, { border: "bottom-subtle", paddingY: "b-md", padding: "t-xl", children: _jsxs(Container, { size: "xl", children: [_jsx(Heading, { level: 1, size: "3xl", weight: "bold", color: "primary", children: "Products" }), _jsx(Text, { className: "mt-1", color: "muted", size: "sm", children: "Discover amazing products and deals" }), _jsx(Div, { className: "mt-3", children: _jsx("a", { href: ROUTES.PUBLIC.AUCTIONS, className: "inline-flex items-center gap-1.5 rounded-full border border-primary/30 bg-primary/10 px-4 py-1.5 text-xs font-medium text-primary-700 dark:text-primary-400 hover:bg-primary/15 transition-colors", children: "\uD83C\uDFF7\uFE0F Looking for unique deals? Browse Auctions \u2192" }) })] }) }), _jsxs(Container, { size: "xl", padding: "x-md", children: [_jsx(AdSlot, { id: "listing-sidebar-top", className: "mb-4 mt-4" }), _jsx(ProductsIndexListing, { initialData: products }), _jsx(AdSlot, { id: "listing-sidebar-bottom", className: "mt-8" })] })] }));
62
+ return (_jsxs(Main, { children: [_jsx(Section, { border: "bottom-subtle", paddingY: "b-md", padding: "t-xl", children: _jsxs(Container, { size: "xl", children: [_jsx(Heading, { level: 1, size: "3xl", weight: "bold", color: "primary", children: "Products" }), _jsx(Text, { className: "mt-1", color: "muted", size: "sm", children: "Discover amazing products and deals" }), _jsx(Div, { className: "mt-3", children: _jsx(TextLink, { variant: "bare", href: String(ROUTES.PUBLIC.AUCTIONS), rounded: "full", paddingX: "sm", size: "xs", weight: "medium", layout: "inline-flex", align: "center", gap: "sm", className: "border border-primary/30 bg-primary/10 py-1.5 text-primary-700 dark:text-primary-400 hover:bg-primary/15 transition-colors", children: "\uD83C\uDFF7\uFE0F Looking for unique deals? Browse Auctions \u2192" }) })] }) }), _jsxs(Container, { size: "xl", padding: "x-md", children: [_jsx(AdSlot, { id: "listing-sidebar-top", className: "mb-4 mt-4" }), _jsx(ProductsIndexListing, { initialData: products }), _jsx(AdSlot, { id: "listing-sidebar-bottom", className: "mt-8" })] })] }));
63
63
  }
@@ -19,7 +19,7 @@ function MemberThumb({ member, isCurrent }) {
19
19
  const image = member.images?.[0] ?? "";
20
20
  const href = memberHref(member);
21
21
  const price = formatCurrency(member.price, member.currency ?? "INR");
22
- return (_jsxs(Link, { href: href, "aria-label": member.title, className: "flex flex-col items-center gap-1.5 flex-shrink-0 w-16 group", children: [_jsxs(Div, { className: `relative w-14 h-14 rounded-full overflow-hidden border-2 transition-all ${isCurrent
22
+ return (_jsxs(Link, { href: href, "aria-label": member.title, className: "flex flex-col items-center gap-1.5 flex-shrink-0 w-16 group", children: [_jsxs(Div, { rounded: "full", className: `relative w-14 h-14 overflow-hidden border-2 transition-all ${isCurrent
23
23
  ? "border-[var(--appkit-color-primary)] ring-2 ring-[var(--appkit-color-primary)]/30"
24
24
  : "border-[var(--appkit-color-border)] group-hover:border-[var(--appkit-color-primary)]"}`, children: [_jsx(MediaImage, { src: image, alt: member.title, size: "card" }), member.isGroupParent && (_jsx(Span, { color: "inverse", rounded: "sm", className: "absolute bottom-0 right-0 bg-[var(--appkit-color-primary)] text-[8px] leading-none px-[0.25rem] py-[0.125rem]", children: "Set" }))] }), _jsx(Text, { className: "text-[10px] leading-tight line-clamp-2 w-full", color: "muted", align: "center", children: member.title }), _jsx(Text, { className: "text-[10px]", color: "primary", weight: "semibold", children: price })] }));
25
25
  }
@@ -4,6 +4,7 @@ import { useEffect, useState } from "react";
4
4
  import Link from "next/link";
5
5
  import { ROUTES } from "../../../next";
6
6
  import { Div, Row, Span, Text } from "../../../ui";
7
+ import { MediaImage } from "../../media/MediaImage";
7
8
  import { formatCurrency } from "../../../utils/number.formatter";
8
9
  import { normalizeListingType } from "../utils/listing-type";
9
10
  import { pluginFor } from "../../../_internal/shared/listing-types/_registry";
@@ -19,11 +20,9 @@ function ListingThumb({ listing, isCurrent, }) {
19
20
  const image = listing.images?.[0] ?? listing.mainImage ?? "";
20
21
  const href = getHref(listing);
21
22
  const price = formatCurrency(listing.price, listing.currency ?? "INR");
22
- return (_jsxs(Link, { href: href, "aria-label": listing.title, className: "flex flex-col items-center gap-1.5 flex-shrink-0 w-16 group", children: [_jsx(Div, { className: `w-14 h-14 rounded-full overflow-hidden border-2 transition-all ${isCurrent
23
+ return (_jsxs(Link, { href: href, "aria-label": listing.title, className: "flex flex-col items-center gap-1.5 flex-shrink-0 w-16 group", children: [_jsx(Div, { rounded: "full", className: `relative w-14 h-14 overflow-hidden border-2 transition-all ${isCurrent
23
24
  ? "border-[var(--appkit-color-primary)] ring-2 ring-[var(--appkit-color-primary)]/30"
24
- : "border-[var(--appkit-color-border)] group-hover:border-[var(--appkit-color-primary)]"}`, children: image ? (
25
- // eslint-disable-next-line @next/next/no-img-element
26
- _jsx("img", { src: image, alt: listing.title, className: "w-full h-full object-cover", loading: "lazy" })) : (_jsx(Row, { textSize: "xs", color: "faint", className: "w-full h-full", surface: "subtle", align: "center", justify: "center", children: "\u00E2\u2014\u00AF" })) }), _jsx(Text, { className: "text-[10px] leading-tight line-clamp-2 w-full", color: "muted", align: "center", children: listing.title }), _jsx(Text, { className: "text-[10px]", color: "primary", weight: "semibold", children: price })] }));
25
+ : "border-[var(--appkit-color-border)] group-hover:border-[var(--appkit-color-primary)]"}`, children: image ? (_jsx(MediaImage, { src: image, alt: listing.title, size: "avatar" })) : (_jsx(Row, { textSize: "xs", color: "faint", className: "w-full h-full", surface: "subtle", align: "center", justify: "center", children: "\u00E2\u2014\u00AF" })) }), _jsx(Text, { className: "text-[10px] leading-tight line-clamp-2 w-full", color: "muted", align: "center", children: listing.title }), _jsx(Text, { className: "text-[10px]", color: "primary", weight: "semibold", children: price })] }));
27
26
  }
28
27
  export function SublistingCarouselSection({ sublistingCategoryId, currentListingId }) {
29
28
  const [open, setOpen] = useState(false);
@@ -7,4 +7,4 @@ export interface CouponsIndexListingProps {
7
7
  /** If set, only show coupons from this store (id, for filtering) */
8
8
  storeId?: string;
9
9
  }
10
- export declare function CouponsIndexListing({ initialCoupons, storeSlug, storeId, }: CouponsIndexListingProps): React.JSX.Element;
10
+ export declare function CouponsIndexListing({ initialCoupons, storeSlug: _storeSlug, storeId, }: CouponsIndexListingProps): React.JSX.Element;
@@ -28,7 +28,7 @@ const COUPON_TYPES = [
28
28
  { value: COUPON_FIELDS.TYPE_VALUES.BUY_X_GET_Y, label: "Buy X Get Y" },
29
29
  ];
30
30
  const FILTER_KEYS = [TABLE_KEYS.TYPE, TABLE_KEYS.DATE_FROM, TABLE_KEYS.DATE_TO];
31
- export function CouponsIndexListing({ initialCoupons, storeSlug, storeId, }) {
31
+ export function CouponsIndexListing({ initialCoupons, storeSlug: _storeSlug, storeId, }) {
32
32
  const table = useUrlTable({ defaults: { pageSize: "12", sort: DEFAULT_SORT } });
33
33
  const [searchInput, setSearchInput] = useState(table.get(TABLE_KEYS.QUERY) || "");
34
34
  const [filterOpen, setFilterOpen] = useState(false);
@@ -19,6 +19,7 @@ const CLS_ICON_PURPLE = "flex h-10 w-10 flex-shrink-0 items-center justify-cente
19
19
  const CLS_ICON_PURPLE_BARE = "flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-lg bg-purple-100 dark:bg-purple-900/30";
20
20
  import Link from "next/link";
21
21
  import { Div, Grid, Heading, RichText, Row, Section, Span, StarRating, Stack, Text } from "../../../ui";
22
+ import { MediaImage } from "../../media/MediaImage";
22
23
  import { maskName } from "../../../security";
23
24
  import { getDefaultLocale } from "../../../core/baseline-resolver";
24
25
  import { normalizeRichTextHtml } from "../../../utils/string.formatter";
@@ -91,9 +92,9 @@ export function ReviewDetailShell({ review, storeHref }) {
91
92
  ? String(ROUTES.PUBLIC.PROFILE(reviewerProfileId))
92
93
  : null;
93
94
  const currentImage = lightboxIdx !== null ? images[lightboxIdx] : null;
94
- return (_jsxs(_Fragment, { children: [_jsx(Div, { surface: "default", className: "border-b border-neutral-200 pt-[2.5rem]", padding: "b-xl", children: _jsxs(Div, { className: "mx-auto max-w-3xl", padding: "x-md", children: [_jsxs(Row, { gap: "sm", className: "mb-4", children: [_jsx(StarRating, { value: review.rating, size: "lg", readOnly: true }), _jsxs(Span, { color: "inverse", weight: "bold", className: "text-[var(--appkit-color-text)] dark:", size: "2xl", children: [review.rating, ".0"] }), review.verified && (_jsx(Span, { layout: "inline-flex", gap: "xs", color: "success", surface: "success-surface", size: "xs", weight: "semibold", rounded: "full", padding: "pill-md", children: "\u2713 Verified Purchase" })), review.featured && (_jsx(Span, { size: "xs", weight: "semibold", className: CLS_RATING_PILL, children: "\u2605 Featured" }))] }), review.title && (_jsx(Heading, { color: "inverse", level: 1, className: "text-[var(--appkit-color-text)] dark: mb-4 leading-snug", size: "2xl", weight: "bold", children: review.title })), _jsxs(Row, { gap: "sm", children: [review.userAvatar ? (_jsx("img", { src: review.userAvatar, alt: displayName, className: "h-11 w-11 flex-shrink-0 object-cover rounded-full ring-2 ring-white ring-[var(--appkit-color-border-subtle)]" })) : (_jsx(Row, { textWeight: "bold", textSize: "base", centered: true, className: "h-11 w-11 flex-shrink-0 bg-primary/10 text-primary ring-2 ring-white ring-[var(--appkit-color-border-subtle)]", rounded: "full", children: initials })), _jsxs(Div, { className: "min-w-0", children: [reviewerHref ? (_jsx(Link, { href: reviewerHref, className: "text-sm font-semibold text-[var(--appkit-color-text)] dark:text-white hover:text-primary transition-colors", children: displayName })) : (_jsx(Span, { color: "inverse", size: "sm", weight: "semibold", className: "text-[var(--appkit-color-text)] dark:", children: review.isAnonymous ? "Anonymous" : displayName })), date && (_jsx(Text, { size: "xs", color: "muted", className: "mt-0.5", children: date }))] })] })] }) }), _jsxs(Stack, { gap: "xl", className: "mx-auto max-w-3xl", paddingY: "y-xl", paddingX: "x-md", children: [review.comment && (_jsx(Section, { children: _jsx(RichText, { html: normalizeRichTextHtml(review.comment), proseClass: "prose prose-neutral dark:prose-invert max-w-none prose-p:leading-relaxed prose-headings:font-semibold prose-img:rounded-lg prose-a:text-primary", className: "text-neutral-700 text-[var(--appkit-color-text-muted)]" }) })), images.length > 0 && (_jsxs(Section, { children: [_jsxs(Heading, { level: 2, className: "tracking-wide mb-3", color: "faint", size: "sm", weight: "semibold", transform: "uppercase", children: ["Photos (", images.length, ")"] }), _jsx(Grid, { gap: "xs", className: "grid-cols-3 sm:grid-cols-4", children: images.map((img, i) => (_jsxs("button", { type: "button", onClick: () => setLightboxIdx(i), "aria-label": `View photo ${i + 1}`, className: "group relative aspect-square overflow-hidden rounded-xl border border-neutral-200 border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] bg-[var(--appkit-color-surface-elevated)] focus:outline-none focus-visible:ring-2 focus-visible:ring-primary", children: [_jsx("img", { src: img.thumbnailUrl ?? img.url, alt: `Review image ${i + 1}`, className: "h-full w-full object-cover transition-transform duration-300 group-hover:scale-105" }), _jsx(Row, { centered: true, className: "absolute inset-0 opacity-0 group-hover:opacity-100 transition-opacity bg-[rgba(0,0,0,0.3)]", children: _jsx(Span, { color: "inverse", size: "xl", children: "\uD83D\uDD0D" }) })] }, i))) })] })), review.video && (_jsxs(Section, { children: [_jsx(Heading, { level: 2, className: "tracking-wide mb-3", color: "faint", size: "sm", weight: "semibold", transform: "uppercase", children: "Video" }), _jsx(Div, { className: `${__O.hidden} border border-[var(--appkit-color-border)] bg-[rgb(0,0,0)] aspect-video`, rounded: "xl", children: _jsx("video", { src: review.video.url, poster: review.video.thumbnailUrl, controls: true, className: "h-full w-full", preload: "metadata" }) })] })), _jsxs(Section, { className: "flex items-[center] gap-[1rem] border-t border-neutral-100", padding: "y-md", children: [_jsx(Div, { textSize: "sm", className: "text-[var(--appkit-color-text-muted)]", children: helpfulCount > 0 && (_jsxs(Span, { children: [_jsx(Span, { color: "inverse", weight: "bold", className: "text-[var(--appkit-color-text)] dark:", children: helpfulCount }), " ", helpfulCount === 1 ? "person" : "people", " found this helpful"] })) }), _jsxs("button", { type: "button", onClick: handleVote, disabled: voted || voting, className: `ml-auto flex items-center gap-2 rounded-lg border px-4 py-2 text-sm font-medium transition-colors ${voted
95
+ return (_jsxs(_Fragment, { children: [_jsx(Div, { surface: "default", className: "border-b border-neutral-200 pt-[2.5rem]", padding: "b-xl", children: _jsxs(Div, { className: "mx-auto max-w-3xl", padding: "x-md", children: [_jsxs(Row, { gap: "sm", className: "mb-4", children: [_jsx(StarRating, { value: review.rating, size: "lg", readOnly: true }), _jsxs(Span, { color: "inverse", weight: "bold", className: "text-[var(--appkit-color-text)] dark:", size: "2xl", children: [review.rating, ".0"] }), review.verified && (_jsx(Span, { layout: "inline-flex", gap: "xs", color: "success", surface: "success-surface", size: "xs", weight: "semibold", rounded: "full", padding: "pill-md", children: "\u2713 Verified Purchase" })), review.featured && (_jsx(Span, { size: "xs", weight: "semibold", className: CLS_RATING_PILL, children: "\u2605 Featured" }))] }), review.title && (_jsx(Heading, { color: "inverse", level: 1, className: "text-[var(--appkit-color-text)] dark: mb-4 leading-snug", size: "2xl", weight: "bold", children: review.title })), _jsxs(Row, { gap: "sm", children: [review.userAvatar ? (_jsx(Div, { className: "relative h-11 w-11 flex-shrink-0 overflow-hidden ring-2 ring-white ring-[var(--appkit-color-border-subtle)]", rounded: "full", children: _jsx(MediaImage, { src: review.userAvatar, alt: displayName, size: "avatar" }) })) : (_jsx(Row, { textWeight: "bold", textSize: "base", centered: true, className: "h-11 w-11 flex-shrink-0 bg-primary/10 text-primary ring-2 ring-white ring-[var(--appkit-color-border-subtle)]", rounded: "full", children: initials })), _jsxs(Div, { className: "min-w-0", children: [reviewerHref ? (_jsx(Link, { href: reviewerHref, className: "text-sm font-semibold text-[var(--appkit-color-text)] dark:text-white hover:text-primary transition-colors", children: displayName })) : (_jsx(Span, { color: "inverse", size: "sm", weight: "semibold", className: "text-[var(--appkit-color-text)] dark:", children: review.isAnonymous ? "Anonymous" : displayName })), date && (_jsx(Text, { size: "xs", color: "muted", className: "mt-0.5", children: date }))] })] })] }) }), _jsxs(Stack, { gap: "xl", className: "mx-auto max-w-3xl", paddingY: "y-xl", paddingX: "x-md", children: [review.comment && (_jsx(Section, { children: _jsx(RichText, { html: normalizeRichTextHtml(review.comment), proseClass: "prose prose-neutral dark:prose-invert max-w-none prose-p:leading-relaxed prose-headings:font-semibold prose-img:rounded-lg prose-a:text-primary", className: "text-neutral-700 text-[var(--appkit-color-text-muted)]" }) })), images.length > 0 && (_jsxs(Section, { children: [_jsxs(Heading, { level: 2, className: "tracking-wide mb-3", color: "faint", size: "sm", weight: "semibold", transform: "uppercase", children: ["Photos (", images.length, ")"] }), _jsx(Grid, { gap: "xs", className: "grid-cols-3 sm:grid-cols-4", children: images.map((img, i) => (_jsxs("button", { type: "button", onClick: () => setLightboxIdx(i), "aria-label": `View photo ${i + 1}`, className: "group relative aspect-square overflow-hidden rounded-xl border border-neutral-200 border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] bg-[var(--appkit-color-surface-elevated)] focus:outline-none focus-visible:ring-2 focus-visible:ring-primary", children: [_jsx(MediaImage, { src: img.thumbnailUrl ?? img.url, alt: `Review image ${i + 1}`, size: "card", className: "transition-transform duration-300 group-hover:scale-105" }), _jsx(Row, { centered: true, className: "absolute inset-0 opacity-0 group-hover:opacity-100 transition-opacity bg-[rgba(0,0,0,0.3)]", children: _jsx(Span, { color: "inverse", size: "xl", children: "\uD83D\uDD0D" }) })] }, i))) })] })), review.video && (_jsxs(Section, { children: [_jsx(Heading, { level: 2, className: "tracking-wide mb-3", color: "faint", size: "sm", weight: "semibold", transform: "uppercase", children: "Video" }), _jsx(Div, { className: `${__O.hidden} border border-[var(--appkit-color-border)] bg-[rgb(0,0,0)] aspect-video`, rounded: "xl", children: _jsx("video", { src: review.video.url, poster: review.video.thumbnailUrl, controls: true, className: "h-full w-full", preload: "metadata" }) })] })), _jsxs(Section, { className: "flex items-[center] gap-[1rem] border-t border-neutral-100", padding: "y-md", children: [_jsx(Div, { textSize: "sm", className: "text-[var(--appkit-color-text-muted)]", children: helpfulCount > 0 && (_jsxs(Span, { children: [_jsx(Span, { color: "inverse", weight: "bold", className: "text-[var(--appkit-color-text)] dark:", children: helpfulCount }), " ", helpfulCount === 1 ? "person" : "people", " found this helpful"] })) }), _jsxs("button", { type: "button", onClick: handleVote, disabled: voted || voting, className: `ml-auto flex items-center gap-2 rounded-lg border px-4 py-2 text-sm font-medium transition-colors ${voted
95
96
  ? CLS_HELPFUL_ACTIVE
96
- : "border-neutral-300 border-[var(--appkit-color-border)] text-neutral-700 text-[var(--appkit-color-text-muted)] hover:border-primary hover:text-primary dark:hover:border-primary dark:hover:text-primary disabled:opacity-50"}`, children: [_jsx(Span, { "aria-hidden": "true", children: voted ? "✓" : "👍" }), voted ? "Marked helpful" : voting ? "Saving…" : "Helpful?"] })] }), _jsxs(Section, { className: "grid gap-[0.75rem] sm:grid-cols-3", children: [productHref && (_jsxs(Link, { href: productHref, className: CLS_RELATED_LINK, children: [_jsx(Span, { className: CLS_ICON_ORANGE, children: "\uD83D\uDCE6" }), _jsxs(Div, { className: "min-w-0", children: [_jsx(Text, { className: CLS_RELATED_LABEL, children: "Product" }), _jsx(Text, { className: CLS_RELATED_TITLE, children: review.productTitle ?? "View Product" })] })] })), sellerHref && (_jsxs(Link, { href: sellerHref, className: CLS_RELATED_LINK, children: [_jsx(Span, { className: CLS_ICON_BLUE, children: "\uD83C\uDFEA" }), _jsxs(Div, { className: "min-w-0", children: [_jsx(Text, { className: CLS_RELATED_LABEL, children: "Seller" }), _jsx(Text, { className: CLS_RELATED_TITLE, children: "View Seller" })] })] })), reviewerHref ? (_jsxs(Link, { href: reviewerHref, className: CLS_RELATED_LINK, children: [_jsx(Span, { className: CLS_ICON_PURPLE, children: "\uD83D\uDC64" }), _jsxs(Div, { className: "min-w-0", children: [_jsx(Text, { className: CLS_RELATED_LABEL, children: "Reviewer" }), _jsx(Text, { className: CLS_RELATED_TITLE, children: displayName })] })] })) : (_jsxs(Row, { surface: "default", gap: "sm", className: `border border-neutral-200 dark:border-[var(--appkit-color-border)] ${__P.p4}`, rounded: "xl", children: [_jsx(Span, { size: "xl", className: CLS_ICON_PURPLE_BARE, children: "\uD83D\uDC64" }), _jsxs(Div, { className: "min-w-0", children: [_jsx(Span, { size: "xs", className: "block mb-0.5", color: "faint", children: "Reviewer" }), _jsx(Span, { color: "inverse", size: "sm", weight: "medium", className: "block text-[var(--appkit-color-text)] dark: truncate", children: "Anonymous" })] })] }))] })] }), lightboxIdx !== null && currentImage && (_jsxs(Row, { centered: true, className: "fixed inset-0 z-50 bg-[rgba(0,0,0,0.95)]", onClick: closeLightbox, role: "dialog", "aria-modal": "true", "aria-label": "Image lightbox", children: [_jsx("button", { type: "button", onClick: closeLightbox, "aria-label": "Close lightbox", className: "absolute top-4 right-4 z-10 flex h-10 w-10 items-center justify-center rounded-full bg-white/10 text-white hover:bg-white/20 transition-colors text-xl", children: "\u00D7" }), _jsxs(Div, { textSize: "sm", className: "absolute top-4 left-1/2 -translate-x-1/2 text-white/70", children: [lightboxIdx + 1, " / ", images.length] }), images.length > 1 && (_jsx("button", { type: "button", onClick: (e) => { e.stopPropagation(); prevImage(); }, "aria-label": "Previous image", className: "absolute left-4 top-1/2 -translate-y-1/2 z-10 flex h-12 w-12 items-center justify-center rounded-full bg-white/10 text-white hover:bg-white/25 transition-colors text-2xl", children: "\u2039" })), _jsx(Row, { centered: true, className: "max-h-[85vh] max-w-[85vw]", onClick: (e) => e.stopPropagation(), children: _jsx("img", { src: currentImage.url, alt: `Review photo ${lightboxIdx + 1}`, className: "max-h-[85vh] max-w-[85vw] rounded-lg object-contain shadow-2xl" }) }), images.length > 1 && (_jsx("button", { type: "button", onClick: (e) => { e.stopPropagation(); nextImage(); }, "aria-label": "Next image", className: "absolute right-4 top-1/2 -translate-y-1/2 z-10 flex h-12 w-12 items-center justify-center rounded-full bg-white/10 text-white hover:bg-white/25 transition-colors text-2xl", children: "\u203A" })), images.length > 1 && (_jsx(Row, { justify: "center", gap: "xs", className: "absolute bottom-4 left-0 right-0", padding: "x-md", children: images.map((img, i) => (_jsx("button", { type: "button", onClick: (e) => { e.stopPropagation(); setLightboxIdx(i); }, "aria-label": `Go to image ${i + 1}`, className: `h-12 w-12 flex-shrink-0 rounded-md overflow-hidden border-2 transition-all ${i === lightboxIdx
97
+ : "border-neutral-300 border-[var(--appkit-color-border)] text-neutral-700 text-[var(--appkit-color-text-muted)] hover:border-primary hover:text-primary dark:hover:border-primary dark:hover:text-primary disabled:opacity-50"}`, children: [_jsx(Span, { "aria-hidden": "true", children: voted ? "✓" : "👍" }), voted ? "Marked helpful" : voting ? "Saving…" : "Helpful?"] })] }), _jsxs(Section, { className: "grid gap-[0.75rem] sm:grid-cols-3", children: [productHref && (_jsxs(Link, { href: productHref, className: CLS_RELATED_LINK, children: [_jsx(Span, { className: CLS_ICON_ORANGE, children: "\uD83D\uDCE6" }), _jsxs(Div, { className: "min-w-0", children: [_jsx(Text, { className: CLS_RELATED_LABEL, children: "Product" }), _jsx(Text, { className: CLS_RELATED_TITLE, children: review.productTitle ?? "View Product" })] })] })), sellerHref && (_jsxs(Link, { href: sellerHref, className: CLS_RELATED_LINK, children: [_jsx(Span, { className: CLS_ICON_BLUE, children: "\uD83C\uDFEA" }), _jsxs(Div, { className: "min-w-0", children: [_jsx(Text, { className: CLS_RELATED_LABEL, children: "Seller" }), _jsx(Text, { className: CLS_RELATED_TITLE, children: "View Seller" })] })] })), reviewerHref ? (_jsxs(Link, { href: reviewerHref, className: CLS_RELATED_LINK, children: [_jsx(Span, { className: CLS_ICON_PURPLE, children: "\uD83D\uDC64" }), _jsxs(Div, { className: "min-w-0", children: [_jsx(Text, { className: CLS_RELATED_LABEL, children: "Reviewer" }), _jsx(Text, { className: CLS_RELATED_TITLE, children: displayName })] })] })) : (_jsxs(Row, { surface: "default", gap: "sm", className: `border border-neutral-200 dark:border-[var(--appkit-color-border)] ${__P.p4}`, rounded: "xl", children: [_jsx(Span, { size: "xl", className: CLS_ICON_PURPLE_BARE, children: "\uD83D\uDC64" }), _jsxs(Div, { className: "min-w-0", children: [_jsx(Span, { size: "xs", className: "block mb-0.5", color: "faint", children: "Reviewer" }), _jsx(Span, { color: "inverse", size: "sm", weight: "medium", className: "block text-[var(--appkit-color-text)] dark: truncate", children: "Anonymous" })] })] }))] })] }), lightboxIdx !== null && currentImage && (_jsxs(Row, { centered: true, className: "fixed inset-0 z-50 bg-[rgba(0,0,0,0.95)]", onClick: closeLightbox, role: "dialog", "aria-modal": "true", "aria-label": "Image lightbox", children: [_jsx("button", { type: "button", onClick: closeLightbox, "aria-label": "Close lightbox", className: "absolute top-4 right-4 z-10 flex h-10 w-10 items-center justify-center rounded-full bg-white/10 text-white hover:bg-white/20 transition-colors text-xl", children: "\u00D7" }), _jsxs(Div, { textSize: "sm", className: "absolute top-4 left-1/2 -translate-x-1/2 text-white/70", children: [lightboxIdx + 1, " / ", images.length] }), images.length > 1 && (_jsx("button", { type: "button", onClick: (e) => { e.stopPropagation(); prevImage(); }, "aria-label": "Previous image", className: "absolute left-4 top-1/2 -translate-y-1/2 z-10 flex h-12 w-12 items-center justify-center rounded-full bg-white/10 text-white hover:bg-white/25 transition-colors text-2xl", children: "\u2039" })), _jsx(Row, { centered: true, className: "relative h-[85vh] w-[85vw]", onClick: (e) => e.stopPropagation(), children: _jsx(MediaImage, { src: currentImage.url, alt: `Review photo ${lightboxIdx + 1}`, size: "hero", objectFit: "contain", className: "rounded-lg shadow-2xl" }) }), images.length > 1 && (_jsx("button", { type: "button", onClick: (e) => { e.stopPropagation(); nextImage(); }, "aria-label": "Next image", className: "absolute right-4 top-1/2 -translate-y-1/2 z-10 flex h-12 w-12 items-center justify-center rounded-full bg-white/10 text-white hover:bg-white/25 transition-colors text-2xl", children: "\u203A" })), images.length > 1 && (_jsx(Row, { justify: "center", gap: "xs", className: "absolute bottom-4 left-0 right-0", padding: "x-md", children: images.map((img, i) => (_jsx("button", { type: "button", onClick: (e) => { e.stopPropagation(); setLightboxIdx(i); }, "aria-label": `Go to image ${i + 1}`, className: `h-12 w-12 flex-shrink-0 rounded-md overflow-hidden border-2 transition-all ${i === lightboxIdx
97
98
  ? "border-white scale-110"
98
- : "border-transparent opacity-60 hover:opacity-100"}`, children: _jsx("img", { src: img.thumbnailUrl ?? img.url, alt: `Thumbnail ${i + 1}`, className: "w-full h-full object-cover" }) }, i))) }))] }))] }));
99
+ : "border-transparent opacity-60 hover:opacity-100"}`, children: _jsx(MediaImage, { src: img.thumbnailUrl ?? img.url, alt: `Thumbnail ${i + 1}`, size: "thumbnail" }) }, i))) }))] }))] }));
99
100
  }
@@ -2,6 +2,7 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useState } from "react";
4
4
  import { Button, Div, Heading, Modal, RichText, Row, Stack, Text } from "../../../ui";
5
+ import { MediaImage } from "../../media/MediaImage";
5
6
  import { StarRating } from "../../../ui";
6
7
  import { maskName } from "../../../security";
7
8
  import { THEMED_TEXT_SUCCESS } from "../../../_internal/shared/styles/themed";
@@ -23,5 +24,5 @@ export function ViewReviewModal({ review, isOpen, onClose, }) {
23
24
  day: "numeric",
24
25
  })
25
26
  : "";
26
- return (_jsx(Modal, { isOpen: isOpen, onClose: onClose, title: "Review Details", children: _jsxs(Stack, { gap: "md", children: [_jsxs(Row, { gap: "3", children: [review.userAvatar ? (_jsx("img", { src: review.userAvatar, alt: displayName, className: "h-10 w-10 flex-shrink-0 object-cover rounded-full" })) : (_jsx(Row, { textWeight: "medium", textSize: "sm", className: "h-10 w-10 flex-shrink-0 bg-neutral-200 text-[var(--appkit-color-text-muted)]", align: "center", justify: "center", rounded: "full", children: displayName.charAt(0).toUpperCase() })), _jsxs(Div, { children: [_jsxs(Row, { gap: "sm", children: [_jsx(Text, { color: "inverse", className: "text-[var(--appkit-color-text)] dark:", weight: "medium", children: displayName }), review.verified && (_jsx(Text, { className: THEMED_TEXT_SUCCESS, size: "xs", children: "\u2713 Verified purchase" }))] }), _jsxs(Row, { className: "mt-0.5", gap: "sm", children: [_jsx(StarRating, { value: review.rating, size: "sm", readOnly: true }), date && (_jsx(Text, { size: "xs", color: "faint", children: date }))] })] })] }), review.title && (_jsx(Heading, { color: "inverse", level: 4, className: "text-[var(--appkit-color-text)] dark:", weight: "semibold", children: review.title })), review.comment && (_jsx(RichText, { html: normalizeRichTextHtml(review.comment), proseClass: "prose prose-sm max-w-none dark:prose-invert prose-p:my-0", className: "text-sm leading-relaxed text-[var(--appkit-color-text-muted)] text-[var(--appkit-color-text-muted)]" })), review.images && review.images.length > 0 && (_jsx(Row, { wrap: true, gap: "sm", children: review.images.map((img, i) => (_jsx("button", { type: "button", "aria-label": `View image ${i + 1}`, onClick: () => setLightboxIdx(i), className: `h-20 w-20 rounded-lg border overflow-hidden transition hover:opacity-80 p-0 flex-shrink-0 ${lightboxIdx === i ? "ring-2 ring-primary-500" : "border-neutral-100 border-[var(--appkit-color-border)]"}`, children: _jsx("img", { src: img.thumbnailUrl ?? img.url, alt: `Review thumbnail ${i + 1}`, className: "w-full h-full object-cover" }) }, i))) })), (review.helpfulCount ?? 0) > 0 && (_jsxs(Text, { size: "xs", color: "faint", children: [review.helpfulCount, " people found this helpful"] })), _jsx(Row, { justify: "end", padding: "t-xs", children: _jsx(Button, { variant: "ghost", onClick: onClose, children: "Close" }) })] }) }));
27
+ return (_jsx(Modal, { isOpen: isOpen, onClose: onClose, title: "Review Details", children: _jsxs(Stack, { gap: "md", children: [_jsxs(Row, { gap: "3", children: [review.userAvatar ? (_jsx(Div, { className: "relative h-10 w-10 flex-shrink-0 overflow-hidden", rounded: "full", children: _jsx(MediaImage, { src: review.userAvatar, alt: displayName, size: "avatar" }) })) : (_jsx(Row, { textWeight: "medium", textSize: "sm", className: "h-10 w-10 flex-shrink-0 bg-neutral-200 text-[var(--appkit-color-text-muted)]", align: "center", justify: "center", rounded: "full", children: displayName.charAt(0).toUpperCase() })), _jsxs(Div, { children: [_jsxs(Row, { gap: "sm", children: [_jsx(Text, { color: "inverse", className: "text-[var(--appkit-color-text)] dark:", weight: "medium", children: displayName }), review.verified && (_jsx(Text, { className: THEMED_TEXT_SUCCESS, size: "xs", children: "\u2713 Verified purchase" }))] }), _jsxs(Row, { className: "mt-0.5", gap: "sm", children: [_jsx(StarRating, { value: review.rating, size: "sm", readOnly: true }), date && (_jsx(Text, { size: "xs", color: "faint", children: date }))] })] })] }), review.title && (_jsx(Heading, { color: "inverse", level: 4, className: "text-[var(--appkit-color-text)] dark:", weight: "semibold", children: review.title })), review.comment && (_jsx(RichText, { html: normalizeRichTextHtml(review.comment), proseClass: "prose prose-sm max-w-none dark:prose-invert prose-p:my-0", className: "text-sm leading-relaxed text-[var(--appkit-color-text-muted)] text-[var(--appkit-color-text-muted)]" })), review.images && review.images.length > 0 && (_jsx(Row, { wrap: true, gap: "sm", children: review.images.map((img, i) => (_jsx("button", { type: "button", "aria-label": `View image ${i + 1}`, onClick: () => setLightboxIdx(i), className: `h-20 w-20 rounded-lg border overflow-hidden transition hover:opacity-80 p-0 flex-shrink-0 ${lightboxIdx === i ? "ring-2 ring-primary-500" : "border-neutral-100 border-[var(--appkit-color-border)]"}`, children: _jsx(MediaImage, { src: img.thumbnailUrl ?? img.url, alt: `Review thumbnail ${i + 1}`, size: "thumbnail" }) }, i))) })), (review.helpfulCount ?? 0) > 0 && (_jsxs(Text, { size: "xs", color: "faint", children: [review.helpfulCount, " people found this helpful"] })), _jsx(Row, { justify: "end", padding: "t-xs", children: _jsx(Button, { variant: "ghost", onClick: onClose, children: "Close" }) })] }) }));
27
28
  }
@@ -92,7 +92,7 @@ export function ReviewsIndexListing({ initialData, variant = "public", }) {
92
92
  const commitSearch = useCallback(() => {
93
93
  table.set(TABLE_KEYS.QUERY, searchInput.trim());
94
94
  }, [searchInput, table]);
95
- const { reviews, total, totalPages, isLoading } = useReviews({
95
+ const { reviews, totalPages, isLoading } = useReviews({
96
96
  q: table.get(TABLE_KEYS.QUERY) || undefined,
97
97
  rating: table.get(TABLE_KEYS.RATING) || undefined,
98
98
  dateFrom: table.get(TABLE_KEYS.DATE_FROM) || undefined,
@@ -2,6 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import Link from "next/link";
3
3
  import { Div, Heading, Pagination, RichText, Row, Skeleton, Span, Stack, Text, } from "../../../ui";
4
4
  import { StarRating } from "../../../ui";
5
+ import { MediaImage } from "../../media/MediaImage";
5
6
  import { maskName } from "../../../security";
6
7
  import { getDefaultLocale } from "../../../core/baseline-resolver";
7
8
  import { normalizeRichTextHtml } from "../../../utils/string.formatter";
@@ -27,7 +28,7 @@ export function ReviewCard({ review, context = "general", className = "" }) {
27
28
  const showProductLink = context !== "listing" && !!productHref;
28
29
  const showProfileLink = !!profileHref;
29
30
  const hasFooter = showStoreLink || showProductLink || showProfileLink;
30
- return (_jsxs(Stack, { padding: "5", shadow: "hover-md", className: `group h-full border border-neutral-200 transition ${className}`, rounded: "xl", surface: "default", children: [_jsxs(Link, { href: reviewHref, className: "flex flex-col flex-1 min-h-0", children: [_jsxs(Row, { align: "start", gap: "3", children: [review.userAvatar ? (_jsx("img", { src: review.userAvatar, alt: displayName, className: "h-9 w-9 flex-shrink-0 object-cover rounded-full" })) : (_jsx(Row, { textWeight: "medium", textSize: "sm", className: "h-9 w-9 flex-shrink-0 bg-neutral-200 text-[var(--appkit-color-text-muted)]", align: "center", justify: "center", rounded: "full", children: initials })), _jsxs(Div, { className: "flex-1 min-w-0", children: [_jsxs(Row, { wrap: true, gap: "sm", children: [_jsx(Span, { color: "inverse", weight: "medium", className: "text-[var(--appkit-color-text)] dark:", children: displayName }), review.verified && (_jsx(Span, { color: "success", surface: "success-surface", size: "xs", weight: "medium", rounded: "full", padding: "pill-xs", children: "Verified" })), date && (_jsx(Span, { size: "xs", color: "muted", children: date }))] }), _jsx(Div, { className: "mt-1", children: _jsx(StarRating, { value: review.rating, size: "sm", readOnly: true }) })] })] }), review.title && (_jsx(Heading, { color: "inverse", level: 4, className: "mt-3 text-[var(--appkit-color-text)] dark:", weight: "semibold", children: review.title })), review.comment && (_jsx(RichText, { html: normalizeRichTextHtml(review.comment), proseClass: "prose prose-sm max-w-none dark:prose-invert prose-p:my-0", className: "mt-2 text-sm leading-relaxed text-[var(--appkit-color-text-muted)] text-[var(--appkit-color-text-muted)]" })), review.images && review.images.length > 0 && (_jsx(Row, { wrap: true, gap: "sm", className: "mt-3", children: review.images.map((img, i) => (_jsx("img", { src: img.thumbnailUrl ?? img.url, alt: `Review image ${i + 1}`, className: "h-16 w-16 object-cover rounded-lg border border-neutral-100" }, i))) })), (review.helpfulCount ?? 0) > 0 && (_jsxs(Text, { className: "mt-3", color: "faint", size: "xs", children: [review.helpfulCount, " found this helpful"] }))] }), hasFooter && (_jsxs(Stack, { gap: "xs", className: "mt-3 border-t border-neutral-100", padding: "t-sm", children: [showStoreLink && (_jsxs(Link, { href: String(ROUTES.PUBLIC.STORE_DETAIL(review.storeSlug)), className: "flex items-center gap-1.5 text-xs font-medium text-primary hover:underline", children: [_jsx(Span, { "aria-hidden": "true", children: "\uD83C\uDFEA" }), _jsx(Span, { truncate: true, children: review.storeName })] })), showProductLink && (_jsxs(Link, { href: productHref, className: "flex items-center gap-1.5 text-xs font-medium text-[var(--appkit-color-text-muted)] text-[var(--appkit-color-text-muted)] hover:text-neutral-700 hover:text-[var(--appkit-color-text-muted)]", children: [_jsx(Span, { "aria-hidden": "true", children: "\uD83D\uDCE6" }), _jsx(Span, { truncate: true, children: review.productTitle ?? "View Product" }), _jsx(Span, { "aria-hidden": "true", className: "ml-auto text-primary group-hover:translate-x-0.5 transition-transform", children: "\u2192" })] })), showProfileLink && (_jsxs(Link, { href: profileHref, className: "flex items-center gap-1.5 text-xs font-medium text-[var(--appkit-color-text-muted)] text-[var(--appkit-color-text-muted)] hover:text-neutral-700 hover:text-[var(--appkit-color-text-muted)]", children: [_jsx(Span, { "aria-hidden": "true", children: "\uD83D\uDC64" }), _jsx(Span, { truncate: true, children: displayName })] }))] }))] }));
31
+ return (_jsxs(Stack, { padding: "5", shadow: "hover-md", className: `group h-full border border-neutral-200 transition ${className}`, rounded: "xl", surface: "default", children: [_jsxs(Link, { href: reviewHref, className: "flex flex-col flex-1 min-h-0", children: [_jsxs(Row, { align: "start", gap: "3", children: [review.userAvatar ? (_jsx(Div, { className: "relative h-9 w-9 flex-shrink-0 overflow-hidden", rounded: "full", children: _jsx(MediaImage, { src: review.userAvatar, alt: displayName, size: "avatar" }) })) : (_jsx(Row, { textWeight: "medium", textSize: "sm", className: "h-9 w-9 flex-shrink-0 bg-neutral-200 text-[var(--appkit-color-text-muted)]", align: "center", justify: "center", rounded: "full", children: initials })), _jsxs(Div, { className: "flex-1 min-w-0", children: [_jsxs(Row, { wrap: true, gap: "sm", children: [_jsx(Span, { color: "inverse", weight: "medium", className: "text-[var(--appkit-color-text)] dark:", children: displayName }), review.verified && (_jsx(Span, { color: "success", surface: "success-surface", size: "xs", weight: "medium", rounded: "full", padding: "pill-xs", children: "Verified" })), date && (_jsx(Span, { size: "xs", color: "muted", children: date }))] }), _jsx(Div, { className: "mt-1", children: _jsx(StarRating, { value: review.rating, size: "sm", readOnly: true }) })] })] }), review.title && (_jsx(Heading, { color: "inverse", level: 4, className: "mt-3 text-[var(--appkit-color-text)] dark:", weight: "semibold", children: review.title })), review.comment && (_jsx(RichText, { html: normalizeRichTextHtml(review.comment), proseClass: "prose prose-sm max-w-none dark:prose-invert prose-p:my-0", className: "mt-2 text-sm leading-relaxed text-[var(--appkit-color-text-muted)] text-[var(--appkit-color-text-muted)]" })), review.images && review.images.length > 0 && (_jsx(Row, { wrap: true, gap: "sm", className: "mt-3", children: review.images.map((img, i) => (_jsx(Div, { className: "relative h-16 w-16 flex-shrink-0 overflow-hidden border border-neutral-100", rounded: "lg", children: _jsx(MediaImage, { src: img.thumbnailUrl ?? img.url, alt: `Review image ${i + 1}`, size: "thumbnail" }) }, i))) })), (review.helpfulCount ?? 0) > 0 && (_jsxs(Text, { className: "mt-3", color: "faint", size: "xs", children: [review.helpfulCount, " found this helpful"] }))] }), hasFooter && (_jsxs(Stack, { gap: "xs", className: "mt-3 border-t border-neutral-100", padding: "t-sm", children: [showStoreLink && (_jsxs(Link, { href: String(ROUTES.PUBLIC.STORE_DETAIL(review.storeSlug)), className: "flex items-center gap-1.5 text-xs font-medium text-primary hover:underline", children: [_jsx(Span, { "aria-hidden": "true", children: "\uD83C\uDFEA" }), _jsx(Span, { truncate: true, children: review.storeName })] })), showProductLink && (_jsxs(Link, { href: productHref, className: "flex items-center gap-1.5 text-xs font-medium text-[var(--appkit-color-text-muted)] text-[var(--appkit-color-text-muted)] hover:text-neutral-700 hover:text-[var(--appkit-color-text-muted)]", children: [_jsx(Span, { "aria-hidden": "true", children: "\uD83D\uDCE6" }), _jsx(Span, { truncate: true, children: review.productTitle ?? "View Product" }), _jsx(Span, { "aria-hidden": "true", className: "ml-auto text-primary group-hover:translate-x-0.5 transition-transform", children: "\u2192" })] })), showProfileLink && (_jsxs(Link, { href: profileHref, className: "flex items-center gap-1.5 text-xs font-medium text-[var(--appkit-color-text-muted)] text-[var(--appkit-color-text-muted)] hover:text-neutral-700 hover:text-[var(--appkit-color-text-muted)]", children: [_jsx(Span, { "aria-hidden": "true", children: "\uD83D\uDC64" }), _jsx(Span, { truncate: true, children: displayName })] }))] }))] }));
31
32
  }
32
33
  export function ReviewsList({ reviews, context = "general", isLoading, totalPages = 1, currentPage = 1, onPageChange, emptyLabel = "No reviews yet", }) {
33
34
  if (isLoading) {
@@ -4,7 +4,7 @@ import { Span, useApiMutation } from "@mohasinac/appkit/client";
4
4
  import { useState } from "react";
5
5
  import { useQueryClient } from "@tanstack/react-query";
6
6
  import { Shield, IndianRupee, UserX, CreditCard, Package, UserCheck, ShieldAlert, Truck } from "lucide-react";
7
- import { Div, Modal, Stack, Row, Text, Checkbox } from "../../../ui";
7
+ import { Div, Modal, Stack, Row, Text, Checkbox, TextLink } from "../../../ui";
8
8
  import { apiClient } from "../../../http";
9
9
  import { ACCOUNT_ENDPOINTS } from "../../../constants/api-endpoints";
10
10
  import { SCAM_CATEGORIES } from "../constants/scam-types";
@@ -28,5 +28,5 @@ export function ScamAwarenessModal({ isOpen, onAcknowledged }) {
28
28
  onAcknowledged();
29
29
  },
30
30
  });
31
- return (_jsx(Modal, { isOpen: isOpen, onClose: () => { }, showCloseButton: false, size: "lg", title: _jsxs(Row, { gap: "sm", align: "center", children: [_jsx(Shield, { className: "h-5 w-5 text-[color:var(--appkit-color-warning,theme(colors.amber.500))]" }), _jsx(Span, { children: "Before you start \u2014 Stay Safe on LetItRip" })] }), actions: _jsx(Row, { gap: "sm", justify: "end", className: "w-full", children: _jsx("button", { className: "appkit-button appkit-button--primary appkit-button--md", disabled: !checked || mutation.isPending, onClick: () => mutation.mutate(), children: mutation.isPending ? "Saving…" : "Continue to LetItRip →" }) }), children: _jsxs(Stack, { gap: "md", children: [_jsx(Text, { variant: "secondary", size: "sm", children: "LetItRip connects you with verified sellers, but collectibles markets attract scams. Take 60 seconds to learn the most common patterns \u2014 it could save your money." }), _jsx(Div, { layout: "grid", gap: "3", className: "grid-cols-1 sm:grid-cols-2", children: SCAM_CATEGORIES.map((cat) => (_jsxs(Div, { className: "flex gap-3 rounded-lg border border-[color:var(--appkit-color-border,theme(colors.zinc.200))] bg-[color:var(--appkit-color-surface,theme(colors.zinc.50))] p-3", children: [_jsx(Span, { layout: "flex-center", className: "mt-0.5 h-8 w-8 shrink-0 bg-[color:var(--appkit-color-warning,theme(colors.amber.500))]/10 text-[color:var(--appkit-color-warning,theme(colors.amber.600))]", rounded: "md", children: CATEGORY_ICONS[cat.id] ?? _jsx(Shield, { className: "h-4 w-4" }) }), _jsxs(Stack, { gap: "none", children: [_jsx(Text, { weight: "semibold", size: "sm", children: cat.label }), _jsx(Text, { variant: "secondary", className: "leading-relaxed", size: "xs", children: cat.description })] })] }, cat.id))) }), _jsxs(Row, { textSize: "sm", gap: "md", wrap: true, children: [_jsx("a", { href: String(ROUTES.PUBLIC.SCAM_TYPES), target: "_blank", rel: "noopener noreferrer", className: "text-[color:var(--appkit-color-primary,theme(colors.blue.600))] hover:underline", children: "See all 27 scam types \u2192" }), _jsx("a", { href: String(ROUTES.PUBLIC.SCAM_FAQS), target: "_blank", rel: "noopener noreferrer", className: "text-[color:var(--appkit-color-primary,theme(colors.blue.600))] hover:underline", children: "Common scam FAQs \u2192" })] }), mutation.isError && (_jsx(Text, { variant: "error", size: "sm", children: "Something went wrong \u2014 please try again." })), _jsx(Checkbox, { id: "scam-awareness-ack", checked: checked, onChange: (e) => setChecked(e.target.checked), label: "I have read the above and understand the risks of buying and selling collectibles online." })] }) }));
31
+ return (_jsx(Modal, { isOpen: isOpen, onClose: () => { }, showCloseButton: false, size: "lg", title: _jsxs(Row, { gap: "sm", align: "center", children: [_jsx(Shield, { className: "h-5 w-5 text-[color:var(--appkit-color-warning,theme(colors.amber.500))]" }), _jsx(Span, { children: "Before you start \u2014 Stay Safe on LetItRip" })] }), actions: _jsx(Row, { gap: "sm", justify: "end", className: "w-full", children: _jsx("button", { className: "appkit-button appkit-button--primary appkit-button--md", disabled: !checked || mutation.isPending, onClick: () => mutation.mutate(), children: mutation.isPending ? "Saving…" : "Continue to LetItRip →" }) }), children: _jsxs(Stack, { gap: "md", children: [_jsx(Text, { variant: "secondary", size: "sm", children: "LetItRip connects you with verified sellers, but collectibles markets attract scams. Take 60 seconds to learn the most common patterns \u2014 it could save your money." }), _jsx(Div, { layout: "grid", gap: "3", className: "grid-cols-1 sm:grid-cols-2", children: SCAM_CATEGORIES.map((cat) => (_jsxs(Div, { layout: "flex", gap: "3", rounded: "lg", padding: "sm", className: "border border-[color:var(--appkit-color-border,theme(colors.zinc.200))] bg-[color:var(--appkit-color-surface,theme(colors.zinc.50))]", children: [_jsx(Span, { layout: "flex-center", className: "mt-0.5 h-8 w-8 shrink-0 bg-[color:var(--appkit-color-warning,theme(colors.amber.500))]/10 text-[color:var(--appkit-color-warning,theme(colors.amber.600))]", rounded: "md", children: CATEGORY_ICONS[cat.id] ?? _jsx(Shield, { className: "h-4 w-4" }) }), _jsxs(Stack, { gap: "none", children: [_jsx(Text, { weight: "semibold", size: "sm", children: cat.label }), _jsx(Text, { variant: "secondary", className: "leading-relaxed", size: "xs", children: cat.description })] })] }, cat.id))) }), _jsxs(Row, { textSize: "sm", gap: "md", wrap: true, children: [_jsx(TextLink, { variant: "bare", href: String(ROUTES.PUBLIC.SCAM_TYPES), target: "_blank", rel: "noopener noreferrer", className: "text-[color:var(--appkit-color-primary,theme(colors.blue.600))] hover:underline", children: "See all 27 scam types \u2192" }), _jsx(TextLink, { variant: "bare", href: String(ROUTES.PUBLIC.SCAM_FAQS), target: "_blank", rel: "noopener noreferrer", className: "text-[color:var(--appkit-color-primary,theme(colors.blue.600))] hover:underline", children: "Common scam FAQs \u2192" })] }), mutation.isError && (_jsx(Text, { variant: "error", size: "sm", children: "Something went wrong \u2014 please try again." })), _jsx(Checkbox, { id: "scam-awareness-ack", checked: checked, onChange: (e) => setChecked(e.target.checked), label: "I have read the above and understand the risks of buying and selling collectibles online." })] }) }));
32
32
  }
@@ -216,7 +216,7 @@ export function Search({ isOpen, onClose, onSearch, onOpen, value, onChange, pla
216
216
  if (inlineBlurRef.current)
217
217
  clearTimeout(inlineBlurRef.current);
218
218
  inlineBlurRef.current = setTimeout(() => setIsInlineOpen(false), 120);
219
- }, placeholder: placeholder ?? labels.placeholder, className: "w-full rounded-lg border border-zinc-300 bg-[var(--appkit-color-surface)] pl-9 text-zinc-900 placeholder:text-zinc-400 focus:border-primary focus:ring-2 focus:ring-primary/20 border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] dark:text-white dark:placeholder:text-slate-500" }), query && (_jsx(Button, { rounded: "full", textColor: "faint", type: "button", variant: "ghost", onClick: handleClear, className: "absolute right-3 p-[0.125rem] hover:text-[var(--appkit-color-text-muted)] dark:hover:text-[var(--appkit-color-text)] transition-colors", "aria-label": labels.clearAriaLabel, children: _jsx("svg", { className: "w-4 h-4", "aria-hidden": "true", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) }))] }), resourceTypes && resourceTypes.length > 0 && (_jsx("select", { value: selectedType, onChange: (e) => handleTypeChange(e.target.value), "aria-label": labels.resourceTypeLabel ?? "Search in", className: "flex-shrink-0 rounded-lg border border-zinc-300 bg-white px-2 py-2 text-sm text-zinc-700 focus:border-primary focus:outline-none focus:ring-2 focus:ring-primary/20 border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] text-[var(--appkit-color-text-muted)] cursor-pointer", children: resourceTypes.map((opt) => (_jsx("option", { value: opt.value, children: opt.label }, opt.value))) })), deferred && (_jsx(Button, { rounded: "lg", paddingX: "sm", paddingY: "sm", type: "button", variant: "primary", onClick: handleDeferredSubmit, "aria-label": labels.ariaLabel, className: "flex-shrink-0", children: _jsx("svg", { className: "w-4 h-4", "aria-hidden": "true", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: SVG_PATH_SEARCH }) }) })), isInlineOpen && (filteredQuickLinks.length > 0 || query) && (_jsxs(Div, { className: "absolute top-full left-0 right-0 mt-2 rounded-xl overflow-hidden border border-zinc-200 bg-[var(--appkit-color-surface)] shadow-lg border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] [z-index:var(--appkit-z-dropdown)]", onMouseDown: (event) => event.preventDefault(), children: [filteredQuickLinks.length > 0 && (_jsx(Ul, { children: filteredQuickLinks.map((link, index) => renderInlineQuickLink(link, index)) })), query && suggestionsLoading && (_jsx(Div, { padding: "inline", children: _jsx(Text, { variant: "secondary", size: "sm", children: labels.searching }) })), query &&
219
+ }, placeholder: placeholder ?? labels.placeholder, className: "w-full rounded-lg border border-zinc-300 bg-[var(--appkit-color-surface)] pl-9 text-zinc-900 placeholder:text-zinc-400 focus:border-primary focus:ring-2 focus:ring-primary/20 border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] dark:text-white dark:placeholder:text-slate-500" }), query && (_jsx(Button, { rounded: "full", textColor: "faint", type: "button", variant: "ghost", onClick: handleClear, className: "absolute right-3 p-[0.125rem] hover:text-[var(--appkit-color-text-muted)] dark:hover:text-[var(--appkit-color-text)] transition-colors", "aria-label": labels.clearAriaLabel, children: _jsx("svg", { className: "w-4 h-4", "aria-hidden": "true", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) }))] }), resourceTypes && resourceTypes.length > 0 && (_jsx("select", { value: selectedType, onChange: (e) => handleTypeChange(e.target.value), "aria-label": labels.resourceTypeLabel ?? "Search in", className: "flex-shrink-0 rounded-lg border border-zinc-300 bg-white px-2 py-2 text-sm text-zinc-700 focus:border-primary focus:outline-none focus:ring-2 focus:ring-primary/20 border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] text-[var(--appkit-color-text-muted)] cursor-pointer", children: resourceTypes.map((opt) => (_jsx("option", { value: opt.value, children: opt.label }, opt.value))) })), deferred && (_jsx(Button, { rounded: "lg", paddingX: "sm", paddingY: "sm", type: "button", variant: "primary", onClick: handleDeferredSubmit, "aria-label": labels.ariaLabel, className: "flex-shrink-0", children: _jsx("svg", { className: "w-4 h-4", "aria-hidden": "true", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: SVG_PATH_SEARCH }) }) })), isInlineOpen && (filteredQuickLinks.length > 0 || query) && (_jsxs(Div, { rounded: "xl", border: "default", shadow: "lg", className: "absolute top-full left-0 right-0 mt-2 overflow-hidden bg-[var(--appkit-color-surface)] [z-index:var(--appkit-z-dropdown)]", onMouseDown: (event) => event.preventDefault(), children: [filteredQuickLinks.length > 0 && (_jsx(Ul, { children: filteredQuickLinks.map((link, index) => renderInlineQuickLink(link, index)) })), query && suggestionsLoading && (_jsx(Div, { padding: "inline", children: _jsx(Text, { variant: "secondary", size: "sm", children: labels.searching }) })), query &&
220
220
  suggestions.slice(0, 5).map((suggestion, suggestionIndex) => {
221
221
  const itemIndex = inlineQuickLinkItems.length + suggestionIndex;
222
222
  const isActive = activeIndex === itemIndex;
@@ -26,4 +26,4 @@ export interface SearchViewProps {
26
26
  renderPagination?: () => React.ReactNode;
27
27
  className?: string;
28
28
  }
29
- export declare function SearchView({ query, total, isLoading, labels, renderSearchInput, renderFilters, renderActiveFilters, renderToolbar, renderResults, renderPagination, className, }: SearchViewProps): React.JSX.Element;
29
+ export declare function SearchView({ query, total, isLoading: _isLoading, labels, renderSearchInput, renderFilters, renderActiveFilters, renderToolbar, renderResults, renderPagination, className, }: SearchViewProps): React.JSX.Element;
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { Div, Heading, Main, Row, Span, Stack, Text } from "../../../ui";
3
- export function SearchView({ query, total, isLoading, labels = {}, renderSearchInput, renderFilters, renderActiveFilters, renderToolbar, renderResults, renderPagination, className = "", }) {
3
+ export function SearchView({ query, total, isLoading: _isLoading, labels = {}, renderSearchInput, renderFilters, renderActiveFilters, renderToolbar, renderResults, renderPagination, className = "", }) {
4
4
  const hasQuery = !!query?.trim();
5
5
  return (_jsx(Main, { className: `min-h-screen ${className}`, children: _jsxs(Stack, { padding: "y-lg", gap: "md", children: [_jsx(Div, { children: renderSearchInput() }), hasQuery && (_jsx(Div, { children: _jsx(Heading, { level: 1, size: "xl", weight: "semibold", children: labels.resultsCount
6
6
  ? labels.resultsCount(total, query)
@@ -2,7 +2,7 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { useCallback, useEffect, useState } from "react";
4
4
  import { MapPin, Pencil, Plus, Trash2, Star } from "lucide-react";
5
- import { Badge, Button, ConfirmDeleteModal, Div, Grid, Heading, Label, Row, SideDrawer, Span, Stack, Table, Thead, Tbody, Tr, Th, Td, Text } from "../../../ui";
5
+ import { Badge, Button, ConfirmDeleteModal, Div, Grid, Heading, Row, SideDrawer, Span, Stack, Table, Thead, Tbody, Tr, Th, Td, Text } from "../../../ui";
6
6
  import { FieldInput } from "../../../ui/forms/FieldInput";
7
7
  import { FieldCheckbox } from "../../../ui/forms/FieldCheckbox";
8
8
  import { ROW_ACTION_META, ROW_ACTION_ID } from "../../../features/products/constants/action-defs";
@@ -12,12 +12,8 @@ import { normalizeError } from "../../../errors/normalize";
12
12
  const __O = {
13
13
  xAuto: "overflow-x-auto",
14
14
  };
15
- const INPUT_CLS = "w-full rounded-lg border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] px-3 py-2 text-sm text-[var(--appkit-color-text)] placeholder-zinc-400 dark:placeholder-zinc-500 focus:outline-none focus:ring-2 focus:ring-[var(--appkit-color-primary)]";
16
15
  const CLS_DEFAULT_PILL = "inline-flex items-center gap-1 rounded-full bg-warning-surface dark:bg-warning-surface text-warning dark:text-warning border border-warning dark:border-warning px-2 py-0.5";
17
16
  const CLS_DELETE_BTN = "rounded-lg p-1.5 text-[var(--appkit-color-text-muted)] hover:bg-error-surface dark:hover:bg-error-surface hover:text-error dark:hover:text-error transition-colors";
18
- function Field({ label, hint, children }) {
19
- return (_jsxs(Stack, { gap: "xs", children: [_jsx(Label, { className: "block", color: "primary", size: "xs", weight: "medium", children: label }), children, hint && _jsx(Text, { size: "xs", color: "muted", children: hint })] }));
20
- }
21
17
  // ---------------------------------------------------------------------------
22
18
  // Helpers
23
19
  // ---------------------------------------------------------------------------
@@ -92,7 +92,7 @@ export function SellerGoogleReviewsView({ onSave, onSync, }) {
92
92
  }
93
93
  }, [onSync, showToast]);
94
94
  if (loading) {
95
- return (_jsx(Stack, { gap: "md", paddingY: "y-lg", paddingX: "x-md", children: Array.from({ length: 3 }).map((_, i) => (_jsx(Div, { className: "h-12 animate-pulse rounded-xl border border-zinc-100 border-[var(--appkit-color-border)] bg-zinc-50 bg-[var(--appkit-color-surface-elevated)]" }, i))) }));
95
+ return (_jsx(Stack, { gap: "md", paddingY: "y-lg", paddingX: "x-md", children: Array.from({ length: 3 }).map((_, i) => (_jsx(Div, { rounded: "xl", border: "default", className: "h-12 animate-pulse bg-[var(--appkit-color-surface-elevated)]" }, i))) }));
96
96
  }
97
97
  const formattedLastSync = draft.lastSyncedAt
98
98
  ? new Date(draft.lastSyncedAt).toLocaleString("en-IN", {
@@ -121,5 +121,5 @@ export function SellerPayoutMethodsView({ onCreateClick, onEditClick, onDelete,
121
121
  window.location.href = String(ROUTES.STORE.PAYOUT_METHODS_EDIT(id));
122
122
  }
123
123
  }, [onEditClick]);
124
- return (_jsxs(Div, { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: 0, searchValue: searchInput, searchPlaceholder: "Search payout methods...", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get(TABLE_KEYS.SORT) || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set(TABLE_KEYS.SORT, v); }, onResetAll: resetAll, hasActiveState: hasActiveState, extra: _jsxs(Button, { gap: "sm", size: "sm", onClick: handleCreate, children: [_jsx(Plus, { className: "h-4 w-4" }), _jsx(Span, { children: "New Method" })] }) }), _jsxs(Div, { paddingX: "x-sm-md", padding: "y-md", children: [errorMessage && (_jsx(Div, { textSize: "sm", className: "mb-4 border border-error/20", color: "error", surface: "danger-surface", padding: "inline", rounded: "xl", children: errorMessage })), isLoading ? (_jsx(Stack, { gap: "3", children: Array.from({ length: 3 }).map((_, i) => (_jsx(Div, { className: "h-20 animate-pulse", border: "subtle", surface: "muted", rounded: "xl" }, i))) })) : rows.length === 0 ? (_jsxs(Div, { className: "text-center", padding: "y-4xl", children: [_jsx(Text, { color: "faint", children: "No payout methods yet \u2014 add a UPI VPA or bank account to receive payouts" }), _jsx(Div, { className: "mt-4", children: _jsx(Button, { size: "sm", onClick: handleCreate, children: "Add payout method" }) })] })) : (_jsx(Stack, { gap: "3", children: rows.map((row) => (_jsx(Div, { className: "rounded-xl border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] px-4 py-3", children: _jsxs(Row, { align: "start", justify: "between", gap: "md", children: [_jsx(Row, { className: "min-w-0", align: "start", gap: "3", children: _jsxs(Div, { className: "min-w-0 flex-1", children: [_jsxs(Row, { align: "center", gap: "sm", wrap: true, children: [_jsx(Text, { size: "sm", weight: "medium", children: row.label }), _jsx(TypeBadge, { type: row.type }), row.isDefault && (_jsx(Span, { layout: "inline-flex", color: "success", surface: "success-surface", size: "xs", weight: "medium", rounded: "full", padding: "pill-xs", children: "Default" })), _jsx(Badge, { variant: row.isActive ? "active" : "inactive", size: "xs", children: row.isActive ? "Active" : "Inactive" })] }), _jsx(Text, { className: "mt-1 font-mono", color: "muted", size: "xs", children: row.maskedIdentifier })] }) }), _jsxs(Row, { className: "shrink-0", align: "center", gap: "sm", children: [!row.isDefault && (_jsx(Button, { size: "sm", variant: "ghost", isLoading: settingDefaultId === row.id, onClick: () => handleSetDefault(row.id), children: "Set Default" })), _jsx(Button, { size: "sm", variant: "outline", onClick: () => handleEdit(row.id), children: "Edit" }), _jsx(Button, { size: "sm", variant: "danger", disabled: deletingId === row.id, onClick: () => setDeleteTargetId(row.id), children: "Delete" })] })] }) }, row.id))) }))] }), deleteTargetId && (_jsx(ConfirmDeleteModal, { isOpen: true, title: "Delete Payout Method", message: "Are you sure you want to delete this payout method? This cannot be undone.", onConfirm: () => handleDelete(deleteTargetId), onClose: () => setDeleteTargetId(null), isDeleting: deletingId === deleteTargetId }))] }));
124
+ return (_jsxs(Div, { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: 0, searchValue: searchInput, searchPlaceholder: "Search payout methods...", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get(TABLE_KEYS.SORT) || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set(TABLE_KEYS.SORT, v); }, onResetAll: resetAll, hasActiveState: hasActiveState, extra: _jsxs(Button, { gap: "sm", size: "sm", onClick: handleCreate, children: [_jsx(Plus, { className: "h-4 w-4" }), _jsx(Span, { children: "New Method" })] }) }), _jsxs(Div, { paddingX: "x-sm-md", padding: "y-md", children: [errorMessage && (_jsx(Div, { textSize: "sm", className: "mb-4 border border-error/20", color: "error", surface: "danger-surface", padding: "inline", rounded: "xl", children: errorMessage })), isLoading ? (_jsx(Stack, { gap: "3", children: Array.from({ length: 3 }).map((_, i) => (_jsx(Div, { className: "h-20 animate-pulse", border: "subtle", surface: "muted", rounded: "xl" }, i))) })) : rows.length === 0 ? (_jsxs(Div, { className: "text-center", padding: "y-4xl", children: [_jsx(Text, { color: "faint", children: "No payout methods yet \u2014 add a UPI VPA or bank account to receive payouts" }), _jsx(Div, { className: "mt-4", children: _jsx(Button, { size: "sm", onClick: handleCreate, children: "Add payout method" }) })] })) : (_jsx(Stack, { gap: "3", children: rows.map((row) => (_jsx(Div, { rounded: "xl", border: "default", padding: "inline", className: "bg-[var(--appkit-color-surface)]", children: _jsxs(Row, { align: "start", justify: "between", gap: "md", children: [_jsx(Row, { className: "min-w-0", align: "start", gap: "3", children: _jsxs(Div, { className: "min-w-0 flex-1", children: [_jsxs(Row, { align: "center", gap: "sm", wrap: true, children: [_jsx(Text, { size: "sm", weight: "medium", children: row.label }), _jsx(TypeBadge, { type: row.type }), row.isDefault && (_jsx(Span, { layout: "inline-flex", color: "success", surface: "success-surface", size: "xs", weight: "medium", rounded: "full", padding: "pill-xs", children: "Default" })), _jsx(Badge, { variant: row.isActive ? "active" : "inactive", size: "xs", children: row.isActive ? "Active" : "Inactive" })] }), _jsx(Text, { className: "mt-1 font-mono", color: "muted", size: "xs", children: row.maskedIdentifier })] }) }), _jsxs(Row, { className: "shrink-0", align: "center", gap: "sm", children: [!row.isDefault && (_jsx(Button, { size: "sm", variant: "ghost", isLoading: settingDefaultId === row.id, onClick: () => handleSetDefault(row.id), children: "Set Default" })), _jsx(Button, { size: "sm", variant: "outline", onClick: () => handleEdit(row.id), children: "Edit" }), _jsx(Button, { size: "sm", variant: "danger", disabled: deletingId === row.id, onClick: () => setDeleteTargetId(row.id), children: "Delete" })] })] }) }, row.id))) }))] }), deleteTargetId && (_jsx(ConfirmDeleteModal, { isOpen: true, title: "Delete Payout Method", message: "Are you sure you want to delete this payout method? This cannot be undone.", onConfirm: () => handleDelete(deleteTargetId), onClose: () => setDeleteTargetId(null), isDeleting: deletingId === deleteTargetId }))] }));
125
125
  }
@@ -4,7 +4,8 @@ import { Row, SIEVE_OP, Stack, sieveFilter } from "@mohasinac/appkit";
4
4
  import { sortBy } from "@mohasinac/appkit";
5
5
  import React, { useState, useCallback } from "react";
6
6
  import { useEntityDelete } from "../../../react/hooks/useEntityDelete";
7
- import { Badge, ConfirmDeleteModal, FilterChipGroup, ListingLayout, RowActionMenu, Span, Text } from "../../../ui";
7
+ import { Badge, ConfirmDeleteModal, Div, FilterChipGroup, ListingLayout, RowActionMenu, Span, Text } from "../../../ui";
8
+ import { MediaImage } from "../../media/MediaImage";
8
9
  import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints";
9
10
  import { SELLER_PRE_ORDER_STATUS_TABS } from "../../admin/constants/filter-tabs";
10
11
  import { ROUTES } from "../../../constants";
@@ -17,7 +18,7 @@ const PRE_ORDER_COLUMNS = [
17
18
  key: "thumbnail",
18
19
  header: "",
19
20
  className: "w-12",
20
- render: (row) => row.imageUrl ? (_jsx("img", { src: row.imageUrl, alt: "", className: "w-10 h-10 rounded-lg object-cover border border-[var(--appkit-color-border)]" })) : (_jsx(Row, { className: "w-10 h-10 bg-[var(--appkit-color-surface-raised)] border border-[var(--appkit-color-border)]", align: "center", justify: "center", rounded: "lg", children: _jsx(Span, { size: "xs", color: "faint", children: "\u2013" }) })),
21
+ render: (row) => row.imageUrl ? (_jsx(Div, { className: "relative w-10 h-10 flex-shrink-0 overflow-hidden border border-[var(--appkit-color-border)]", rounded: "lg", children: _jsx(MediaImage, { src: row.imageUrl, alt: "", size: "thumbnail" }) })) : (_jsx(Row, { className: "w-10 h-10 bg-[var(--appkit-color-surface-raised)] border border-[var(--appkit-color-border)]", align: "center", justify: "center", rounded: "lg", children: _jsx(Span, { size: "xs", color: "faint", children: "\u2013" }) })),
21
22
  },
22
23
  {
23
24
  key: "primary",