@mohasinac/appkit 2.7.50 โ†’ 2.7.52

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 (143) hide show
  1. package/dist/_internal/server/jobs/core/__tests__/couponExpiry.test.d.ts +1 -0
  2. package/dist/_internal/server/jobs/core/__tests__/couponExpiry.test.js +65 -0
  3. package/dist/_internal/server/jobs/core/__tests__/listingProcessor.test.d.ts +1 -0
  4. package/dist/_internal/server/jobs/core/__tests__/listingProcessor.test.js +163 -0
  5. package/dist/_internal/server/jobs/core/__tests__/mediaTmpCleanup.test.d.ts +1 -0
  6. package/dist/_internal/server/jobs/core/__tests__/mediaTmpCleanup.test.js +115 -0
  7. package/dist/_internal/server/jobs/core/__tests__/pendingOrderTimeout.test.d.ts +1 -0
  8. package/dist/_internal/server/jobs/core/__tests__/pendingOrderTimeout.test.js +96 -0
  9. package/dist/client.d.ts +29 -6
  10. package/dist/client.js +16 -4
  11. package/dist/constants/api-endpoints.d.ts +42 -0
  12. package/dist/constants/api-endpoints.js +14 -0
  13. package/dist/features/_guide-cls.d.ts +13 -0
  14. package/dist/features/_guide-cls.js +14 -0
  15. package/dist/features/about/components/HelpPageView.js +29 -26
  16. package/dist/features/account/components/BuyerAccountGuideView.d.ts +1 -0
  17. package/dist/features/account/components/BuyerAccountGuideView.js +39 -0
  18. package/dist/features/account/components/BuyerAuctionsGuideView.d.ts +1 -0
  19. package/dist/features/account/components/BuyerAuctionsGuideView.js +38 -0
  20. package/dist/features/account/components/BuyerOrdersGuideView.d.ts +1 -0
  21. package/dist/features/account/components/BuyerOrdersGuideView.js +48 -0
  22. package/dist/features/account/components/BuyerShoppingGuideView.d.ts +1 -0
  23. package/dist/features/account/components/BuyerShoppingGuideView.js +38 -0
  24. package/dist/features/admin/components/AdminAnalyticsGuideView.d.ts +1 -0
  25. package/dist/features/admin/components/AdminAnalyticsGuideView.js +24 -0
  26. package/dist/features/admin/components/AdminBlogEditorView.js +100 -77
  27. package/dist/features/admin/components/AdminBundleEditorView.js +20 -14
  28. package/dist/features/admin/components/AdminBundlesView.d.ts +1 -3
  29. package/dist/features/admin/components/AdminBundlesView.js +173 -52
  30. package/dist/features/admin/components/AdminCatalogGuideView.d.ts +1 -0
  31. package/dist/features/admin/components/AdminCatalogGuideView.js +28 -0
  32. package/dist/features/admin/components/AdminContentGuideView.d.ts +1 -0
  33. package/dist/features/admin/components/AdminContentGuideView.js +36 -0
  34. package/dist/features/admin/components/AdminCouponEditorView.js +1 -1
  35. package/dist/features/admin/components/AdminGuideHubView.d.ts +5 -0
  36. package/dist/features/admin/components/AdminGuideHubView.js +79 -0
  37. package/dist/features/admin/components/AdminOrdersGuideView.d.ts +1 -0
  38. package/dist/features/admin/components/AdminOrdersGuideView.js +44 -0
  39. package/dist/features/admin/components/AdminProductsView.js +8 -3
  40. package/dist/features/admin/components/AdminSiteConfigGuideView.d.ts +1 -0
  41. package/dist/features/admin/components/AdminSiteConfigGuideView.js +21 -0
  42. package/dist/features/admin/components/AdminStoresGuideView.d.ts +1 -0
  43. package/dist/features/admin/components/AdminStoresGuideView.js +32 -0
  44. package/dist/features/admin/components/AdminTeamGuideView.d.ts +1 -0
  45. package/dist/features/admin/components/AdminTeamGuideView.js +33 -0
  46. package/dist/features/admin/components/AdminTrustGuideView.d.ts +1 -0
  47. package/dist/features/admin/components/AdminTrustGuideView.js +40 -0
  48. package/dist/features/admin/components/AdminUsersGuideView.d.ts +1 -0
  49. package/dist/features/admin/components/AdminUsersGuideView.js +38 -0
  50. package/dist/features/categories/components/CategoryBundlesListing.js +3 -33
  51. package/dist/features/categories/components/index.d.ts +0 -2
  52. package/dist/features/categories/components/index.js +0 -1
  53. package/dist/features/events/components/AdminEventEditorView.js +223 -269
  54. package/dist/features/grouped/repository/grouped-listings.repository.d.ts +9 -0
  55. package/dist/features/grouped/repository/grouped-listings.repository.js +12 -0
  56. package/dist/features/media/upload/MediaUploadField.js +1 -1
  57. package/dist/features/pre-orders/components/PreOrdersIndexListing.js +3 -1
  58. package/dist/features/products/components/AuctionsIndexListing.js +3 -1
  59. package/dist/features/products/components/MarketplaceBundleCard.d.ts +21 -0
  60. package/dist/features/products/components/MarketplaceBundleCard.js +56 -0
  61. package/dist/features/products/components/ProductsIndexListing.js +3 -1
  62. package/dist/features/products/components/index.d.ts +2 -4
  63. package/dist/features/products/components/index.js +1 -2
  64. package/dist/features/promotions/schemas/firestore.js +1 -1
  65. package/dist/features/reviews/components/index.d.ts +0 -2
  66. package/dist/features/reviews/components/index.js +0 -1
  67. package/dist/features/seller/components/BrandInlineSelect.js +23 -3
  68. package/dist/features/seller/components/CategoryInlineSelect.js +20 -3
  69. package/dist/features/seller/components/SellerAnalyticsAlertsView.d.ts +6 -0
  70. package/dist/features/seller/components/SellerAnalyticsAlertsView.js +124 -0
  71. package/dist/features/seller/components/SellerAnalyticsView.d.ts +2 -0
  72. package/dist/features/seller/components/SellerAnalyticsView.js +17 -9
  73. package/dist/features/seller/components/SellerBundlesView.d.ts +5 -0
  74. package/dist/features/seller/components/SellerBundlesView.js +104 -0
  75. package/dist/features/seller/components/SellerClassifiedView.d.ts +5 -0
  76. package/dist/features/seller/components/SellerClassifiedView.js +113 -0
  77. package/dist/features/seller/components/SellerDashboardView.js +19 -7
  78. package/dist/features/seller/components/SellerDigitalCodesView.d.ts +5 -0
  79. package/dist/features/seller/components/SellerDigitalCodesView.js +115 -0
  80. package/dist/features/seller/components/SellerGoogleReviewsView.d.ts +14 -0
  81. package/dist/features/seller/components/SellerGoogleReviewsView.js +95 -0
  82. package/dist/features/seller/components/SellerGroupedListingsView.d.ts +6 -0
  83. package/dist/features/seller/components/SellerGroupedListingsView.js +112 -0
  84. package/dist/features/seller/components/SellerLiveView.d.ts +5 -0
  85. package/dist/features/seller/components/SellerLiveView.js +113 -0
  86. package/dist/features/seller/components/SellerOrdersView.js +18 -2
  87. package/dist/features/seller/components/SellerPayoutMethodsView.d.ts +7 -0
  88. package/dist/features/seller/components/SellerPayoutMethodsView.js +120 -0
  89. package/dist/features/seller/components/SellerPayoutSettingsView.js +50 -12
  90. package/dist/features/seller/components/SellerProductShell.d.ts +1 -1
  91. package/dist/features/seller/components/SellerProductShell.js +9 -7
  92. package/dist/features/seller/components/SellerProductsFilterDrawer.js +3 -1
  93. package/dist/features/seller/components/SellerProductsView.js +48 -54
  94. package/dist/features/seller/components/SellerShippingConfigsView.d.ts +7 -0
  95. package/dist/features/seller/components/SellerShippingConfigsView.js +149 -0
  96. package/dist/features/seller/components/SellerShippingView.js +37 -10
  97. package/dist/features/seller/components/SellerStoreCategoriesView.d.ts +9 -0
  98. package/dist/features/seller/components/SellerStoreCategoriesView.js +122 -0
  99. package/dist/features/seller/components/SellerStorefrontView.d.ts +0 -7
  100. package/dist/features/seller/components/SellerStorefrontView.js +26 -29
  101. package/dist/features/seller/components/SellerTemplatesView.d.ts +10 -0
  102. package/dist/features/seller/components/SellerTemplatesView.js +265 -0
  103. package/dist/features/seller/components/index.d.ts +26 -0
  104. package/dist/features/seller/components/index.js +13 -0
  105. package/dist/features/stores/api/[storeSlug]/reviews/route.js +49 -7
  106. package/dist/features/stores/components/StoreCapabilitiesGuideView.d.ts +3 -0
  107. package/dist/features/stores/components/StoreCapabilitiesGuideView.js +101 -0
  108. package/dist/features/stores/components/StoreFinanceGuideView.d.ts +3 -0
  109. package/dist/features/stores/components/StoreFinanceGuideView.js +79 -0
  110. package/dist/features/stores/components/StoreGuideHubView.d.ts +5 -0
  111. package/dist/features/stores/components/StoreGuideHubView.js +89 -0
  112. package/dist/features/stores/components/StoreListingsGuideView.d.ts +3 -0
  113. package/dist/features/stores/components/StoreListingsGuideView.js +151 -0
  114. package/dist/features/stores/components/StoreOrdersGuideView.d.ts +3 -0
  115. package/dist/features/stores/components/StoreOrdersGuideView.js +122 -0
  116. package/dist/features/stores/components/StoreReviewsListing.js +100 -23
  117. package/dist/features/stores/components/StoreSettingsGuideView.d.ts +3 -0
  118. package/dist/features/stores/components/StoreSettingsGuideView.js +56 -0
  119. package/dist/features/stores/components/index.d.ts +12 -1
  120. package/dist/features/stores/components/index.js +6 -1
  121. package/dist/features/stores/hooks/useStores.d.ts +5 -0
  122. package/dist/features/stores/hooks/useStores.js +10 -0
  123. package/dist/features/stores/manifest.js +1 -1
  124. package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.js +13 -2
  125. package/dist/index.d.ts +54 -9
  126. package/dist/index.js +58 -15
  127. package/dist/next/routing/route-map.d.ts +55 -0
  128. package/dist/next/routing/route-map.js +25 -0
  129. package/dist/providers/db-firebase/__tests__/filter-aliases.test.d.ts +1 -0
  130. package/dist/providers/db-firebase/__tests__/filter-aliases.test.js +93 -0
  131. package/dist/providers/db-firebase/sieve.d.ts +49 -0
  132. package/dist/providers/db-firebase/sieve.js +61 -8
  133. package/dist/repositories/index.d.ts +1 -0
  134. package/dist/repositories/index.js +2 -0
  135. package/dist/tailwind-utilities.css +1 -1
  136. package/dist/ui/components/ListingToolbar.d.ts +8 -1
  137. package/dist/ui/components/ListingToolbar.js +4 -2
  138. package/dist/ui/components/__tests__/BulkActionBar.test.d.ts +1 -0
  139. package/dist/ui/components/__tests__/BulkActionBar.test.js +96 -0
  140. package/dist/ui/components/__tests__/ListingToolbar.test.d.ts +1 -0
  141. package/dist/ui/components/__tests__/ListingToolbar.test.js +125 -0
  142. package/dist/ui/index.d.ts +1 -1
  143. package/package.json +8 -2
@@ -0,0 +1,21 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Settings } from "lucide-react";
3
+ import { Div, Heading, Text, Section, Alert } from "../../../ui";
4
+ import { GC } from "../../_guide-cls";
5
+ export function AdminSiteConfigGuideView() {
6
+ const SETTING_GROUPS = [
7
+ { name: "branding", desc: "Site name, tagline, logo URL, favicon. These values override the default SVG wordmark." },
8
+ { name: "appearance", desc: "Theme colour tokens, dark mode default, custom CSS overrides." },
9
+ { name: "announcementBanner", desc: "Sitewide banner โ€” message, type (info/warning/promo), start/end dates, dismissible toggle." },
10
+ { name: "seoDefaults", desc: "Default meta title suffix, meta description, og:image, and robots directives for pages without explicit metadata." },
11
+ { name: "contactSocial", desc: "Email, phone, social media URLs, WhatsApp business number." },
12
+ { name: "watermark", desc: "Watermark text and opacity applied to all product images via the /api/media proxy." },
13
+ { name: "fees", desc: "platformFee (%), Razorpay gateway fee pass-through toggle, GST rate on platform fees." },
14
+ { name: "integrations", desc: "API keys: Razorpay (live/test), Shiprocket, Resend, WhatsApp Cloud API. Keys are encrypted at rest โ€” never log or export." },
15
+ { name: "shipping", desc: "Default shipping carriers, free shipping threshold (paise), COD availability toggle." },
16
+ { name: "auctionConfig", desc: "Global bid increment default, auto-extend window (minutes), minimum auction duration." },
17
+ { name: "platformLimits", desc: "Cart item cap (50), wishlist cap (20), history cap (50), support ticket limits (2 general + 1 per order)." },
18
+ { name: "legalPages", desc: "Body HTML for Terms of Service, Privacy Policy, Refund Policy, and Shipping Policy. Rendered on their respective static pages." },
19
+ ];
20
+ return (_jsxs(Div, { className: "space-y-8 pb-10 max-w-3xl mx-auto", children: [_jsxs(Section, { children: [_jsxs(Div, { className: "flex items-center gap-3 mb-2", children: [_jsx(Div, { className: "flex-shrink-0 w-10 h-10 rounded-xl flex items-center justify-center", style: { background: "linear-gradient(135deg,var(--appkit-color-primary-700,#4f46e5) 0%,var(--appkit-color-cobalt,#2563eb) 100%)" }, children: _jsx(Settings, { className: "w-5 h-5 text-white" }) }), _jsx(Text, { className: "text-sm font-semibold text-[var(--appkit-color-text-muted)] uppercase tracking-widest", children: "Admin Guide" })] }), _jsx(Heading, { level: 1, className: "text-2xl md:text-3xl font-bold text-[var(--appkit-color-text)] mb-2", children: "Site Configuration" }), _jsxs(Text, { className: "text-[var(--appkit-color-text-muted)]", children: ["All site settings are stored in a single Firestore document at ", _jsx("code", { className: "text-xs", children: "site_settings/global" }), ". Changes take effect on the next page render (ISR or cache revalidation)."] })] }), _jsxs(Section, { className: GC.sectionWrap, children: [_jsxs(Div, { className: GC.sectionHeader, children: [_jsx(Settings, { className: "w-5 h-5 text-[var(--appkit-color-primary)]" }), _jsx(Heading, { level: 2, className: GC.sectionTitle, children: "Settings Groups" })] }), _jsx(Div, { className: "px-6 py-5 space-y-4", children: SETTING_GROUPS.map(({ name, desc }) => (_jsxs(Div, { className: "flex gap-3 text-sm", children: [_jsx(Text, { className: "flex-shrink-0 font-mono font-semibold text-[var(--appkit-color-primary)] w-40 text-xs", children: name }), _jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", children: desc })] }, name))) })] }), _jsxs(Section, { className: GC.sectionWrap, children: [_jsxs(Div, { className: GC.sectionHeader, children: [_jsx(Settings, { className: "w-5 h-5 text-amber-500" }), _jsx(Heading, { level: 2, className: GC.sectionTitle, children: "API Keys & Integrations" })] }), _jsx(Div, { className: "px-6 py-5", children: _jsxs(Alert, { variant: "warning", children: ["API keys in ", _jsx("code", { className: "text-xs", children: "integrations" }), " are stored encrypted. They are masked in the admin UI \u2014 you see ", _jsx("code", { className: "text-xs", children: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" }), " by design. To rotate a key: paste the new value into the field and save. The old key is immediately invalidated on your payment/shipping provider's side \u2014 test in staging first. Never paste API keys into Slack, email, or any external service."] }) })] }), _jsxs(Section, { className: GC.sectionWrap, children: [_jsxs(Div, { className: GC.sectionHeader, children: [_jsx(Settings, { className: "w-5 h-5 text-[var(--appkit-color-primary)]" }), _jsx(Heading, { level: 2, className: GC.sectionTitle, children: "Feature Flags" })] }), _jsxs(Div, { className: "px-6 py-5 space-y-3", children: [_jsxs(Text, { className: "text-sm text-[var(--appkit-color-text-muted)]", children: ["Feature flags are boolean toggles under ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "siteSettings" }), ". They control platform-wide features without a code deploy:"] }), _jsxs("ul", { className: "list-disc list-inside space-y-1 text-sm text-[var(--appkit-color-text-muted)]", children: [_jsxs("li", { children: [_jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "enableAuctions" }), " \u2014 globally enable/disable all auction listings."] }), _jsxs("li", { children: [_jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "enablePreOrders" }), " \u2014 globally enable/disable pre-order creation."] }), _jsxs("li", { children: [_jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "maintenanceMode" }), " \u2014 shows a maintenance banner and blocks non-admin access."] })] }), _jsx(Text, { className: "text-sm text-[var(--appkit-color-text-muted)]", children: "Flags are evaluated per-request via ISR cache \u2014 a change may take up to the revalidation interval (3600s default) to propagate to all pages." })] })] })] }));
21
+ }
@@ -0,0 +1 @@
1
+ export declare function AdminStoresGuideView(): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,32 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { Store, GitBranch, Edit, Shield, MapPin, Ban } from "lucide-react";
3
+ import { Div, Heading, Text, Section, Alert } from "../../../ui";
4
+ import { GC } from "../../_guide-cls";
5
+ export function AdminStoresGuideView() {
6
+ return (_jsxs(Div, { className: "space-y-8 pb-10 max-w-3xl mx-auto", children: [_jsxs(Section, { children: [_jsxs(Div, { className: "flex items-center gap-3 mb-2", children: [_jsx(Div, { className: "flex-shrink-0 w-10 h-10 rounded-xl flex items-center justify-center", style: { background: "linear-gradient(135deg,var(--appkit-color-primary-700,#4f46e5) 0%,var(--appkit-color-cobalt,#2563eb) 100%)" }, children: _jsx(Store, { className: "w-5 h-5 text-white" }) }), _jsx(Text, { className: "text-sm font-semibold text-[var(--appkit-color-text-muted)] uppercase tracking-widest", children: "Admin Guide" })] }), _jsx(Heading, { level: 1, className: "text-2xl md:text-3xl font-bold text-[var(--appkit-color-text)] mb-2", children: "Stores & Sellers" }), _jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", children: "Store lifecycle, identity architecture, capabilities, and suspension on LetItRip." })] }), [
7
+ {
8
+ Icon: Store, title: "Store Lifecycle",
9
+ content: (_jsxs("ul", { className: GC.listMuted, children: [_jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "Creation" }), ": Seller registers \u2192 completes onboarding wizard \u2192 admin reviews \u2192 store goes ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "active" }), "."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "Status values" }), ": ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "active" }), " (visible and selling), ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "suspended" }), " (hidden, not selling), ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "pending_review" }), " (awaiting admin approval)."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "isVerified badge" }), ": Awarded when the store has a consistent track record (\u226520 delivered orders, \u22654.0 rating, 3+ months active). Click the toggle in AdminStoreEditorView after reviewing the store's history."] })] })),
10
+ },
11
+ {
12
+ Icon: GitBranch, title: "Store Identity Architecture",
13
+ content: (_jsxs(_Fragment, { children: [_jsxs(Alert, { variant: "info", title: "Critical rule \u2014 read before editing any store or order.", children: [_jsx("code", { className: "text-xs", children: "storeId = storeSlug" }), " (public-facing, used in all product and order references).", _jsx("br", {}), _jsx("code", { className: "text-xs", children: "ownerId = Firebase Auth UID" }), " (internal only \u2014 never exposed in API responses)."] }), _jsxs("ul", { className: "space-y-2 text-sm text-[var(--appkit-color-text-muted)] mt-4", children: [_jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "Why separate?" }), " Allows future store ownership transfer without rewriting all product/order documents."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "Two-step lookup" }), ": To find a store by owner, query ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "stores where ownerId == uid" }), ". Never join products by ownerId directly."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "Anti-patterns to reject" }), ": PRs that filter ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "products where ownerId ==" }), " \u2014 the correct field is ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "storeId" }), "."] })] })] })),
14
+ },
15
+ {
16
+ Icon: Edit, title: "Store Editor Walkthrough",
17
+ content: (_jsxs("ul", { className: GC.listMuted, children: [_jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "storeName / storeDescription" }), ": Public-facing. Shown on the store profile page."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "ownerId" }), ": Read-only after store creation. Changing ownership requires engineering involvement."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "status Select" }), ": Suspend a store with ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "suspended" }), "; this hides all listings and shows a banner on the store profile."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "payoutDetails" }), ": UPI VPA and bank account details. Treated as PII \u2014 masked in the UI and encrypted in Firestore. Always verify details with the seller before issuing payouts."] })] })),
18
+ },
19
+ {
20
+ Icon: Shield, title: "Capabilities Management",
21
+ content: (_jsxs(_Fragment, { children: [_jsx(Text, { className: "text-sm text-[var(--appkit-color-text-muted)] mb-3", children: "Capabilities are admin-granted feature flags on a store. The Capabilities section in AdminStoreEditorView shows all 18 flags with toggles." }), _jsxs(Alert, { variant: "warning", children: ["These capabilities require documented contractual approval before granting: ", _jsx("strong", { children: "lower_commission_rate" }), " (commission rate change agreement), ", _jsx("strong", { children: "extended_return_window" }), " (operational review), ", _jsx("strong", { children: "api_access" }), " (technical integration agreement). Do not toggle these without a senior admin sign-off on file."] })] })),
22
+ },
23
+ {
24
+ Icon: MapPin, title: "Store Addresses (Pickup Locations)",
25
+ content: (_jsxs("ul", { className: GC.listMuted, children: [_jsxs("li", { children: ["Stored in the ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "storeAddresses" }), " collection. ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "storeId" }), " must exactly match the store's slug (e.g. ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "store-pokemon-palace" }), ")."] }), _jsxs("li", { children: [_jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "isPickupLocation: true" }), " flags this address as a buyer pickup option during checkout."] }), _jsx("li", { children: "Convention: no more than 3 active pickup locations per store." })] })),
26
+ },
27
+ {
28
+ Icon: Ban, title: "Suspending a Store",
29
+ content: (_jsxs("ul", { className: GC.listMuted, children: [_jsxs("li", { children: [_jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "status: \"suspended\"" }), " \u2014 hides all the store's products from search; the store profile shows \"Currently Unavailable\"; the seller receives an in-app notification."] }), _jsx("li", { children: "Suspension does NOT cancel pending orders \u2014 those must be handled separately." }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "Hard-banning the owner" }), " is a separate, more severe action \u2014 see the Trust & Safety guide. A hard ban cascades to suspend the store automatically."] })] })),
30
+ },
31
+ ].map(({ Icon, title, content }) => (_jsxs(Section, { className: "rounded-2xl border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] overflow-hidden", children: [_jsxs(Div, { className: "flex items-center gap-3 px-6 py-4 border-b border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface-2,var(--appkit-color-border))]/20", children: [_jsx(Icon, { className: "w-5 h-5 text-[var(--appkit-color-primary)]" }), _jsx(Heading, { level: 2, className: "text-base font-semibold text-[var(--appkit-color-text)]", children: title })] }), _jsx(Div, { className: "px-6 py-5", children: content })] }, title)))] }));
32
+ }
@@ -0,0 +1 @@
1
+ export declare function AdminTeamGuideView(): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,33 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { Users, Shield } from "lucide-react";
3
+ import { Div, Heading, Text, Section, Alert } from "../../../ui";
4
+ export function AdminTeamGuideView() {
5
+ const PERMISSION_GROUPS = [
6
+ { name: "content_manager", desc: "Blog, FAQs, Events, Carousel, Sections, Ads, Newsletter read + write." },
7
+ { name: "catalog_manager", desc: "Products, Categories, Brands, Reviews read + write." },
8
+ { name: "store_manager", desc: "Stores, Store Addresses, Capabilities read + write." },
9
+ { name: "order_manager", desc: "Orders, Returns, Payouts read + write + dispute tools." },
10
+ { name: "trust_safety", desc: "Scam Registry, Support Tickets, Moderation, Reports, Bans." },
11
+ { name: "analytics_viewer", desc: "Analytics, Revenue dashboard โ€” read only." },
12
+ { name: "site_admin", desc: "Site Settings, Feature Flags, Navigation, Roles โ€” write." },
13
+ { name: "superadmin", desc: "All of the above + Team management + User role changes." },
14
+ ];
15
+ return (_jsxs(Div, { className: "space-y-8 pb-10 max-w-3xl mx-auto", children: [_jsxs(Section, { children: [_jsxs(Div, { className: "flex items-center gap-3 mb-2", children: [_jsx(Div, { className: "flex-shrink-0 w-10 h-10 rounded-xl flex items-center justify-center", style: { background: "linear-gradient(135deg,var(--appkit-color-primary-700,#4f46e5) 0%,var(--appkit-color-cobalt,#2563eb) 100%)" }, children: _jsx(Users, { className: "w-5 h-5 text-white" }) }), _jsx(Text, { className: "text-sm font-semibold text-[var(--appkit-color-text-muted)] uppercase tracking-widest", children: "Admin Guide" })] }), _jsx(Heading, { level: 1, className: "text-2xl md:text-3xl font-bold text-[var(--appkit-color-text)] mb-2", children: "Team & Permissions" }), _jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", children: "How roles, permissions, and employee accounts work on LetItRip." })] }), [
16
+ {
17
+ Icon: Shield, title: "Role vs Permission: Key Difference",
18
+ content: (_jsxs(_Fragment, { children: [_jsxs(Text, { className: "text-sm text-[var(--appkit-color-text-muted)] mb-3", children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "Role" }), " (", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "user.role" }), ") is a coarse-grained classification: ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "user" }), ", ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "seller" }), ", ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "moderator" }), ", ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "employee" }), ", ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "admin" }), "."] }), _jsxs(Text, { className: "text-sm text-[var(--appkit-color-text-muted)] mb-3", children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "Permissions" }), " (", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "user.permissions[]" }), ") are fine-grained capabilities: e.g. ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "admin:orders:read" }), ", ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "admin:products:write" }), "."] }), _jsxs(Alert, { variant: "info", children: [_jsx("code", { className: "text-xs", children: "role: \"admin\"" }), " bypasses all RBAC permission checks \u2014 it's a superuser flag. ", _jsx("code", { className: "text-xs", children: "role: \"employee\"" }), " is governed entirely by ", _jsx("code", { className: "text-xs", children: "user.permissions[]" }), "."] })] })),
19
+ },
20
+ {
21
+ Icon: Users, title: "Permission Groups",
22
+ content: (_jsxs(_Fragment, { children: [_jsx(Text, { className: "text-sm text-[var(--appkit-color-text-muted)] mb-3", children: "Permission groups are predefined bundles. Assign a group to an employee to give them a coherent set of access rights:" }), _jsx(Div, { className: "space-y-2", children: PERMISSION_GROUPS.map(({ name, desc }) => (_jsxs(Div, { className: "flex gap-3 text-sm", children: [_jsx(Text, { className: "flex-shrink-0 font-mono text-xs font-semibold text-[var(--appkit-color-primary)] w-40", children: name }), _jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", children: desc })] }, name))) })] })),
23
+ },
24
+ {
25
+ Icon: Users, title: "Employee Invite Flow",
26
+ content: (_jsxs("ul", { className: "space-y-2 text-sm text-[var(--appkit-color-text-muted)]", children: [_jsxs("li", { children: ["Go to ", _jsx("strong", { children: "Admin \u2192 Team \u2192 Invite Employee" }), ". Enter the person's email and select their permission group."] }), _jsxs("li", { children: ["They receive an invitation email with a sign-up link. On first login, their Firestore profile is created with ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "role: \"employee\"" }), " and the selected permissions array."] }), _jsx("li", { children: "To update permissions later: edit the employee in the Team section. Changes take effect on their next login (session tokens carry the old permissions until refreshed)." }), _jsxs("li", { children: ["To offboard: use ", _jsx("strong", { children: "Revoke Access" }), " in Team \u2014 sets ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "isDisabled: true" }), " on their Auth account and clears all permissions."] })] })),
27
+ },
28
+ {
29
+ Icon: Shield, title: "The 85+ Permission System",
30
+ content: (_jsxs(_Fragment, { children: [_jsxs(Text, { className: "text-sm text-[var(--appkit-color-text-muted)] mb-3", children: ["Permissions follow the pattern ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "admin:{resource}:{action}" }), ". Actions: ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "read" }), ", ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "write" }), ", ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "delete" }), ", ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "view" }), "."] }), _jsxs(Text, { className: "text-sm text-[var(--appkit-color-text-muted)]", children: ["The full permission list is defined in ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "appkit/src/features/auth/schemas/firestore.ts" }), ". Custom roles (specific permission combinations) can be created at ", _jsx("strong", { children: "Admin \u2192 Custom Roles" }), " \u2014 use these when a predefined group is too broad or too narrow for a hire."] })] })),
31
+ },
32
+ ].map(({ Icon, title, content }) => (_jsxs(Section, { className: "rounded-2xl border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] overflow-hidden", children: [_jsxs(Div, { className: "flex items-center gap-3 px-6 py-4 border-b border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface-2,var(--appkit-color-border))]/20", children: [_jsx(Icon, { className: "w-5 h-5 text-[var(--appkit-color-primary)]" }), _jsx(Heading, { level: 2, className: "text-base font-semibold text-[var(--appkit-color-text)]", children: title })] }), _jsx(Div, { className: "px-6 py-5", children: content })] }, title)))] }));
33
+ }
@@ -0,0 +1 @@
1
+ export declare function AdminTrustGuideView(): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,40 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { Shield, Ban, AlertTriangle, Headphones, Flag, ClipboardList } from "lucide-react";
3
+ import { Div, Heading, Text, Section, Alert } from "../../../ui";
4
+ import { GC } from "../../_guide-cls";
5
+ const STILL_ALLOWED = "โœ“ Still allowed";
6
+ export function AdminTrustGuideView() {
7
+ return (_jsxs(Div, { className: "space-y-8 pb-10 max-w-3xl mx-auto", children: [_jsxs(Section, { children: [_jsxs(Div, { className: "flex items-center gap-3 mb-2", children: [_jsx(Div, { className: "flex-shrink-0 w-10 h-10 rounded-xl flex items-center justify-center", style: { background: "linear-gradient(135deg,var(--appkit-color-primary-700,#4f46e5) 0%,var(--appkit-color-cobalt,#2563eb) 100%)" }, children: _jsx(Shield, { className: "w-5 h-5 text-white" }) }), _jsx(Text, { className: "text-sm font-semibold text-[var(--appkit-color-text-muted)] uppercase tracking-widest", children: "Admin Guide" })] }), _jsx(Heading, { level: 1, className: "text-2xl md:text-3xl font-bold text-[var(--appkit-color-text)] mb-2", children: "Trust & Safety" }), _jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", children: "Bans, scam registry, support tickets, moderation, and reports on LetItRip." })] }), [
8
+ {
9
+ Icon: Ban, title: "Soft Ban vs Hard Ban",
10
+ content: (_jsxs(_Fragment, { children: [_jsx(Div, { className: "overflow-x-auto", children: _jsxs("table", { className: "w-full text-sm border-collapse", children: [_jsx("thead", { children: _jsx("tr", { className: "border-b border-[var(--appkit-color-border)]", children: ["", "Soft Ban", "Hard Ban"].map((h) => (_jsx("th", { className: "text-left py-2 pr-4 font-semibold text-[var(--appkit-color-text)]", children: h }, h))) }) }), _jsx("tbody", { className: "text-[var(--appkit-color-text-muted)] text-sm", children: [
11
+ ["Login", STILL_ALLOWED, "โœ— Blocked"],
12
+ ["Browse", STILL_ALLOWED, STILL_ALLOWED],
13
+ ["Buy", "Depends on scope", "โœ— Blocked"],
14
+ ["Sell", "Depends on scope", "โœ— Blocked โ€” store suspended"],
15
+ ["Bid", "Can restrict with place_bids scope", "โœ— Blocked"],
16
+ ["Duration", "Set expiry date", "Permanent until admin lifts"],
17
+ ].map(([action, soft, hard]) => (_jsxs("tr", { className: "border-b border-[var(--appkit-color-border)]/50", children: [_jsx("td", { className: "py-2 pr-4 font-medium text-[var(--appkit-color-text)]", children: action }), _jsx("td", { className: "py-2 pr-4", children: soft }), _jsx("td", { className: "py-2", children: hard })] }, action))) })] }) }), _jsxs(Text, { className: "text-sm text-[var(--appkit-color-text-muted)] mt-3", children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "Soft ban scopes" }), ": ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "place_bids" }), ", ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "write_reviews" }), ", ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "create_listings" }), ", ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "open_tickets" }), ", ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "join_events" }), ". Multiple scopes can be combined."] })] })),
18
+ },
19
+ {
20
+ Icon: AlertTriangle, title: "Scam Registry",
21
+ content: (_jsxs("ul", { className: GC.listMuted, children: [_jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "27 scam types" }), ": Documented in the registry, covering fake payments, empty-box shipping, counterfeit graded cards, and more."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "Scammer profile" }), ": Stored with slug prefix ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "scammer-" }), ". Includes phone, UPI VPA, and social handles as identifiers."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "Report review" }), ": All community-submitted reports go through a review queue before publishing. Require at least 2 corroborating reports or 1 strong piece of evidence (payment screenshot, police complaint)."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "Takedown requests" }), ": Route to senior admin with legal involvement. Preserve evidence before any deletion."] })] })),
22
+ },
23
+ {
24
+ Icon: Headphones, title: "Support Tickets",
25
+ content: (_jsxs("ul", { className: GC.listMuted, children: [_jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "SLA" }), ": 24\u201348 hours first response. Escalation: 72-hour unresponded tickets go to senior admin queue automatically."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "Categories" }), ": order_issue, billing_payment, account_access, seller_dispute, technical, other."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "Limit" }), ": Buyers can have 2 active general tickets + 1 per active order. This prevents abuse. Admins can override the limit for legitimate edge cases."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "Closing tickets" }), ": Only close a ticket after confirming the issue is resolved. Auto-close (7 days no response from buyer) is enabled for status-inquiry tickets only."] })] })),
26
+ },
27
+ {
28
+ Icon: Flag, title: "Moderation Queue",
29
+ content: (_jsxs("ul", { className: GC.listMuted, children: [_jsx("li", { children: "The moderation queue surfaces flagged listings, reviews, and user-generated content for review." }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "Listing flags" }), ": Counterfeit claim, inappropriate images, misleading description. Each flag requires a decision: dismiss, warn seller, remove listing."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "Review flags" }), ": PII in review text, slurs, spam. Decision: edit (remove PII), hide (dispute pending), or delete (violation confirmed)."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "Appeals" }), ": Any moderation action can be appealed by the seller/user via a support ticket. Document your original decision clearly in the mod log."] })] })),
30
+ },
31
+ {
32
+ Icon: ClipboardList, title: "Item Requests",
33
+ content: (_jsxs("ul", { className: GC.listMuted, children: [_jsx("li", { children: "Buyers can submit \"Want to Buy\" item requests for items not currently listed on LetItRip." }), _jsx("li", { children: "Admins review requests and can forward them to relevant verified sellers via the Item Requests section." }), _jsx("li", { children: "High-frequency requests (5+ requests for the same item) should be shared with the seller community newsletter." })] })),
34
+ },
35
+ {
36
+ Icon: Shield, title: "Reports",
37
+ content: (_jsxs(_Fragment, { children: [_jsx(Text, { className: "text-sm text-[var(--appkit-color-text-muted)] mb-3", children: "User-submitted reports about accounts, listings, or behaviour. Different from scam registry entries \u2014 reports are internal and not published publicly." }), _jsx(Alert, { variant: "warning", children: "Reports contain PII (reporter identity). Access is restricted to trust_safety permission group. Do not discuss report details outside the admin system. If a report involves a current employee, escalate to the highest admin immediately." })] })),
38
+ },
39
+ ].map(({ Icon, title, content }) => (_jsxs(Section, { className: "rounded-2xl border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] overflow-hidden", children: [_jsxs(Div, { className: "flex items-center gap-3 px-6 py-4 border-b border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface-2,var(--appkit-color-border))]/20", children: [_jsx(Icon, { className: "w-5 h-5 text-[var(--appkit-color-primary)]" }), _jsx(Heading, { level: 2, className: "text-base font-semibold text-[var(--appkit-color-text)]", children: title })] }), _jsx(Div, { className: "px-6 py-5", children: content })] }, title)))] }));
40
+ }
@@ -0,0 +1 @@
1
+ export declare function AdminUsersGuideView(): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,38 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { Users, Search, Edit, Monitor, UserCog, AlertTriangle } from "lucide-react";
3
+ import { Div, Heading, Text, Section, Alert } from "../../../ui";
4
+ import { GC } from "../../_guide-cls";
5
+ export function AdminUsersGuideView() {
6
+ return (_jsxs(Div, { className: "space-y-8 pb-10 max-w-3xl mx-auto", children: [_jsxs(Section, { children: [_jsxs(Div, { className: "flex items-center gap-3 mb-2", children: [_jsx(Div, { className: "flex-shrink-0 w-10 h-10 rounded-xl flex items-center justify-center", style: { background: "linear-gradient(135deg,var(--appkit-color-primary-700,#4f46e5) 0%,var(--appkit-color-cobalt,#2563eb) 100%)" }, children: _jsx(Users, { className: "w-5 h-5 text-white" }) }), _jsx(Text, { className: "text-sm font-semibold text-[var(--appkit-color-text-muted)] uppercase tracking-widest", children: "Admin Guide" })] }), _jsx(Heading, { level: 1, className: "text-2xl md:text-3xl font-bold text-[var(--appkit-color-text)] mb-2", children: "Users & Accounts" }), _jsx(Text, { className: "text-[var(--appkit-color-text-muted)]", children: "Managing users, roles, sessions, and employee accounts on LetItRip." })] }), [
7
+ {
8
+ Icon: Users, title: "User Roles Overview",
9
+ content: (_jsx(Div, { className: "overflow-x-auto", children: _jsxs("table", { className: "w-full text-sm border-collapse", children: [_jsx("thead", { children: _jsx("tr", { className: "border-b border-[var(--appkit-color-border)]", children: ["Role", "What they can do", "How assigned"].map((h) => (_jsx("th", { className: "text-left py-2 pr-4 font-semibold text-[var(--appkit-color-text)]", children: h }, h))) }) }), _jsx("tbody", { className: "text-[var(--appkit-color-text-muted)]", children: [
10
+ ["user", "Browse, buy, bid, wishlist, reviews, support tickets", "Auto on registration"],
11
+ ["seller", "Everything above + store management + listings", "Auto when store is created"],
12
+ ["moderator", "Review content, manage scam reports, FAQ moderation", "Admin team invite"],
13
+ ["employee", "Assigned permission-group access to admin sections", "Admin team invite"],
14
+ ["admin", "Full access to all admin sections, bypasses RBAC checks", "Manual via Firebase console"],
15
+ ].map(([role, can, how]) => (_jsxs("tr", { className: "border-b border-[var(--appkit-color-border)]/50", children: [_jsx("td", { className: "py-2 pr-4 font-mono text-xs text-[var(--appkit-color-primary)]", children: role }), _jsx("td", { className: "py-2 pr-4", children: can }), _jsx("td", { className: "py-2", children: how })] }, role))) })] }) })),
16
+ },
17
+ {
18
+ Icon: Search, title: "User List & Search",
19
+ content: (_jsxs("ul", { className: GC.listMuted, children: [_jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "Columns" }), ": display name, email, role badge, emailVerified, createdAt, last login."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "Filter chips" }), ": All, by role, verified only, banned."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "Search" }), ": by email or displayName. Email matches use the HMAC blind index \u2014 searching partial emails returns no results."] })] })),
20
+ },
21
+ {
22
+ Icon: Edit, title: "Editing a User",
23
+ content: (_jsxs(_Fragment, { children: [_jsx(Text, { className: "text-sm text-[var(--appkit-color-text-muted)] mb-3", children: "The AdminUserEditorView opens in a side drawer. Fields:" }), _jsxs("ul", { className: GC.listMuted, children: [_jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "role Select" }), " \u2014 changing to ", _jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "admin" }), " bypasses all RBAC checks. Only do this with explicit senior approval."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "emailVerified toggle" }), " \u2014 manually mark an email as verified (e.g. after manual ID check)."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "isDisabled" }), " \u2014 disables Firebase Auth login without a full hard ban. User sees \"account suspended\" on login."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "PII note" }), " \u2014 email and phone are HMAC-indexed. The UI shows the hashed index, not the plaintext value. Never store plaintext in Firestore."] })] })] })),
24
+ },
25
+ {
26
+ Icon: Monitor, title: "Sessions Management",
27
+ content: (_jsxs("ul", { className: GC.listMuted, children: [_jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "Session table" }), " shows: browser, OS, device type, masked IP (last octet zeroed), last activity, and estimated location."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "Force expire" }), " a session if you suspect account takeover \u2014 the user will be signed out on their next request."] }), _jsxs("li", { children: [_jsx("strong", { className: "text-[var(--appkit-color-text)]", children: "Hard ban cascade" }), " \u2014 issuing a hard ban automatically expires all active sessions for that user."] })] })),
28
+ },
29
+ {
30
+ Icon: UserCog, title: "Employee Accounts",
31
+ content: (_jsxs("ul", { className: GC.listMuted, children: [_jsxs("li", { children: ["Create employee accounts via ", _jsx("strong", { children: "Admin \u2192 Team" }), ", not by manually writing to Firestore."] }), _jsxs("li", { children: [_jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "role: \"employee\"" }), " has no elevated Firestore rules by default \u2014 access is governed entirely by the permission group assigned to them."] }), _jsxs("li", { children: [_jsx("code", { className: "text-xs bg-[var(--appkit-color-border)] px-1 rounded", children: "role: \"admin\"" }), " bypasses all RBAC \u2014 use sparingly. One admin account per real person maximum."] })] })),
32
+ },
33
+ {
34
+ Icon: AlertTriangle, title: "PII Handling Notice",
35
+ content: (_jsx(Alert, { variant: "warning", children: "Email and phone are encrypted at rest and indexed via HMAC blind index. Never export raw user data outside of the admin panel. Any CSV export (future) de-identifies PII before download. If you encounter plaintext email or phone data in Firestore directly \u2014 report it to the engineering team immediately." })),
36
+ },
37
+ ].map(({ Icon, title, content }) => (_jsxs(Section, { className: "rounded-2xl border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] overflow-hidden", children: [_jsxs(Div, { className: "flex items-center gap-3 px-6 py-4 border-b border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface-2,var(--appkit-color-border))]/20", children: [_jsx(Icon, { className: "w-5 h-5 text-[var(--appkit-color-primary)]" }), _jsx(Heading, { level: 2, className: "text-base font-semibold text-[var(--appkit-color-text)]", children: title })] }), _jsx(Div, { className: "px-6 py-5", children: content })] }, title)))] }));
38
+ }
@@ -9,13 +9,11 @@ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
9
9
  * sort/search/filter/pagination on top of the initial snapshot.
10
10
  */
11
11
  import { useMemo, useCallback, useState } from "react";
12
- import Link from "next/link";
13
- import { Badge, Div, Row, Text } from "../../../ui";
12
+ import { Div, Text } from "../../../ui";
14
13
  import { ListingToolbar, Pagination, FilterDrawer } from "../../../ui";
15
14
  import { useUrlTable } from "../../../react/hooks/useUrlTable";
16
- import { ROUTES } from "../../../next/routing/route-map";
17
- import { formatCurrency } from "../../../utils/number.formatter";
18
15
  import { BundleBuyNowCta } from "./BundleBuyNowCta";
16
+ import { MarketplaceBundleCard } from "../../products/components/MarketplaceBundleCard";
19
17
  import { TABLE_KEYS } from "../../../constants/table-keys";
20
18
  const PAGE_SIZE = 12;
21
19
  const FILTER_KEYS = ["showOutOfStock"];
@@ -26,15 +24,6 @@ const SORT_OPTIONS = [
26
24
  { value: "-price", label: "Price: High to Low" },
27
25
  ];
28
26
  const DEFAULT_SORT = "-createdAt";
29
- const STOCK_BADGE_TEXT = {
30
- in_stock: "",
31
- out_of_stock: "Not active",
32
- };
33
- const STOCK_BADGE_VARIANT = {
34
- in_stock: "success",
35
- out_of_stock: "warning",
36
- };
37
- const PLACEHOLDER_EMOJI = "๐Ÿ“ฆ";
38
27
  export function CategoryBundlesListing({ initialBundles, brandName, onBuyNow, }) {
39
28
  const table = useUrlTable({ defaults: { sort: DEFAULT_SORT } });
40
29
  const [searchInput, setSearchInput] = useState(table.get(TABLE_KEYS.QUERY) || "");
@@ -94,24 +83,5 @@ export function CategoryBundlesListing({ initialBundles, brandName, onBuyNow, })
94
83
  return (_jsx(Div, { className: "rounded-2xl border border-dashed border-zinc-200 py-16 text-center dark:border-zinc-700", children: _jsxs(Text, { color: "muted", children: ["No bundles available", brandName ? ` for ${brandName}` : "", " yet."] }) }));
95
84
  }
96
85
  return (_jsxs(Div, { className: "min-h-[40vh]", children: [_jsx(ListingToolbar, { filterCount: filterActiveCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search bundles...", onSearchChange: setSearchInput, onSearchCommit: commitSearch, onSearchKeyDown: (e) => { if (e.key === "Enter")
97
- commitSearch(); }, sortValue: sort, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set(TABLE_KEYS.SORT, v); }, onResetAll: resetAll, hasActiveState: hasActiveState }), totalPages > 1 && (_jsx("div", { className: "sticky top-[calc(var(--header-height,0px)+44px)] z-10 flex justify-center bg-white/95 dark:bg-slate-900/95 backdrop-blur-sm border-b border-zinc-200 dark:border-slate-700 px-3 py-1.5", children: _jsx(Pagination, { currentPage: safePage, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) })), _jsx("div", { className: "py-6", children: pageItems.length === 0 ? (_jsxs(Text, { className: "py-16 text-center text-sm text-zinc-500 dark:text-zinc-400", children: ["No bundles match your search", brandName ? ` for ${brandName}` : "", "."] })) : (_jsx("div", { className: "grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3", children: pageItems.map((bundle) => (_jsx(BundleCard, { bundle: bundle, onBuyNow: onBuyNow }, bundle.id))) })) }), _jsx(FilterDrawer, { open: filterOpen, onOpen: openFilters, onClose: () => setFilterOpen(false), onApply: applyFilters, onReset: () => setPendingShowOutOfStock(false), activeCount: filterActiveCount, hideTrigger: true, children: _jsx("div", { className: "space-y-4 p-4", children: _jsxs("label", { className: "flex items-center justify-between gap-3 cursor-pointer", children: [_jsx("span", { className: "text-sm font-medium text-zinc-700 dark:text-zinc-300", children: "Show out-of-stock bundles" }), _jsx("button", { type: "button", role: "switch", "aria-checked": pendingShowOutOfStock, onClick: () => setPendingShowOutOfStock((v) => !v), className: `relative inline-flex h-5 w-9 flex-shrink-0 items-center rounded-full transition-colors duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-1 ${pendingShowOutOfStock ? "bg-primary" : "bg-zinc-300 dark:bg-slate-600"}`, children: _jsx("span", { className: `inline-block h-3.5 w-3.5 transform rounded-full bg-white shadow-sm transition-transform duration-200 ${pendingShowOutOfStock ? "translate-x-[19px]" : "translate-x-[3px]"}` }) })] }) }) })] }));
98
- }
99
- function BundleCard({ bundle, onBuyNow }) {
100
- const memberCount = bundle.bundleProductIds?.length ?? 0;
101
- const stock = bundle.bundleStockStatus ?? "in_stock";
102
- const badge = STOCK_BADGE_TEXT[stock];
103
- const cover = bundle.display?.coverImage;
104
- const href = String(ROUTES.PUBLIC.BUNDLE_DETAIL?.(bundle.slug) ?? "#");
105
- const price = bundle.bundlePriceInPaise;
106
- // Plan ยง8 โ€” render a 2x2 collage of member product images when the bundle's
107
- // bundleItemDetails carry denormalised imageURLs. Falls back to the single
108
- // hero cover (or emoji placeholder) when fewer than 2 are available.
109
- const collageTiles = (bundle.bundleItemDetails ?? [])
110
- .filter((d) => Boolean(d.imageURL))
111
- .slice(0, 4);
112
- const showCollage = collageTiles.length >= 2;
113
- const overflow = memberCount - collageTiles.length;
114
- return (_jsxs("div", { className: "flex flex-col rounded-xl border border-zinc-200 bg-white dark:border-zinc-800 dark:bg-zinc-900", children: [_jsxs(Link, { href: href, className: "group block flex-1 p-3 hover:no-underline", children: [_jsx(Div, { className: "mb-2 aspect-video overflow-hidden rounded-lg bg-zinc-100 dark:bg-zinc-800", children: showCollage ? (_jsx(Div, { className: `grid h-full w-full gap-0.5 ${collageTiles.length === 2 ? "grid-cols-2 grid-rows-1" : "grid-cols-2 grid-rows-2"}`, children: collageTiles.map((tile, i) => (_jsxs(Div, { className: "relative overflow-hidden bg-zinc-50 dark:bg-zinc-800", children: [_jsx("img", { src: tile.imageURL, alt: tile.title ?? `${bundle.name} item ${i + 1}`, className: "h-full w-full object-cover transition-transform group-hover:scale-105", loading: "lazy" }), i === collageTiles.length - 1 && overflow > 0 && (_jsxs(Div, { className: "absolute inset-0 flex items-center justify-center bg-black/55 text-sm font-semibold text-white", children: ["+", overflow] }))] }, `${tile.productId}-${i}`))) })) : cover ? (
115
- // eslint-disable-next-line @next/next/no-img-element
116
- _jsx("img", { src: cover, alt: bundle.name, className: "h-full w-full object-cover transition-transform group-hover:scale-105", loading: "lazy" })) : (_jsx(Div, { className: "flex h-full w-full items-center justify-center text-3xl", children: PLACEHOLDER_EMOJI })) }), _jsx(Text, { className: "line-clamp-2 text-sm font-semibold", children: bundle.name }), _jsxs(Row, { gap: "sm", align: "center", className: "mt-1", children: [_jsx(Text, { size: "sm", weight: "bold", children: price ? formatCurrency(price / 100, "INR") : "โ€”" }), _jsxs(Text, { size: "xs", color: "muted", children: [memberCount, " item", memberCount !== 1 ? "s" : ""] })] }), badge && (_jsx(Badge, { variant: STOCK_BADGE_VARIANT[stock], className: "mt-1", children: badge }))] }), onBuyNow && (_jsx(Div, { className: "border-t border-zinc-100 p-3 pt-2 dark:border-zinc-800", children: _jsx(BundleBuyNowCta, { bundleSlug: bundle.slug, outOfStock: stock === "out_of_stock", onBuyNow: onBuyNow, compact: true }) }))] }));
86
+ commitSearch(); }, sortValue: sort, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set(TABLE_KEYS.SORT, v); }, onResetAll: resetAll, hasActiveState: hasActiveState }), totalPages > 1 && (_jsx("div", { className: "sticky top-[calc(var(--header-height,0px)+44px)] z-10 flex justify-center bg-white/95 dark:bg-slate-900/95 backdrop-blur-sm border-b border-zinc-200 dark:border-slate-700 px-3 py-1.5", children: _jsx(Pagination, { currentPage: safePage, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) })), _jsx("div", { className: "py-6", children: pageItems.length === 0 ? (_jsxs(Text, { className: "py-16 text-center text-sm text-zinc-500 dark:text-zinc-400", children: ["No bundles match your search", brandName ? ` for ${brandName}` : "", "."] })) : (_jsx("div", { className: "grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3", children: pageItems.map((bundle) => (_jsxs("div", { className: "flex flex-col", children: [_jsx(MarketplaceBundleCard, { bundle: bundle }), onBuyNow && (_jsx("div", { className: "border-t border-zinc-100 px-3 pt-2 pb-3 dark:border-zinc-800 -mt-px rounded-b-xl border border-t-0 border-zinc-200 dark:border-zinc-800 bg-white dark:bg-zinc-900", children: _jsx(BundleBuyNowCta, { bundleSlug: bundle.slug, outOfStock: bundle.bundleStockStatus === "out_of_stock", onBuyNow: onBuyNow, compact: true }) }))] }, bundle.id))) })) }), _jsx(FilterDrawer, { open: filterOpen, onOpen: openFilters, onClose: () => setFilterOpen(false), onApply: applyFilters, onReset: () => setPendingShowOutOfStock(false), activeCount: filterActiveCount, hideTrigger: true, children: _jsx("div", { className: "space-y-4 p-4", children: _jsxs("label", { className: "flex items-center justify-between gap-3 cursor-pointer", children: [_jsx("span", { className: "text-sm font-medium text-zinc-700 dark:text-zinc-300", children: "Show out-of-stock bundles" }), _jsx("button", { type: "button", role: "switch", "aria-checked": pendingShowOutOfStock, onClick: () => setPendingShowOutOfStock((v) => !v), className: `relative inline-flex h-5 w-9 flex-shrink-0 items-center rounded-full transition-colors duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-1 ${pendingShowOutOfStock ? "bg-primary" : "bg-zinc-300 dark:bg-slate-600"}`, children: _jsx("span", { className: `inline-block h-3.5 w-3.5 transform rounded-full bg-white shadow-sm transition-transform duration-200 ${pendingShowOutOfStock ? "translate-x-[19px]" : "translate-x-[3px]"}` }) })] }) }) })] }));
117
87
  }
@@ -6,8 +6,6 @@ export type { BreadcrumbTrailProps } from "./BreadcrumbTrail";
6
6
  export { BreadcrumbTrail } from "./BreadcrumbTrail";
7
7
  export { ConcernCard } from "./ConcernCard";
8
8
  export { ConcernGrid } from "./ConcernGrid";
9
- export { CategoriesListView } from "./CategoriesListView";
10
- export type { CategoriesListViewProps } from "./CategoriesListView";
11
9
  export { CategoryFilters, CATEGORY_FILTER_KEYS, CATEGORY_ADMIN_SORT_OPTIONS, CATEGORY_SELLER_SORT_OPTIONS, CATEGORY_PUBLIC_SORT_OPTIONS, getCategoryFilterKeys, getCategorySortOptions, } from "./CategoryFilters";
12
10
  export type { CategoryFiltersProps, CategoryFilterVariant, } from "./CategoryFilters";
13
11
  export { CategorySortSelect } from "./CategorySortSelect";
@@ -3,7 +3,6 @@ export { CategoryTree } from "./CategoryTree";
3
3
  export { BreadcrumbTrail } from "./BreadcrumbTrail";
4
4
  export { ConcernCard } from "./ConcernCard";
5
5
  export { ConcernGrid } from "./ConcernGrid";
6
- export { CategoriesListView } from "./CategoriesListView";
7
6
  export { CategoryFilters, CATEGORY_FILTER_KEYS, CATEGORY_ADMIN_SORT_OPTIONS, CATEGORY_SELLER_SORT_OPTIONS, CATEGORY_PUBLIC_SORT_OPTIONS, getCategoryFilterKeys, getCategorySortOptions, } from "./CategoryFilters";
8
7
  export { CategorySortSelect } from "./CategorySortSelect";
9
8
  export { CategoryProductsView } from "./CategoryProductsView";