@mohasinac/appkit 2.7.35 → 2.7.37

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 (186) hide show
  1. package/dist/_internal/client/features/layout/DashboardLayoutClient.js +1 -1
  2. package/dist/_internal/client/features/seller/print-center/InventoryLabel.d.ts +12 -0
  3. package/dist/_internal/client/features/seller/print-center/InventoryLabel.js +49 -0
  4. package/dist/_internal/client/features/seller/print-center/LabelDesignPicker.d.ts +7 -0
  5. package/dist/_internal/client/features/seller/print-center/LabelDesignPicker.js +32 -0
  6. package/dist/_internal/client/features/seller/print-center/OrderPackingLabel.d.ts +28 -0
  7. package/dist/_internal/client/features/seller/print-center/OrderPackingLabel.js +33 -0
  8. package/dist/_internal/client/features/seller/print-center/PhysicalLocationModal.d.ts +12 -0
  9. package/dist/_internal/client/features/seller/print-center/PhysicalLocationModal.js +30 -0
  10. package/dist/_internal/client/features/seller/print-center/PrintCenterView.d.ts +12 -0
  11. package/dist/_internal/client/features/seller/print-center/PrintCenterView.js +102 -0
  12. package/dist/_internal/client/features/seller/print-center/PrintGrid.d.ts +12 -0
  13. package/dist/_internal/client/features/seller/print-center/PrintGrid.js +13 -0
  14. package/dist/_internal/client/features/seller/print-center/StoreCard.d.ts +19 -0
  15. package/dist/_internal/client/features/seller/print-center/StoreCard.js +30 -0
  16. package/dist/_internal/client/features/seller/print-center/WebsiteCard.d.ts +11 -0
  17. package/dist/_internal/client/features/seller/print-center/WebsiteCard.js +25 -0
  18. package/dist/_internal/client/features/seller/print-center/index.d.ts +11 -0
  19. package/dist/_internal/client/features/seller/print-center/index.js +10 -0
  20. package/dist/_internal/client/features/seller/print-center/types.d.ts +20 -0
  21. package/dist/_internal/client/features/seller/print-center/types.js +20 -0
  22. package/dist/_internal/client/features/seller/print-center/useInventoryPdf.d.ts +18 -0
  23. package/dist/_internal/client/features/seller/print-center/useInventoryPdf.js +76 -0
  24. package/dist/_internal/server/features/auctions/og.d.ts +1 -0
  25. package/dist/_internal/server/features/auctions/og.js +2 -1
  26. package/dist/_internal/server/features/blog/og.d.ts +1 -0
  27. package/dist/_internal/server/features/blog/og.js +3 -2
  28. package/dist/_internal/server/features/brands/og.d.ts +1 -0
  29. package/dist/_internal/server/features/brands/og.js +2 -1
  30. package/dist/_internal/server/features/bundles/og.d.ts +1 -0
  31. package/dist/_internal/server/features/bundles/og.js +2 -1
  32. package/dist/_internal/server/features/categories/og.d.ts +1 -0
  33. package/dist/_internal/server/features/categories/og.js +2 -1
  34. package/dist/_internal/server/features/checkout/actions.js +13 -5
  35. package/dist/_internal/server/features/classified/og.d.ts +2 -0
  36. package/dist/_internal/server/features/classified/og.js +2 -1
  37. package/dist/_internal/server/features/digital-code/og.d.ts +2 -0
  38. package/dist/_internal/server/features/digital-code/og.js +2 -1
  39. package/dist/_internal/server/features/events/og.d.ts +1 -0
  40. package/dist/_internal/server/features/events/og.js +3 -1
  41. package/dist/_internal/server/features/live/og.d.ts +2 -0
  42. package/dist/_internal/server/features/live/og.js +2 -1
  43. package/dist/_internal/server/features/pre-orders/og.d.ts +1 -0
  44. package/dist/_internal/server/features/pre-orders/og.js +2 -1
  45. package/dist/_internal/server/features/products/og.d.ts +3 -1
  46. package/dist/_internal/server/features/products/og.js +2 -1
  47. package/dist/_internal/server/features/seo/index.d.ts +1 -1
  48. package/dist/_internal/server/features/seo/index.js +1 -1
  49. package/dist/_internal/server/features/seo/og.d.ts +8 -1
  50. package/dist/_internal/server/features/seo/og.js +28 -8
  51. package/dist/_internal/server/features/stores/og.d.ts +1 -0
  52. package/dist/_internal/server/features/stores/og.js +3 -2
  53. package/dist/_internal/server/features/sublisting-categories/og.d.ts +1 -0
  54. package/dist/_internal/server/features/sublisting-categories/og.js +2 -1
  55. package/dist/_internal/server/jobs/core/draftPrune.d.ts +2 -0
  56. package/dist/_internal/server/jobs/core/draftPrune.js +15 -0
  57. package/dist/_internal/server/jobs/core/onBidPlaced.js +1 -1
  58. package/dist/_internal/server/jobs/core/onScamReportCreate.js +18 -14
  59. package/dist/_internal/server/jobs/core/onScamReportRejected.js +10 -7
  60. package/dist/_internal/server/jobs/core/onScamReportVerified.js +10 -7
  61. package/dist/_internal/server/jobs/core/promotions.d.ts +1 -0
  62. package/dist/_internal/server/jobs/core/promotions.js +21 -6
  63. package/dist/_internal/server/jobs/handlers/assignSpinPrize.js +18 -1
  64. package/dist/_internal/server/jobs/handlers/draftPrune.d.ts +2 -0
  65. package/dist/_internal/server/jobs/handlers/draftPrune.js +2 -0
  66. package/dist/_internal/server/jobs/handlers/index.d.ts +1 -0
  67. package/dist/_internal/server/jobs/handlers/index.js +2 -0
  68. package/dist/_internal/server/jobs/handlers/triggerEventRaffle.js +15 -1
  69. package/dist/_internal/shared/actions/action-registry.js +32 -0
  70. package/dist/_internal/shared/features/blog/schema.d.ts +8 -8
  71. package/dist/_internal/shared/features/categories/bundle-schemas.d.ts +10 -10
  72. package/dist/_internal/shared/features/orders/schema.d.ts +8 -8
  73. package/dist/_internal/shared/features/products/schema.d.ts +8 -8
  74. package/dist/_internal/shared/features/promotions/schema.d.ts +6 -6
  75. package/dist/_internal/shared/features/reviews/schema.d.ts +2 -2
  76. package/dist/client.d.ts +13 -1
  77. package/dist/client.js +7 -1
  78. package/dist/configs/next.js +1 -0
  79. package/dist/constants/api-endpoints.d.ts +15 -0
  80. package/dist/constants/api-endpoints.js +5 -0
  81. package/dist/core/server-action.d.ts +4 -0
  82. package/dist/errors/error-codes.d.ts +18 -0
  83. package/dist/errors/error-codes.js +18 -0
  84. package/dist/errors/index.d.ts +1 -1
  85. package/dist/errors/index.js +1 -1
  86. package/dist/errors/messages.d.ts +1 -0
  87. package/dist/errors/messages.js +1 -0
  88. package/dist/features/account/components/UserSidebar.js +1 -1
  89. package/dist/features/account/schemas/index.d.ts +12 -12
  90. package/dist/features/admin/components/AdminBundlesView.js +20 -2
  91. package/dist/features/admin/components/AdminPayoutsView.js +2 -1
  92. package/dist/features/admin/components/AdminProductsView.js +13 -0
  93. package/dist/features/admin/components/AdminSidebar.js +1 -1
  94. package/dist/features/admin/components/AdminStoresView.js +43 -5
  95. package/dist/features/admin/components/AdminUsersView.js +53 -6
  96. package/dist/features/admin/schemas/firestore.d.ts +1 -1
  97. package/dist/features/auctions/actions/bid-actions.js +13 -6
  98. package/dist/features/auctions/components/PlaceBidFormClient.js +10 -2
  99. package/dist/features/auctions/repository/bid.repository.d.ts +7 -0
  100. package/dist/features/auctions/repository/bid.repository.js +16 -0
  101. package/dist/features/auctions/schemas/index.d.ts +18 -18
  102. package/dist/features/auth/schemas/index.d.ts +2 -2
  103. package/dist/features/before-after/schemas/index.d.ts +2 -2
  104. package/dist/features/blog/actions/blog-actions.d.ts +32 -32
  105. package/dist/features/blog/components/BlogPostForm.js +2 -1
  106. package/dist/features/blog/schemas/index.d.ts +38 -38
  107. package/dist/features/categories/components/CategoryForm.js +1 -0
  108. package/dist/features/categories/schemas/index.d.ts +10 -10
  109. package/dist/features/collections/schemas/index.d.ts +4 -4
  110. package/dist/features/consultation/schemas/index.d.ts +9 -9
  111. package/dist/features/corporate/schemas/index.d.ts +4 -4
  112. package/dist/features/events/schemas/index.d.ts +50 -50
  113. package/dist/features/faq/actions/faq-actions.d.ts +6 -6
  114. package/dist/features/faq/schemas/index.d.ts +8 -8
  115. package/dist/features/homepage/actions/homepage-section-actions.d.ts +4 -4
  116. package/dist/features/homepage/components/SectionCarousel.js +1 -8
  117. package/dist/features/layout/AppLayoutShell.js +1 -1
  118. package/dist/features/layout/AutoBreadcrumbs.js +1 -1
  119. package/dist/features/media/AvatarUpload.js +1 -1
  120. package/dist/features/media/types/index.d.ts +4 -4
  121. package/dist/features/media/upload/ImageUpload.js +18 -9
  122. package/dist/features/media/upload/MediaUploadList.js +2 -2
  123. package/dist/features/orders/schemas/firestore.d.ts +6 -0
  124. package/dist/features/orders/schemas/index.d.ts +10 -10
  125. package/dist/features/orders/types/index.d.ts +5 -0
  126. package/dist/features/payments/schemas/index.d.ts +4 -4
  127. package/dist/features/pre-orders/schemas/index.d.ts +8 -8
  128. package/dist/features/products/components/PrizeDrawItemsEditor.js +1 -1
  129. package/dist/features/products/components/ProductForm.js +20 -2
  130. package/dist/features/products/repository/products.repository.d.ts +3 -1
  131. package/dist/features/products/repository/products.repository.js +12 -1
  132. package/dist/features/products/schemas/firestore.d.ts +7 -0
  133. package/dist/features/products/schemas/index.d.ts +34 -34
  134. package/dist/features/products/schemas/product-features.validators.d.ts +6 -6
  135. package/dist/features/products/types/index.d.ts +6 -0
  136. package/dist/features/promotions/schemas/index.d.ts +14 -14
  137. package/dist/features/reviews/schemas/index.d.ts +18 -18
  138. package/dist/features/seller/actions/offer-actions.js +10 -1
  139. package/dist/features/seller/components/PhysicalLocationModal.d.ts +12 -0
  140. package/dist/features/seller/components/PhysicalLocationModal.js +30 -0
  141. package/dist/features/seller/components/PrintCenterView.d.ts +40 -0
  142. package/dist/features/seller/components/PrintCenterView.js +6 -0
  143. package/dist/features/seller/components/SellerOrdersView.js +48 -3
  144. package/dist/features/seller/components/SellerProductShell.d.ts +1 -0
  145. package/dist/features/seller/components/SellerProductShell.js +26 -4
  146. package/dist/features/seller/components/SellerProductsView.js +54 -13
  147. package/dist/features/seller/components/SellerSidebar.js +1 -1
  148. package/dist/features/seller/components/index.d.ts +1 -0
  149. package/dist/features/seller/components/index.js +1 -0
  150. package/dist/features/seller/schemas/firestore.d.ts +2 -0
  151. package/dist/features/seller/schemas/firestore.js +1 -0
  152. package/dist/features/seller/schemas/index.d.ts +22 -22
  153. package/dist/features/shell/FormShell.js +1 -1
  154. package/dist/features/shell/StepForm.d.ts +3 -1
  155. package/dist/features/shell/StepForm.js +3 -3
  156. package/dist/features/stores/schemas/index.d.ts +4 -4
  157. package/dist/index.d.ts +9 -1
  158. package/dist/index.js +6 -1
  159. package/dist/next/routing/route-map.d.ts +8 -0
  160. package/dist/next/routing/route-map.js +3 -0
  161. package/dist/seed/homepage-sections-seed-data.js +10 -10
  162. package/dist/server.d.ts +1 -1
  163. package/dist/server.js +1 -1
  164. package/dist/tailwind-utilities.css +1 -1
  165. package/dist/ui/components/FormField.js +1 -0
  166. package/dist/ui/components/RowActionMenu.js +45 -10
  167. package/dist/ui/components/SideDrawer.style.css +2 -2
  168. package/dist/ui/forms/FieldCheckbox.d.ts +13 -0
  169. package/dist/ui/forms/FieldCheckbox.js +25 -0
  170. package/dist/ui/forms/FieldInput.d.ts +11 -0
  171. package/dist/ui/forms/FieldInput.js +25 -0
  172. package/dist/ui/forms/FieldSelect.d.ts +17 -0
  173. package/dist/ui/forms/FieldSelect.js +25 -0
  174. package/dist/ui/forms/FormShell.d.ts +48 -0
  175. package/dist/ui/forms/FormShell.js +176 -0
  176. package/dist/ui/forms/FormShell.style.css +287 -0
  177. package/dist/ui/forms/index.d.ts +8 -0
  178. package/dist/ui/forms/index.js +4 -0
  179. package/dist/ui/index.d.ts +9 -0
  180. package/dist/ui/index.js +5 -0
  181. package/dist/utils/action-response.d.ts +6 -0
  182. package/dist/utils/action-response.js +22 -0
  183. package/dist/utils/index.d.ts +1 -0
  184. package/dist/utils/index.js +1 -0
  185. package/dist/validation/schemas.d.ts +10 -10
  186. package/package.json +2 -2
@@ -0,0 +1,40 @@
1
+ interface PrintCenterStore {
2
+ id: string;
3
+ storeName: string;
4
+ storeDescription?: string;
5
+ storeLogoURL?: string;
6
+ storeCategory?: string;
7
+ }
8
+ interface PrintCenterProduct {
9
+ id: string;
10
+ name: string;
11
+ price: number;
12
+ slug: string;
13
+ listingType?: string;
14
+ condition?: string;
15
+ stockCount?: number;
16
+ physicalLocation?: string;
17
+ }
18
+ interface PrintCenterOrder {
19
+ id: string;
20
+ createdAt: string;
21
+ status: string;
22
+ buyerDisplayName?: string;
23
+ buyerCity?: string;
24
+ items: {
25
+ productName: string;
26
+ quantity: number;
27
+ price: number;
28
+ }[];
29
+ physicalLocation?: string;
30
+ }
31
+ interface PrintCenterViewProps {
32
+ store?: PrintCenterStore | null;
33
+ publicBaseUrl?: string;
34
+ isAdmin?: boolean;
35
+ brandName?: string;
36
+ initialProducts?: PrintCenterProduct[];
37
+ initialOrders?: PrintCenterOrder[];
38
+ }
39
+ export declare function PrintCenterView({ store, brandName }: PrintCenterViewProps): import("react/jsx-runtime").JSX.Element;
40
+ export {};
@@ -0,0 +1,6 @@
1
+ "use client";
2
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
3
+ import { Heading, Text } from "../../../ui/components/Typography";
4
+ export function PrintCenterView({ store, brandName = "LetItRip" }) {
5
+ return (_jsxs("div", { className: "flex flex-col items-center justify-center py-24 text-center gap-4", children: [_jsxs(Heading, { level: 2, children: [brandName, " Print Center"] }), store && _jsx(Text, { size: "sm", variant: "muted", children: store.storeName }), _jsx(Text, { size: "sm", variant: "muted", children: "Print center features are coming soon." })] }));
6
+ }
@@ -1,12 +1,16 @@
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 } from "lucide-react";
4
+ import { X, Eye, Printer, MapPin } from "lucide-react";
5
5
  import { useUrlTable } from "../../../react/hooks/useUrlTable";
6
6
  import { useBulkSelection } from "../../../react/hooks/useBulkSelection";
7
- import { Badge, Button, Div, FilterChipGroup, Heading, Input, ListingToolbar, Pagination, ListingViewShell, Select, SideDrawer, Stack, Text } from "../../../ui";
7
+ import { useActionDispatch } from "../../../react/hooks/use-action-dispatch";
8
+ import { BulkActionBar, Badge, Button, Div, FilterChipGroup, Heading, Input, ListingToolbar, Pagination, ListingViewShell, Select, SideDrawer, Stack, Text } from "../../../ui";
8
9
  import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints";
9
10
  import { SELLER_ORDER_STATUS_TABS } from "../../admin/constants/filter-tabs";
11
+ import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
12
+ import { PhysicalLocationModal } from "./PhysicalLocationModal";
13
+ import { ROUTES } from "../../../constants";
10
14
  import { toRecordArray, toRelativeDate, toRupees, toStringValue, useSellerListingData, } from "../hooks/useSellerListingData";
11
15
  import { DataTable } from "../../admin/components/DataTable";
12
16
  // ---------------------------------------------------------------------------
@@ -111,6 +115,8 @@ export function SellerOrdersView({ orderDetailApiBase = SELLER_ENDPOINTS.ORDERS,
111
115
  const hasChildren = React.Children.count(children) > 0;
112
116
  const [view, setView] = useState("table");
113
117
  const [selectedOrderId, setSelectedOrderId] = useState(null);
118
+ const [setLocationOpen, setSetLocationOpen] = useState(false);
119
+ const dispatch = useActionDispatch();
114
120
  const table = useUrlTable({ defaults: { pageSize: String(PAGE_SIZE), sort: DEFAULT_SORT } });
115
121
  const [searchInput, setSearchInput] = useState(table.get("q") || "");
116
122
  const [filterOpen, setFilterOpen] = useState(false);
@@ -151,6 +157,7 @@ export function SellerOrdersView({ orderDetailApiBase = SELLER_ENDPOINTS.ORDERS,
151
157
  q: table.get("q") || undefined,
152
158
  mapRows: (response) => toRecordArray(response.orders).map((item, index) => {
153
159
  const itemsArr = Array.isArray(item.items) ? item.items : [];
160
+ const loc = item.physicalLocation;
154
161
  return {
155
162
  id: toStringValue(item.id, `order-${index}`),
156
163
  primary: toStringValue(item.id, "Order"),
@@ -160,6 +167,9 @@ export function SellerOrdersView({ orderDetailApiBase = SELLER_ENDPOINTS.ORDERS,
160
167
  itemCount: itemsArr.length,
161
168
  totalAmount: Number(item.totalAmount ?? item.total ?? 0),
162
169
  buyerName: toStringValue(item.buyerName ?? item.buyerDisplayName, "Unknown buyer"),
170
+ physicalLocation: loc && typeof loc.zone === "string"
171
+ ? { zone: loc.zone, shelf: loc.shelf ?? "", bin: loc.bin ?? "" }
172
+ : undefined,
163
173
  };
164
174
  }),
165
175
  getTotal: (response, mappedRows) => typeof response.meta?.total === "number" ? response.meta.total : mappedRows.length,
@@ -184,6 +194,12 @@ export function SellerOrdersView({ orderDetailApiBase = SELLER_ENDPOINTS.ORDERS,
184
194
  className: "w-32",
185
195
  render: (row) => (_jsx(Badge, { variant: STATUS_BADGE_VARIANT[row.status?.toUpperCase()] ?? "default", children: row.status })),
186
196
  },
197
+ {
198
+ key: "physicalLocation",
199
+ header: "Staging",
200
+ className: "w-28",
201
+ 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
+ },
187
203
  {
188
204
  key: "updatedAt",
189
205
  header: "Date",
@@ -193,8 +209,37 @@ export function SellerOrdersView({ orderDetailApiBase = SELLER_ENDPOINTS.ORDERS,
193
209
  ];
194
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" }) })), []);
195
211
  const selection = useBulkSelection({ items: rows, keyExtractor: (r) => r.id });
212
+ const handlePrintPackingSlips = useCallback(() => {
213
+ const ids = selection.selectedIds.join(",");
214
+ void dispatch({
215
+ type: "NAVIGATE",
216
+ href: `${String(ROUTES.STORE.INVENTORY_PRINT)}?type=order&ids=${ids}&autoprint=1`,
217
+ });
218
+ }, [selection.selectedIds, dispatch]);
219
+ const handleSetLocation = useCallback(async (loc) => {
220
+ await fetch(SELLER_ENDPOINTS.ORDERS_BULK_LOCATION, {
221
+ method: "PATCH",
222
+ headers: { "Content-Type": "application/json" },
223
+ body: JSON.stringify({ orderIds: selection.selectedIds, physicalLocation: loc }),
224
+ });
225
+ setSetLocationOpen(false);
226
+ }, [selection.selectedIds]);
227
+ const bulkActions = [
228
+ {
229
+ id: ACTIONS.STORE["print-packing-slips"].id,
230
+ label: ACTIONS.STORE["print-packing-slips"].label,
231
+ icon: _jsx(Printer, { className: "w-4 h-4" }),
232
+ onClick: handlePrintPackingSlips,
233
+ },
234
+ {
235
+ id: ACTIONS.STORE["set-location"].id,
236
+ label: ACTIONS.STORE["set-location"].label,
237
+ icon: _jsx(MapPin, { className: "w-4 h-4" }),
238
+ onClick: () => setSetLocationOpen(true),
239
+ },
240
+ ];
196
241
  if (hasChildren) {
197
242
  return _jsx(ListingViewShell, { portal: "seller", ...props, children: children });
198
243
  }
199
- return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search by order ID or buyer name", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set("sort", v); }, showTableView: true, view: view, onViewChange: (v) => setView(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: currentPage, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) })), _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 })), _jsx(DataTable, { rows: rows, columns: columns, isLoading: isLoading, emptyLabel: "No orders yet", renderRowActions: renderRowActions })] }), filterOpen && (_jsxs(_Fragment, { children: [_jsx("div", { className: "fixed inset-0 z-40 bg-black/40", "aria-hidden": "true", onClick: () => setFilterOpen(false) }), _jsxs("div", { className: "fixed inset-y-0 left-0 z-50 flex w-80 flex-col bg-white dark:bg-slate-900 shadow-2xl", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: [_jsx("span", { className: "text-base font-semibold text-zinc-900 dark:text-zinc-100", children: "Filters" }), _jsxs("div", { className: "flex items-center gap-2", children: [activeFilterCount > 0 && (_jsx("button", { type: "button", onClick: clearFilters, className: "text-xs text-zinc-500 hover:text-rose-500 transition-colors", children: "Clear all" })), _jsx("button", { type: "button", onClick: () => setFilterOpen(false), "aria-label": "Close", className: "rounded-lg p-1.5 text-zinc-500 hover:bg-zinc-100 dark:hover:bg-slate-800 transition-colors", children: _jsx(X, { className: "h-5 w-5" }) })] })] }), _jsx("div", { className: "flex-1 overflow-y-auto px-4 py-4 space-y-5", children: _jsx(FilterChipGroup, { label: "Status", tabs: STATUS_OPTIONS, value: pendingFilters.status ?? "", onChange: (id) => setPendingFilters((p) => ({ ...p, status: id })) }) }), _jsx("div", { className: "border-t border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: _jsxs("button", { type: "button", onClick: applyFilters, className: "w-full rounded-lg bg-[var(--appkit-color-primary)] py-2.5 text-sm font-semibold text-white transition-colors active:scale-[0.98]", children: ["Apply", activeFilterCount > 0 ? ` (${activeFilterCount})` : ""] }) })] })] })), selectedOrderId && (_jsx(OrderDetailDrawer, { orderId: selectedOrderId, apiBase: orderDetailApiBase, onClose: () => setSelectedOrderId(null) }))] }));
244
+ return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search by order ID or buyer name", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set("sort", v); }, showTableView: true, view: view, onViewChange: (v) => setView(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: currentPage, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) })), selection.selectedIds.length > 0 && (_jsx("div", { className: "sticky top-[calc(var(--header-height,0px)+88px)] z-20 px-3 sm:px-4 py-2 bg-white/95 dark:bg-slate-900/95 backdrop-blur-sm border-b border-zinc-200 dark:border-slate-700", children: _jsx(BulkActionBar, { selectedCount: selection.selectedIds.length, onClearSelection: selection.clearSelection, actions: bulkActions }) })), _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 })), _jsx(DataTable, { rows: rows, columns: columns, isLoading: isLoading, emptyLabel: "No orders yet", selectedIds: selection.selectedIdSet, onToggleSelect: selection.toggle, onToggleSelectAll: () => selection.toggleAll(), renderRowActions: renderRowActions })] }), filterOpen && (_jsxs(_Fragment, { children: [_jsx("div", { className: "fixed inset-0 z-40 bg-black/40", "aria-hidden": "true", onClick: () => setFilterOpen(false) }), _jsxs("div", { className: "fixed inset-y-0 left-0 z-50 flex w-80 flex-col bg-white dark:bg-slate-900 shadow-2xl", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: [_jsx("span", { className: "text-base font-semibold text-zinc-900 dark:text-zinc-100", children: "Filters" }), _jsxs("div", { className: "flex items-center gap-2", children: [activeFilterCount > 0 && (_jsx("button", { type: "button", onClick: clearFilters, className: "text-xs text-zinc-500 hover:text-rose-500 transition-colors", children: "Clear all" })), _jsx("button", { type: "button", onClick: () => setFilterOpen(false), "aria-label": "Close", className: "rounded-lg p-1.5 text-zinc-500 hover:bg-zinc-100 dark:hover:bg-slate-800 transition-colors", children: _jsx(X, { className: "h-5 w-5" }) })] })] }), _jsx("div", { className: "flex-1 overflow-y-auto px-4 py-4 space-y-5", children: _jsx(FilterChipGroup, { label: "Status", tabs: STATUS_OPTIONS, value: pendingFilters.status ?? "", onChange: (id) => setPendingFilters((p) => ({ ...p, status: id })) }) }), _jsx("div", { className: "border-t border-zinc-200 dark:border-slate-700 px-4 py-3.5", children: _jsxs("button", { type: "button", onClick: applyFilters, className: "w-full rounded-lg bg-[var(--appkit-color-primary)] py-2.5 text-sm font-semibold text-white transition-colors active:scale-[0.98]", children: ["Apply", activeFilterCount > 0 ? ` (${activeFilterCount})` : ""] }) })] })] })), selectedOrderId && (_jsx(OrderDetailDrawer, { orderId: selectedOrderId, apiBase: orderDetailApiBase, onClose: () => setSelectedOrderId(null) })), setLocationOpen && (_jsx(PhysicalLocationModal, { count: selection.selectedIds.length, onSave: handleSetLocation, onClose: () => setSetLocationOpen(false) }))] }));
200
245
  }
@@ -10,6 +10,7 @@ export interface SellerProductDraft {
10
10
  tags?: string[];
11
11
  mainImage?: string;
12
12
  images?: string[];
13
+ video?: string;
13
14
  youtubeId?: string;
14
15
  price?: number;
15
16
  compareAtPrice?: number;
@@ -2,9 +2,9 @@
2
2
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useCallback, useRef, useState } from "react";
4
4
  import { useRouter } from "next/navigation";
5
- import { FormShell, StepForm, useFormShell } from "../../shell";
5
+ import { FormShell, StepForm, StepFormActions, useFormShell } from "../../shell";
6
6
  import { Alert, Button, Div, FormField, FormGroup, Heading, Section, Stack, Text, Toggle } from "../../../ui";
7
- import { ImageUpload, MediaUploadList, useMediaUpload } from "../../media";
7
+ import { ImageUpload, MediaUploadField, MediaUploadList, useMediaUpload } from "../../media";
8
8
  import { StoreAddressSelectorCreate } from "../../stores/components/StoreAddressSelectorCreate";
9
9
  const CONDITION_OPTIONS = [
10
10
  { value: "new", label: "New" },
@@ -52,7 +52,11 @@ function StepMedia({ values, onChange, storeSlug = "store", }) {
52
52
  store: storeSlug,
53
53
  category: values.category ?? "uncategorized",
54
54
  });
55
- }, accept: "image/*", maxItems: 10, maxSizeMB: 10, helperText: "Show multiple angles, grading details, or box contents." }), _jsx(FormField, { name: "youtubeId", label: "YouTube Video ID (optional)", type: "text", value: values.youtubeId ?? "", onChange: (v) => onChange({ youtubeId: v }), placeholder: "e.g. dQw4w9WgXcQ", helpText: "Paste the 11-character ID from the YouTube URL" })] }));
55
+ }, accept: "image/*,video/*", maxItems: 10, maxSizeMB: 10, helperText: "Show multiple angles, grading details, or box contents." }), _jsx(MediaUploadField, { label: "Product Video (optional)", value: values.video ?? "", onChange: (url) => onChange({ video: url }), onUpload: (file) => upload(file, "products", true, {
56
+ type: "product-video",
57
+ name: values.title ?? "product",
58
+ store: storeSlug,
59
+ }), kind: "video", helperText: "MP4, WebM or QuickTime \u2014 max 50 MB" }), _jsx(FormField, { name: "youtubeId", label: "YouTube Video ID (optional)", type: "text", value: values.youtubeId ?? "", onChange: (v) => onChange({ youtubeId: v }), placeholder: "e.g. dQw4w9WgXcQ", helpText: "Paste the 11-character ID from the YouTube URL" })] }));
56
60
  }
57
61
  // ── Step 3: Auction Settings ───────────────────────────────────────────────
58
62
  function StepAuctionSettings({ values, onChange, }) {
@@ -139,6 +143,7 @@ const EDIT_SECTIONS = [
139
143
  export function SellerProductShell({ mode, listingType = "standard", initialValues, onSave, onPublish, onDiscard, isLoading = false, storeSlug, renderCategorySelector, renderBrandSelector, renderAddressSelector, renderTemplateSelector, onSaveAsTemplate, previewSlot, }) {
140
144
  const [draft, setDraft] = useState(initialValues ?? { status: "draft", condition: "new" });
141
145
  const [currentStep, setCurrentStep] = useState(0);
146
+ const [stepError, setStepError] = useState(null);
142
147
  const { isDirty, markDirty, markClean } = useFormShell();
143
148
  const router = useRouter();
144
149
  const update = useCallback((partial) => {
@@ -225,12 +230,29 @@ export function SellerProductShell({ mode, listingType = "standard", initialValu
225
230
  render: ({ values, onChange }) => (_jsx(StepPublish, { values: values, onChange: onChange })),
226
231
  },
227
232
  ];
233
+ const handleNext = useCallback(async () => {
234
+ const step = steps[currentStep];
235
+ if (step?.validate) {
236
+ const err = step.validate(draft);
237
+ if (err) {
238
+ setStepError(err);
239
+ return;
240
+ }
241
+ }
242
+ setStepError(null);
243
+ if (currentStep < steps.length - 1) {
244
+ setCurrentStep((c) => c + 1);
245
+ }
246
+ else {
247
+ await handlePublish();
248
+ }
249
+ }, [currentStep, steps, draft, handlePublish]);
228
250
  const breadcrumb = mode === "create" ? `Store / ${listingTypeLabel}s / New` : `Store / ${listingTypeLabel}s / Edit`;
229
251
  const title = mode === "create"
230
252
  ? `New ${listingTypeLabel}`
231
253
  : draft.title ?? `Edit ${listingTypeLabel}`;
232
254
  if (mode === "create") {
233
- return (_jsx(FormShell, { isOpen: true, onClose: handleDiscard, title: title, breadcrumb: breadcrumb, isDirty: isDirty, isLoading: isLoading, previewSlot: previewSlot, children: _jsx(StepForm, { steps: steps, values: draft, onChange: update, onComplete: handlePublish, completeLabel: `Publish ${listingTypeLabel}`, currentStep: currentStep, onStepChange: setCurrentStep, isLoading: isLoading }) }));
255
+ return (_jsx(FormShell, { isOpen: true, onClose: handleDiscard, title: title, breadcrumb: breadcrumb, isDirty: isDirty, isLoading: isLoading, previewSlot: previewSlot, renderBottomBar: () => (_jsxs("div", { className: "flex-shrink-0 border-t border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)]", children: [_jsx(StepFormActions, { currentStep: currentStep, totalSteps: steps.length, onNext: () => void handleNext(), onPrev: currentStep > 0 ? () => setCurrentStep((c) => c - 1) : undefined, completeLabel: `Publish ${listingTypeLabel}`, isLoading: isLoading && currentStep === steps.length - 1, disabled: isLoading }), stepError && (_jsx(Text, { className: "px-5 pb-3 text-sm text-[var(--appkit-color-error)]", children: stepError }))] })), children: _jsx(StepForm, { steps: steps, values: draft, onChange: update, onComplete: handlePublish, completeLabel: `Publish ${listingTypeLabel}`, currentStep: currentStep, onStepChange: setCurrentStep, isLoading: isLoading, hideActions: true }) }));
234
256
  }
235
257
  // Edit mode — FormShell with section nav + full form
236
258
  const editSections = [
@@ -2,10 +2,11 @@
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
4
  import { useActionDispatch } from "../../../react/hooks/use-action-dispatch";
5
- import { X, Pencil, Trash2 } from "lucide-react";
5
+ import { X, Pencil, Trash2, Printer, MapPin } from "lucide-react";
6
+ import { PhysicalLocationModal } from "./PhysicalLocationModal";
6
7
  import { useUrlTable } from "../../../react/hooks/useUrlTable";
7
8
  import { useBulkSelection } from "../../../react/hooks/useBulkSelection";
8
- import { Alert, Badge, Button, Div, FilterChipGroup, ListingToolbar, ListingViewShell, Pagination, Row, Span, Text } from "../../../ui";
9
+ import { Alert, Badge, BulkActionBar, Button, Div, FilterChipGroup, ListingToolbar, ListingViewShell, Pagination, Row, Span, Text } from "../../../ui";
9
10
  import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints";
10
11
  import { SELLER_PRODUCT_STATUS_TABS } from "../../admin/constants/filter-tabs";
11
12
  import { ROUTES } from "../../../constants";
@@ -85,6 +86,12 @@ const PRODUCT_COLUMNS = [
85
86
  className: "w-28",
86
87
  render: (row) => (_jsx(Span, { className: "text-xs text-[var(--appkit-color-text-muted)]", children: row.updatedAt })),
87
88
  },
89
+ {
90
+ key: "physicalLocation",
91
+ header: "Location",
92
+ className: "w-28",
93
+ render: (row) => row.physicalLocation ? (_jsxs(Span, { className: "text-xs font-mono text-[var(--appkit-color-text-muted)]", children: [row.physicalLocation.zone, "/", row.physicalLocation.shelf, "/", row.physicalLocation.bin] })) : (_jsx(Span, { className: "text-xs text-[var(--appkit-color-text-faint)]", children: "\u2014" })),
94
+ },
88
95
  ];
89
96
  export function SellerProductsView({ onDeleteProduct, children, ...props }) {
90
97
  const hasChildren = React.Children.count(children) > 0;
@@ -95,6 +102,7 @@ export function SellerProductsView({ onDeleteProduct, children, ...props }) {
95
102
  const [filterOpen, setFilterOpen] = useState(false);
96
103
  const [listingKind, setListingKind] = useState("all");
97
104
  const [deletingId, setDeletingId] = useState(null);
105
+ const [setLocationOpen, setSetLocationOpen] = useState(false);
98
106
  const [pendingFilters, setPendingFilters] = useState(() => Object.fromEntries(FILTER_KEYS.map((k) => [k, table.get(k)])));
99
107
  const openFilters = useCallback(() => {
100
108
  setPendingFilters(Object.fromEntries(FILTER_KEYS.map((k) => [k, table.get(k)])));
@@ -172,6 +180,10 @@ export function SellerProductsView({ onDeleteProduct, children, ...props }) {
172
180
  imageUrl: toStringValue(item.mainImage ?? item.images?.[0], undefined),
173
181
  listingKind: kind,
174
182
  price: priceRaw ? `₹${(priceRaw / 100).toLocaleString("en-IN")}` : "—",
183
+ physicalLocation: item.physicalLocation &&
184
+ typeof item.physicalLocation.zone === "string"
185
+ ? item.physicalLocation
186
+ : undefined,
175
187
  };
176
188
  }),
177
189
  getTotal: (response, mappedRows) => typeof response.meta?.total === "number" ? response.meta.total : mappedRows.length,
@@ -203,15 +215,44 @@ export function SellerProductsView({ onDeleteProduct, children, ...props }) {
203
215
  setDeletingId(null);
204
216
  }
205
217
  };
206
- return (_jsx(_Fragment, { children: _jsxs(Div, { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search products by name\u2026", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set("sort", v); }, showTableView: true, view: view, onViewChange: (v) => setView(v), onResetAll: resetAll, hasActiveState: hasActiveState }), _jsx(TypeChips, { active: listingKind, onChange: handleKindChange }), totalPages > 1 && (_jsx(Div, { className: "sticky z-10 flex justify-center bg-[var(--appkit-color-surface)]/95 backdrop-blur-sm border-b border-[var(--appkit-color-border)] px-3 py-1.5", style: { top: "calc(var(--header-height, 0px) + 44px)" }, children: _jsx(Pagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) })), _jsxs(Div, { className: "py-4 px-3 lg:px-4", children: [errorMessage && (_jsx(Alert, { variant: "error", className: "mb-4", children: errorMessage })), _jsx(DataTable, { columns: PRODUCT_COLUMNS, rows: rows, isLoading: isLoading, emptyLabel: listingKind !== "all"
207
- ? `No ${listingKind} listings found`
208
- : "No products listed yet", getRowHref: (row) => row.listingKind === "auction"
209
- ? String(ROUTES.STORE.AUCTIONS_EDIT(row.id))
210
- : row.listingKind === "pre-order"
211
- ? String(ROUTES.STORE.PRE_ORDERS_EDIT(row.id))
212
- : row.listingKind === "prize-draw"
213
- ? String(ROUTES.STORE.PRIZE_DRAWS_EDIT(row.id))
214
- : String(ROUTES.STORE.PRODUCTS_EDIT(row.id)), renderRowActions: onDeleteProduct
215
- ? (row) => (_jsxs(Row, { className: "gap-1", children: [_jsx(Button, { variant: "ghost", size: "sm", onClick: (e) => { e.stopPropagation(); handleEdit(row); }, "aria-label": ACTIONS.STORE["edit-listing"].ariaLabel, children: _jsx(Pencil, { className: "w-4 h-4" }) }), _jsx(Button, { variant: "ghost", size: "sm", action: ACTIONS.STORE["delete-listing"], onClick: (e) => { e.stopPropagation(); void handleDelete(row); }, disabled: deletingId === row.id, className: "text-[var(--appkit-color-error)] hover:bg-[var(--appkit-color-border-subtle)]", children: _jsx(Trash2, { className: "w-4 h-4" }) })] }))
216
- : undefined })] }), filterOpen && (_jsxs(_Fragment, { children: [_jsx(Div, { role: "presentation", className: "fixed inset-0 z-40 bg-black/40", onClick: () => setFilterOpen(false) }), _jsxs(Div, { className: "fixed inset-y-0 left-0 z-50 flex w-80 flex-col bg-[var(--appkit-color-surface)] shadow-2xl", children: [_jsxs(Row, { justify: "between", className: "border-b border-[var(--appkit-color-border)] px-4 py-3.5", children: [_jsx(Text, { className: "text-base font-semibold text-[var(--appkit-color-text)]", children: "Filters" }), _jsxs(Row, { className: "gap-2", children: [activeFilterCount > 0 && (_jsx(Button, { variant: "ghost", size: "sm", onClick: clearFilters, className: "text-xs text-[var(--appkit-color-text-muted)] hover:text-[var(--appkit-color-error)]", children: "Clear all" })), _jsx(Button, { variant: "ghost", size: "sm", onClick: () => setFilterOpen(false), "aria-label": "Close filters", children: _jsx(X, { className: "h-5 w-5" }) })] })] }), _jsx(Div, { className: "flex-1 overflow-y-auto px-4 py-4 space-y-5", children: _jsx(FilterChipGroup, { label: "Status", tabs: STATUS_OPTIONS, value: pendingFilters.status ?? "", onChange: (id) => setPendingFilters((p) => ({ ...p, status: id })) }) }), _jsx(Div, { className: "border-t border-[var(--appkit-color-border)] px-4 py-3.5", children: _jsxs(Button, { variant: "primary", onClick: applyFilters, className: "w-full rounded-lg py-2.5 active:scale-[0.98]", children: ["Apply Filters", activeFilterCount > 0 ? ` (${activeFilterCount})` : ""] }) })] })] }))] }) }));
218
+ const handleBulkPrintLabels = useCallback(() => {
219
+ const ids = selection.selectedIds.join(",");
220
+ void dispatch({
221
+ type: "NAVIGATE",
222
+ href: `${String(ROUTES.STORE.INVENTORY_PRINT)}?type=product&ids=${ids}&autoprint=1`,
223
+ });
224
+ }, [selection.selectedIds, dispatch]);
225
+ const handleSetLocation = useCallback(async (loc) => {
226
+ await fetch(SELLER_ENDPOINTS.PRODUCTS_BULK_LOCATION, {
227
+ method: "PATCH",
228
+ headers: { "Content-Type": "application/json" },
229
+ body: JSON.stringify({ productIds: selection.selectedIds, physicalLocation: loc }),
230
+ });
231
+ setSetLocationOpen(false);
232
+ }, [selection.selectedIds]);
233
+ const bulkActions = [
234
+ {
235
+ id: ACTIONS.STORE["print-labels"].id,
236
+ label: ACTIONS.STORE["print-labels"].label,
237
+ icon: _jsx(Printer, { className: "w-4 h-4" }),
238
+ onClick: handleBulkPrintLabels,
239
+ },
240
+ {
241
+ id: ACTIONS.STORE["set-location"].id,
242
+ label: ACTIONS.STORE["set-location"].label,
243
+ icon: _jsx(MapPin, { className: "w-4 h-4" }),
244
+ onClick: () => setSetLocationOpen(true),
245
+ },
246
+ ];
247
+ return (_jsxs(_Fragment, { children: [_jsxs(Div, { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: activeFilterCount, onFiltersClick: openFilters, searchValue: searchInput, searchPlaceholder: "Search products by name\u2026", onSearchChange: setSearchInput, onSearchCommit: commitSearch, sortValue: table.get("sort") || DEFAULT_SORT, sortOptions: SORT_OPTIONS, onSortChange: (v) => { table.set("sort", v); }, showTableView: true, view: view, onViewChange: (v) => setView(v), onResetAll: resetAll, hasActiveState: hasActiveState }), _jsx(TypeChips, { active: listingKind, onChange: handleKindChange }), totalPages > 1 && (_jsx(Div, { className: "sticky z-10 flex justify-center bg-[var(--appkit-color-surface)]/95 backdrop-blur-sm border-b border-[var(--appkit-color-border)] px-3 py-1.5", style: { top: "calc(var(--header-height, 0px) + 44px)" }, children: _jsx(Pagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: (p) => table.setPage(p) }) })), selection.selectedIds.length > 0 && (_jsx(Div, { className: "sticky z-20 px-3 lg:px-4 py-2 bg-[var(--appkit-color-surface)]/95 backdrop-blur-sm border-b border-[var(--appkit-color-border)]", style: { top: "calc(var(--header-height, 0px) + 88px)" }, children: _jsx(BulkActionBar, { selectedCount: selection.selectedIds.length, onClearSelection: selection.clearSelection, actions: bulkActions }) })), _jsxs(Div, { className: "py-4 px-3 lg:px-4", children: [errorMessage && (_jsx(Alert, { variant: "error", className: "mb-4", children: errorMessage })), _jsx(DataTable, { columns: PRODUCT_COLUMNS, rows: rows, isLoading: isLoading, emptyLabel: listingKind !== "all"
248
+ ? `No ${listingKind} listings found`
249
+ : "No products listed yet", selectedIds: selection.selectedIdSet, onToggleSelect: selection.toggle, onToggleSelectAll: (next) => selection.toggleAll(), getRowHref: (row) => row.listingKind === "auction"
250
+ ? String(ROUTES.STORE.AUCTIONS_EDIT(row.id))
251
+ : row.listingKind === "pre-order"
252
+ ? String(ROUTES.STORE.PRE_ORDERS_EDIT(row.id))
253
+ : row.listingKind === "prize-draw"
254
+ ? String(ROUTES.STORE.PRIZE_DRAWS_EDIT(row.id))
255
+ : String(ROUTES.STORE.PRODUCTS_EDIT(row.id)), renderRowActions: onDeleteProduct
256
+ ? (row) => (_jsxs(Row, { className: "gap-1", children: [_jsx(Button, { variant: "ghost", size: "sm", onClick: (e) => { e.stopPropagation(); handleEdit(row); }, "aria-label": ACTIONS.STORE["edit-listing"].ariaLabel, children: _jsx(Pencil, { className: "w-4 h-4" }) }), _jsx(Button, { variant: "ghost", size: "sm", action: ACTIONS.STORE["delete-listing"], onClick: (e) => { e.stopPropagation(); void handleDelete(row); }, disabled: deletingId === row.id, className: "text-[var(--appkit-color-error)] hover:bg-[var(--appkit-color-border-subtle)]", children: _jsx(Trash2, { className: "w-4 h-4" }) })] }))
257
+ : undefined })] }), filterOpen && (_jsxs(_Fragment, { children: [_jsx(Div, { role: "presentation", className: "fixed inset-0 z-40 bg-black/40", onClick: () => setFilterOpen(false) }), _jsxs(Div, { className: "fixed inset-y-0 left-0 z-50 flex w-80 flex-col bg-[var(--appkit-color-surface)] shadow-2xl", children: [_jsxs(Row, { justify: "between", className: "border-b border-[var(--appkit-color-border)] px-4 py-3.5", children: [_jsx(Text, { className: "text-base font-semibold text-[var(--appkit-color-text)]", children: "Filters" }), _jsxs(Row, { className: "gap-2", children: [activeFilterCount > 0 && (_jsx(Button, { variant: "ghost", size: "sm", onClick: clearFilters, className: "text-xs text-[var(--appkit-color-text-muted)] hover:text-[var(--appkit-color-error)]", children: "Clear all" })), _jsx(Button, { variant: "ghost", size: "sm", onClick: () => setFilterOpen(false), "aria-label": "Close filters", children: _jsx(X, { className: "h-5 w-5" }) })] })] }), _jsx(Div, { className: "flex-1 overflow-y-auto px-4 py-4 space-y-5", children: _jsx(FilterChipGroup, { label: "Status", tabs: STATUS_OPTIONS, value: pendingFilters.status ?? "", onChange: (id) => setPendingFilters((p) => ({ ...p, status: id })) }) }), _jsx(Div, { className: "border-t border-[var(--appkit-color-border)] px-4 py-3.5", children: _jsxs(Button, { variant: "primary", onClick: applyFilters, className: "w-full rounded-lg py-2.5 active:scale-[0.98]", children: ["Apply Filters", activeFilterCount > 0 ? ` (${activeFilterCount})` : ""] }) })] })] }))] }), setLocationOpen && (_jsx(PhysicalLocationModal, { count: selection.selectedIds.length, onSave: handleSetLocation, onClose: () => setSetLocationOpen(false) }))] }));
217
258
  }
@@ -56,7 +56,7 @@ export function StoreSidebar({ items, groups, activeHref, storeName, storeLogoUR
56
56
  height: "calc(100vh - var(--header-height, 3.5rem))",
57
57
  width: "18rem",
58
58
  transform: desktopOpen ? "translateX(0)" : "translateX(calc(-100% + 1.25rem))",
59
- }, children: [_jsxs("div", { className: "flex-1 bg-white dark:bg-slate-950 border-r border-zinc-200 dark:border-slate-700 flex flex-col overflow-hidden shadow-xl", children: [_jsx("div", { className: "px-4 py-3.5 border-b border-zinc-100 dark:border-slate-800 shrink-0", children: _jsxs("div", { className: "flex items-center gap-3 min-w-0", children: [storeLogoURL ? (_jsx(Div, { role: "img", "aria-label": storeName, className: CLS_STORE_AVATAR, style: { backgroundImage: `url(${storeLogoURL})` } })) : (_jsx(Div, { className: CLS_STORE_FALLBACK, children: storeName?.[0]?.toUpperCase() })), _jsx(Text, { className: CLS_STORE_NAME, children: storeName || panelTitle })] }) }), _jsx("div", { className: "flex-1 overflow-y-auto", children: navContent })] }), _jsx("button", { type: "button", onClick: handleToggle, "aria-label": desktopOpen ? "Collapse sidebar" : "Expand sidebar", className: "w-5 shrink-0 flex items-center justify-center transition-opacity rounded-r-md shadow-md hover:opacity-85", style: { background: "linear-gradient(to bottom, var(--appkit-color-cobalt-700), var(--appkit-color-cobalt))" }, children: _jsx("svg", { className: "w-3 h-3 text-white", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": "true", children: desktopOpen ? (_jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2.5, d: "M11 19l-7-7 7-7m8 14l-7-7 7-7" })) : (_jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2.5, d: "M13 5l7 7-7 7M5 5l7 7-7 7" })) }) })] }), _jsx("div", { className: "md:hidden", children: _jsx(BottomSheet, { open: mobileOpen, onClose: close, title: panelTitle, children: groups ? (_jsx(GroupsContent, { groups: groups, activeHref: activeHref, storeName: storeName, storeLogoURL: storeLogoURL, onItemClick: close })) : (_jsx(FlatContent, { items: items, activeHref: activeHref, storeName: storeName, storeLogoURL: storeLogoURL, onItemClick: close })) }) })] }));
59
+ }, children: [_jsxs("div", { className: "flex-1 bg-white dark:bg-slate-950 border-r border-zinc-200 dark:border-slate-700 flex flex-col overflow-hidden shadow-xl", children: [_jsx("div", { className: "px-4 py-3.5 border-b border-zinc-100 dark:border-slate-800 shrink-0", children: _jsxs("div", { className: "flex items-center gap-3 min-w-0", children: [storeLogoURL ? (_jsx(Div, { role: "img", "aria-label": storeName, className: CLS_STORE_AVATAR, style: { backgroundImage: `url(${storeLogoURL})` } })) : (_jsx(Div, { className: CLS_STORE_FALLBACK, children: storeName?.[0]?.toUpperCase() })), _jsx(Text, { className: CLS_STORE_NAME, children: storeName || panelTitle })] }) }), _jsx("div", { className: "flex-1 overflow-y-auto", children: navContent })] }), _jsx("button", { type: "button", onClick: handleToggle, "aria-label": desktopOpen ? "Collapse sidebar" : "Expand sidebar", className: "w-9 shrink-0 flex items-center justify-center cursor-pointer rounded-r-[1.25rem] shadow-lg transition-all duration-200 hover:shadow-xl hover:brightness-110 active:scale-[0.96]", style: { background: "linear-gradient(to bottom, #c2410c, #ea580c)" }, children: _jsx("svg", { className: `w-4 h-4 text-white drop-shadow-sm transition-transform duration-300 ${desktopOpen ? "" : "rotate-180"}`, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2.5, d: "M15 19l-7-7 7-7" }) }) })] }), _jsx("div", { className: "md:hidden", children: _jsx(BottomSheet, { open: mobileOpen, onClose: close, title: panelTitle, children: groups ? (_jsx(GroupsContent, { groups: groups, activeHref: activeHref, storeName: storeName, storeLogoURL: storeLogoURL, onItemClick: close })) : (_jsx(FlatContent, { items: items, activeHref: activeHref, storeName: storeName, storeLogoURL: storeLogoURL, onItemClick: close })) }) })] }));
60
60
  }
61
61
  return (_jsxs(_Fragment, { children: [mounted && mobileOpen &&
62
62
  createPortal(_jsx(DrawerPanel, { title: panelTitle, onClose: close, children: navContent }), document.body), _jsx("div", { className: "md:hidden", children: _jsx(BottomSheet, { open: mobileOpen, onClose: close, title: panelTitle, children: groups ? (_jsx(GroupsContent, { groups: groups, activeHref: activeHref, storeName: storeName, storeLogoURL: storeLogoURL, onItemClick: close })) : (_jsx(FlatContent, { items: items, activeHref: activeHref, storeName: storeName, storeLogoURL: storeLogoURL, onItemClick: close })) }) })] }));
@@ -11,6 +11,7 @@ export { SellerPreOrdersView } from "./SellerPreOrdersView";
11
11
  export type { SellerPreOrdersViewProps } from "./SellerPreOrdersView";
12
12
  export { SellerPrizeDrawsView } from "./SellerPrizeDrawsView";
13
13
  export type { SellerPrizeDrawsViewProps } from "./SellerPrizeDrawsView";
14
+ export { PrintCenterView } from "./PrintCenterView";
14
15
  export { SellerOrdersView } from "./SellerOrdersView";
15
16
  export type { SellerOrdersViewProps } from "./SellerOrdersView";
16
17
  export { SellerOffersView } from "./SellerOffersView";
@@ -5,6 +5,7 @@ export { SellerProductsView } from "./SellerProductsView";
5
5
  export { SellerAuctionsView } from "./SellerAuctionsView";
6
6
  export { SellerPreOrdersView } from "./SellerPreOrdersView";
7
7
  export { SellerPrizeDrawsView } from "./SellerPrizeDrawsView";
8
+ export { PrintCenterView } from "./PrintCenterView";
8
9
  export { SellerOrdersView } from "./SellerOrdersView";
9
10
  export { SellerOffersView } from "./SellerOffersView";
10
11
  export { SellerOffersPanel } from "./SellerOffersPanel";
@@ -34,6 +34,7 @@ export interface OfferDocument {
34
34
  sellerNote?: string;
35
35
  expiresAt: Date;
36
36
  acceptedAt?: Date;
37
+ checkoutDeadline?: Date;
37
38
  respondedAt?: Date;
38
39
  createdAt: Date;
39
40
  updatedAt: Date;
@@ -59,6 +60,7 @@ export declare const OFFER_FIELDS: {
59
60
  readonly SELLER_NOTE: "sellerNote";
60
61
  readonly EXPIRES_AT: "expiresAt";
61
62
  readonly ACCEPTED_AT: "acceptedAt";
63
+ readonly CHECKOUT_DEADLINE: "checkoutDeadline";
62
64
  readonly RESPONDED_AT: "respondedAt";
63
65
  readonly CREATED_AT: "createdAt";
64
66
  readonly UPDATED_AT: "updatedAt";
@@ -40,6 +40,7 @@ export const OFFER_FIELDS = {
40
40
  SELLER_NOTE: "sellerNote",
41
41
  EXPIRES_AT: "expiresAt",
42
42
  ACCEPTED_AT: "acceptedAt",
43
+ CHECKOUT_DEADLINE: "checkoutDeadline",
43
44
  RESPONDED_AT: "respondedAt",
44
45
  CREATED_AT: "createdAt",
45
46
  UPDATED_AT: "updatedAt",
@@ -85,11 +85,11 @@ export declare const sellerStoreSchema: z.ZodObject<{
85
85
  createdAt: z.ZodString;
86
86
  updatedAt: z.ZodString;
87
87
  }, "strip", z.ZodTypeAny, {
88
- id: string;
89
- createdAt: string;
90
- updatedAt: string;
91
88
  status: "pending" | "active" | "rejected" | "suspended";
89
+ createdAt: string;
90
+ id: string;
92
91
  storeName: string;
92
+ updatedAt: string;
93
93
  isPublic: boolean;
94
94
  storeSlug: string;
95
95
  ownerId: string;
@@ -117,11 +117,11 @@ export declare const sellerStoreSchema: z.ZodObject<{
117
117
  isVacationMode?: boolean | undefined;
118
118
  vacationMessage?: string | undefined;
119
119
  }, {
120
- id: string;
121
- createdAt: string;
122
- updatedAt: string;
123
120
  status: "pending" | "active" | "rejected" | "suspended";
121
+ createdAt: string;
122
+ id: string;
124
123
  storeName: string;
124
+ updatedAt: string;
125
125
  isPublic: boolean;
126
126
  storeSlug: string;
127
127
  ownerId: string;
@@ -168,12 +168,12 @@ export declare const payoutRecordSchema: z.ZodObject<{
168
168
  updatedAt: z.ZodString;
169
169
  }, "strip", z.ZodTypeAny, {
170
170
  currency: string;
171
- id: string;
171
+ status: "pending" | "failed" | "processing" | "completed";
172
172
  createdAt: string;
173
+ id: string;
173
174
  updatedAt: string;
174
- status: "failed" | "pending" | "processing" | "completed";
175
- requestedAt: string;
176
175
  sellerName: string;
176
+ requestedAt: string;
177
177
  sellerEmail: string;
178
178
  amount: number;
179
179
  grossAmount: number;
@@ -185,12 +185,12 @@ export declare const payoutRecordSchema: z.ZodObject<{
185
185
  processedAt?: string | undefined;
186
186
  }, {
187
187
  currency: string;
188
- id: string;
188
+ status: "pending" | "failed" | "processing" | "completed";
189
189
  createdAt: string;
190
+ id: string;
190
191
  updatedAt: string;
191
- status: "failed" | "pending" | "processing" | "completed";
192
- requestedAt: string;
193
192
  sellerName: string;
193
+ requestedAt: string;
194
194
  sellerEmail: string;
195
195
  amount: number;
196
196
  grossAmount: number;
@@ -209,19 +209,19 @@ export declare const sellerListParamsSchema: z.ZodObject<{
209
209
  perPage: z.ZodOptional<z.ZodNumber>;
210
210
  sort: z.ZodOptional<z.ZodString>;
211
211
  }, "strip", z.ZodTypeAny, {
212
- sort?: string | undefined;
213
- perPage?: number | undefined;
214
212
  status?: "pending" | "active" | "rejected" | "suspended" | undefined;
215
- q?: string | undefined;
213
+ sort?: string | undefined;
216
214
  category?: string | undefined;
215
+ q?: string | undefined;
217
216
  page?: number | undefined;
218
- }, {
219
- sort?: string | undefined;
220
217
  perPage?: number | undefined;
218
+ }, {
221
219
  status?: "pending" | "active" | "rejected" | "suspended" | undefined;
222
- q?: string | undefined;
220
+ sort?: string | undefined;
223
221
  category?: string | undefined;
222
+ q?: string | undefined;
224
223
  page?: number | undefined;
224
+ perPage?: number | undefined;
225
225
  }>;
226
226
  export declare const payoutListParamsSchema: z.ZodObject<{
227
227
  sellerId: z.ZodOptional<z.ZodString>;
@@ -230,15 +230,15 @@ export declare const payoutListParamsSchema: z.ZodObject<{
230
230
  perPage: z.ZodOptional<z.ZodNumber>;
231
231
  sort: z.ZodOptional<z.ZodString>;
232
232
  }, "strip", z.ZodTypeAny, {
233
+ status?: "pending" | "failed" | "processing" | "completed" | undefined;
233
234
  sort?: string | undefined;
234
- perPage?: number | undefined;
235
- status?: "failed" | "pending" | "processing" | "completed" | undefined;
236
235
  page?: number | undefined;
236
+ perPage?: number | undefined;
237
237
  sellerId?: string | undefined;
238
238
  }, {
239
+ status?: "pending" | "failed" | "processing" | "completed" | undefined;
239
240
  sort?: string | undefined;
240
- perPage?: number | undefined;
241
- status?: "failed" | "pending" | "processing" | "completed" | undefined;
242
241
  page?: number | undefined;
242
+ perPage?: number | undefined;
243
243
  sellerId?: string | undefined;
244
244
  }>;
@@ -102,5 +102,5 @@ export function FormShell({ isOpen, onClose, title, breadcrumb, isDirty = false,
102
102
  };
103
103
  if (!isOpen)
104
104
  return null;
105
- return (_jsxs(_Fragment, { children: [_jsx("div", { className: "fixed inset-0 bg-black/50 backdrop-blur-[2px]", style: { zIndex: "calc(var(--appkit-z-modal) - 1)" }, "aria-hidden": "true", onClick: attemptClose }), _jsxs("div", { ref: panelRef, role: "dialog", "aria-modal": "true", "aria-label": title, className: "fixed top-0 bottom-0 left-0 right-0 lg:left-[10%] lg:right-[10%] flex flex-col bg-[var(--appkit-color-surface)] shadow-2xl", style: { zIndex: "var(--appkit-z-modal)" }, children: [_jsxs("div", { className: "flex-shrink-0 sticky top-0 z-10 border-b border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] px-4 py-3 flex items-center gap-3", children: [previewMode ? (_jsxs("button", { type: "button", onClick: () => setPreviewMode(false), "aria-label": "Back to edit", className: "rounded-lg p-1.5 text-[var(--appkit-color-text-muted)] hover:bg-[var(--appkit-color-border-subtle)] transition-colors flex-shrink-0 flex items-center gap-1.5 text-sm", children: [_jsx(ArrowLeft, { className: "w-4 h-4" }), _jsx("span", { className: "hidden sm:inline", children: "Back to Edit" })] })) : (_jsx("button", { type: "button", onClick: attemptClose, "aria-label": "Close", className: "rounded-lg p-1.5 text-[var(--appkit-color-text-muted)] hover:bg-[var(--appkit-color-border-subtle)] transition-colors flex-shrink-0", children: _jsx(X, { className: "w-5 h-5" }) })), _jsxs("div", { className: "flex-1 min-w-0", children: [breadcrumb && (_jsx(Text, { className: "text-xs text-[var(--appkit-color-text-muted)] truncate mb-0.5", children: breadcrumb })), _jsx(Text, { className: "text-sm font-semibold text-[var(--appkit-color-text)] truncate", children: previewMode ? `Preview — ${title}` : title })] }), _jsx("div", { className: "flex items-center gap-2 flex-shrink-0", children: previewMode ? null : (_jsxs(_Fragment, { children: [previewSlot && (_jsxs("button", { type: "button", onClick: () => setPreviewMode(true), className: "flex items-center gap-1.5 rounded-lg px-3 py-1.5 text-sm text-[var(--appkit-color-text-muted)] hover:bg-[var(--appkit-color-border-subtle)] transition-colors border border-[var(--appkit-color-border)]", children: [_jsx(Eye, { className: "w-4 h-4" }), _jsx("span", { className: "hidden sm:inline", children: "Preview" })] })), onSaveDraft && (_jsx(Button, { variant: "outline", size: "sm", onClick: handleSaveDraft, disabled: isLoading || savingDraft || publishing, isLoading: savingDraft, children: saveLabel })), onPublish && (_jsx(Button, { variant: "primary", size: "sm", onClick: handlePublish, disabled: isLoading || savingDraft || publishing, isLoading: publishing, children: publishLabel }))] })) })] }), _jsxs("div", { className: "flex flex-1 overflow-hidden", children: [sections && sections.length > 0 && !previewMode && (_jsx("nav", { "aria-label": "Form sections", className: "hidden lg:flex flex-col flex-shrink-0 w-48 border-r border-[var(--appkit-color-border)] py-4 px-3 gap-1 overflow-y-auto", children: sections.map((sec) => (_jsx("button", { type: "button", onClick: () => scrollToSection(sec.id), className: "text-left text-sm px-3 py-2 rounded-lg text-[var(--appkit-color-text-muted)] hover:text-[var(--appkit-color-text)] hover:bg-[var(--appkit-color-border-subtle)] transition-colors", children: sec.label }, sec.id))) })), sections && sections.length > 0 && !previewMode && (_jsx("div", { className: "lg:hidden fixed top-[var(--form-shell-topbar-h,57px)] left-0 right-0 z-10 flex overflow-x-auto gap-1 px-4 py-2 bg-[var(--appkit-color-surface)] border-b border-[var(--appkit-color-border)]", children: sections.map((sec) => (_jsx("button", { type: "button", onClick: () => scrollToSection(sec.id), className: "flex-shrink-0 text-xs px-3 py-1.5 rounded-full border border-[var(--appkit-color-border)] text-[var(--appkit-color-text-muted)] hover:border-[var(--appkit-color-primary)] hover:text-[var(--appkit-color-primary)] transition-colors whitespace-nowrap", children: sec.label }, sec.id))) })), _jsx("div", { ref: bodyRef, className: classNames("flex-1 overflow-y-auto", sections && sections.length > 0 && !previewMode ? "pt-0 lg:pt-0" : ""), children: previewMode && previewSlot ? (_jsxs(_Fragment, { children: [_jsxs("div", { className: "sticky top-0 z-10 flex items-center gap-2 bg-[var(--appkit-color-warning-surface)] border-b border-[var(--appkit-color-warning)] px-4 py-2 text-sm text-[var(--appkit-color-warning-text,var(--appkit-color-warning))]", children: [_jsx(Eye, { className: "w-4 h-4 flex-shrink-0" }), _jsx("span", { children: "Preview \u2014 not visible to buyers until published" })] }), _jsx("div", { className: "py-4", children: previewSlot() })] })) : (_jsx("div", { className: "max-w-3xl mx-auto px-4 py-6 sm:px-6", children: children })) })] }), !previewMode && renderBottomBar ? (renderBottomBar()) : !previewMode && (onSaveDraft || onPublish) ? (_jsxs("div", { className: "flex-shrink-0 sticky bottom-0 z-10 border-t border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] px-4 py-3 flex items-center justify-between", children: [_jsx(Button, { variant: "ghost", size: "sm", onClick: attemptClose, disabled: isLoading, children: FORM_ACTION_META[FORM_ACTION_ID.DISCARD].label }), _jsxs("div", { className: "flex items-center gap-2", children: [onSaveDraft && (_jsx(Button, { variant: "outline", size: "sm", onClick: handleSaveDraft, disabled: isLoading || savingDraft || publishing, isLoading: savingDraft, children: saveLabel })), onPublish && (_jsxs(Button, { variant: "primary", size: "sm", onClick: handlePublish, disabled: isLoading || savingDraft || publishing, isLoading: publishing, children: [publishLabel, " \u2192"] }))] })] })) : null] }), showUnsaved && (_jsxs(_Fragment, { children: [_jsx("div", { className: "fixed inset-0 bg-black/60", style: { zIndex: "calc(var(--appkit-z-modal) + 5)" }, onClick: () => setShowUnsaved(false) }), _jsxs("div", { className: "fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[90vw] max-w-sm bg-[var(--appkit-color-surface)] rounded-xl shadow-2xl p-6", style: { zIndex: "calc(var(--appkit-z-modal) + 5)" }, children: [_jsxs("div", { className: "flex gap-3 mb-4", children: [_jsx("span", { className: "flex-shrink-0 w-10 h-10 rounded-full bg-[var(--appkit-color-warning-surface)] flex items-center justify-center", children: _jsx(AlertTriangle, { className: "w-5 h-5 text-[var(--appkit-color-warning)]" }) }), _jsxs(_Fragment, { children: [_jsx(Text, { className: "font-semibold text-[var(--appkit-color-text)]", children: "Unsaved changes" }), _jsx(Text, { className: "text-sm text-[var(--appkit-color-text-muted)] mt-1", children: "You have unsaved changes. Leave without saving?" })] })] }), _jsxs("div", { className: "flex gap-2 justify-end", children: [_jsx(Button, { variant: "outline", size: "sm", onClick: () => setShowUnsaved(false), children: "Stay" }), _jsx(Button, { variant: "danger", size: "sm", onClick: () => { setShowUnsaved(false); onClose(); }, children: "Leave" })] })] })] }))] }));
105
+ return (_jsxs(_Fragment, { children: [_jsx("div", { className: "fixed inset-0 bg-black/50 backdrop-blur-[2px]", style: { zIndex: "calc(var(--appkit-z-modal) - 1)" }, "aria-hidden": "true", onClick: attemptClose }), _jsxs("div", { ref: panelRef, role: "dialog", "aria-modal": "true", "aria-label": title, className: "fixed top-0 bottom-0 left-0 right-0 lg:left-[10%] lg:right-[10%] flex flex-col bg-[var(--appkit-color-surface)] shadow-2xl", style: { zIndex: "var(--appkit-z-modal)" }, children: [_jsxs("div", { className: "flex-shrink-0 sticky top-0 z-10 border-b border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] px-5 py-3 flex items-center gap-3", children: [previewMode ? (_jsxs("button", { type: "button", onClick: () => setPreviewMode(false), "aria-label": "Back to edit", className: "rounded-lg p-1.5 text-[var(--appkit-color-text-muted)] hover:bg-[var(--appkit-color-border-subtle)] transition-colors flex-shrink-0 flex items-center gap-1.5 text-sm", children: [_jsx(ArrowLeft, { className: "w-4 h-4" }), _jsx("span", { className: "hidden sm:inline", children: "Back to Edit" })] })) : (_jsx("button", { type: "button", onClick: attemptClose, "aria-label": "Close", className: "rounded-lg p-1.5 text-[var(--appkit-color-text-muted)] hover:bg-[var(--appkit-color-border-subtle)] transition-colors flex-shrink-0", children: _jsx(X, { className: "w-5 h-5" }) })), _jsxs("div", { className: "flex-1 min-w-0", children: [breadcrumb && (_jsx(Text, { className: "text-xs text-[var(--appkit-color-text-muted)] truncate mb-0.5", children: breadcrumb })), _jsx(Text, { className: "text-sm font-semibold text-[var(--appkit-color-text)] truncate", children: previewMode ? `Preview — ${title}` : title })] }), _jsx("div", { className: "flex items-center gap-2 flex-shrink-0", children: previewMode ? null : (_jsxs(_Fragment, { children: [previewSlot && (_jsxs("button", { type: "button", onClick: () => setPreviewMode(true), className: "flex items-center gap-1.5 rounded-lg px-3 py-1.5 text-sm text-[var(--appkit-color-text-muted)] hover:bg-[var(--appkit-color-border-subtle)] transition-colors border border-[var(--appkit-color-border)]", children: [_jsx(Eye, { className: "w-4 h-4" }), _jsx("span", { className: "hidden sm:inline", children: "Preview" })] })), onSaveDraft && (_jsx(Button, { variant: "outline", size: "sm", onClick: handleSaveDraft, disabled: isLoading || savingDraft || publishing, isLoading: savingDraft, children: saveLabel })), onPublish && (_jsx(Button, { variant: "primary", size: "sm", onClick: handlePublish, disabled: isLoading || savingDraft || publishing, isLoading: publishing, children: publishLabel }))] })) })] }), _jsxs("div", { className: "flex flex-1 overflow-hidden", children: [sections && sections.length > 0 && !previewMode && (_jsx("nav", { "aria-label": "Form sections", className: "hidden lg:flex flex-col flex-shrink-0 w-48 border-r border-[var(--appkit-color-border)] py-4 px-3 gap-1 overflow-y-auto", children: sections.map((sec) => (_jsx("button", { type: "button", onClick: () => scrollToSection(sec.id), className: "text-left text-sm px-3 py-2 rounded-lg text-[var(--appkit-color-text-muted)] hover:text-[var(--appkit-color-text)] hover:bg-[var(--appkit-color-border-subtle)] transition-colors", children: sec.label }, sec.id))) })), sections && sections.length > 0 && !previewMode && (_jsx("div", { className: "lg:hidden fixed top-[var(--form-shell-topbar-h,57px)] left-0 right-0 z-10 flex overflow-x-auto gap-1 px-5 py-2 bg-[var(--appkit-color-surface)] border-b border-[var(--appkit-color-border)]", children: sections.map((sec) => (_jsx("button", { type: "button", onClick: () => scrollToSection(sec.id), className: "flex-shrink-0 text-xs px-3 py-1.5 rounded-full border border-[var(--appkit-color-border)] text-[var(--appkit-color-text-muted)] hover:border-[var(--appkit-color-primary)] hover:text-[var(--appkit-color-primary)] transition-colors whitespace-nowrap", children: sec.label }, sec.id))) })), _jsx("div", { ref: bodyRef, className: classNames("flex-1 overflow-y-auto", sections && sections.length > 0 && !previewMode ? "pt-0 lg:pt-0" : ""), children: previewMode && previewSlot ? (_jsxs(_Fragment, { children: [_jsxs("div", { className: "sticky top-0 z-10 flex items-center gap-2 bg-[var(--appkit-color-warning-surface)] border-b border-[var(--appkit-color-warning)] px-4 py-2 text-sm text-[var(--appkit-color-warning-text,var(--appkit-color-warning))]", children: [_jsx(Eye, { className: "w-4 h-4 flex-shrink-0" }), _jsx("span", { children: "Preview \u2014 not visible to buyers until published" })] }), _jsx("div", { className: "py-4", children: previewSlot() })] })) : (_jsx("div", { className: "max-w-3xl mx-auto px-5 py-6 sm:px-6", children: children })) })] }), !previewMode && renderBottomBar ? (renderBottomBar()) : !previewMode && (onSaveDraft || onPublish) ? (_jsxs("div", { className: "flex-shrink-0 sticky bottom-0 z-10 border-t border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] px-5 py-3 flex items-center justify-between", children: [_jsx(Button, { variant: "ghost", size: "sm", onClick: attemptClose, disabled: isLoading, children: FORM_ACTION_META[FORM_ACTION_ID.DISCARD].label }), _jsxs("div", { className: "flex items-center gap-2", children: [onSaveDraft && (_jsx(Button, { variant: "outline", size: "sm", onClick: handleSaveDraft, disabled: isLoading || savingDraft || publishing, isLoading: savingDraft, children: saveLabel })), onPublish && (_jsxs(Button, { variant: "primary", size: "sm", onClick: handlePublish, disabled: isLoading || savingDraft || publishing, isLoading: publishing, children: [publishLabel, " \u2192"] }))] })] })) : null] }), showUnsaved && (_jsxs(_Fragment, { children: [_jsx("div", { className: "fixed inset-0 bg-black/60", style: { zIndex: "calc(var(--appkit-z-modal) + 5)" }, onClick: () => setShowUnsaved(false) }), _jsxs("div", { className: "fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[90vw] max-w-sm bg-[var(--appkit-color-surface)] rounded-xl shadow-2xl p-6", style: { zIndex: "calc(var(--appkit-z-modal) + 5)" }, children: [_jsxs("div", { className: "flex gap-3 mb-4", children: [_jsx("span", { className: "flex-shrink-0 w-10 h-10 rounded-full bg-[var(--appkit-color-warning-surface)] flex items-center justify-center", children: _jsx(AlertTriangle, { className: "w-5 h-5 text-[var(--appkit-color-warning)]" }) }), _jsxs(_Fragment, { children: [_jsx(Text, { className: "font-semibold text-[var(--appkit-color-text)]", children: "Unsaved changes" }), _jsx(Text, { className: "text-sm text-[var(--appkit-color-text-muted)] mt-1", children: "You have unsaved changes. Leave without saving?" })] })] }), _jsxs("div", { className: "flex gap-2 justify-end", children: [_jsx(Button, { variant: "outline", size: "sm", onClick: () => setShowUnsaved(false), children: "Stay" }), _jsx(Button, { variant: "danger", size: "sm", onClick: () => { setShowUnsaved(false); onClose(); }, children: "Leave" })] })] })] }))] }));
106
106
  }
@@ -21,6 +21,8 @@ export interface StepFormProps<T extends object = Record<string, unknown>> {
21
21
  /** Current step index (0-based). Controlled from outside. */
22
22
  currentStep: number;
23
23
  onStepChange: (step: number) => void;
24
+ /** Suppress the built-in action bar. Use FormShell's renderBottomBar instead. */
25
+ hideActions?: boolean;
24
26
  }
25
27
  export interface StepFormActionsProps {
26
28
  currentStep: number;
@@ -41,4 +43,4 @@ export declare function StepIndicator({ steps, currentStep, onStepClick, }: {
41
43
  currentStep: number;
42
44
  onStepClick?: (index: number) => void;
43
45
  }): import("react/jsx-runtime").JSX.Element;
44
- export declare function StepForm<T extends object = Record<string, unknown>>({ steps, values, onChange, onComplete, completeLabel, isLoading, formId, currentStep, onStepChange, }: StepFormProps<T>): import("react/jsx-runtime").JSX.Element;
46
+ export declare function StepForm<T extends object = Record<string, unknown>>({ steps, values, onChange, onComplete, completeLabel, isLoading, formId, currentStep, onStepChange, hideActions, }: StepFormProps<T>): import("react/jsx-runtime").JSX.Element;
@@ -10,7 +10,7 @@ export function StepFormActions({ currentStep, totalSteps, onNext, onPrev, compl
10
10
  const isFirst = currentStep === 0;
11
11
  const isLast = currentStep === totalSteps - 1;
12
12
  const nextStepLabel = `Next →`;
13
- return (_jsxs("div", { className: "flex items-center justify-between gap-2 px-4 py-3 border-t border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)]", children: [_jsx(_Fragment, { children: !isFirst && onPrev && (_jsx(Button, { variant: "outline", size: "sm", onClick: onPrev, disabled: disabled || isLoading, children: "\u2190 Back" })) }), _jsxs("div", { className: "flex items-center gap-3", children: [_jsxs("span", { className: "text-xs text-[var(--appkit-color-text-muted)]", children: [currentStep + 1, " / ", totalSteps] }), _jsx(Button, { variant: "primary", size: "sm", onClick: onNext, disabled: disabled || isLoading, isLoading: isLoading && isLast, children: isLast ? completeLabel : nextStepLabel })] })] }));
13
+ return (_jsxs("div", { className: "flex items-center justify-between gap-2 px-5 py-3 border-t border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)]", children: [_jsx(_Fragment, { children: !isFirst && onPrev && (_jsx(Button, { variant: "outline", size: "sm", onClick: onPrev, disabled: disabled || isLoading, children: "\u2190 Back" })) }), _jsxs("div", { className: "flex items-center gap-3", children: [_jsxs("span", { className: "text-xs text-[var(--appkit-color-text-muted)]", children: [currentStep + 1, " / ", totalSteps] }), _jsx(Button, { variant: "primary", size: "sm", onClick: onNext, disabled: disabled || isLoading, isLoading: isLoading && isLast, children: isLast ? completeLabel : nextStepLabel })] })] }));
14
14
  }
15
15
  /** Step indicator bar shown above step content. */
16
16
  export function StepIndicator({ steps, currentStep, onStepClick, }) {
@@ -30,7 +30,7 @@ export function StepIndicator({ steps, currentStep, onStepClick, }) {
30
30
  : "bg-[var(--appkit-color-border)]") }))] }, i));
31
31
  }) }));
32
32
  }
33
- export function StepForm({ steps, values, onChange, onComplete, completeLabel = "Publish Now", isLoading = false, formId, currentStep, onStepChange, }) {
33
+ export function StepForm({ steps, values, onChange, onComplete, completeLabel = "Publish Now", isLoading = false, formId, currentStep, onStepChange, hideActions = false, }) {
34
34
  const [stepErrors, setStepErrors] = useState({});
35
35
  const [stepError, setStepError] = useState(null);
36
36
  // Persist step to localStorage if formId provided
@@ -78,5 +78,5 @@ export function StepForm({ steps, values, onChange, onComplete, completeLabel =
78
78
  return (_jsxs("div", { className: "flex flex-col", children: [_jsx(StepIndicator, { steps: steps, currentStep: currentStep, onStepClick: (i) => { if (i < currentStep) {
79
79
  setStepError(null);
80
80
  onStepChange(i);
81
- } } }), _jsx("div", { className: "flex-1", children: currentStepDef?.render({ values, onChange, errors: stepErrors }) }), stepError && (_jsx(Text, { className: "mt-3 text-sm text-[var(--appkit-color-error)]", children: stepError })), _jsx(StepFormActions, { currentStep: currentStep, totalSteps: steps.length, onNext: () => void goNext(), onPrev: currentStep > 0 ? goPrev : undefined, completeLabel: completeLabel, isLoading: isLoading && isLast, disabled: isLoading })] }));
81
+ } } }), _jsx("div", { className: "flex-1", children: currentStepDef?.render({ values, onChange, errors: stepErrors }) }), !hideActions && stepError && (_jsx(Text, { className: "mt-3 text-sm text-[var(--appkit-color-error)]", children: stepError })), !hideActions && (_jsx(StepFormActions, { currentStep: currentStep, totalSteps: steps.length, onNext: () => void goNext(), onPrev: currentStep > 0 ? goPrev : undefined, completeLabel: completeLabel, isLoading: isLoading && isLast, disabled: isLoading }))] }));
82
82
  }