@mohasinac/appkit 3.3.6 → 3.4.1

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 (141) 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/FAQPageView.js +0 -2
  12. package/dist/features/about/components/FeesView.js +13 -1
  13. package/dist/features/about/components/HowCheckoutWorksView.js +17 -3
  14. package/dist/features/about/components/HowEmiWorksView.d.ts +3 -0
  15. package/dist/features/about/components/HowEmiWorksView.js +117 -0
  16. package/dist/features/about/components/PublicProfileView.js +1 -4
  17. package/dist/features/about/index.d.ts +2 -0
  18. package/dist/features/about/index.js +1 -0
  19. package/dist/features/account/components/BecomeSellerView.d.ts +1 -1
  20. package/dist/features/account/components/BecomeSellerView.js +1 -1
  21. package/dist/features/account/components/NotificationBell.js +1 -2
  22. package/dist/features/account/components/UserSupportView.js +0 -1
  23. package/dist/features/admin/components/AdminAdsView.js +3 -3
  24. package/dist/features/admin/components/AdminBlogEditorView.js +2 -2
  25. package/dist/features/admin/components/AdminBundleEditorView.js +0 -4
  26. package/dist/features/admin/components/AdminCarouselEditorView.js +3 -3
  27. package/dist/features/admin/components/AdminCarouselView.js +3 -2
  28. package/dist/features/admin/components/AdminGuideHubView.js +2 -2
  29. package/dist/features/admin/components/AdminMediaView.js +2 -4
  30. package/dist/features/admin/components/AdminUserEditorView.d.ts +1 -1
  31. package/dist/features/admin/components/AdminUserEditorView.js +1 -1
  32. package/dist/features/admin/components/QuickActionsPanel.js +2 -2
  33. package/dist/features/auctions/components/AuctionDetailPageView.js +1 -1
  34. package/dist/features/blog/components/BlogFeaturedCard.js +2 -1
  35. package/dist/features/blog/components/BlogIndexListing.js +1 -1
  36. package/dist/features/blog/components/BlogListView.js +2 -1
  37. package/dist/features/blog/components/BlogPostForm.js +1 -1
  38. package/dist/features/blog/components/BlogPostView.js +2 -1
  39. package/dist/features/cart/components/CartDrawer.js +2 -1
  40. package/dist/features/categories/components/BrandDetailPageView.js +2 -1
  41. package/dist/features/categories/components/BundleCollage.js +2 -3
  42. package/dist/features/categories/components/CategoriesIndexListing.js +1 -5
  43. package/dist/features/categories/components/CategoryDetailPageView.js +2 -2
  44. package/dist/features/categories/components/CategoryGrid.js +2 -1
  45. package/dist/features/categories/components/CategoryProductsView.d.ts +1 -1
  46. package/dist/features/categories/components/CategoryProductsView.js +1 -1
  47. package/dist/features/categories/components/ConcernCard.js +2 -1
  48. package/dist/features/collections/components/CollectionCard.js +2 -1
  49. package/dist/features/consultation/components/ConsultationForm.js +0 -1
  50. package/dist/features/contact/components/ContactInfoSidebar.js +2 -2
  51. package/dist/features/copilot/components/AdminCopilotView.js +0 -9
  52. package/dist/features/events/components/EventFormDrawer.d.ts +1 -1
  53. package/dist/features/events/components/EventFormDrawer.js +1 -1
  54. package/dist/features/events/components/EventPollWidget.js +2 -2
  55. package/dist/features/events/components/EventsIndexListing.js +1 -1
  56. package/dist/features/faq/actions/faq-actions.d.ts +2 -10
  57. package/dist/features/faq/actions/faq-actions.js +0 -4
  58. package/dist/features/homepage/components/AdSlot.js +2 -1
  59. package/dist/features/homepage/components/CustomCardsSection.js +2 -3
  60. package/dist/features/homepage/components/FeaturedBundlesSection.js +2 -3
  61. package/dist/features/homepage/components/GoogleReviewsSection.js +4 -3
  62. package/dist/features/homepage/components/HeroBanner.js +0 -1
  63. package/dist/features/homepage/components/SectionCarousel.d.ts +1 -1
  64. package/dist/features/homepage/components/SectionCarousel.js +1 -2
  65. package/dist/features/homepage/components/SocialFeedSection.js +2 -5
  66. package/dist/features/homepage/components/SocialPostCard.js +4 -3
  67. package/dist/features/media/MediaImage.d.ts +10 -1
  68. package/dist/features/media/MediaImage.js +6 -2
  69. package/dist/features/media/MediaPickerModal.js +2 -3
  70. package/dist/features/media/upload/MediaUploadList.js +2 -2
  71. package/dist/features/orders/components/OrdersList.js +2 -1
  72. package/dist/features/pre-orders/components/PreOrderDetailPageView.js +1 -0
  73. package/dist/features/products/api/route.js +1 -2
  74. package/dist/features/products/components/CompareOverlay.js +2 -3
  75. package/dist/features/products/components/CustomSectionTabContent.js +2 -2
  76. package/dist/features/products/components/FeatureBadge.js +0 -6
  77. package/dist/features/products/components/GroupSettingsPanel.js +2 -3
  78. package/dist/features/products/components/MarketplaceBundleCard.js +2 -1
  79. package/dist/features/products/components/MarketplacePrizeDrawCard.js +2 -3
  80. package/dist/features/products/components/PrizeDrawCollage.js +2 -3
  81. package/dist/features/products/components/PrizeDrawEntryActions.d.ts +1 -1
  82. package/dist/features/products/components/PrizeDrawEntryActions.js +3 -3
  83. package/dist/features/products/components/PrizeRevealModal.js +3 -4
  84. package/dist/features/products/components/ProductDetailActions.d.ts +1 -1
  85. package/dist/features/products/components/ProductDetailActions.js +1 -1
  86. package/dist/features/products/components/ProductDetailPageView.d.ts +3 -1
  87. package/dist/features/products/components/ProductDetailPageView.js +3 -2
  88. package/dist/features/products/components/ProductFeatureBadges.d.ts +7 -1
  89. package/dist/features/products/components/ProductFeatureBadges.js +16 -3
  90. package/dist/features/products/components/ProductGradingTab.js +2 -2
  91. package/dist/features/products/components/ProductsIndexPageView.js +2 -2
  92. package/dist/features/products/components/SublistingCarouselSection.js +3 -4
  93. package/dist/features/promotions/components/CouponsIndexListing.d.ts +1 -1
  94. package/dist/features/promotions/components/CouponsIndexListing.js +1 -1
  95. package/dist/features/reviews/components/ReviewDetailShell.js +4 -3
  96. package/dist/features/reviews/components/ReviewModal.js +2 -1
  97. package/dist/features/reviews/components/ReviewsIndexListing.js +1 -1
  98. package/dist/features/reviews/components/ReviewsList.js +2 -1
  99. package/dist/features/scams/components/ScamAwarenessModal.js +2 -2
  100. package/dist/features/search/components/SearchView.d.ts +1 -1
  101. package/dist/features/search/components/SearchView.js +1 -1
  102. package/dist/features/seller/components/SellerAddressesView.js +1 -5
  103. package/dist/features/seller/components/SellerPreOrdersView.js +3 -2
  104. package/dist/features/seller/components/SellerPrizeDrawsView.js +3 -2
  105. package/dist/features/seller/components/SellerProductsView.js +2 -1
  106. package/dist/features/seller/components/SellerSidebar.js +5 -4
  107. package/dist/features/shell/StepForm.js +1 -1
  108. package/dist/features/stores/components/InteractiveStoreCard.js +2 -3
  109. package/dist/features/stores/components/StoreAboutView.js +2 -2
  110. package/dist/features/stores/components/StoreCapabilitiesGuideView.js +2 -2
  111. package/dist/features/stores/components/StoreFinanceGuideView.js +2 -2
  112. package/dist/features/stores/components/StoreGuideHubView.js +2 -2
  113. package/dist/features/stores/components/StoreHeader.js +2 -1
  114. package/dist/features/stores/components/StoreListingsGuideView.js +2 -2
  115. package/dist/features/stores/components/StoreNavTabs.js +2 -2
  116. package/dist/features/stores/components/StoreOrdersGuideView.js +2 -2
  117. package/dist/features/stores/components/StoreSettingsGuideView.js +3 -3
  118. package/dist/features/wishlist/components/WishlistPage.js +2 -1
  119. package/dist/features/wishlist/components/WishlistView.js +0 -7
  120. package/dist/index.d.ts +2 -0
  121. package/dist/index.js +3 -0
  122. package/dist/next/routing/route-map.d.ts +2 -0
  123. package/dist/next/routing/route-map.js +1 -0
  124. package/dist/seed/factories/product.factory.js +0 -32
  125. package/dist/seed/faq-seed-data.js +23 -4
  126. package/dist/styles.css +4 -1
  127. package/dist/tailwind-utilities.css +1 -1
  128. package/dist/tokens/index.js +6 -458
  129. package/dist/ui/DataTable.js +0 -21
  130. package/dist/ui/components/Anchor.d.ts +3 -1
  131. package/dist/ui/components/Anchor.js +1 -0
  132. package/dist/ui/components/Avatar.style.css +3 -0
  133. package/dist/ui/components/Breadcrumb.js +2 -1
  134. package/dist/ui/components/FormActionBar.js +2 -1
  135. package/dist/ui/components/ListingLayout.d.ts +1 -1
  136. package/dist/ui/components/ListingLayout.js +1 -1
  137. package/dist/ui/components/Motion.js +1 -1
  138. package/dist/ui/components/QuickCreateModal.js +2 -1
  139. package/dist/ui/components/SlottedListingView.d.ts +1 -1
  140. package/dist/ui/components/SlottedListingView.js +1 -2
  141. package/package.json +1 -1
@@ -4,6 +4,7 @@ import { normalizeError } from "../../../../errors/normalize";
4
4
  import { useState } from "react";
5
5
  import Link from "next/link";
6
6
  import { Badge, Button, Container, Div, Heading, Row, Section, Stack, Text, } from "../../../../ui";
7
+ import { MediaImage } from "../../../../features/media/MediaImage";
7
8
  import { ROUTES } from "../../../../next/routing/route-map";
8
9
  import { formatCurrency } from "../../../../utils/number.formatter";
9
10
  const __P = {
@@ -50,5 +51,5 @@ export function ClassifiedDetailView({ product, isLoading = false, onContactSell
50
51
  setPending(false);
51
52
  }
52
53
  }
53
- return (_jsx(Container, { children: _jsx(Section, { padding: "y-xl", children: _jsxs(Stack, { gap: "lg", children: [product.images.length > 0 && (_jsx(Div, { className: `${__O.hidden} bg-muted`, rounded: "lg", children: _jsx("img", { src: product.mainImage || product.images[0], alt: product.title, className: "h-80 w-full object-contain" }) })), _jsxs(Stack, { gap: "sm", children: [_jsxs(Row, { gap: "sm", wrap: true, children: [_jsx(Badge, { variant: "secondary", children: "Classified" }), meta?.negotiable && _jsx(Badge, { variant: "secondary", children: "Negotiable" }), meta?.acceptsShipping && _jsx(Badge, { variant: "secondary", children: "Shipping available" })] }), _jsx(Heading, { level: 1, weight: "bold", size: "2xl", children: product.title }), _jsx(Text, { className: "text-primary", size: "2xl", weight: "semibold", children: price }), location && (_jsx(Text, { className: "text-muted-foreground", size: "sm", children: location })), _jsx(Text, { className: "text-muted-foreground", children: product.description })] }), conversation ? (_jsxs(Div, { className: `border border-border bg-muted/40 ${__P.p4}`, rounded: "lg", children: [_jsx(Text, { className: "mb-2", weight: "medium", children: "Conversation started!" }), _jsx(Link, { href: ROUTES.USER.MESSAGES, className: "text-primary underline underline-offset-2", children: "Go to your messages \u2192" })] })) : (_jsxs(Stack, { gap: "sm", children: [error && (_jsx(Text, { className: "text-destructive", size: "sm", children: error })), _jsx(Button, { type: "button", variant: "primary", size: "lg", isLoading: pending, disabled: pending, onClick: handleContactSeller, className: "w-full", children: "Contact Seller" })] }))] }) }) }));
54
+ return (_jsx(Container, { children: _jsx(Section, { padding: "y-xl", children: _jsxs(Stack, { gap: "lg", children: [product.images.length > 0 && (_jsx(Div, { className: `relative h-80 w-full ${__O.hidden} bg-muted`, rounded: "lg", children: _jsx(MediaImage, { src: product.mainImage || product.images[0], alt: product.title, size: "hero", objectFit: "contain" }) })), _jsxs(Stack, { gap: "sm", children: [_jsxs(Row, { gap: "sm", wrap: true, children: [_jsx(Badge, { variant: "secondary", children: "Classified" }), meta?.negotiable && _jsx(Badge, { variant: "secondary", children: "Negotiable" }), meta?.acceptsShipping && _jsx(Badge, { variant: "secondary", children: "Shipping available" })] }), _jsx(Heading, { level: 1, weight: "bold", size: "2xl", children: product.title }), _jsx(Text, { className: "text-primary", size: "2xl", weight: "semibold", children: price }), location && (_jsx(Text, { className: "text-muted-foreground", size: "sm", children: location })), _jsx(Text, { className: "text-muted-foreground", children: product.description })] }), conversation ? (_jsxs(Div, { className: `border border-border bg-muted/40 ${__P.p4}`, rounded: "lg", children: [_jsx(Text, { className: "mb-2", weight: "medium", children: "Conversation started!" }), _jsx(Link, { href: ROUTES.USER.MESSAGES, className: "text-primary underline underline-offset-2", children: "Go to your messages \u2192" })] })) : (_jsxs(Stack, { gap: "sm", children: [error && (_jsx(Text, { className: "text-destructive", size: "sm", children: error })), _jsx(Button, { type: "button", variant: "primary", size: "lg", isLoading: pending, disabled: pending, onClick: handleContactSeller, className: "w-full", children: "Contact Seller" })] }))] }) }) }));
54
55
  }
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { Badge, Container, Div, Heading, Row, Section, Stack, Text, } from "../../../../ui";
4
+ import { MediaImage } from "../../../../features/media/MediaImage";
4
5
  import { formatCurrency } from "../../../../utils/number.formatter";
5
6
  import { CodeRevealPanel } from "./CodeRevealPanel";
6
7
  const __P = {
@@ -16,5 +17,5 @@ export function DigitalCodeDetailView({ product, isLoading = false, orderId, fet
16
17
  const meta = product.digitalCode;
17
18
  const price = formatCurrency(product.price, product.currency ?? "INR");
18
19
  const codesLeft = meta?.codesAvailable ?? 0;
19
- return (_jsx(Container, { children: _jsx(Section, { padding: "y-xl", children: _jsxs(Stack, { gap: "lg", children: [product.images.length > 0 && (_jsx(Div, { className: `${__O.hidden} bg-muted`, rounded: "lg", children: _jsx("img", { src: product.mainImage || product.images[0], alt: product.title, className: "h-80 w-full object-contain" }) })), _jsxs(Stack, { gap: "sm", children: [_jsxs(Row, { gap: "sm", wrap: true, children: [_jsx(Badge, { variant: "secondary", children: "Digital Code" }), codesLeft > 0 ? (_jsxs(Badge, { variant: "active", children: [codesLeft, " available"] })) : (_jsx(Badge, { variant: "danger", children: "Sold out" }))] }), _jsx(Heading, { level: 1, weight: "bold", size: "2xl", children: product.title }), _jsx(Text, { className: "text-primary", size: "2xl", weight: "semibold", children: price }), _jsx(Text, { className: "text-muted-foreground", children: product.description })] }), orderId && fetchCode ? (_jsx(CodeRevealPanel, { orderId: orderId, redemptionInstructions: meta?.redemptionInstructions, fetchCode: fetchCode })) : (_jsxs(Div, { className: `border border-border bg-muted/40 ${__P.p4}`, rounded: "lg", children: [_jsx(Text, { className: "text-muted-foreground", size: "sm", children: "After purchase, return to your order to reveal the code instantly." }), meta?.redemptionInstructions && (_jsx(Text, { className: "mt-2", size: "sm", children: meta.redemptionInstructions }))] }))] }) }) }));
20
+ return (_jsx(Container, { children: _jsx(Section, { padding: "y-xl", children: _jsxs(Stack, { gap: "lg", children: [product.images.length > 0 && (_jsx(Div, { className: `relative h-80 w-full ${__O.hidden} bg-muted`, rounded: "lg", children: _jsx(MediaImage, { src: product.mainImage || product.images[0], alt: product.title, size: "hero", objectFit: "contain" }) })), _jsxs(Stack, { gap: "sm", children: [_jsxs(Row, { gap: "sm", wrap: true, children: [_jsx(Badge, { variant: "secondary", children: "Digital Code" }), codesLeft > 0 ? (_jsxs(Badge, { variant: "active", children: [codesLeft, " available"] })) : (_jsx(Badge, { variant: "danger", children: "Sold out" }))] }), _jsx(Heading, { level: 1, weight: "bold", size: "2xl", children: product.title }), _jsx(Text, { className: "text-primary", size: "2xl", weight: "semibold", children: price }), _jsx(Text, { className: "text-muted-foreground", children: product.description })] }), orderId && fetchCode ? (_jsx(CodeRevealPanel, { orderId: orderId, redemptionInstructions: meta?.redemptionInstructions, fetchCode: fetchCode })) : (_jsxs(Div, { className: `border border-border bg-muted/40 ${__P.p4}`, rounded: "lg", children: [_jsx(Text, { className: "text-muted-foreground", size: "sm", children: "After purchase, return to your order to reveal the code instantly." }), meta?.redemptionInstructions && (_jsx(Text, { className: "mt-2", size: "sm", children: meta.redemptionInstructions }))] }))] }) }) }));
20
21
  }
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { Badge, Container, Div, Heading, Row, Section, Stack, Text, } from "../../../../ui";
4
+ import { MediaImage } from "../../../../features/media/MediaImage";
4
5
  import { formatCurrency } from "../../../../utils/number.formatter";
5
6
  const __P = {
6
7
  p4: "p-4",
@@ -19,6 +20,6 @@ export function LiveItemDetailView({ product, isLoading = false, renderActions,
19
20
  const price = formatCurrency(product.price, product.currency ?? "INR");
20
21
  const jurisdictions = meta?.jurisdictionAllowed ?? [];
21
22
  const transport = meta?.transport;
22
- return (_jsx(Container, { children: _jsx(Section, { padding: "y-xl", children: _jsxs(Stack, { gap: "lg", children: [product.images.length > 0 && (_jsx(Div, { className: `${__O.hidden} bg-muted`, rounded: "lg", children: _jsx("img", { src: product.mainImage || product.images[0], alt: product.title, className: "h-80 w-full object-contain" }) })), _jsxs(Stack, { gap: "sm", children: [_jsxs(Row, { gap: "sm", wrap: true, children: [_jsx(Badge, { variant: "secondary", children: "Live Item" }), meta?.vendorVerified && (_jsx(Badge, { variant: "active", children: "Verified Seller" })), meta?.cites && (_jsxs(Badge, { variant: "warning", children: ["CITES: ", meta.cites] }))] }), _jsx(Heading, { level: 1, weight: "bold", size: "2xl", children: product.title }), meta?.species && (_jsxs(Text, { className: "italic text-muted-foreground", size: "sm", children: [meta.species, meta.sex && meta.sex !== "n/a" && ` · ${meta.sex}`, meta.ageMonths !== undefined && ` · ${meta.ageMonths}mo`] })), _jsx(Text, { className: "text-primary", size: "2xl", weight: "semibold", children: price }), _jsx(Text, { className: "text-muted-foreground", children: product.description })] }), jurisdictions.length > 0 && (_jsxs(Div, { className: CLS_WARN_BOX, children: [_jsx(Text, { className: CLS_WARN_TITLE, children: "Delivery restrictions" }), _jsxs(Text, { className: CLS_WARN_BODY, children: ["This item can only be shipped to: ", jurisdictions.join(", ")] })] })), transport && (_jsxs(Div, { textSize: "sm", className: `border border-border bg-muted/40 ${__P.p4}`, rounded: "lg", children: [_jsx(Text, { weight: "medium", children: "Transport" }), _jsxs(Text, { className: "text-muted-foreground", children: ["Method: ", transport.method, transport.handlingFeeInPaise !== undefined &&
23
+ return (_jsx(Container, { children: _jsx(Section, { padding: "y-xl", children: _jsxs(Stack, { gap: "lg", children: [product.images.length > 0 && (_jsx(Div, { className: `relative h-80 w-full ${__O.hidden} bg-muted`, rounded: "lg", children: _jsx(MediaImage, { src: product.mainImage || product.images[0], alt: product.title, size: "hero", objectFit: "contain" }) })), _jsxs(Stack, { gap: "sm", children: [_jsxs(Row, { gap: "sm", wrap: true, children: [_jsx(Badge, { variant: "secondary", children: "Live Item" }), meta?.vendorVerified && (_jsx(Badge, { variant: "active", children: "Verified Seller" })), meta?.cites && (_jsxs(Badge, { variant: "warning", children: ["CITES: ", meta.cites] }))] }), _jsx(Heading, { level: 1, weight: "bold", size: "2xl", children: product.title }), meta?.species && (_jsxs(Text, { className: "italic text-muted-foreground", size: "sm", children: [meta.species, meta.sex && meta.sex !== "n/a" && ` · ${meta.sex}`, meta.ageMonths !== undefined && ` · ${meta.ageMonths}mo`] })), _jsx(Text, { className: "text-primary", size: "2xl", weight: "semibold", children: price }), _jsx(Text, { className: "text-muted-foreground", children: product.description })] }), jurisdictions.length > 0 && (_jsxs(Div, { className: CLS_WARN_BOX, children: [_jsx(Text, { className: CLS_WARN_TITLE, children: "Delivery restrictions" }), _jsxs(Text, { className: CLS_WARN_BODY, children: ["This item can only be shipped to: ", jurisdictions.join(", ")] })] })), transport && (_jsxs(Div, { textSize: "sm", className: `border border-border bg-muted/40 ${__P.p4}`, rounded: "lg", children: [_jsx(Text, { weight: "medium", children: "Transport" }), _jsxs(Text, { className: "text-muted-foreground", children: ["Method: ", transport.method, transport.handlingFeeInPaise !== undefined &&
23
24
  ` · Handling: ${formatCurrency(transport.handlingFeeInPaise, "INR")}`, transport.insuranceIncluded && " · Insurance included"] })] })), meta?.careInfo && (_jsxs(Div, { textSize: "sm", className: `border border-border bg-muted/40 ${__P.p4}`, rounded: "lg", children: [_jsx(Text, { weight: "medium", children: "Care information" }), _jsx(Text, { className: "mt-1 text-muted-foreground", children: meta.careInfo })] })), renderActions?.()] }) }) }));
24
25
  }
@@ -79,7 +79,7 @@ export function LotteryAdminEditView({ eventId, initialData, onSubmit, }) {
79
79
  : []),
80
80
  ];
81
81
  const slotsWithIdx = slots.map((s, i) => ({ ...s, _idx: i }));
82
- return (_jsx(Container, { children: _jsx(Section, { children: _jsx(Form, { onSubmit: (e) => e.preventDefault(), className: "space-y-6", children: ({ setFieldError, clearErrors }) => (_jsxs(Stack, { gap: "xl", children: [_jsx(Heading, { level: 1, size: "2xl", weight: "bold", children: eventId ? "Edit Lottery" : "Create Lottery" }), _jsxs(Stack, { gap: "md", children: [_jsx(Heading, { level: 2, size: "lg", weight: "semibold", children: "Basic Info" }), _jsx(FieldInput, { name: "title", label: "Title", required: true, value: title, onChange: (v) => { setTitle(v); clearErrors(); } }), _jsx(FieldInput, { name: "description", label: "Description", value: description, onChange: (v) => { setDescription(v); clearErrors(); } })] }), _jsxs(Stack, { gap: "md", children: [_jsx(Heading, { level: 2, size: "lg", weight: "semibold", children: "Configuration" }), _jsx(FieldSelect, { name: "pricingMode", label: "Pricing Mode", value: pricingMode, options: [
82
+ return (_jsx(Container, { children: _jsx(Section, { children: _jsx(Form, { onSubmit: (e) => e.preventDefault(), className: "space-y-6", children: ({ clearErrors }) => (_jsxs(Stack, { gap: "xl", children: [_jsx(Heading, { level: 1, size: "2xl", weight: "bold", children: eventId ? "Edit Lottery" : "Create Lottery" }), _jsxs(Stack, { gap: "md", children: [_jsx(Heading, { level: 2, size: "lg", weight: "semibold", children: "Basic Info" }), _jsx(FieldInput, { name: "title", label: "Title", required: true, value: title, onChange: (v) => { setTitle(v); clearErrors(); } }), _jsx(FieldInput, { name: "description", label: "Description", value: description, onChange: (v) => { setDescription(v); clearErrors(); } })] }), _jsxs(Stack, { gap: "md", children: [_jsx(Heading, { level: 2, size: "lg", weight: "semibold", children: "Configuration" }), _jsx(FieldSelect, { name: "pricingMode", label: "Pricing Mode", value: pricingMode, options: [
83
83
  { label: "Uniform (all slots same price)", value: "uniform" },
84
84
  { label: "Variable (per-slot pricing)", value: "variable" },
85
85
  ], onChange: (v) => setPricingMode(v) }), pricingMode === "uniform" && (_jsx(FieldInput, { name: "uniformPrice", label: "Price per Slot (\u20B9)", type: "number", value: uniformPrice, onChange: (v) => setUniformPrice(v) })), _jsx(FieldInput, { name: "drawWindowMinutes", label: "Draw Window (minutes)", type: "number", value: drawWindowMinutes, onChange: (v) => setDrawWindowMinutes(v) }), _jsx(FieldInput, { name: "maxPullsPerTx", label: "Max Pulls per Transaction", type: "number", value: maxPullsPerTx, onChange: (v) => setMaxPullsPerTx(v) }), _jsx(FieldInput, { name: "maxPullsPerUser", label: "Max Pulls per User", type: "number", value: maxPullsPerUser, onChange: (v) => setMaxPullsPerUser(v) })] }), _jsxs(Stack, { gap: "md", children: [_jsxs(Row, { align: "center", justify: "between", children: [_jsxs(Heading, { level: 2, size: "lg", weight: "semibold", children: ["Slots (", slots.length, ")"] }), _jsx(Button, { type: "button", variant: "secondary", size: "sm", onClick: addSlot, disabled: slots.length >= 200, children: "+ Add Slot" })] }), _jsx(DataTable, { data: slotsWithIdx, columns: slotColumns, keyExtractor: (s) => String(s.slotNumber), emptyMessage: "No slots yet.", actions: (s) => slots.length > 1 ? (_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => removeSlot(s._idx), "aria-label": `Remove slot ${s.slotNumber}`, children: "\u00D7" })) : null })] }), error && _jsx(Text, { className: "text-error", size: "sm", role: "alert", children: error }), _jsx(Button, { type: "submit", variant: "primary", isLoading: isPending, onClick: handleSubmit, className: "w-full sm:w-auto", children: isPending ? "Saving…" : eventId ? "Update Lottery" : "Create Lottery" })] })) }) }) }));
@@ -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 { Stack, Row, Text, Heading, Badge, Section, Container, Div, Anchor, } from "../../../../ui";
5
+ import { MediaImage } from "../../../../features/media/MediaImage";
5
6
  import { ROUTES } from "../../../../next/routing/route-map";
6
7
  import { LotterySlotGrid } from "./LotterySlotGrid";
7
8
  import { LotteryPullForm } from "./LotteryPullForm";
@@ -14,5 +15,5 @@ export function LotteryDetailView({ event, user, currentEntry }) {
14
15
  const config = event.lotteryConfig;
15
16
  const isActive = event.status === "active";
16
17
  const isEnded = event.status === "ended" || event.status === "cancelled";
17
- return (_jsx(Container, { children: _jsx(Section, { children: _jsxs(Stack, { gap: "xl", children: [event.coverImageUrl ? (_jsx(Div, { rounded: "2xl", className: "overflow-hidden", style: { aspectRatio: "16/9", maxHeight: "16rem" }, children: _jsx("img", { src: event.coverImageUrl, alt: event.title, className: "w-full h-full object-cover" }) })) : (_jsx(Div, { rounded: "2xl", surface: "subtle", padding: "xl", align: "center", justify: "center", children: _jsx(Text, { size: "5xl", children: "\uD83C\uDFB0" }) })), _jsxs(Stack, { gap: "sm", children: [_jsxs(Row, { gap: "xs", align: "center", wrap: true, children: [_jsx(Badge, { variant: isActive ? "success" : isEnded ? "danger" : "warning", children: event.status }), config && (_jsxs(Badge, { variant: "info", children: [config.slots.filter((s) => s.isBooked).length, "/", config.totalSlots, " slots claimed"] }))] }), _jsx(Heading, { level: 1, size: "3xl", weight: "bold", children: event.title }), event.description ? (_jsx(Text, { color: "muted", size: "sm", children: event.description.replace(/<[^>]+>/g, "").slice(0, 200) })) : null, event.endsAt ? (_jsxs(Text, { size: "sm", color: "muted", children: ["Ends: ", new Date(event.endsAt).toLocaleDateString("en-IN", { dateStyle: "long" })] })) : null] }), config && config.slots.length > 0 ? (_jsxs(Stack, { gap: "sm", children: [_jsx(Heading, { level: 2, size: "xl", weight: "semibold", children: "Slots" }), _jsx(LotterySlotGrid, { slots: config.slots, totalSlots: config.totalSlots })] })) : null, isActive && config && (_jsx(Div, { padding: "md", rounded: "2xl", surface: "card", className: "border border-[var(--appkit-color-border)]", children: !user ? (_jsxs(Stack, { gap: "md", className: "text-center", children: [_jsx(Heading, { level: 2, size: "xl", weight: "semibold", children: "Want to Participate?" }), _jsx(Text, { color: "muted", children: "Log in to submit your lottery entry." }), _jsx(Anchor, { href: String(ROUTES.AUTH.LOGIN), tone: "brand", children: "Log In to Enter" })] })) : pulledEntry ? (_jsxs(Stack, { gap: "sm", surface: "success-surface", padding: "md", rounded: "xl", className: "border border-success/20", children: [_jsxs(Heading, { level: 2, size: "lg", weight: "bold", className: "text-success", children: ["You're Lottery #", pulledEntry.userLotteryNumber, "!"] }), _jsxs(Text, { className: "text-success", size: "sm", children: ["Assigned to Slot #", pulledEntry.assignedPrizeSlotNumber, pulledEntry.slotName ? ` — ${pulledEntry.slotName}` : "", "."] })] })) : (_jsx(LotteryPullForm, { sourceType: "event", eventId: event.id, totalSlots: config.totalSlots, maxPullsPerUser: config.maxPullsPerUser, onSuccess: (res) => setPulledEntry(res) })) })), isEnded && !pulledEntry && (_jsx(Stack, { gap: "sm", surface: "muted", padding: "md", rounded: "xl", children: _jsx(Text, { color: "muted", weight: "semibold", children: "This lottery has ended." }) }))] }) }) }));
18
+ return (_jsx(Container, { children: _jsx(Section, { children: _jsxs(Stack, { gap: "xl", children: [event.coverImageUrl ? (_jsx(Div, { rounded: "2xl", className: "relative overflow-hidden", style: { aspectRatio: "16/9", maxHeight: "16rem" }, children: _jsx(MediaImage, { src: event.coverImageUrl, alt: event.title, size: "hero" }) })) : (_jsx(Div, { rounded: "2xl", surface: "subtle", padding: "xl", align: "center", justify: "center", children: _jsx(Text, { size: "5xl", children: "\uD83C\uDFB0" }) })), _jsxs(Stack, { gap: "sm", children: [_jsxs(Row, { gap: "xs", align: "center", wrap: true, children: [_jsx(Badge, { variant: isActive ? "success" : isEnded ? "danger" : "warning", children: event.status }), config && (_jsxs(Badge, { variant: "info", children: [config.slots.filter((s) => s.isBooked).length, "/", config.totalSlots, " slots claimed"] }))] }), _jsx(Heading, { level: 1, size: "3xl", weight: "bold", children: event.title }), event.description ? (_jsx(Text, { color: "muted", size: "sm", children: event.description.replace(/<[^>]+>/g, "").slice(0, 200) })) : null, event.endsAt ? (_jsxs(Text, { size: "sm", color: "muted", children: ["Ends: ", new Date(event.endsAt).toLocaleDateString("en-IN", { dateStyle: "long" })] })) : null] }), config && config.slots.length > 0 ? (_jsxs(Stack, { gap: "sm", children: [_jsx(Heading, { level: 2, size: "xl", weight: "semibold", children: "Slots" }), _jsx(LotterySlotGrid, { slots: config.slots, totalSlots: config.totalSlots })] })) : null, isActive && config && (_jsx(Div, { padding: "md", rounded: "2xl", surface: "card", className: "border border-[var(--appkit-color-border)]", children: !user ? (_jsxs(Stack, { gap: "md", className: "text-center", children: [_jsx(Heading, { level: 2, size: "xl", weight: "semibold", children: "Want to Participate?" }), _jsx(Text, { color: "muted", children: "Log in to submit your lottery entry." }), _jsx(Anchor, { href: String(ROUTES.AUTH.LOGIN), tone: "brand", children: "Log In to Enter" })] })) : pulledEntry ? (_jsxs(Stack, { gap: "sm", surface: "success-surface", padding: "md", rounded: "xl", className: "border border-success/20", children: [_jsxs(Heading, { level: 2, size: "lg", weight: "bold", className: "text-success", children: ["You're Lottery #", pulledEntry.userLotteryNumber, "!"] }), _jsxs(Text, { className: "text-success", size: "sm", children: ["Assigned to Slot #", pulledEntry.assignedPrizeSlotNumber, pulledEntry.slotName ? ` — ${pulledEntry.slotName}` : "", "."] })] })) : (_jsx(LotteryPullForm, { sourceType: "event", eventId: event.id, totalSlots: config.totalSlots, maxPullsPerUser: config.maxPullsPerUser, onSuccess: (res) => setPulledEntry(res) })) })), isEnded && !pulledEntry && (_jsx(Stack, { gap: "sm", surface: "muted", padding: "md", rounded: "xl", children: _jsx(Text, { color: "muted", weight: "semibold", children: "This lottery has ended." }) }))] }) }) }));
18
19
  }
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { Stack, Row, Text, Heading, Badge, Card, Section, Container, Anchor, Div, Grid, } from "../../../../ui";
4
+ import { MediaImage } from "../../../../features/media/MediaImage";
4
5
  /**
5
6
  * Card grid of lotteries.
6
7
  * Admin sees all statuses; public sees active only.
@@ -16,7 +17,7 @@ export function LotteryListView({ items, adminMode = false }) {
16
17
  const claimed = event.lotteryConfig?.slots.filter((s) => s.isBooked).length ?? 0;
17
18
  const total = event.lotteryConfig?.totalSlots ?? 0;
18
19
  const slotsLeft = total - claimed;
19
- return (_jsx(Anchor, { href: `/lottery/${event.id}`, tone: "brand", rounded: "2xl", className: "block focus:outline-none focus-visible:ring-2 focus-visible:ring-primary", "aria-label": `${event.title} lottery`, children: _jsxs(Card, { variant: "default", padding: "none", animate: "hoverLift", className: "overflow-hidden", children: [event.coverImageUrl ? (_jsx(Div, { className: "aspect-video overflow-hidden", children: _jsx("img", { src: event.coverImageUrl, alt: event.title, className: "w-full h-full object-cover" }) })) : (_jsx(Div, { className: "aspect-video", surface: "muted", align: "center", justify: "center", children: _jsx(Text, { size: "3xl", children: "\uD83C\uDFB0" }) })), _jsxs(Stack, { gap: "xs", padding: "md", children: [_jsxs(Row, { gap: "xs", align: "center", wrap: true, children: [_jsx(Badge, { variant: event.status === "active"
20
+ return (_jsx(Anchor, { href: `/lottery/${event.id}`, tone: "brand", rounded: "2xl", className: "block focus:outline-none focus-visible:ring-2 focus-visible:ring-primary", "aria-label": `${event.title} lottery`, children: _jsxs(Card, { variant: "default", padding: "none", animate: "hoverLift", className: "overflow-hidden", children: [event.coverImageUrl ? (_jsx(Div, { className: "relative aspect-video overflow-hidden", children: _jsx(MediaImage, { src: event.coverImageUrl, alt: event.title, size: "card" }) })) : (_jsx(Div, { className: "aspect-video", surface: "muted", align: "center", justify: "center", children: _jsx(Text, { size: "3xl", children: "\uD83C\uDFB0" }) })), _jsxs(Stack, { gap: "xs", padding: "md", children: [_jsxs(Row, { gap: "xs", align: "center", wrap: true, children: [_jsx(Badge, { variant: event.status === "active"
20
21
  ? "success"
21
22
  : event.status === "ended"
22
23
  ? "danger"
@@ -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 { Stack, Row, Text, Heading, Badge, Section, Container, Div, Anchor, } from "../../../../ui";
5
+ import { MediaImage } from "../../../../features/media/MediaImage";
5
6
  import { ROUTES } from "../../../../next/routing/route-map";
6
7
  import { LotterySlotGrid } from "./LotterySlotGrid";
7
8
  import { LotteryPullForm } from "./LotteryPullForm";
@@ -15,5 +16,5 @@ export function PrizeDrawLotteryDetailView({ product, user, currentEntry, }) {
15
16
  : null);
16
17
  const config = product.lotteryConfig;
17
18
  const isActive = product.status === "published";
18
- return (_jsx(Container, { children: _jsx(Section, { children: _jsxs(Stack, { gap: "xl", children: [product.mainImage ? (_jsx(Div, { rounded: "2xl", className: "overflow-hidden", style: { aspectRatio: "16/9", maxHeight: "16rem" }, children: _jsx("img", { src: product.mainImage, alt: product.title, className: "w-full h-full object-cover" }) })) : (_jsx(Div, { rounded: "2xl", surface: "muted", padding: "xl", align: "center", justify: "center", children: _jsx(Text, { size: "5xl", children: "\uD83C\uDF81" }) })), _jsxs(Stack, { gap: "sm", children: [_jsxs(Row, { gap: "xs", align: "center", wrap: true, children: [_jsx(Badge, { variant: "info", children: "Lottery Prize Draw" }), config && (_jsxs(Badge, { variant: isActive ? "success" : "secondary", children: [config.slots.filter((s) => s.isBooked).length, "/", config.totalSlots, " claimed"] }))] }), _jsx(Heading, { level: 1, size: "3xl", weight: "bold", children: product.title }), product.description ? (_jsx(Text, { color: "muted", children: product.description })) : null] }), config && config.slots.length > 0 ? (_jsxs(Stack, { gap: "sm", children: [_jsx(Heading, { level: 2, size: "xl", weight: "semibold", children: "Slots" }), _jsx(LotterySlotGrid, { slots: config.slots, totalSlots: config.totalSlots })] })) : null, isActive && config && (_jsx(Div, { padding: "md", rounded: "2xl", surface: "card", className: "border border-[var(--appkit-color-border)]", children: !user ? (_jsxs(Stack, { gap: "md", className: "text-center", children: [_jsx(Heading, { level: 2, size: "xl", weight: "semibold", children: "Want to Enter?" }), _jsx(Text, { color: "muted", children: "Log in to submit your entry." }), _jsx(Anchor, { href: String(ROUTES.AUTH.LOGIN), tone: "brand", children: "Log In to Enter" })] })) : pulledEntry ? (_jsxs(Stack, { gap: "sm", surface: "success-surface", padding: "md", rounded: "xl", className: "border border-success/20", children: [_jsxs(Heading, { level: 2, size: "lg", weight: "bold", className: "text-success", children: ["You're Entry #", pulledEntry.userLotteryNumber, "!"] }), _jsxs(Text, { className: "text-success", size: "sm", children: ["Assigned to Slot #", pulledEntry.assignedPrizeSlotNumber, pulledEntry.slotName ? ` — ${pulledEntry.slotName}` : "", "."] })] })) : (_jsx(LotteryPullForm, { sourceType: "product", productId: product.id, totalSlots: config.totalSlots, maxPullsPerUser: config.maxPullsPerUser, onSuccess: (res) => setPulledEntry(res) })) }))] }) }) }));
19
+ return (_jsx(Container, { children: _jsx(Section, { children: _jsxs(Stack, { gap: "xl", children: [product.mainImage ? (_jsx(Div, { rounded: "2xl", className: "relative overflow-hidden", style: { aspectRatio: "16/9", maxHeight: "16rem" }, children: _jsx(MediaImage, { src: product.mainImage, alt: product.title, size: "hero" }) })) : (_jsx(Div, { rounded: "2xl", surface: "muted", padding: "xl", align: "center", justify: "center", children: _jsx(Text, { size: "5xl", children: "\uD83C\uDF81" }) })), _jsxs(Stack, { gap: "sm", children: [_jsxs(Row, { gap: "xs", align: "center", wrap: true, children: [_jsx(Badge, { variant: "info", children: "Lottery Prize Draw" }), config && (_jsxs(Badge, { variant: isActive ? "success" : "secondary", children: [config.slots.filter((s) => s.isBooked).length, "/", config.totalSlots, " claimed"] }))] }), _jsx(Heading, { level: 1, size: "3xl", weight: "bold", children: product.title }), product.description ? (_jsx(Text, { color: "muted", children: product.description })) : null] }), config && config.slots.length > 0 ? (_jsxs(Stack, { gap: "sm", children: [_jsx(Heading, { level: 2, size: "xl", weight: "semibold", children: "Slots" }), _jsx(LotterySlotGrid, { slots: config.slots, totalSlots: config.totalSlots })] })) : null, isActive && config && (_jsx(Div, { padding: "md", rounded: "2xl", surface: "card", className: "border border-[var(--appkit-color-border)]", children: !user ? (_jsxs(Stack, { gap: "md", className: "text-center", children: [_jsx(Heading, { level: 2, size: "xl", weight: "semibold", children: "Want to Enter?" }), _jsx(Text, { color: "muted", children: "Log in to submit your entry." }), _jsx(Anchor, { href: String(ROUTES.AUTH.LOGIN), tone: "brand", children: "Log In to Enter" })] })) : pulledEntry ? (_jsxs(Stack, { gap: "sm", surface: "success-surface", padding: "md", rounded: "xl", className: "border border-success/20", children: [_jsxs(Heading, { level: 2, size: "lg", weight: "bold", className: "text-success", children: ["You're Entry #", pulledEntry.userLotteryNumber, "!"] }), _jsxs(Text, { className: "text-success", size: "sm", children: ["Assigned to Slot #", pulledEntry.assignedPrizeSlotNumber, pulledEntry.slotName ? ` — ${pulledEntry.slotName}` : "", "."] })] })) : (_jsx(LotteryPullForm, { sourceType: "product", productId: product.id, totalSlots: config.totalSlots, maxPullsPerUser: config.maxPullsPerUser, onSuccess: (res) => setPulledEntry(res) })) }))] }) }) }));
19
20
  }
@@ -712,7 +712,6 @@ export async function verifyAndPlaceRazorpayOrderAction(input) {
712
712
  const siteSettings = await siteSettingsRepository.getSingleton();
713
713
  const platformFeePercent = siteSettings?.commissions?.platformFeePercent ?? 5;
714
714
  const gstPercent = siteSettings?.commissions?.gstPercent ?? 18;
715
- const commissions = siteSettings?.commissions ?? CHECKOUT_DEFAULT_COMMISSIONS;
716
715
  const isValid = await verifyPaymentSignatureWithKeys({
717
716
  razorpay_order_id,
718
717
  razorpay_payment_id,
@@ -55,8 +55,6 @@ export async function submitLotteryPullAction(input) {
55
55
  // Product lottery — load via product repository (not implemented here; caller ensures correct source)
56
56
  throw new ValidationError("Product lottery pull must go through the product lottery pull route.");
57
57
  }
58
- // Compute weights
59
- const weightedSlots = assignSlotWeights(lotteryConfig);
60
58
  // Check draw window
61
59
  if (!isDrawWindowOpen(lotteryConfig)) {
62
60
  throw new LotteryError("LOTTERY_FULL", "All slots have been claimed.");
@@ -36,7 +36,7 @@ export async function createReviewAction(input) {
36
36
  }
37
37
  export async function replyToReviewAction(input) {
38
38
  return wrapAction(async () => {
39
- const user = await requireRoleUser(["seller", "admin"]);
39
+ await requireRoleUser(["seller", "admin"]);
40
40
  const parsed = replyToReviewSchema.safeParse(input);
41
41
  if (!parsed.success) {
42
42
  throw new ValidationError(parsed.error.issues[0]?.message ?? "Invalid input");
@@ -1,12 +1,10 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { ROUTES } from "../../../constants";
3
- import { PAGE_CONTAINER } from "../../../_internal/shared/styles/page";
4
3
  import { FLEX_ROW } from "../../../_internal/shared/styles/themed";
5
4
  import { Aside, Container, Details, Div, Heading, Nav, RichTextRenderer, Row, Section, Span, Stack, Summary, Text } from "../../../ui";
6
5
  import { TextLink } from "../../../ui";
7
6
  import { HelpCircle, ChevronRight } from "lucide-react";
8
7
  export async function FAQPageView({ category, } = {}) {
9
- const page = { container: PAGE_CONTAINER };
10
8
  const flex = { row: FLEX_ROW };
11
9
  const { getTranslations, getMessages } = await import("next-intl/server");
12
10
  const t = await getTranslations("faqs");
@@ -53,6 +53,18 @@ export async function FeesView({} = {}) {
53
53
  who: t("paidByBuyer"),
54
54
  note: t("shippingFeeNote"),
55
55
  },
56
+ {
57
+ category: t("emiSurchargeFeeTitle"),
58
+ rate: t("emiSurchargeFeeRate"),
59
+ who: t("paidByBuyer"),
60
+ note: t("emiSurchargeFeeNote"),
61
+ },
62
+ {
63
+ category: t("codHandlingFeeTitle"),
64
+ rate: t("codHandlingFeeRate"),
65
+ who: t("paidByBuyer"),
66
+ note: t("codHandlingFeeNote"),
67
+ },
56
68
  ];
57
69
  const OFFER_PAYOUT_ROWS = [
58
70
  { label: t("grossSale"), example: "₹1,000" },
@@ -70,6 +82,6 @@ function renderFeeTableSection(t, themed, rows) {
70
82
  function renderPayoutExampleSection(t, themed, rows) {
71
83
  return (_jsxs(Section, { children: [_jsx(Heading, { level: 2, className: "mb-3", children: t("payoutExampleTitle") }), _jsx(Text, { variant: "secondary", className: "mb-6", children: t("payoutExampleSubtitle") }), _jsxs(Div, { className: `${__P.p5} max-w-sm`, border: "default", surface: "muted", rounded: "xl", children: [_jsx(Heading, { level: 3, className: "mb-4", size: "base", children: t("payoutExampleProduct") }), _jsx(Stack, { gap: "sm", children: rows.map((row, i) => (_jsxs(Row, { textWeight: "bold", textSize: "sm", className: `${row.highlight ? "border-t border-[var(--appkit-color-border)] mt-2" : ""}`, paddingY: row.highlight ? "t-xs" : undefined, justify: "between", children: [_jsx(Text, { className: row.highlight ? "font-bold" : "text-[var(--appkit-color-text-muted)]", children: row.label }), _jsx(Text, { className: row.highlight ? CLS_HIGHLIGHT : "", children: row.example })] }, i))) })] })] }));
72
84
  }
73
- function renderDisclaimerSection(t, themed) {
85
+ function renderDisclaimerSection(t, _themed) {
74
86
  return (_jsxs(Section, { className: `${__P.p5}`, border: "default", surface: "subtle", rounded: "xl", children: [_jsx(Heading, { level: 3, className: "mb-2", size: "base", children: t("disclaimerTitle") }), _jsx(Caption, { className: "leading-relaxed", children: t("disclaimerText") })] }));
75
87
  }
@@ -3,7 +3,7 @@ import { ROUTES } from "../../../constants";
3
3
  import { PAGE_CONTAINER } from "../../../_internal/shared/styles/page";
4
4
  import { Div, FlowDiagram, Heading, Row, Section, Stack, Text } from "../../../ui";
5
5
  import { TextLink } from "../../../ui";
6
- import { Smartphone, Banknote } from "lucide-react";
6
+ import { Wallet, Smartphone, Banknote, CalendarClock } from "lucide-react";
7
7
  const __P = {
8
8
  p5: "p-5",
9
9
  p8: "p-8",
@@ -21,19 +21,33 @@ export async function HowCheckoutWorksView({} = {}) {
21
21
  ];
22
22
  const PAYMENT_METHODS = [
23
23
  {
24
- icon: Smartphone,
24
+ icon: Wallet,
25
25
  title: t("pm1Title"),
26
26
  text: t("pm1Text"),
27
27
  color: "bg-primary/5 border-primary/20 dark:bg-primary/10 dark:border-primary/30",
28
28
  iconColor: "text-primary",
29
29
  },
30
30
  {
31
- icon: Banknote,
31
+ icon: Smartphone,
32
32
  title: t("pm2Title"),
33
33
  text: t("pm2Text"),
34
+ color: "bg-sky-50 border-sky-200 dark:bg-sky-900/20 dark:border-sky-700",
35
+ iconColor: "text-sky-600 dark:text-sky-400",
36
+ },
37
+ {
38
+ icon: Banknote,
39
+ title: t("pm3Title"),
40
+ text: t("pm3Text"),
34
41
  color: "bg-emerald-50 border-emerald-200 dark:bg-emerald-900/20 dark:border-emerald-700",
35
42
  iconColor: "text-emerald-600 dark:text-emerald-400",
36
43
  },
44
+ {
45
+ icon: CalendarClock,
46
+ title: t("pm4Title"),
47
+ text: t("pm4Text"),
48
+ color: "bg-violet-50 border-violet-200 dark:bg-violet-900/20 dark:border-violet-700",
49
+ iconColor: "text-violet-600 dark:text-violet-400",
50
+ },
37
51
  ];
38
52
  const DIAGRAM_STEPS = [
39
53
  {
@@ -0,0 +1,3 @@
1
+ export interface HowEmiWorksViewProps {
2
+ }
3
+ export declare function HowEmiWorksView({}?: HowEmiWorksViewProps): Promise<import("react").JSX.Element>;
@@ -0,0 +1,117 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { ROUTES } from "../../../constants";
3
+ import { PAGE_CONTAINER } from "../../../_internal/shared/styles/page";
4
+ import { THEMED_BG_PRIMARY, THEMED_BG_SECONDARY } from "../../../_internal/shared/styles/themed";
5
+ import { Alert, Caption, Div, FlowDiagram, Heading, Row, Section, Stack, Table, Tbody, Td, Text, Th, Thead, Tr } from "../../../ui";
6
+ import { TextLink } from "../../../ui";
7
+ import { CalendarClock, Wallet, TrendingUp, ShieldCheck } from "lucide-react";
8
+ const __P = {
9
+ p5: "p-5",
10
+ p8: "p-8",
11
+ };
12
+ const __O = {
13
+ xAuto: "overflow-x-auto",
14
+ };
15
+ export async function HowEmiWorksView({} = {}) {
16
+ const page = { container: PAGE_CONTAINER };
17
+ const themed = { bgPrimary: THEMED_BG_PRIMARY, bgSecondary: THEMED_BG_SECONDARY };
18
+ const { getTranslations } = await import("next-intl/server");
19
+ const t = await getTranslations("howEmiWorks");
20
+ const STEPS = [
21
+ { number: 1, icon: "🛒", title: t("step1Title"), text: t("step1Text") },
22
+ { number: 2, icon: "✅", title: t("step2Title"), text: t("step2Text") },
23
+ { number: 3, icon: "💳", title: t("step3Title"), text: t("step3Text") },
24
+ { number: 4, icon: "📅", title: t("step4Title"), text: t("step4Text") },
25
+ { number: 5, icon: "🎉", title: t("step5Title"), text: t("step5Text") },
26
+ ];
27
+ const INFO_CARDS = [
28
+ {
29
+ icon: Wallet,
30
+ title: t("infoCard1Title"),
31
+ text: t("infoCard1Text"),
32
+ color: "bg-primary/5 border-primary/20 dark:bg-primary/10 dark:border-primary/30",
33
+ iconColor: "text-primary",
34
+ },
35
+ {
36
+ icon: CalendarClock,
37
+ title: t("infoCard2Title"),
38
+ text: t("infoCard2Text"),
39
+ color: "bg-emerald-50 border-emerald-200 dark:bg-emerald-900/20 dark:border-emerald-700",
40
+ iconColor: "text-emerald-600 dark:text-emerald-400",
41
+ },
42
+ {
43
+ icon: TrendingUp,
44
+ title: t("infoCard3Title"),
45
+ text: t("infoCard3Text"),
46
+ color: "bg-sky-50 border-sky-200 dark:bg-sky-900/20 dark:border-sky-700",
47
+ iconColor: "text-sky-600 dark:text-sky-400",
48
+ },
49
+ {
50
+ icon: ShieldCheck,
51
+ title: t("infoCard4Title"),
52
+ text: t("infoCard4Text"),
53
+ color: "bg-violet-50 border-violet-200 dark:bg-violet-900/20 dark:border-violet-700",
54
+ iconColor: "text-violet-600 dark:text-violet-400",
55
+ },
56
+ ];
57
+ const EXAMPLE_ROWS = [
58
+ { label: t("exampleOrderTotal"), example: "₹15,000" },
59
+ { label: `${t("exampleToken")} (10%)`, example: "− ₹1,500" },
60
+ { label: t("exampleRemaining"), example: "= ₹13,500" },
61
+ { label: `${t("exampleSurcharge")} (1%/mo × 3mo)`, example: "+ ₹405" },
62
+ { label: t("exampleMonthly"), example: "₹4,635 × 3", highlight: true },
63
+ ];
64
+ const DIAGRAM_STEPS = [
65
+ {
66
+ emoji: "🛒",
67
+ circleClass: "bg-[var(--appkit-color-border-subtle)] border-2 border-[var(--appkit-color-border)]",
68
+ badge: t("step1Title"),
69
+ badgeClass: "bg-[var(--appkit-color-border-subtle)] text-[var(--appkit-color-text-muted)]",
70
+ desc: t("diagramStep1Desc"),
71
+ },
72
+ {
73
+ emoji: "✅",
74
+ circleClass: "bg-primary/10 dark:bg-primary/15 border-2 border-primary/30 dark:border-primary/40",
75
+ badge: t("step2Title"),
76
+ badgeClass: "bg-primary/10 dark:bg-primary/15 text-primary",
77
+ desc: t("diagramStep2Desc"),
78
+ },
79
+ {
80
+ emoji: "💳",
81
+ circleClass: "bg-violet-100 dark:bg-violet-900/40 border-2 border-violet-400 dark:border-violet-600",
82
+ badge: t("step3Title"),
83
+ badgeClass: "bg-violet-100 dark:bg-violet-900/40 text-violet-700 dark:text-violet-300",
84
+ desc: t("diagramStep3Desc"),
85
+ },
86
+ {
87
+ emoji: "📅",
88
+ circleClass: "bg-amber-100 dark:bg-amber-900/40 border-2 border-amber-300 dark:border-amber-600",
89
+ badge: t("step4Title"),
90
+ badgeClass: "bg-amber-100 dark:bg-amber-900/40 text-amber-700 dark:text-amber-300",
91
+ desc: t("diagramStep4Desc"),
92
+ },
93
+ {
94
+ emoji: "🎉",
95
+ circleClass: "bg-emerald-100 dark:bg-emerald-900/40 border-2 border-emerald-400 dark:border-emerald-600",
96
+ badge: t("step5Title"),
97
+ badgeClass: "bg-emerald-100 dark:bg-emerald-900/40 text-emerald-700 dark:text-emerald-300",
98
+ desc: t("diagramStep5Desc"),
99
+ },
100
+ ];
101
+ return (_jsxs(Div, { className: "-mx-4 md:-mx-6 lg:-mx-8 -mt-6 sm:-mt-8 lg:-mt-10", children: [_jsx(Section, { color: "inverse", tone: "accent-banner", padding: "banner", children: _jsxs(Div, { className: `${page.container.md} text-center`, children: [_jsx(Heading, { color: "inverse", level: 1, variant: "none", className: "mb-4", children: t("title") }), _jsx(Text, { color: "inverse", variant: "none", className: "/80 max-w-2xl mx-auto", children: t("subtitle") })] }) }), _jsxs(Stack, { gap: "14", className: `${page.container.md}`, padding: "content-banner", children: [renderEligibilityAlert(t), renderEmiSteps(t, STEPS), _jsx(Section, { children: _jsx(FlowDiagram, { title: `💳 ${t("diagramTitle")}`, titleClass: "text-primary", connectorClass: "bg-primary/20 dark:bg-primary/30", steps: DIAGRAM_STEPS, centered: true }) }), renderEmiInfoCards(INFO_CARDS), renderEmiExample(t, themed, EXAMPLE_ROWS), renderEmiCta(t)] })] }));
102
+ }
103
+ function renderEligibilityAlert(t) {
104
+ return (_jsx(Alert, { variant: "info", title: t("eligibilityTitle"), children: t("eligibilityText") }));
105
+ }
106
+ function renderEmiSteps(t, steps) {
107
+ return (_jsxs(Section, { children: [_jsx(Heading, { level: 2, className: "mb-8", align: "center", children: t("stepsTitle") }), _jsx(Stack, { gap: "5", children: steps.map(({ number, icon, title, text }) => (_jsxs(Row, { className: `${__P.p5}`, border: "default", surface: "muted", align: "start", gap: "md", rounded: "xl", children: [_jsx(Row, { align: "center", justify: "center", className: "flex-shrink-0 w-10 h-10 bg-primary/10 dark:bg-primary/15", rounded: "full", children: icon }), _jsxs(Div, { children: [_jsxs(Text, { className: "mb-0.5", weight: "semibold", children: [number, ". ", title] }), _jsx(Text, { variant: "secondary", className: "leading-relaxed", size: "sm", children: text })] })] }, number))) })] }));
108
+ }
109
+ function renderEmiInfoCards(cards) {
110
+ return (_jsx(Section, { children: _jsx(Div, { layout: "grid", gap: "5", className: "md:grid-cols-2", children: cards.map(({ icon: Icon, title, text, color, iconColor }) => (_jsxs(Div, { className: `border ${__P.p5} ${color}`, rounded: "xl", children: [_jsx(Row, { align: "center", justify: "center", className: "w-10 h-10 mb-3", surface: "default", rounded: "lg", children: _jsx(Icon, { className: `w-5 h-5 ${iconColor}` }) }), _jsx(Text, { className: "mb-1", weight: "semibold", children: title }), _jsx(Text, { variant: "secondary", className: "leading-relaxed", size: "sm", children: text })] }, title))) }) }));
111
+ }
112
+ function renderEmiExample(t, themed, rows) {
113
+ return (_jsxs(Section, { children: [_jsx(Heading, { level: 2, className: "mb-3", align: "center", children: t("exampleTitle") }), _jsx(Text, { variant: "secondary", className: "mb-8 max-w-xl mx-auto", align: "center", children: t("exampleSubtitle") }), _jsx(Div, { className: `${__O.xAuto}`, border: "default", rounded: "xl", children: _jsxs(Table, { size: "sm", children: [_jsx(Thead, { className: themed.bgSecondary, children: _jsxs(Tr, { children: [_jsx(Th, { className: "text-left", padding: "md", weight: "semibold", children: t("exampleColLine") }), _jsx(Th, { className: "text-right", padding: "md", weight: "semibold", children: t("exampleColAmount") })] }) }), _jsx(Tbody, { className: "divide-y divide-neutral-100 divide-[var(--appkit-color-border)]", children: rows.map((row, i) => (_jsxs(Tr, { className: `${themed.bgPrimary} ${row.highlight ? "font-bold" : ""}`, children: [_jsx(Td, { padding: "md", weight: row.highlight ? "bold" : "medium", children: row.label }), _jsx(Td, { className: `text-right ${row.highlight ? "text-primary" : ""}`, padding: "md", children: row.example })] }, i))) })] }) }), _jsx(Caption, { className: "mt-3 block", color: "muted", children: t("exampleNote") })] }));
114
+ }
115
+ function renderEmiCta(t) {
116
+ return (_jsxs(Section, { className: `${__P.p8} text-center`, border: "default", surface: "subtle", rounded: "2xl", children: [_jsx(Heading, { level: 2, className: "mb-3", children: t("ctaTitle") }), _jsx(Text, { variant: "secondary", className: "mb-6 max-w-lg mx-auto", children: t("ctaText") }), _jsxs(Row, { align: "center", justify: "center", gap: "md", wrap: true, children: [_jsx(TextLink, { href: String(ROUTES.PUBLIC.PRODUCTS), children: t("ctaBrowse") }), _jsx(TextLink, { href: String(ROUTES.PUBLIC.HOW_CHECKOUT_WORKS), variant: "muted", children: t("ctaCheckout") })] })] }));
117
+ }
@@ -108,7 +108,7 @@ function buildProfileStatItems(t, ctx) {
108
108
  ];
109
109
  }
110
110
  function renderProfileHero(t, ctx) {
111
- const { displayName, photoURL, memberSince, isSeller, storeSlug, flex, page } = ctx;
111
+ const { displayName, photoURL, memberSince, isSeller, storeSlug, page } = ctx;
112
112
  return (_jsx(Section, { color: "inverse", tone: "accent-banner", paddingY: "y-2-5xl", children: _jsx(Div, { className: `${page.container.md}`, children: _jsxs(Stack, { direction: "sm-row", wrap: true, align: "center", smAlign: "end", gap: "md", children: [_jsx(Row, { align: "center", justify: "center", className: `w-20 h-20 flex-shrink-0 ${__O.hidden}`, surface: "default", rounded: "full", children: photoURL ? _jsx(MediaImage, { src: photoURL, alt: displayName, size: "avatar", fallback: "\uD83D\uDC64" }) : _jsx(User, { className: "w-10 h-10 text-white/60" }) }), _jsxs(Stack, { gap: "xs", className: "text-center sm:text-left", children: [_jsxs(Row, { justify: "start", gap: "xs", wrap: true, children: [_jsx(Heading, { color: "inverse", level: 1, variant: "none", className: "mb-0", children: displayName }), isSeller && _jsx(Span, { color: "inverse", size: "xs", weight: "semibold", className: "bg-[white]/20", padding: "pill-sm", rounded: "full", children: t("roleSeller") })] }), _jsx(Text, { color: "inverse", variant: "none", size: "sm", children: memberSince })] }), isSeller && storeSlug && (_jsx(Div, { className: "sm:ml-auto", children: _jsxs(Link, { href: String(ROUTES.PUBLIC.STORE_DETAIL(storeSlug)), className: "inline-flex items-center gap-1.5 rounded-full border border-white/30 bg-white/10 hover:bg-white/20 px-4 py-2 text-sm font-medium text-white transition-colors", children: [_jsx(ExternalLink, { className: "w-3.5 h-3.5" }), t("visitStore")] }) }))] }) }) }));
113
113
  }
114
114
  function renderProfileStatsRow(flex, statItems) {
@@ -127,9 +127,6 @@ function renderStoreDescriptionSection(isSeller, storeSlug, storeDescription, st
127
127
  function renderProfileListingsSection(t, products, storeSlug) {
128
128
  return (_jsxs(Section, { children: [_jsx(Heading, { level: 2, className: "mb-4", children: t("listingsTitle") }), products.length === 0 ? (_jsxs(Div, { rounded: "2xl", padding: "3xl", className: "text-center", border: "default", surface: "subtle", children: [_jsx(ShoppingBag, { className: CLS_EMPTY_ICON }), _jsx(Text, { variant: "secondary", size: "sm", children: t("noListings") })] })) : (_jsx(Grid, { gap: "md", className: "grid-cols-2 sm:grid-cols-3 lg:grid-cols-4", children: products.slice(0, 8).map((p) => _jsx(ProductCard, { product: toProductItem(p), href: getProductHref(p) }, p.id)) })), products.length > 8 && storeSlug && (_jsx(Div, { className: "mt-4 text-center", children: _jsx(Link, { href: String(ROUTES.PUBLIC.STORE_PRODUCTS(storeSlug)), className: "text-sm font-medium text-primary hover:underline", children: t("viewAllListings", { count: products.length }) }) }))] }));
129
129
  }
130
- function renderProfileReviewsSection(t, reviews, storeSlug) {
131
- return (_jsxs(Section, { children: [_jsx(Heading, { level: 2, className: "mb-4", children: t("reviewsReceivedTitle") }), reviews.length === 0 ? (_jsxs(Div, { rounded: "2xl", padding: "3xl", className: "text-center", border: "default", surface: "subtle", children: [_jsx(Star, { className: CLS_EMPTY_ICON }), _jsx(Text, { variant: "secondary", size: "sm", children: t("noReviewsReceived") })] })) : (_jsx(Grid, { gap: "md", className: "grid-cols-1 sm:grid-cols-2", children: reviews.slice(0, 6).map((review) => _jsx(ReviewCard, { review: review }, review.id)) })), reviews.length > 6 && storeSlug && (_jsx(Div, { className: "mt-4 text-center", children: _jsx(Link, { href: String(ROUTES.PUBLIC.STORE_REVIEWS(storeSlug)), className: "text-sm font-medium text-primary hover:underline", children: t("viewAllReviews", { count: reviews.length }) }) }))] }));
132
- }
133
130
  function renderAuthoredReviewsSection(t, reviews, displayName) {
134
131
  return (_jsxs(Section, { children: [_jsx(Heading, { level: 2, className: "mb-4", children: t("reviewsAuthoredTitle", { name: displayName }) }), reviews.length === 0 ? (_jsxs(Div, { rounded: "2xl", padding: "3xl", className: "text-center", border: "default", surface: "subtle", children: [_jsx(Star, { className: CLS_EMPTY_ICON }), _jsx(Text, { variant: "secondary", size: "sm", children: t("noReviewsAuthored", { name: displayName }) })] })) : (_jsx(Grid, { gap: "md", className: "grid-cols-1 sm:grid-cols-2", children: reviews.slice(0, 6).map((review) => _jsx(ReviewCard, { review: review }, review.id)) }))] }));
135
132
  }
@@ -10,6 +10,8 @@ export { ShippingPolicyView } from "./components/ShippingPolicyView";
10
10
  export type { ShippingPolicyViewProps } from "./components/ShippingPolicyView";
11
11
  export { HowCheckoutWorksView } from "./components/HowCheckoutWorksView";
12
12
  export type { HowCheckoutWorksViewProps } from "./components/HowCheckoutWorksView";
13
+ export { HowEmiWorksView } from "./components/HowEmiWorksView";
14
+ export type { HowEmiWorksViewProps } from "./components/HowEmiWorksView";
13
15
  export { HowOffersWorkView } from "./components/HowOffersWorkView";
14
16
  export type { HowOffersWorkViewProps } from "./components/HowOffersWorkView";
15
17
  export { HowOrdersWorkView } from "./components/HowOrdersWorkView";
@@ -4,6 +4,7 @@ export { FeesView } from "./components/FeesView";
4
4
  export { SecurityPrivacyView } from "./components/SecurityPrivacyView";
5
5
  export { ShippingPolicyView } from "./components/ShippingPolicyView";
6
6
  export { HowCheckoutWorksView } from "./components/HowCheckoutWorksView";
7
+ export { HowEmiWorksView } from "./components/HowEmiWorksView";
7
8
  export { HowOffersWorkView } from "./components/HowOffersWorkView";
8
9
  export { HowOrdersWorkView } from "./components/HowOrdersWorkView";
9
10
  export { HowReviewsWorkView } from "./components/HowReviewsWorkView";
@@ -14,4 +14,4 @@ export interface BecomeSellerViewProps {
14
14
  isLoading?: boolean;
15
15
  className?: string;
16
16
  }
17
- export declare function BecomeSellerView({ labels, renderGuide, renderSuccess, renderAlreadySeller, state, isLoading, className, }: BecomeSellerViewProps): React.JSX.Element;
17
+ export declare function BecomeSellerView({ labels, renderGuide, renderSuccess, renderAlreadySeller, state, isLoading: _isLoading, className, }: BecomeSellerViewProps): React.JSX.Element;
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Div, Heading } from "../../../ui";
3
- export function BecomeSellerView({ labels = {}, renderGuide, renderSuccess, renderAlreadySeller, state = "guide", isLoading = false, className = "", }) {
3
+ export function BecomeSellerView({ labels = {}, renderGuide, renderSuccess, renderAlreadySeller, state = "guide", isLoading: _isLoading = false, className = "", }) {
4
4
  return (_jsxs(Div, { className: className, children: [labels.title && state === "guide" && (_jsx(Heading, { level: 1, className: "mb-6", size: "2xl", weight: "bold", children: labels.title })), state === "guide" && renderGuide?.(), state === "success" && renderSuccess?.(), state === "already-seller" && renderAlreadySeller?.()] }));
5
5
  }
@@ -32,7 +32,7 @@ const DEFAULT_ICONS = {
32
32
  export function NotificationBell({ limit = 10, viewAllHref, labels, icons, renderLink, onMarkAllReadSuccess, onMarkAllReadError, buttonClassName = "", dropdownClassName = "", hideOnMobile = true, }) {
33
33
  const [isOpen, setIsOpen] = useState(false);
34
34
  const dropdownRef = useRef(null);
35
- const { showSuccess, showError } = useMessage();
35
+ const { showSuccess, showError: _showError } = useMessage();
36
36
  const { showToast } = useToast();
37
37
  const { notifications, unreadCount, isLoading, refetch, markRead, markAllRead, isMarkingAll, } = useNotifications(limit);
38
38
  const notificationIcons = { ...DEFAULT_ICONS, ...icons };
@@ -55,7 +55,6 @@ export function NotificationBell({ limit = 10, viewAllHref, labels, icons, rende
55
55
  }
56
56
  }, [markRead, refetch, showToast]);
57
57
  const emitSuccess = onMarkAllReadSuccess ?? showSuccess;
58
- const emitError = onMarkAllReadError ?? showError;
59
58
  const handleMarkAllRead = useCallback(async () => {
60
59
  try {
61
60
  await markAllRead(undefined);
@@ -16,7 +16,6 @@ const __O = {
16
16
  yAuto: "overflow-y-auto",
17
17
  };
18
18
  // --- Constants ---------------------------------------------------------------
19
- const CLS_INPUT = "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 focus:outline-none focus:ring-2 focus:ring-primary-500";
20
19
  const CATEGORY_OPTIONS = [
21
20
  { label: "Order Issue", value: "order_issue" },
22
21
  { label: "Billing / Payment", value: "billing_payment" },
@@ -4,7 +4,7 @@ import { normalizeError } from "../../../errors/normalize";
4
4
  import { useApiMutation } from "@mohasinac/appkit/client";
5
5
  import React from "react";
6
6
  import { useQuery, useQueryClient } from "@tanstack/react-query";
7
- import { Alert, Button, Div, Input, Label, Row, Select, Stack, StackedViewShell, Text } from "../../../ui";
7
+ import { Alert, Button, Div, Input, Label, Row, Select, Stack, StackedViewShell, Text, TextLink } from "../../../ui";
8
8
  import { apiClient } from "../../../http";
9
9
  import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
10
10
  import { DataTable } from "./DataTable";
@@ -117,7 +117,7 @@ export function AdminAdsView({ endpoint = ADMIN_ENDPOINTS.ADS, labels = {}, crea
117
117
  render: (row) => {
118
118
  const nextStatus = row.status === "active" ? "paused" : "active";
119
119
  const cannotPublish = nextStatus === "active" && row.publishReady === false;
120
- return (_jsxs(Row, { align: "center", gap: "sm", children: [renderEditLink ? renderEditLink(row) : (_jsx("a", { className: "inline-flex h-8 items-center rounded-md border border-neutral-200 px-3 text-xs border-[var(--appkit-color-border)]", href: `/admin/ads/${row.id}/edit`, children: "Edit" })), _jsx(Button, { size: "sm", variant: "outline", disabled: statusMutation.isPending || cannotPublish, onClick: () => statusMutation.mutate({ id: row.id, nextStatus }), children: row.status === "active" ? "Pause" : "Publish" })] }));
120
+ return (_jsxs(Row, { align: "center", gap: "sm", children: [renderEditLink ? renderEditLink(row) : (_jsx(TextLink, { variant: "bare", href: `/admin/ads/${row.id}/edit`, rounded: "md", paddingX: "sm", size: "xs", layout: "inline-flex", align: "center", className: "h-8 border border-neutral-200 border-[var(--appkit-color-border)]", children: "Edit" })), _jsx(Button, { size: "sm", variant: "outline", disabled: statusMutation.isPending || cannotPublish, onClick: () => statusMutation.mutate({ id: row.id, nextStatus }), children: row.status === "active" ? "Pause" : "Publish" })] }));
121
121
  },
122
122
  },
123
123
  ], [renderEditLink, statusMutation]);
@@ -156,7 +156,7 @@ export function AdminAdsView({ endpoint = ADMIN_ENDPOINTS.ADS, labels = {}, crea
156
156
  settingsMutation.mutate(payload);
157
157
  };
158
158
  return (_jsx(StackedViewShell, { portal: "admin", ...rest, title: labels.title ?? "Ad Inventory", sections: [
159
- _jsxs(Row, { align: "center", justify: "between", gap: "3", children: [_jsx(Text, { variant: "secondary", children: "Manage ad inventory, placement mapping, and publishing state." }), _jsx("a", { href: createHref, className: "inline-flex h-9 items-center rounded-md bg-neutral-900 px-3 text-sm font-medium text-white bg-[var(--appkit-color-surface)] dark:text-[var(--appkit-color-text)]", children: "New ad" })] }),
159
+ _jsxs(Row, { align: "center", justify: "between", gap: "3", children: [_jsx(Text, { variant: "secondary", children: "Manage ad inventory, placement mapping, and publishing state." }), _jsx(TextLink, { variant: "bare", href: createHref, rounded: "md", paddingX: "sm", size: "sm", weight: "medium", layout: "inline-flex", align: "center", className: "h-9 bg-neutral-900 text-white bg-[var(--appkit-color-surface)] dark:text-[var(--appkit-color-text)]", children: "New ad" })] }),
160
160
  adsQuery.error ? (_jsx(Alert, { variant: "error", title: "Could not load ads", children: adsQuery.error instanceof Error ? adsQuery.error.message : "Unknown error" })) : null,
161
161
  _jsx(AdsSettingsPanel, { adsenseClientId: adsenseClientId, setAdsenseClientId: setAdsenseClientId, thirdPartyScriptUrl: thirdPartyScriptUrl, setThirdPartyScriptUrl: setThirdPartyScriptUrl, consentRequired: consentRequired, setConsentRequired: setConsentRequired, serverCredentialIssues: serverCredentialIssues, localCredentialIssues: localCredentialIssues, credentialStatus: credentialStatus, providerCredentialsMasked: adsQuery.data?.providerCredentialsMasked, settingsMutation: settingsMutation, hasPendingCredentialInput: hasPendingCredentialInput, currentConsentRequired: Boolean(adsQuery.data?.consentRequired), settingsMessage: settingsMessage, onSave: saveSettings }),
162
162
  _jsx(AdsFilterRow, { q: q, setQ: setQ, status: status, setStatus: setStatus, provider: provider, setProvider: setProvider, placement: placement, setPlacement: setPlacement, placements: placements, onPageReset: () => setPage(1) }),
@@ -5,7 +5,7 @@ import { useApiMutation } from "@mohasinac/appkit/client";
5
5
  import React from "react";
6
6
  import { useQuery } from "@tanstack/react-query";
7
7
  import { Button, ConfirmDeleteModal, Div, Heading, Input, RichTextEditor, RichTextRenderer, Row, Select, Span, Stack, StackedViewShell, TagInput, Text, Toggle, useToast } from "../../../ui";
8
- import { ImageUpload, useMediaUpload } from "../../media";
8
+ import { ImageUpload, MediaImage, useMediaUpload } from "../../media";
9
9
  import { apiClient } from "../../../http";
10
10
  import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
11
11
  import { StepForm } from "../../shell";
@@ -200,7 +200,7 @@ export function AdminBlogEditorView({ postId, onSaved, onDeleted, embedded, ...r
200
200
  if (embedded) {
201
201
  return _jsx(Div, { className: `${__O.yAuto} ${__P.p4}`, children: formContent });
202
202
  }
203
- const previewSection = (_jsxs(Div, { rounded: "lg", padding: "5", className: "border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface-raised)] max-h-[calc(100vh-12rem)] overflow-y-auto", children: [_jsx(Row, { textSize: "xs", textWeight: "semibold", color: "muted", className: "mb-3 uppercase tracking-wide", align: "center", gap: "sm", children: _jsx(Span, { children: "Live preview" }) }), draft.coverImage ? (_jsx("img", { src: draft.coverImage, alt: "", className: "w-full rounded-md mb-4 object-cover max-h-64" })) : null, _jsx(Heading, { level: 1, className: "mb-1", size: "2xl", weight: "bold", children: draft.title || "Untitled post" }), _jsxs(Text, { className: "text-[var(--appkit-color-text-muted)] mb-4", size: "xs", children: [draft.authorName || "Anonymous", draft.category ? ` · ${draft.category}` : ""] }), draft.excerpt ? (_jsx(Text, { className: "italic text-[var(--appkit-color-text-secondary)] mb-4", children: draft.excerpt })) : null, _jsx(RichTextRenderer, { html: draft.content || "<em>No content yet…</em>" }), draft.tags.length > 0 ? (_jsx(Row, { wrap: true, gap: "xs", className: "mt-6", children: draft.tags.map((t) => (_jsxs(Span, { size: "xs", className: "bg-[var(--appkit-color-surface)] border border-[var(--appkit-color-border)]", rounded: "full", padding: "pill-xs", children: ["#", t] }, t))) })) : null] }, "preview"));
203
+ const previewSection = (_jsxs(Div, { rounded: "lg", padding: "5", className: "border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface-raised)] max-h-[calc(100vh-12rem)] overflow-y-auto", children: [_jsx(Row, { textSize: "xs", textWeight: "semibold", color: "muted", className: "mb-3 uppercase tracking-wide", align: "center", gap: "sm", children: _jsx(Span, { children: "Live preview" }) }), draft.coverImage ? (_jsx(Div, { className: "relative h-64 w-full mb-4 overflow-hidden", rounded: "md", children: _jsx(MediaImage, { src: draft.coverImage, alt: "", size: "hero" }) })) : null, _jsx(Heading, { level: 1, className: "mb-1", size: "2xl", weight: "bold", children: draft.title || "Untitled post" }), _jsxs(Text, { className: "text-[var(--appkit-color-text-muted)] mb-4", size: "xs", children: [draft.authorName || "Anonymous", draft.category ? ` · ${draft.category}` : ""] }), draft.excerpt ? (_jsx(Text, { className: "italic text-[var(--appkit-color-text-secondary)] mb-4", children: draft.excerpt })) : null, _jsx(RichTextRenderer, { html: draft.content || "<em>No content yet…</em>" }), draft.tags.length > 0 ? (_jsx(Row, { wrap: true, gap: "xs", className: "mt-6", children: draft.tags.map((t) => (_jsxs(Span, { size: "xs", className: "bg-[var(--appkit-color-surface)] border border-[var(--appkit-color-border)]", rounded: "full", padding: "pill-xs", children: ["#", t] }, t))) })) : null] }, "preview"));
204
204
  return (_jsx(StackedViewShell, { portal: "admin", ...rest, title: isEdit ? "Edit Post" : "New Blog Post", sections: [
205
205
  _jsxs(Div, { className: "lg:grid lg:grid-cols-[3fr_2fr] lg:gap-[1.5rem]", children: [_jsx(Div, { children: formContent }), _jsx(Div, { className: "mt-6 lg:mt-0 lg:sticky lg:top-4 lg:self-start", children: previewSection })] }, "split"),
206
206
  ] }));
@@ -51,10 +51,6 @@ const bundleFormSchema = z.object({
51
51
  isActive: z.boolean(),
52
52
  coverImage: z.string().optional().or(z.literal("")),
53
53
  }).passthrough();
54
- async function parseResponseError(res) {
55
- const err = (await res.json().catch(() => null));
56
- return err?.error?.message ?? `Create failed: ${res.status}`;
57
- }
58
54
  function bundleToForm(bundle) {
59
55
  if (!bundle)
60
56
  return EMPTY_FORM;