@mohasinac/appkit 2.7.49 → 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 (232) hide show
  1. package/dist/_internal/client/features/layout/SidebarCollapseToggle.d.ts +19 -0
  2. package/dist/_internal/client/features/layout/SidebarCollapseToggle.js +15 -0
  3. package/dist/_internal/client/features/layout/index.d.ts +2 -0
  4. package/dist/_internal/client/features/layout/index.js +1 -0
  5. package/dist/_internal/server/features/checkout/actions.js +25 -2
  6. package/dist/_internal/server/features/promotions/actions.js +3 -1
  7. package/dist/_internal/server/jobs/core/__tests__/couponExpiry.test.d.ts +1 -0
  8. package/dist/_internal/server/jobs/core/__tests__/couponExpiry.test.js +65 -0
  9. package/dist/_internal/server/jobs/core/__tests__/listingProcessor.test.d.ts +1 -0
  10. package/dist/_internal/server/jobs/core/__tests__/listingProcessor.test.js +163 -0
  11. package/dist/_internal/server/jobs/core/__tests__/mediaTmpCleanup.test.d.ts +1 -0
  12. package/dist/_internal/server/jobs/core/__tests__/mediaTmpCleanup.test.js +115 -0
  13. package/dist/_internal/server/jobs/core/__tests__/pendingOrderTimeout.test.d.ts +1 -0
  14. package/dist/_internal/server/jobs/core/__tests__/pendingOrderTimeout.test.js +96 -0
  15. package/dist/_internal/shared/actions/action-registry.js +149 -0
  16. package/dist/client.d.ts +45 -6
  17. package/dist/client.js +27 -4
  18. package/dist/constants/api-endpoints.d.ts +42 -0
  19. package/dist/constants/api-endpoints.js +14 -0
  20. package/dist/features/_guide-cls.d.ts +13 -0
  21. package/dist/features/_guide-cls.js +14 -0
  22. package/dist/features/about/components/HelpPageView.js +29 -26
  23. package/dist/features/account/components/BuyerAccountGuideView.d.ts +1 -0
  24. package/dist/features/account/components/BuyerAccountGuideView.js +39 -0
  25. package/dist/features/account/components/BuyerAuctionsGuideView.d.ts +1 -0
  26. package/dist/features/account/components/BuyerAuctionsGuideView.js +38 -0
  27. package/dist/features/account/components/BuyerOrdersGuideView.d.ts +1 -0
  28. package/dist/features/account/components/BuyerOrdersGuideView.js +48 -0
  29. package/dist/features/account/components/BuyerShoppingGuideView.d.ts +1 -0
  30. package/dist/features/account/components/BuyerShoppingGuideView.js +38 -0
  31. package/dist/features/account/components/UserSidebar.js +2 -1
  32. package/dist/features/admin/components/AdminAnalyticsGuideView.d.ts +1 -0
  33. package/dist/features/admin/components/AdminAnalyticsGuideView.js +24 -0
  34. package/dist/features/admin/components/AdminBlogEditorView.js +102 -75
  35. package/dist/features/admin/components/AdminBundleEditorView.js +20 -14
  36. package/dist/features/admin/components/AdminBundlesView.d.ts +1 -3
  37. package/dist/features/admin/components/AdminBundlesView.js +173 -52
  38. package/dist/features/admin/components/AdminCatalogGuideView.d.ts +1 -0
  39. package/dist/features/admin/components/AdminCatalogGuideView.js +28 -0
  40. package/dist/features/admin/components/AdminContentGuideView.d.ts +1 -0
  41. package/dist/features/admin/components/AdminContentGuideView.js +36 -0
  42. package/dist/features/admin/components/AdminCouponEditorView.js +1 -1
  43. package/dist/features/admin/components/AdminGuideHubView.d.ts +5 -0
  44. package/dist/features/admin/components/AdminGuideHubView.js +79 -0
  45. package/dist/features/admin/components/AdminOrdersGuideView.d.ts +1 -0
  46. package/dist/features/admin/components/AdminOrdersGuideView.js +44 -0
  47. package/dist/features/admin/components/AdminProductsView.js +8 -3
  48. package/dist/features/admin/components/AdminSidebar.js +2 -1
  49. package/dist/features/admin/components/AdminSiteConfigGuideView.d.ts +1 -0
  50. package/dist/features/admin/components/AdminSiteConfigGuideView.js +21 -0
  51. package/dist/features/admin/components/AdminStoresGuideView.d.ts +1 -0
  52. package/dist/features/admin/components/AdminStoresGuideView.js +32 -0
  53. package/dist/features/admin/components/AdminTeamGuideView.d.ts +1 -0
  54. package/dist/features/admin/components/AdminTeamGuideView.js +33 -0
  55. package/dist/features/admin/components/AdminTrustGuideView.d.ts +1 -0
  56. package/dist/features/admin/components/AdminTrustGuideView.js +40 -0
  57. package/dist/features/admin/components/AdminUsersGuideView.d.ts +1 -0
  58. package/dist/features/admin/components/AdminUsersGuideView.js +38 -0
  59. package/dist/features/auth/repository/session.repository.js +16 -1
  60. package/dist/features/cart/hooks/useAddToCart.d.ts +2 -0
  61. package/dist/features/cart/hooks/useAddToCart.js +2 -0
  62. package/dist/features/cart/hooks/useGuestCart.d.ts +2 -0
  63. package/dist/features/cart/utils/guest-cart.d.ts +7 -0
  64. package/dist/features/cart/utils/pending-ops.d.ts +6 -0
  65. package/dist/features/categories/components/CategoryBundlesListing.js +3 -25
  66. package/dist/features/categories/components/CategoryProductsListing.js +6 -10
  67. package/dist/features/categories/components/index.d.ts +0 -2
  68. package/dist/features/categories/components/index.js +0 -1
  69. package/dist/features/categories/schemas/firestore.d.ts +9 -0
  70. package/dist/features/events/components/AdminEventEditorView.js +223 -269
  71. package/dist/features/events/components/EventRaffleWinnerView.d.ts +9 -1
  72. package/dist/features/events/components/EventRaffleWinnerView.js +3 -3
  73. package/dist/features/events/components/SpinWheelView.js +3 -3
  74. package/dist/features/grouped/repository/grouped-listings.repository.d.ts +9 -0
  75. package/dist/features/grouped/repository/grouped-listings.repository.js +12 -0
  76. package/dist/features/layout/BottomNavLayout.d.ts +5 -0
  77. package/dist/features/layout/BottomNavLayout.js +21 -0
  78. package/dist/features/layout/TitleBar.js +7 -1
  79. package/dist/features/layout/TitleBarLayout.d.ts +8 -2
  80. package/dist/features/layout/TitleBarLayout.js +11 -7
  81. package/dist/features/media/upload/MediaUploadField.js +1 -1
  82. package/dist/features/orders/schemas/index.d.ts +2 -2
  83. package/dist/features/pre-orders/components/PreOrdersIndexListing.js +12 -6
  84. package/dist/features/products/components/AuctionsIndexListing.js +3 -1
  85. package/dist/features/products/components/MarketplaceBundleCard.d.ts +21 -0
  86. package/dist/features/products/components/MarketplaceBundleCard.js +56 -0
  87. package/dist/features/products/components/PrizeDrawDetailPageView.js +1 -1
  88. package/dist/features/products/components/PrizeDrawEntryActions.d.ts +3 -1
  89. package/dist/features/products/components/PrizeDrawEntryActions.js +8 -12
  90. package/dist/features/products/components/ProductDetailActions.d.ts +5 -1
  91. package/dist/features/products/components/ProductDetailActions.js +3 -1
  92. package/dist/features/products/components/ProductDetailPageView.d.ts +2 -0
  93. package/dist/features/products/components/ProductDetailPageView.js +4 -0
  94. package/dist/features/products/components/ProductGrid.js +3 -3
  95. package/dist/features/products/components/ProductsIndexListing.js +18 -9
  96. package/dist/features/products/components/index.d.ts +2 -4
  97. package/dist/features/products/components/index.js +1 -2
  98. package/dist/features/promotions/components/CouponCard.d.ts +11 -1
  99. package/dist/features/promotions/components/CouponCard.js +36 -2
  100. package/dist/features/promotions/repository/claimed-coupons.repository.d.ts +27 -0
  101. package/dist/features/promotions/repository/claimed-coupons.repository.js +115 -0
  102. package/dist/features/promotions/schemas/firestore.d.ts +34 -0
  103. package/dist/features/promotions/schemas/firestore.js +14 -1
  104. package/dist/features/reviews/components/index.d.ts +0 -2
  105. package/dist/features/reviews/components/index.js +0 -1
  106. package/dist/features/seller/components/BrandInlineSelect.js +23 -3
  107. package/dist/features/seller/components/CategoryInlineSelect.js +20 -3
  108. package/dist/features/seller/components/SellerAddressesView.js +3 -2
  109. package/dist/features/seller/components/SellerAnalyticsAlertsView.d.ts +6 -0
  110. package/dist/features/seller/components/SellerAnalyticsAlertsView.js +124 -0
  111. package/dist/features/seller/components/SellerAnalyticsView.d.ts +2 -0
  112. package/dist/features/seller/components/SellerAnalyticsView.js +17 -9
  113. package/dist/features/seller/components/SellerBidsView.js +33 -3
  114. package/dist/features/seller/components/SellerBundlesView.d.ts +5 -0
  115. package/dist/features/seller/components/SellerBundlesView.js +104 -0
  116. package/dist/features/seller/components/SellerClassifiedView.d.ts +5 -0
  117. package/dist/features/seller/components/SellerClassifiedView.js +113 -0
  118. package/dist/features/seller/components/SellerDashboardView.js +19 -7
  119. package/dist/features/seller/components/SellerDigitalCodesView.d.ts +5 -0
  120. package/dist/features/seller/components/SellerDigitalCodesView.js +115 -0
  121. package/dist/features/seller/components/SellerGoogleReviewsView.d.ts +14 -0
  122. package/dist/features/seller/components/SellerGoogleReviewsView.js +95 -0
  123. package/dist/features/seller/components/SellerGroupedListingsView.d.ts +6 -0
  124. package/dist/features/seller/components/SellerGroupedListingsView.js +112 -0
  125. package/dist/features/seller/components/SellerLiveView.d.ts +5 -0
  126. package/dist/features/seller/components/SellerLiveView.js +113 -0
  127. package/dist/features/seller/components/SellerOrdersView.js +53 -2
  128. package/dist/features/seller/components/SellerPayoutMethodsView.d.ts +7 -0
  129. package/dist/features/seller/components/SellerPayoutMethodsView.js +120 -0
  130. package/dist/features/seller/components/SellerPayoutSettingsView.js +50 -12
  131. package/dist/features/seller/components/SellerProductShell.d.ts +3 -1
  132. package/dist/features/seller/components/SellerProductShell.js +35 -11
  133. package/dist/features/seller/components/SellerProductsCards.d.ts +19 -0
  134. package/dist/features/seller/components/SellerProductsCards.js +19 -0
  135. package/dist/features/seller/components/SellerProductsFilterDrawer.d.ts +14 -0
  136. package/dist/features/seller/components/SellerProductsFilterDrawer.js +22 -0
  137. package/dist/features/seller/components/SellerProductsView.d.ts +3 -1
  138. package/dist/features/seller/components/SellerProductsView.js +92 -49
  139. package/dist/features/seller/components/SellerReviewsView.js +67 -4
  140. package/dist/features/seller/components/SellerShippingConfigsView.d.ts +7 -0
  141. package/dist/features/seller/components/SellerShippingConfigsView.js +149 -0
  142. package/dist/features/seller/components/SellerShippingView.js +37 -10
  143. package/dist/features/seller/components/SellerSidebar.js +2 -1
  144. package/dist/features/seller/components/SellerStoreCategoriesView.d.ts +9 -0
  145. package/dist/features/seller/components/SellerStoreCategoriesView.js +122 -0
  146. package/dist/features/seller/components/SellerStorefrontView.d.ts +0 -7
  147. package/dist/features/seller/components/SellerStorefrontView.js +26 -29
  148. package/dist/features/seller/components/SellerTemplatesView.d.ts +10 -0
  149. package/dist/features/seller/components/SellerTemplatesView.js +265 -0
  150. package/dist/features/seller/components/index.d.ts +26 -0
  151. package/dist/features/seller/components/index.js +13 -0
  152. package/dist/features/seller/components/seller-products-styles.d.ts +7 -0
  153. package/dist/features/seller/components/seller-products-styles.js +14 -0
  154. package/dist/features/shell/FormShell.d.ts +7 -1
  155. package/dist/features/shell/FormShell.js +5 -2
  156. package/dist/features/store-extensions/index.d.ts +4 -0
  157. package/dist/features/store-extensions/index.js +4 -0
  158. package/dist/features/store-extensions/repository/rbac.repositories.d.ts +23 -0
  159. package/dist/features/store-extensions/repository/rbac.repositories.js +32 -0
  160. package/dist/features/store-extensions/repository/store-extensions.repositories.d.ts +91 -0
  161. package/dist/features/store-extensions/repository/store-extensions.repositories.js +127 -0
  162. package/dist/features/store-extensions/schemas/firestore.d.ts +244 -0
  163. package/dist/features/store-extensions/schemas/firestore.js +158 -0
  164. package/dist/features/store-extensions/schemas/rbac.d.ts +65 -0
  165. package/dist/features/store-extensions/schemas/rbac.js +43 -0
  166. package/dist/features/stores/api/[storeSlug]/reviews/route.js +49 -7
  167. package/dist/features/stores/components/InteractiveStoreCard.js +7 -3
  168. package/dist/features/stores/components/StoreCapabilitiesGuideView.d.ts +3 -0
  169. package/dist/features/stores/components/StoreCapabilitiesGuideView.js +101 -0
  170. package/dist/features/stores/components/StoreFinanceGuideView.d.ts +3 -0
  171. package/dist/features/stores/components/StoreFinanceGuideView.js +79 -0
  172. package/dist/features/stores/components/StoreGuideHubView.d.ts +5 -0
  173. package/dist/features/stores/components/StoreGuideHubView.js +89 -0
  174. package/dist/features/stores/components/StoreListingsGuideView.d.ts +3 -0
  175. package/dist/features/stores/components/StoreListingsGuideView.js +151 -0
  176. package/dist/features/stores/components/StoreOrdersGuideView.d.ts +3 -0
  177. package/dist/features/stores/components/StoreOrdersGuideView.js +122 -0
  178. package/dist/features/stores/components/StoreProductsListing.js +6 -10
  179. package/dist/features/stores/components/StoreReviewsListing.js +100 -23
  180. package/dist/features/stores/components/StoreSettingsGuideView.d.ts +3 -0
  181. package/dist/features/stores/components/StoreSettingsGuideView.js +56 -0
  182. package/dist/features/stores/components/index.d.ts +12 -1
  183. package/dist/features/stores/components/index.js +6 -1
  184. package/dist/features/stores/hooks/useStores.d.ts +5 -0
  185. package/dist/features/stores/hooks/useStores.js +10 -0
  186. package/dist/features/stores/manifest.js +1 -1
  187. package/dist/features/stores/schemas/firestore.d.ts +2 -0
  188. package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.js +13 -2
  189. package/dist/index.d.ts +60 -9
  190. package/dist/index.js +66 -15
  191. package/dist/next/routing/route-map.d.ts +134 -0
  192. package/dist/next/routing/route-map.js +59 -0
  193. package/dist/providers/db-firebase/__tests__/filter-aliases.test.d.ts +1 -0
  194. package/dist/providers/db-firebase/__tests__/filter-aliases.test.js +93 -0
  195. package/dist/providers/db-firebase/sieve.d.ts +49 -0
  196. package/dist/providers/db-firebase/sieve.js +61 -8
  197. package/dist/react/hooks/useFormStatePreservation.d.ts +17 -0
  198. package/dist/react/hooks/useFormStatePreservation.js +62 -0
  199. package/dist/react/hooks/useInlineRowEdit.d.ts +24 -0
  200. package/dist/react/hooks/useInlineRowEdit.js +68 -0
  201. package/dist/react/index.d.ts +4 -0
  202. package/dist/react/index.js +4 -0
  203. package/dist/repositories/index.d.ts +5 -0
  204. package/dist/repositories/index.js +7 -0
  205. package/dist/seed/actions/demo-seed-actions.d.ts +1 -1
  206. package/dist/seed/claimed-coupons-seed-data.d.ts +13 -0
  207. package/dist/seed/claimed-coupons-seed-data.js +79 -0
  208. package/dist/seed/index.d.ts +2 -0
  209. package/dist/seed/index.js +3 -0
  210. package/dist/seed/manifest.js +17 -0
  211. package/dist/seed/store-extensions-seed-data.d.ts +19 -0
  212. package/dist/seed/store-extensions-seed-data.js +421 -0
  213. package/dist/tailwind-utilities.css +1 -1
  214. package/dist/ui/components/Button.style.css +20 -12
  215. package/dist/ui/components/ClaimCouponButton.d.ts +28 -0
  216. package/dist/ui/components/ClaimCouponButton.js +89 -0
  217. package/dist/ui/components/ListingToolbar.d.ts +8 -1
  218. package/dist/ui/components/ListingToolbar.js +4 -2
  219. package/dist/ui/components/QuickCreateModal.d.ts +15 -0
  220. package/dist/ui/components/QuickCreateModal.js +48 -0
  221. package/dist/ui/components/QuickCreateModal.style.css +84 -0
  222. package/dist/ui/components/StickyBottomBar.d.ts +22 -0
  223. package/dist/ui/components/StickyBottomBar.js +20 -0
  224. package/dist/ui/components/VacationBanner.d.ts +11 -0
  225. package/dist/ui/components/VacationBanner.js +16 -0
  226. package/dist/ui/components/__tests__/BulkActionBar.test.d.ts +1 -0
  227. package/dist/ui/components/__tests__/BulkActionBar.test.js +96 -0
  228. package/dist/ui/components/__tests__/ListingToolbar.test.d.ts +1 -0
  229. package/dist/ui/components/__tests__/ListingToolbar.test.js +125 -0
  230. package/dist/ui/index.d.ts +9 -1
  231. package/dist/ui/index.js +4 -0
  232. package/package.json +8 -2
@@ -0,0 +1,115 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useState, useCallback } from "react";
4
+ import { Plus } from "lucide-react";
5
+ import { useUrlTable } from "../../../react/hooks/useUrlTable";
6
+ import { useBulkSelection } from "../../../react/hooks/useBulkSelection";
7
+ import { BulkActionBar, Button, DataTable, Div, ListingToolbar, Pagination, Text, } from "../../../ui";
8
+ import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints";
9
+ import { ROUTES } from "../../..";
10
+ import { toRecordArray, toRelativeDate, toRupees, toStringValue, useSellerListingData, } from "../hooks/useSellerListingData";
11
+ import { TABLE_KEYS } from "../../../constants/table-keys";
12
+ const PAGE_SIZE = 25;
13
+ const DEFAULT_SORT = "-createdAt";
14
+ const SORT_OPTIONS = [
15
+ { value: "-createdAt", label: "Newest" },
16
+ { value: "createdAt", label: "Oldest" },
17
+ { value: "productTitle", label: "Name A–Z" },
18
+ { value: "price", label: "Price: Low–High" },
19
+ ];
20
+ const COLUMNS = [
21
+ {
22
+ key: "title",
23
+ header: "Product",
24
+ render: (row) => _jsx(Text, { className: "text-sm font-medium", children: row.title }),
25
+ },
26
+ {
27
+ key: "price",
28
+ header: "Price",
29
+ render: (row) => _jsx(Text, { className: "text-sm tabular-nums", children: row.price }),
30
+ },
31
+ {
32
+ key: "codePoolSize",
33
+ header: "Total Codes",
34
+ render: (row) => (_jsx(Text, { className: "text-sm tabular-nums", children: row.codePoolSize !== null ? row.codePoolSize : "—" })),
35
+ },
36
+ {
37
+ key: "codesAvailable",
38
+ header: "Available",
39
+ render: (row) => (_jsx(Text, { className: "text-sm tabular-nums", children: row.codesAvailable !== null ? row.codesAvailable : "—" })),
40
+ },
41
+ {
42
+ key: "deliveryMethod",
43
+ header: "Delivery",
44
+ render: (row) => (_jsx("span", { className: "inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium bg-zinc-100 text-zinc-600 dark:bg-slate-800 dark:text-slate-400 capitalize", children: row.deliveryMethod.replace(/-/g, " ") })),
45
+ },
46
+ {
47
+ key: "status",
48
+ header: "Status",
49
+ render: (row) => (_jsx("span", { className: `inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium capitalize ${row.status === "active"
50
+ ? "bg-emerald-100 text-emerald-700 dark:bg-emerald-900/40 dark:text-emerald-300"
51
+ : "bg-zinc-100 text-zinc-600 dark:bg-slate-800 dark:text-slate-400"}`, children: row.status })),
52
+ },
53
+ {
54
+ key: "createdAt",
55
+ header: "Created",
56
+ render: (row) => _jsx(Text, { className: "text-sm text-[var(--appkit-color-text-muted)]", children: row.createdAt }),
57
+ },
58
+ ];
59
+ export function SellerDigitalCodesView({ onCreateClick, onBulkDelete, }) {
60
+ const table = useUrlTable({ defaults: { pageSize: String(PAGE_SIZE), sort: DEFAULT_SORT } });
61
+ const [searchInput, setSearchInput] = useState(table.get(TABLE_KEYS.QUERY) || "");
62
+ const [view] = useState("table");
63
+ const commitSearch = useCallback(() => {
64
+ table.set(TABLE_KEYS.QUERY, searchInput.trim());
65
+ }, [searchInput, table]);
66
+ const resetAll = useCallback(() => {
67
+ table.setMany({ [TABLE_KEYS.QUERY]: "", [TABLE_KEYS.SORT]: "" });
68
+ setSearchInput("");
69
+ }, [table]);
70
+ const hasActiveState = !!table.get(TABLE_KEYS.QUERY) || table.get(TABLE_KEYS.SORT) !== DEFAULT_SORT;
71
+ const { rows, total, isLoading, errorMessage } = useSellerListingData({
72
+ queryKey: ["seller", "digital-codes"],
73
+ endpoint: SELLER_ENDPOINTS.PRODUCTS,
74
+ page: table.getNumber(TABLE_KEYS.PAGE, 1),
75
+ pageSize: PAGE_SIZE,
76
+ sorts: table.get(TABLE_KEYS.SORT) || DEFAULT_SORT,
77
+ filters: "listingType==digital-code",
78
+ q: table.get(TABLE_KEYS.QUERY) || undefined,
79
+ mapRows: (response) => toRecordArray(response.products).map((item, index) => {
80
+ const dc = (item.digitalCode ?? {});
81
+ return {
82
+ id: toStringValue(item.id, `dc-${index}`),
83
+ raw: item,
84
+ title: toStringValue(item.productTitle ?? item.title, "Untitled"),
85
+ price: toRupees(item.price),
86
+ codePoolSize: typeof dc.codePoolSize === "number" ? dc.codePoolSize : null,
87
+ codesAvailable: typeof dc.codesAvailable === "number" ? dc.codesAvailable : null,
88
+ deliveryMethod: toStringValue(dc.codeDeliveryMethod, "auto-claim"),
89
+ status: toStringValue(item.status, "draft"),
90
+ createdAt: toRelativeDate(item.createdAt),
91
+ };
92
+ }),
93
+ getTotal: (response, mappedRows) => typeof response.meta?.total === "number" ? response.meta.total : mappedRows.length,
94
+ });
95
+ const currentPage = table.getNumber(TABLE_KEYS.PAGE, 1);
96
+ const totalPages = Math.ceil(total / PAGE_SIZE);
97
+ const selection = useBulkSelection({ items: rows, keyExtractor: (r) => r.id });
98
+ const bulkActions = onBulkDelete
99
+ ? [{
100
+ id: "bulk-delete",
101
+ label: "Delete selected",
102
+ variant: "danger",
103
+ onClick: async () => { await onBulkDelete(selection.selectedIds); selection.clearSelection(); },
104
+ }]
105
+ : [];
106
+ const handleCreate = useCallback(() => {
107
+ if (onCreateClick) {
108
+ onCreateClick();
109
+ }
110
+ else {
111
+ window.location.href = String(ROUTES.STORE.DIGITAL_CODES_NEW);
112
+ }
113
+ }, [onCreateClick]);
114
+ return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: 0, searchValue: searchInput, searchPlaceholder: "Search digital code products...", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get(TABLE_KEYS.SORT) || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set(TABLE_KEYS.SORT, v); }, showTableView: true, view: view, onViewChange: () => { }, onResetAll: resetAll, hasActiveState: hasActiveState, extra: _jsxs(Button, { size: "sm", onClick: handleCreate, className: "flex items-center gap-1.5", children: [_jsx(Plus, { className: "h-4 w-4" }), _jsx("span", { children: "New Digital Code" })] }) }), 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: currentPage, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) })), selection.selectedCount > 0 && bulkActions.length > 0 && (_jsx(BulkActionBar, { selectedCount: selection.selectedCount, actions: bulkActions, onClearSelection: selection.clearSelection })), _jsxs("div", { className: "py-4 px-3 sm:px-4", children: [errorMessage && (_jsx(Div, { className: "mb-4 rounded-xl border border-red-200 bg-red-50 dark:bg-red-950/40 dark:border-red-900/60 px-4 py-3 text-sm text-red-700 dark:text-red-200", children: errorMessage })), isLoading ? (_jsx(Div, { className: "space-y-2", children: Array.from({ length: 5 }).map((_, i) => (_jsx(Div, { className: "h-14 animate-pulse rounded-xl border border-zinc-100 dark:border-slate-700 bg-zinc-50 dark:bg-slate-800" }, i))) })) : rows.length === 0 ? (_jsx(Div, { className: "py-16 text-center", children: _jsx(Text, { className: "text-zinc-400 dark:text-zinc-500", children: "No digital code products yet \u2014 sell Steam keys, gift cards, and more" }) })) : (_jsx(DataTable, { columns: COLUMNS, data: rows, keyExtractor: (r) => r.id, selectable: bulkActions.length > 0, selectedIds: selection.selectedIds, onSelectionChange: (ids) => selection.setSelectedIds(ids) }))] })] }));
115
+ }
@@ -0,0 +1,14 @@
1
+ interface GoogleConfigDraft {
2
+ placeId: string;
3
+ businessName: string;
4
+ isConnected: boolean;
5
+ averageRating?: number;
6
+ totalReviews?: number;
7
+ lastSyncedAt?: string;
8
+ }
9
+ export interface SellerGoogleReviewsViewProps {
10
+ onSave?: (data: Partial<GoogleConfigDraft>) => Promise<void>;
11
+ onSync?: () => Promise<void>;
12
+ }
13
+ export declare function SellerGoogleReviewsView({ onSave, onSync, }: SellerGoogleReviewsViewProps): import("react/jsx-runtime").JSX.Element;
14
+ export {};
@@ -0,0 +1,95 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useCallback, useEffect, useState } from "react";
4
+ import { RefreshCw } from "lucide-react";
5
+ import { Alert, Button, Div, FormField, Heading, Section, Stack, Text, Toggle, } from "../../../ui";
6
+ import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints";
7
+ const EMPTY_DRAFT = {
8
+ placeId: "",
9
+ businessName: "",
10
+ isConnected: false,
11
+ };
12
+ export function SellerGoogleReviewsView({ onSave, onSync, }) {
13
+ const [draft, setDraft] = useState(EMPTY_DRAFT);
14
+ const [loading, setLoading] = useState(true);
15
+ const [saving, setSaving] = useState(false);
16
+ const [syncing, setSyncing] = useState(false);
17
+ const [saveMessage, setSaveMessage] = useState(null);
18
+ useEffect(() => {
19
+ fetch(SELLER_ENDPOINTS.GOOGLE_REVIEWS, { credentials: "include" })
20
+ .then((r) => r.json())
21
+ .then((j) => {
22
+ const data = j?.data ?? j ?? {};
23
+ setDraft({
24
+ placeId: String(data.placeId ?? ""),
25
+ businessName: String(data.businessName ?? ""),
26
+ isConnected: Boolean(data.isConnected),
27
+ averageRating: typeof data.averageRating === "number" ? data.averageRating : undefined,
28
+ totalReviews: typeof data.totalReviews === "number" ? data.totalReviews : undefined,
29
+ lastSyncedAt: data.lastSyncedAt ? String(data.lastSyncedAt) : undefined,
30
+ });
31
+ })
32
+ .catch(() => { })
33
+ .finally(() => setLoading(false));
34
+ }, []);
35
+ const handleSave = useCallback(async () => {
36
+ setSaving(true);
37
+ setSaveMessage(null);
38
+ try {
39
+ if (onSave) {
40
+ await onSave(draft);
41
+ }
42
+ else {
43
+ const res = await fetch(SELLER_ENDPOINTS.GOOGLE_REVIEWS, {
44
+ method: "PUT",
45
+ headers: { "Content-Type": "application/json" },
46
+ credentials: "include",
47
+ body: JSON.stringify({
48
+ placeId: draft.placeId.trim() || undefined,
49
+ businessName: draft.businessName.trim() || undefined,
50
+ isConnected: draft.isConnected,
51
+ }),
52
+ });
53
+ setSaveMessage({ text: res.ok ? "Settings saved." : "Save failed.", ok: res.ok });
54
+ }
55
+ }
56
+ catch {
57
+ setSaveMessage({ text: "Save failed. Please try again.", ok: false });
58
+ }
59
+ finally {
60
+ setSaving(false);
61
+ }
62
+ }, [draft, onSave]);
63
+ const handleSync = useCallback(async () => {
64
+ setSyncing(true);
65
+ setSaveMessage(null);
66
+ try {
67
+ if (onSync) {
68
+ await onSync();
69
+ }
70
+ else {
71
+ const res = await fetch(SELLER_ENDPOINTS.GOOGLE_REVIEWS_SYNC, {
72
+ method: "POST",
73
+ credentials: "include",
74
+ });
75
+ setSaveMessage({ text: res.ok ? "Sync queued." : "Sync failed.", ok: res.ok });
76
+ }
77
+ }
78
+ catch {
79
+ setSaveMessage({ text: "Sync failed. Please try again.", ok: false });
80
+ }
81
+ finally {
82
+ setSyncing(false);
83
+ }
84
+ }, [onSync]);
85
+ if (loading) {
86
+ return (_jsx("div", { className: "space-y-4 py-6 px-4", children: Array.from({ length: 3 }).map((_, i) => (_jsx("div", { className: "h-12 animate-pulse rounded-xl border border-zinc-100 dark:border-slate-700 bg-zinc-50 dark:bg-slate-800" }, i))) }));
87
+ }
88
+ const formattedLastSync = draft.lastSyncedAt
89
+ ? new Date(draft.lastSyncedAt).toLocaleString("en-IN", {
90
+ dateStyle: "medium",
91
+ timeStyle: "short",
92
+ })
93
+ : "Never";
94
+ return (_jsx("div", { className: "py-4 px-3 sm:px-4 max-w-2xl", children: _jsxs(Stack, { gap: "lg", children: [_jsxs(Section, { children: [_jsx(Heading, { level: 3, className: "mb-1", children: "Google Business Settings" }), _jsx(Text, { className: "text-sm text-[var(--appkit-color-text-muted)] mb-4", children: "Connect your Google Business profile to sync reviews to your storefront." }), _jsxs(Stack, { gap: "md", children: [_jsx(Toggle, { checked: draft.isConnected, onChange: (v) => setDraft((d) => ({ ...d, isConnected: v })), label: "Show Google reviews on my store page" }), _jsx(FormField, { name: "placeId", label: "Google Place ID", type: "text", value: draft.placeId, onChange: (v) => setDraft((d) => ({ ...d, placeId: v })), placeholder: "ChIJ\u2026", helpText: "Find your Place ID at developers.google.com/maps/documentation/places/web-service/place-id" }), _jsx(FormField, { name: "businessName", label: "Business name", type: "text", value: draft.businessName, onChange: (v) => setDraft((d) => ({ ...d, businessName: v })), placeholder: "Pok\u00E9mon Palace" })] })] }), (draft.averageRating !== undefined || draft.totalReviews !== undefined) && (_jsxs(Section, { children: [_jsx(Heading, { level: 3, className: "mb-3", children: "Review Stats" }), _jsxs("div", { className: "flex flex-wrap gap-6", children: [draft.averageRating !== undefined && (_jsxs(Div, { children: [_jsx(Text, { className: "text-xs text-[var(--appkit-color-text-muted)] uppercase tracking-wide", children: "Avg rating" }), _jsx(Text, { className: "text-2xl font-bold tabular-nums", children: draft.averageRating.toFixed(1) })] })), draft.totalReviews !== undefined && (_jsxs(Div, { children: [_jsx(Text, { className: "text-xs text-[var(--appkit-color-text-muted)] uppercase tracking-wide", children: "Total reviews" }), _jsx(Text, { className: "text-2xl font-bold tabular-nums", children: draft.totalReviews })] })), _jsxs(Div, { children: [_jsx(Text, { className: "text-xs text-[var(--appkit-color-text-muted)] uppercase tracking-wide", children: "Last synced" }), _jsx(Text, { className: "text-sm", children: formattedLastSync })] })] })] })), saveMessage && (_jsx(Alert, { variant: saveMessage.ok ? "success" : "error", children: saveMessage.text })), _jsxs("div", { className: "flex items-center justify-between gap-3 border-t border-[var(--appkit-color-border)] pt-4", children: [_jsxs(Button, { variant: "outline", size: "sm", onClick: handleSync, isLoading: syncing, disabled: saving || !draft.placeId.trim(), className: "flex items-center gap-1.5", children: [_jsx(RefreshCw, { className: "h-3.5 w-3.5" }), "Sync now"] }), _jsx(Button, { variant: "primary", size: "sm", onClick: handleSave, isLoading: saving, disabled: syncing, children: "Save Settings" })] })] }) }));
95
+ }
@@ -0,0 +1,6 @@
1
+ export interface SellerGroupedListingsViewProps {
2
+ onCreateClick?: () => void;
3
+ onEditClick?: (id: string) => void;
4
+ onDeleteClick?: (id: string) => void;
5
+ }
6
+ export declare function SellerGroupedListingsView({ onCreateClick, onEditClick, onDeleteClick, }: SellerGroupedListingsViewProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,112 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useState, useCallback } from "react";
4
+ import { useUrlTable } from "../../../react/hooks/useUrlTable";
5
+ import { useBulkSelection } from "../../../react/hooks/useBulkSelection";
6
+ import { Badge, BulkActionBar, Button, ListingToolbar, Pagination } from "../../../ui";
7
+ import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints";
8
+ import { toRecordArray, toRelativeDate, toStringValue, useSellerListingData, } from "../hooks/useSellerListingData";
9
+ import { DataTable } from "../../admin/components/DataTable";
10
+ // ---------------------------------------------------------------------------
11
+ // Config
12
+ // ---------------------------------------------------------------------------
13
+ const PAGE_SIZE = 25;
14
+ const DEFAULT_SORT = "-createdAt";
15
+ const SORT_OPTIONS = [
16
+ { value: "-createdAt", label: "Newest" },
17
+ { value: "createdAt", label: "Oldest" },
18
+ { value: "title", label: "Title A–Z" },
19
+ { value: "-title", label: "Title Z–A" },
20
+ ];
21
+ const THEME_LABELS = {
22
+ related: "Related",
23
+ character: "Character",
24
+ lineage: "Lineage",
25
+ set: "Set",
26
+ generic: "Generic",
27
+ };
28
+ const VISIBILITY_BADGE = {
29
+ visible: "success",
30
+ hidden: "warning",
31
+ };
32
+ // ---------------------------------------------------------------------------
33
+ // Columns
34
+ // ---------------------------------------------------------------------------
35
+ const COLUMNS = [
36
+ {
37
+ key: "title",
38
+ header: "Title",
39
+ render: (r) => _jsx("span", { className: "font-medium text-zinc-900 dark:text-zinc-100", children: r.title }),
40
+ },
41
+ {
42
+ key: "groupTheme",
43
+ header: "Theme",
44
+ render: (r) => (_jsx(Badge, { variant: "default", children: THEME_LABELS[r.groupTheme] ?? r.groupTheme })),
45
+ },
46
+ {
47
+ key: "productCount",
48
+ header: "Products",
49
+ render: (r) => _jsx("span", { className: "text-sm text-zinc-600 dark:text-zinc-400", children: r.productCount }),
50
+ },
51
+ {
52
+ key: "visibilityStatus",
53
+ header: "Visibility",
54
+ render: (r) => (_jsx(Badge, { variant: VISIBILITY_BADGE[r.visibilityStatus] ?? "default", children: r.visibilityStatus === "visible" ? "Visible" : "Hidden" })),
55
+ },
56
+ {
57
+ key: "isActive",
58
+ header: "Status",
59
+ render: (r) => (_jsx(Badge, { variant: r.isActive ? "success" : "default", children: r.isActive ? "Active" : "Inactive" })),
60
+ },
61
+ {
62
+ key: "createdAt",
63
+ header: "Created",
64
+ render: (r) => _jsx("span", { className: "text-xs text-zinc-500 dark:text-zinc-400", children: r.createdAt }),
65
+ },
66
+ ];
67
+ export function SellerGroupedListingsView({ onCreateClick, onEditClick, onDeleteClick, }) {
68
+ const table = useUrlTable({ defaults: { pageSize: String(PAGE_SIZE), sort: DEFAULT_SORT } });
69
+ const [searchInput, setSearchInput] = useState(table.get("q") || "");
70
+ const resetAll = useCallback(() => {
71
+ table.setMany({ q: "", sort: "" });
72
+ setSearchInput("");
73
+ }, [table]);
74
+ const commitSearch = useCallback(() => {
75
+ table.set("q", searchInput.trim());
76
+ }, [searchInput, table]);
77
+ const hasActiveState = !!table.get("q") || table.get("sort") !== DEFAULT_SORT;
78
+ const { rows, total, isLoading, errorMessage } = useSellerListingData({
79
+ queryKey: ["seller", "grouped-listings"],
80
+ endpoint: SELLER_ENDPOINTS.GROUPED_LISTINGS,
81
+ page: table.getNumber("page", 1),
82
+ pageSize: PAGE_SIZE,
83
+ sorts: table.get("sort") || DEFAULT_SORT,
84
+ q: table.get("q") || undefined,
85
+ mapRows: (response) => toRecordArray(response.items).map((item, index) => ({
86
+ id: toStringValue(item.id, `group-${index}`),
87
+ title: toStringValue(item.title, "Untitled group"),
88
+ groupTheme: toStringValue(item.groupTheme, "generic"),
89
+ productCount: Array.isArray(item.productIds) ? item.productIds.length : 0,
90
+ isActive: item.isActive === true,
91
+ visibilityStatus: toStringValue(item.visibilityStatus, "hidden"),
92
+ createdAt: toRelativeDate(item.createdAt),
93
+ })),
94
+ getTotal: (response, mappedRows) => typeof response.meta?.total === "number" ? response.meta.total : mappedRows.length,
95
+ });
96
+ const currentPage = table.getNumber("page", 1);
97
+ const totalPages = Math.ceil(total / PAGE_SIZE);
98
+ const selection = useBulkSelection({ items: rows, keyExtractor: (r) => r.id });
99
+ const bulkActions = [
100
+ {
101
+ id: "delete",
102
+ label: "Delete selected",
103
+ variant: "danger",
104
+ onClick: () => {
105
+ for (const id of selection.selectedIds)
106
+ onDeleteClick?.(id);
107
+ selection.clearSelection();
108
+ },
109
+ },
110
+ ];
111
+ return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { searchValue: searchInput, searchPlaceholder: "Search grouped listings", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set("sort", v); }, onResetAll: resetAll, hasActiveState: hasActiveState, extra: onCreateClick ? (_jsx(Button, { size: "sm", onClick: onCreateClick, children: "+ New Group" })) : null }), selection.selectedCount > 0 && (_jsx(BulkActionBar, { selectedCount: selection.selectedCount, actions: bulkActions, onClearSelection: selection.clearSelection })), 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: currentPage, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) })), _jsx(DataTable, { columns: COLUMNS, rows: rows, isLoading: isLoading, emptyLabel: errorMessage ?? "No grouped listings yet", selectedIds: selection.selectedIdSet, onToggleSelect: (id, _selected) => selection.toggle(id), onToggleSelectAll: (_next) => selection.toggleAll(), renderRowActions: (row) => (_jsxs("div", { className: "flex gap-1", children: [_jsx(Button, { size: "sm", variant: "ghost", onClick: () => onEditClick?.(row.id), children: "Edit" }), _jsx(Button, { size: "sm", variant: "ghost", onClick: () => onDeleteClick?.(row.id), children: "Delete" })] })) })] }));
112
+ }
@@ -0,0 +1,5 @@
1
+ export interface SellerLiveViewProps {
2
+ onCreateClick?: () => void;
3
+ onBulkDelete?: (ids: string[]) => Promise<void>;
4
+ }
5
+ export declare function SellerLiveView({ onCreateClick, onBulkDelete, }: SellerLiveViewProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,113 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useState, useCallback } from "react";
4
+ import { Plus } from "lucide-react";
5
+ import { useUrlTable } from "../../../react/hooks/useUrlTable";
6
+ import { useBulkSelection } from "../../../react/hooks/useBulkSelection";
7
+ import { BulkActionBar, Button, DataTable, Div, ListingToolbar, Pagination, Text, } from "../../../ui";
8
+ import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints";
9
+ import { ROUTES } from "../../..";
10
+ import { toRecordArray, toRelativeDate, toRupees, toStringValue, useSellerListingData, } from "../hooks/useSellerListingData";
11
+ import { TABLE_KEYS } from "../../../constants/table-keys";
12
+ const PAGE_SIZE = 25;
13
+ const DEFAULT_SORT = "-createdAt";
14
+ const SORT_OPTIONS = [
15
+ { value: "-createdAt", label: "Newest" },
16
+ { value: "createdAt", label: "Oldest" },
17
+ { value: "productTitle", label: "Name A–Z" },
18
+ { value: "price", label: "Price: Low–High" },
19
+ { value: "-price", label: "Price: High–Low" },
20
+ ];
21
+ const COLUMNS = [
22
+ {
23
+ key: "title",
24
+ header: "Item",
25
+ render: (row) => (_jsxs(Div, { children: [_jsx(Text, { className: "text-sm font-medium", children: row.title }), row.species && (_jsx(Text, { className: "text-xs text-[var(--appkit-color-text-muted)] italic", children: row.species }))] })),
26
+ },
27
+ {
28
+ key: "price",
29
+ header: "Price",
30
+ render: (row) => _jsx(Text, { className: "text-sm tabular-nums", children: row.price }),
31
+ },
32
+ {
33
+ key: "ageMonths",
34
+ header: "Age",
35
+ render: (row) => (_jsx(Text, { className: "text-sm text-[var(--appkit-color-text-muted)]", children: row.ageMonths !== null ? `${row.ageMonths}mo` : "—" })),
36
+ },
37
+ {
38
+ key: "vendorVerified",
39
+ header: "Verified",
40
+ render: (row) => (_jsx("span", { className: `inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium ${row.vendorVerified
41
+ ? "bg-emerald-100 text-emerald-700 dark:bg-emerald-900/40 dark:text-emerald-300"
42
+ : "bg-amber-100 text-amber-700 dark:bg-amber-900/40 dark:text-amber-300"}`, children: row.vendorVerified ? "Verified" : "Pending" })),
43
+ },
44
+ {
45
+ key: "status",
46
+ header: "Status",
47
+ render: (row) => (_jsx("span", { className: `inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium capitalize ${row.status === "active"
48
+ ? "bg-emerald-100 text-emerald-700 dark:bg-emerald-900/40 dark:text-emerald-300"
49
+ : "bg-zinc-100 text-zinc-600 dark:bg-slate-800 dark:text-slate-400"}`, children: row.status })),
50
+ },
51
+ {
52
+ key: "createdAt",
53
+ header: "Listed",
54
+ render: (row) => _jsx(Text, { className: "text-sm text-[var(--appkit-color-text-muted)]", children: row.createdAt }),
55
+ },
56
+ ];
57
+ export function SellerLiveView({ onCreateClick, onBulkDelete, }) {
58
+ const table = useUrlTable({ defaults: { pageSize: String(PAGE_SIZE), sort: DEFAULT_SORT } });
59
+ const [searchInput, setSearchInput] = useState(table.get(TABLE_KEYS.QUERY) || "");
60
+ const [view] = useState("table");
61
+ const commitSearch = useCallback(() => {
62
+ table.set(TABLE_KEYS.QUERY, searchInput.trim());
63
+ }, [searchInput, table]);
64
+ const resetAll = useCallback(() => {
65
+ table.setMany({ [TABLE_KEYS.QUERY]: "", [TABLE_KEYS.SORT]: "" });
66
+ setSearchInput("");
67
+ }, [table]);
68
+ const hasActiveState = !!table.get(TABLE_KEYS.QUERY) || table.get(TABLE_KEYS.SORT) !== DEFAULT_SORT;
69
+ const { rows, total, isLoading, errorMessage } = useSellerListingData({
70
+ queryKey: ["seller", "live-items"],
71
+ endpoint: SELLER_ENDPOINTS.PRODUCTS,
72
+ page: table.getNumber(TABLE_KEYS.PAGE, 1),
73
+ pageSize: PAGE_SIZE,
74
+ sorts: table.get(TABLE_KEYS.SORT) || DEFAULT_SORT,
75
+ filters: "listingType==live",
76
+ q: table.get(TABLE_KEYS.QUERY) || undefined,
77
+ mapRows: (response) => toRecordArray(response.products).map((item, index) => {
78
+ const live = (item.liveItem ?? {});
79
+ return {
80
+ id: toStringValue(item.id, `live-${index}`),
81
+ raw: item,
82
+ title: toStringValue(item.productTitle ?? item.title, "Untitled"),
83
+ price: toRupees(item.price),
84
+ species: toStringValue(live.species, ""),
85
+ ageMonths: typeof live.ageMonths === "number" ? live.ageMonths : null,
86
+ vendorVerified: Boolean(live.vendorVerified),
87
+ status: toStringValue(item.status, "draft"),
88
+ createdAt: toRelativeDate(item.createdAt),
89
+ };
90
+ }),
91
+ getTotal: (response, mappedRows) => typeof response.meta?.total === "number" ? response.meta.total : mappedRows.length,
92
+ });
93
+ const currentPage = table.getNumber(TABLE_KEYS.PAGE, 1);
94
+ const totalPages = Math.ceil(total / PAGE_SIZE);
95
+ const selection = useBulkSelection({ items: rows, keyExtractor: (r) => r.id });
96
+ const bulkActions = onBulkDelete
97
+ ? [{
98
+ id: "bulk-delete",
99
+ label: "Delete selected",
100
+ variant: "danger",
101
+ onClick: async () => { await onBulkDelete(selection.selectedIds); selection.clearSelection(); },
102
+ }]
103
+ : [];
104
+ const handleCreate = useCallback(() => {
105
+ if (onCreateClick) {
106
+ onCreateClick();
107
+ }
108
+ else {
109
+ window.location.href = String(ROUTES.STORE.LIVE_ITEMS_NEW);
110
+ }
111
+ }, [onCreateClick]);
112
+ return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: 0, searchValue: searchInput, searchPlaceholder: "Search live items by name or species...", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get(TABLE_KEYS.SORT) || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set(TABLE_KEYS.SORT, v); }, showTableView: true, view: view, onViewChange: () => { }, onResetAll: resetAll, hasActiveState: hasActiveState, extra: _jsxs(Button, { size: "sm", onClick: handleCreate, className: "flex items-center gap-1.5", children: [_jsx(Plus, { className: "h-4 w-4" }), _jsx("span", { children: "New Live Item" })] }) }), 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: currentPage, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) })), selection.selectedCount > 0 && bulkActions.length > 0 && (_jsx(BulkActionBar, { selectedCount: selection.selectedCount, actions: bulkActions, onClearSelection: selection.clearSelection })), _jsxs("div", { className: "py-4 px-3 sm:px-4", children: [errorMessage && (_jsx(Div, { className: "mb-4 rounded-xl border border-red-200 bg-red-50 dark:bg-red-950/40 dark:border-red-900/60 px-4 py-3 text-sm text-red-700 dark:text-red-200", children: errorMessage })), isLoading ? (_jsx(Div, { className: "space-y-2", children: Array.from({ length: 5 }).map((_, i) => (_jsx(Div, { className: "h-14 animate-pulse rounded-xl border border-zinc-100 dark:border-slate-700 bg-zinc-50 dark:bg-slate-800" }, i))) })) : rows.length === 0 ? (_jsx(Div, { className: "py-16 text-center", children: _jsx(Text, { className: "text-zinc-400 dark:text-zinc-500", children: "No live items yet \u2014 list animals, plants, or other living specimens" }) })) : (_jsx(DataTable, { columns: COLUMNS, data: rows, keyExtractor: (r) => r.id, selectable: bulkActions.length > 0, selectedIds: selection.selectedIds, onSelectionChange: (ids) => selection.setSelectedIds(ids) }))] })] }));
113
+ }
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import React, { useState, useCallback } from "react";
4
- import { X, Eye, Printer, MapPin } from "lucide-react";
4
+ import { X, Eye, Printer, MapPin, Truck } from "lucide-react";
5
5
  import { useUrlTable } from "../../../react/hooks/useUrlTable";
6
6
  import { useBulkSelection } from "../../../react/hooks/useBulkSelection";
7
7
  import { useActionDispatch } from "../../../react/hooks/use-action-dispatch";
@@ -34,8 +34,11 @@ const STATUS_BADGE_VARIANT = {
34
34
  };
35
35
  const UPDATE_STATUS_OPTIONS = [
36
36
  { value: "", label: "— keep current —" },
37
+ { value: "confirmed", label: "Confirmed" },
37
38
  { value: "processing", label: "Processing" },
38
39
  { value: "shipped", label: "Shipped" },
40
+ { value: "delivered", label: "Delivered" },
41
+ { value: "cancelled", label: "Cancelled" },
39
42
  ];
40
43
  // ---------------------------------------------------------------------------
41
44
  // Order Detail Drawer
@@ -200,6 +203,24 @@ export function SellerOrdersView({ orderDetailApiBase = SELLER_ENDPOINTS.ORDERS,
200
203
  className: "w-28",
201
204
  render: (row) => row.physicalLocation ? (_jsxs("span", { className: "text-xs font-mono text-zinc-500 dark:text-zinc-400", children: [row.physicalLocation.zone, "/", row.physicalLocation.shelf, "/", row.physicalLocation.bin] })) : (_jsx("span", { className: "text-xs text-zinc-400 dark:text-zinc-600", children: "\u2014" })),
202
205
  },
206
+ {
207
+ key: "shipping",
208
+ header: "Shipping",
209
+ className: "w-32",
210
+ render: (row) => {
211
+ const r = row;
212
+ return (_jsx("span", { className: "text-xs text-zinc-600 dark:text-zinc-300", children: r.shippingMethod ?? r.carrier ?? "—" }));
213
+ },
214
+ },
215
+ {
216
+ key: "weight",
217
+ header: "Weight",
218
+ className: "w-20 text-right",
219
+ render: (row) => {
220
+ const r = row;
221
+ return (_jsx("span", { className: "text-xs text-zinc-500 dark:text-zinc-400 tabular-nums", children: r.weightGrams ? `${r.weightGrams} g` : "—" }));
222
+ },
223
+ },
203
224
  {
204
225
  key: "updatedAt",
205
226
  header: "Date",
@@ -207,7 +228,20 @@ export function SellerOrdersView({ orderDetailApiBase = SELLER_ENDPOINTS.ORDERS,
207
228
  render: (row) => _jsx("span", { className: "text-xs text-zinc-500 dark:text-zinc-400", children: row.updatedAt }),
208
229
  },
209
230
  ];
210
- const renderRowActions = useCallback((row) => (_jsx("button", { type: "button", onClick: () => setSelectedOrderId(row.id), title: "View order details", className: "rounded-lg p-1.5 text-zinc-500 hover:bg-zinc-100 dark:hover:bg-slate-800 hover:text-zinc-700 dark:hover:text-zinc-300 transition-colors", children: _jsx(Eye, { className: "h-4 w-4" }) })), []);
231
+ const handleQuickShip = useCallback(async (row, e) => {
232
+ e.stopPropagation();
233
+ const res = await fetch(`${orderDetailApiBase}/${row.id}`, {
234
+ method: "PATCH",
235
+ headers: { "Content-Type": "application/json" },
236
+ body: JSON.stringify({ status: "shipped" }),
237
+ }).catch(() => null);
238
+ if (res?.ok)
239
+ setSelectedOrderId(null);
240
+ }, [orderDetailApiBase]);
241
+ const renderRowActions = useCallback((row) => {
242
+ const isShippable = ["PENDING", "PROCESSING", "CONFIRMED"].includes(row.status?.toUpperCase() ?? "");
243
+ return (_jsxs("div", { className: "flex items-center gap-1", children: [isShippable && (_jsx(Button, { variant: "ghost", size: "sm", onClick: (e) => void handleQuickShip(row, e), "aria-label": "Mark as shipped", title: "Mark shipped", children: _jsx(Truck, { className: "h-4 w-4" }) })), _jsx(Button, { variant: "ghost", size: "sm", onClick: (e) => { e.stopPropagation(); setSelectedOrderId(row.id); }, title: "View order details", "aria-label": "View order details", children: _jsx(Eye, { className: "h-4 w-4" }) })] }));
244
+ }, [handleQuickShip]);
211
245
  const selection = useBulkSelection({ items: rows, keyExtractor: (r) => r.id });
212
246
  const handlePrintPackingSlips = useCallback(() => {
213
247
  const ids = selection.selectedIds.join(",");
@@ -224,6 +258,17 @@ export function SellerOrdersView({ orderDetailApiBase = SELLER_ENDPOINTS.ORDERS,
224
258
  });
225
259
  setSetLocationOpen(false);
226
260
  }, [selection.selectedIds]);
261
+ // S-STORE-5-A — bulk order selection → single payout request.
262
+ const requestPayoutForSelection = useCallback(async () => {
263
+ if (!selection.selectedIds.length)
264
+ return;
265
+ await fetch("/api/store/payouts/request", {
266
+ method: "POST",
267
+ headers: { "Content-Type": "application/json" },
268
+ body: JSON.stringify({ orderIds: selection.selectedIds }),
269
+ }).catch(() => null);
270
+ selection.clearSelection();
271
+ }, [selection]);
227
272
  const bulkActions = [
228
273
  {
229
274
  id: ACTIONS.STORE["print-packing-slips"].id,
@@ -237,6 +282,12 @@ export function SellerOrdersView({ orderDetailApiBase = SELLER_ENDPOINTS.ORDERS,
237
282
  icon: _jsx(MapPin, { className: "w-4 h-4" }),
238
283
  onClick: () => setSetLocationOpen(true),
239
284
  },
285
+ {
286
+ id: ACTIONS.STORE["request-payout"].id,
287
+ label: ACTIONS.STORE["request-payout"].label,
288
+ onClick: () => void requestPayoutForSelection(),
289
+ variant: "primary",
290
+ },
240
291
  ];
241
292
  if (hasChildren) {
242
293
  return _jsx(ListingViewShell, { portal: "seller", ...props, children: children });
@@ -0,0 +1,7 @@
1
+ export interface SellerPayoutMethodsViewProps {
2
+ onCreateClick?: () => void;
3
+ onEditClick?: (id: string) => void;
4
+ onDelete?: (id: string) => Promise<void>;
5
+ onSetDefault?: (id: string) => Promise<void>;
6
+ }
7
+ export declare function SellerPayoutMethodsView({ onCreateClick, onEditClick, onDelete, onSetDefault, }: SellerPayoutMethodsViewProps): import("react/jsx-runtime").JSX.Element;