@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
@@ -1,9 +1,10 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useCallback, useEffect, useState } from "react";
4
- import { Alert, Badge, Button, Div, FormField, Heading, Section, Stack, Text } from "../../../ui";
4
+ import { Alert, Badge, Div, FormField, Heading, Stack, Text } from "../../../ui";
5
5
  import { StackedViewShell } from "../../../ui";
6
6
  import { StoreAddressSelectorCreate } from "../../stores/components/StoreAddressSelectorCreate";
7
+ import { StepForm } from "../../shell";
7
8
  const DEFAULT_DRAFT = {
8
9
  method: "custom",
9
10
  customCarrierName: "",
@@ -11,6 +12,8 @@ const DEFAULT_DRAFT = {
11
12
  shiprocketEmail: "",
12
13
  shiprocketPassword: "",
13
14
  pickupAddressId: "",
15
+ freeShippingThreshold: "",
16
+ fragileSurcharge: "",
14
17
  };
15
18
  export function SellerShippingView({ apiBase = "/api/store/shipping" }) {
16
19
  const [draft, setDraft] = useState(DEFAULT_DRAFT);
@@ -19,6 +22,7 @@ export function SellerShippingView({ apiBase = "/api/store/shipping" }) {
19
22
  const [saving, setSaving] = useState(false);
20
23
  const [error, setError] = useState(null);
21
24
  const [success, setSuccess] = useState(false);
25
+ const [currentStep, setCurrentStep] = useState(0);
22
26
  useEffect(() => {
23
27
  fetch(apiBase)
24
28
  .then((r) => r.json())
@@ -32,13 +36,19 @@ export function SellerShippingView({ apiBase = "/api/store/shipping" }) {
32
36
  shiprocketEmail: cfg.shiprocketEmail ?? "",
33
37
  shiprocketPassword: "",
34
38
  pickupAddressId: "",
39
+ freeShippingThreshold: (res?.data?.freeShippingThreshold ?? 0)
40
+ ? String(res.data.freeShippingThreshold / 100)
41
+ : "",
42
+ fragileSurcharge: (res?.data?.fragileSurcharge ?? 0)
43
+ ? String(res.data.fragileSurcharge / 100)
44
+ : "",
35
45
  });
36
46
  })
37
47
  .catch(() => { })
38
48
  .finally(() => setLoading(false));
39
49
  }, [apiBase]);
40
- const update = useCallback((key, value) => {
41
- setDraft((prev) => ({ ...prev, [key]: value }));
50
+ const update = useCallback((partial) => {
51
+ setDraft((prev) => ({ ...prev, ...partial }));
42
52
  setSuccess(false);
43
53
  }, []);
44
54
  const handleSave = async () => {
@@ -46,7 +56,7 @@ export function SellerShippingView({ apiBase = "/api/store/shipping" }) {
46
56
  setSuccess(false);
47
57
  setSaving(true);
48
58
  try {
49
- const body = draft.method === "custom"
59
+ const methodFields = draft.method === "custom"
50
60
  ? {
51
61
  method: "custom",
52
62
  customCarrierName: draft.customCarrierName.trim(),
@@ -58,6 +68,12 @@ export function SellerShippingView({ apiBase = "/api/store/shipping" }) {
58
68
  ? { shiprocketCredentials: { email: draft.shiprocketEmail, password: draft.shiprocketPassword } }
59
69
  : {}),
60
70
  };
71
+ const body = {
72
+ ...methodFields,
73
+ ...(draft.pickupAddressId ? { pickupAddressId: draft.pickupAddressId } : {}),
74
+ freeShippingThreshold: Math.round(parseFloat(draft.freeShippingThreshold || "0") * 100),
75
+ fragileSurcharge: Math.round(parseFloat(draft.fragileSurcharge || "0") * 100),
76
+ };
61
77
  const res = await fetch(apiBase, {
62
78
  method: "PATCH",
63
79
  headers: { "Content-Type": "application/json" },
@@ -77,13 +93,24 @@ export function SellerShippingView({ apiBase = "/api/store/shipping" }) {
77
93
  setSaving(false);
78
94
  }
79
95
  };
80
- const isCustom = draft.method === "custom";
81
96
  const busy = loading || saving;
97
+ const steps = [
98
+ {
99
+ label: "Method",
100
+ render: ({ values, onChange }) => (_jsxs(Stack, { gap: "md", children: [_jsx(Heading, { level: 3, className: "mb-2", children: "Shipping Method" }), current && (_jsxs(Div, { className: "flex items-center gap-2 mb-2", children: [_jsx(Badge, { variant: current.isConfigured ? "success" : "warning", children: current.isConfigured ? "Configured" : "Not configured" }), current.method === "shiprocket" && (_jsx(Badge, { variant: current.isTokenValid ? "success" : "danger", children: current.isTokenValid ? "Shiprocket connected" : "Shiprocket token expired" }))] })), _jsx(Stack, { gap: "sm", children: ["custom", "shiprocket"].map((m) => (_jsxs("label", { className: "flex items-center gap-3 p-3 rounded-lg border border-[var(--appkit-color-border)] cursor-pointer has-[:checked]:border-[var(--appkit-color-primary)] has-[:checked]:bg-[var(--appkit-color-primary)]/5", children: [_jsx("input", { type: "radio", name: "method", value: m, checked: values.method === m, onChange: () => onChange({ method: m }), className: "accent-[var(--appkit-color-primary)]", disabled: busy }), _jsxs(Div, { children: [_jsx(Text, { className: "font-medium", children: m === "custom" ? "Custom / Manual" : "Shiprocket" }), _jsx(Text, { className: "text-sm text-[var(--appkit-color-text-muted)]", children: m === "custom"
101
+ ? "Set a fixed shipping fee and carrier name for all orders."
102
+ : "Automated shipping via Shiprocket — connect your account for label generation and tracking." })] })] }, m))) }), values.method === "custom" && (_jsxs(Stack, { gap: "md", className: "mt-2", children: [_jsx(FormField, { name: "customCarrierName", label: "Carrier Name", type: "text", value: values.customCarrierName, onChange: (v) => onChange({ customCarrierName: v }), placeholder: "e.g. India Post, DTDC, Delhivery", disabled: busy }), _jsx(FormField, { name: "customShippingPrice", label: "Shipping Price (\u20B9)", type: "number", value: values.customShippingPrice, onChange: (v) => onChange({ customShippingPrice: v }), placeholder: "0 for free shipping", helpText: "Charged to buyer at checkout. Enter 0 for free shipping.", disabled: busy })] })), values.method === "shiprocket" && (_jsxs(Stack, { gap: "md", className: "mt-2", children: [_jsx(FormField, { name: "shiprocketEmail", label: "Shiprocket Email", type: "email", value: values.shiprocketEmail, onChange: (v) => onChange({ shiprocketEmail: v }), placeholder: "your@email.com", disabled: busy }), _jsx(FormField, { name: "shiprocketPassword", label: current?.isTokenValid ? "Password (leave blank to keep existing token)" : "Password", type: "password", value: values.shiprocketPassword, onChange: (v) => onChange({ shiprocketPassword: v }), placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", helpText: current?.isTokenValid ? "Only fill this to re-authenticate." : "Required to connect your Shiprocket account.", disabled: busy })] }))] })),
103
+ },
104
+ {
105
+ label: "Pickup Address",
106
+ render: ({ values, onChange }) => (_jsxs(Stack, { gap: "md", children: [_jsx(Heading, { level: 3, className: "mb-2", children: "Pickup Address" }), current?.pickupAddress && (_jsxs(Alert, { variant: "info", children: ["Current pickup: ", current.pickupAddress.locationName ?? "", current.pickupAddress.city ? `, ${current.pickupAddress.city}` : "", current.pickupAddress.isVerified ? " — ✓ Verified" : " — Pending OTP verification"] })), _jsx(StoreAddressSelectorCreate, { value: values.pickupAddressId, onChange: (id) => onChange({ pickupAddressId: id }), label: "Pickup Address", disabled: busy }), _jsx(Text, { className: "text-xs text-[var(--appkit-color-text-muted)]", children: "Registering a pickup address sends an OTP to your phone for verification." })] })),
107
+ },
108
+ {
109
+ label: "Rules",
110
+ render: ({ values, onChange }) => (_jsxs(Stack, { gap: "md", children: [_jsx(Heading, { level: 3, className: "mb-2", children: "Shipping Rules" }), _jsx(FormField, { name: "freeShippingThreshold", label: "Free Shipping Threshold (\u20B9)", type: "number", value: values.freeShippingThreshold, onChange: (v) => onChange({ freeShippingThreshold: v }), placeholder: "e.g. 500 \u2014 orders above this get free shipping", helpText: "Leave blank or 0 to disable free shipping offers.", disabled: busy }), _jsx(FormField, { name: "fragileSurcharge", label: "Fragile Item Surcharge (\u20B9)", type: "number", value: values.fragileSurcharge, onChange: (v) => onChange({ fragileSurcharge: v }), placeholder: "e.g. 50 \u2014 added for items marked fragile", helpText: "Leave blank or 0 to disable the fragile surcharge.", disabled: busy })] })),
111
+ },
112
+ ];
82
113
  return (_jsx(StackedViewShell, { portal: "seller", title: "Shipping Configuration", sections: [
83
- _jsxs(Stack, { gap: "lg", children: [current && (_jsxs(Div, { className: "flex items-center gap-2", children: [_jsx(Badge, { variant: current.isConfigured ? "success" : "warning", children: current.isConfigured ? "Configured" : "Not configured" }), current.method === "shiprocket" && (_jsx(Badge, { variant: current.isTokenValid ? "success" : "danger", children: current.isTokenValid ? "Shiprocket connected" : "Shiprocket token expired" }))] })), error && _jsx(Alert, { variant: "error", children: error }), success && _jsx(Alert, { variant: "success", children: "Shipping configuration saved." }), _jsxs(Section, { children: [_jsx(Heading, { level: 3, className: "mb-3", children: "Shipping Method" }), _jsx(Stack, { gap: "sm", children: ["custom", "shiprocket"].map((m) => (_jsxs("label", { className: "flex items-center gap-3 p-3 rounded-lg border border-[var(--appkit-color-border)] cursor-pointer has-[:checked]:border-[var(--appkit-color-primary)] has-[:checked]:bg-[var(--appkit-color-primary)]/5", children: [_jsx("input", { type: "radio", name: "method", value: m, checked: draft.method === m, onChange: () => update("method", m), className: "accent-[var(--appkit-color-primary)]", disabled: busy }), _jsxs(Div, { children: [_jsx(Text, { className: "font-medium capitalize", children: m === "custom" ? "Custom / Manual" : "Shiprocket" }), _jsx(Text, { className: "text-sm text-[var(--appkit-color-text-muted)]", children: m === "custom"
84
- ? "Set a fixed shipping fee and carrier name for all orders."
85
- : "Automated shipping via Shiprocket — connect your account for label generation and tracking." })] })] }, m))) })] }), isCustom && (_jsxs(Section, { children: [_jsx(Heading, { level: 3, className: "mb-3", children: "Custom Shipping Details" }), _jsxs(Stack, { gap: "md", children: [_jsx(FormField, { name: "customCarrierName", label: "Carrier Name", type: "text", value: draft.customCarrierName, onChange: (v) => update("customCarrierName", v), placeholder: "e.g. India Post, DTDC, Delhivery", disabled: busy }), _jsx(FormField, { name: "customShippingPrice", label: "Shipping Price (\u20B9)", type: "number", value: draft.customShippingPrice, onChange: (v) => update("customShippingPrice", v), placeholder: "0 for free shipping", helpText: "Charged to buyer at checkout. Enter 0 for free shipping.", disabled: busy })] })] })), !isCustom && (_jsxs(Section, { children: [_jsx(Heading, { level: 3, className: "mb-3", children: "Shiprocket Account" }), _jsxs(Stack, { gap: "md", children: [_jsx(FormField, { name: "shiprocketEmail", label: "Shiprocket Email", type: "email", value: draft.shiprocketEmail, onChange: (v) => update("shiprocketEmail", v), placeholder: "your@email.com", disabled: busy }), _jsx(FormField, { name: "shiprocketPassword", label: current?.isTokenValid ? "Password (leave blank to keep existing token)" : "Password", type: "password", value: draft.shiprocketPassword, onChange: (v) => update("shiprocketPassword", v), placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", helpText: current?.isTokenValid ? "Only fill this to re-authenticate." : "Required to connect your Shiprocket account.", disabled: busy }), _jsxs(Div, { children: [_jsx(StoreAddressSelectorCreate, { value: draft.pickupAddressId, onChange: (id) => update("pickupAddressId", id), label: "Pickup Address (optional)", disabled: busy }), _jsx(Text, { className: "mt-1 text-xs text-[var(--appkit-color-text-muted)]", children: "Registering a pickup address sends an OTP to your phone for verification." })] }), current?.pickupAddress && (_jsxs(Alert, { variant: "info", children: ["Current pickup: ", current.pickupAddress.locationName ?? "", current.pickupAddress.city ? `, ${current.pickupAddress.city}` : "", current.pickupAddress.isVerified
86
- ? " — ✓ Verified"
87
- : " — Pending OTP verification"] }))] })] })), _jsx(Div, { className: "flex justify-end pt-2 border-t border-[var(--appkit-color-border)]", children: _jsx(Button, { variant: "primary", onClick: handleSave, disabled: busy, isLoading: saving, children: "Save Configuration" }) })] }, "shipping"),
114
+ _jsxs("div", { children: [error && _jsx(Alert, { variant: "error", className: "mb-4", children: error }), success && _jsx(Alert, { variant: "success", className: "mb-4", children: "Shipping configuration saved." }), _jsx(StepForm, { steps: steps, values: draft, onChange: update, onComplete: handleSave, formId: "seller-shipping", currentStep: currentStep, onStepChange: setCurrentStep, completeLabel: "Save Configuration", isLoading: busy })] }, "shipping"),
88
115
  ] }));
89
116
  }
@@ -5,6 +5,7 @@ import { createPortal } from "react-dom";
5
5
  import Link from "next/link";
6
6
  import { Div, Li, Nav, Row, Span, Text, Ul } from "../../../ui";
7
7
  import { BottomSheet } from "../../layout/BottomSheet";
8
+ import { SidebarCollapseToggle } from "../../../_internal/client/features/layout/SidebarCollapseToggle";
8
9
  const CLS_STORE_AVATAR = "h-8 w-8 rounded-md bg-cover bg-center flex-shrink-0";
9
10
  const CLS_STORE_FALLBACK = "flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-md bg-primary/10 text-sm font-bold text-primary";
10
11
  const CLS_STORE_NAME = "text-sm font-semibold text-zinc-900 dark:text-zinc-100 truncate";
@@ -56,7 +57,7 @@ export function StoreSidebar({ items, groups, activeHref, storeName, storeLogoUR
56
57
  height: "calc(100vh - var(--header-height, 3.5rem))",
57
58
  width: "18rem",
58
59
  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-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
+ }, 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(SidebarCollapseToggle, { expanded: desktopOpen, onToggle: handleToggle })] }), _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
61
  }
61
62
  return (_jsxs(_Fragment, { children: [mounted && mobileOpen &&
62
63
  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 })) }) })] }));
@@ -0,0 +1,9 @@
1
+ export interface SellerStoreCategoriesViewProps {
2
+ onCreateClick?: () => void;
3
+ onEditClick?: (id: string) => void;
4
+ onDelete?: (id: string) => Promise<void>;
5
+ onBulkDelete?: (ids: string[]) => Promise<void>;
6
+ onBulkActivate?: (ids: string[]) => Promise<void>;
7
+ onBulkDeactivate?: (ids: string[]) => Promise<void>;
8
+ }
9
+ export declare function SellerStoreCategoriesView({ onCreateClick, onEditClick, onDelete, onBulkDelete, onBulkActivate, onBulkDeactivate, }: SellerStoreCategoriesViewProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,122 @@
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, ConfirmDeleteModal, DataTable, Div, ListingToolbar, Pagination, RowActionMenu, Text, } from "../../../ui";
8
+ import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints";
9
+ import { ROUTES } from "../../../next";
10
+ import { toRecordArray, toStringValue, useSellerListingData, } from "../hooks/useSellerListingData";
11
+ import { TABLE_KEYS } from "../../../constants/table-keys";
12
+ const PAGE_SIZE = 25;
13
+ const DEFAULT_SORT = "displayOrder";
14
+ const SORT_OPTIONS = [
15
+ { value: "displayOrder", label: "Display Order" },
16
+ { value: "label", label: "Label A–Z" },
17
+ { value: "-label", label: "Label Z–A" },
18
+ { value: "-createdAt", label: "Newest" },
19
+ ];
20
+ const COLUMNS = [
21
+ {
22
+ key: "label",
23
+ header: "Label",
24
+ render: (row) => (_jsxs(Div, { children: [_jsx(Text, { className: "text-sm font-medium", children: row.label }), _jsxs(Text, { className: "text-xs text-[var(--appkit-color-text-muted)]", children: ["/", row.slug] })] })),
25
+ },
26
+ {
27
+ key: "productCount",
28
+ header: "Products",
29
+ render: (row) => _jsx(Text, { className: "text-sm tabular-nums", children: row.productCount }),
30
+ },
31
+ {
32
+ key: "isActive",
33
+ header: "Status",
34
+ render: (row) => (_jsx("span", { className: `inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium ${row.isActive
35
+ ? "bg-emerald-100 text-emerald-700 dark:bg-emerald-900/40 dark:text-emerald-300"
36
+ : "bg-zinc-100 text-zinc-600 dark:bg-slate-800 dark:text-slate-400"}`, children: row.isActive ? "Active" : "Hidden" })),
37
+ },
38
+ ];
39
+ export function SellerStoreCategoriesView({ onCreateClick, onEditClick, onDelete, onBulkDelete, onBulkActivate, onBulkDeactivate, }) {
40
+ const table = useUrlTable({ defaults: { pageSize: String(PAGE_SIZE), sort: DEFAULT_SORT } });
41
+ const [searchInput, setSearchInput] = useState(table.get(TABLE_KEYS.QUERY) || "");
42
+ const [deleteTargetId, setDeleteTargetId] = useState(null);
43
+ const [deletingId, setDeletingId] = useState(null);
44
+ const commitSearch = useCallback(() => { table.set(TABLE_KEYS.QUERY, searchInput.trim()); }, [searchInput, table]);
45
+ const resetAll = useCallback(() => {
46
+ table.setMany({ [TABLE_KEYS.QUERY]: "", [TABLE_KEYS.SORT]: "" });
47
+ setSearchInput("");
48
+ }, [table]);
49
+ const hasActiveState = !!table.get(TABLE_KEYS.QUERY) || table.get(TABLE_KEYS.SORT) !== DEFAULT_SORT;
50
+ const { rows, total, isLoading, errorMessage, refetch } = useSellerListingData({
51
+ queryKey: ["seller", "store-categories"],
52
+ endpoint: SELLER_ENDPOINTS.STORE_CATEGORIES,
53
+ page: table.getNumber(TABLE_KEYS.PAGE, 1),
54
+ pageSize: PAGE_SIZE,
55
+ sorts: table.get(TABLE_KEYS.SORT) || DEFAULT_SORT,
56
+ q: table.get(TABLE_KEYS.QUERY) || undefined,
57
+ mapRows: (response) => toRecordArray(response.items).map((item, index) => ({
58
+ id: toStringValue(item.id, `cat-${index}`),
59
+ raw: item,
60
+ label: String(item.label ?? ""),
61
+ slug: String(item.slug ?? ""),
62
+ productCount: Number(item.productIds?.length ?? 0),
63
+ isActive: Boolean(item.isActive),
64
+ })),
65
+ getTotal: (response, rows) => typeof response.total === "number" ? response.total : rows.length,
66
+ });
67
+ const currentPage = table.getNumber(TABLE_KEYS.PAGE, 1);
68
+ const totalPages = Math.ceil(total / PAGE_SIZE);
69
+ const selection = useBulkSelection({ items: rows, keyExtractor: (r) => r.id });
70
+ const handleDelete = useCallback(async (id) => {
71
+ if (!onDelete)
72
+ return;
73
+ setDeletingId(id);
74
+ try {
75
+ await onDelete(id);
76
+ refetch?.();
77
+ }
78
+ finally {
79
+ setDeletingId(null);
80
+ setDeleteTargetId(null);
81
+ }
82
+ }, [onDelete, refetch]);
83
+ const bulkActions = [
84
+ ...(onBulkDelete ? [{
85
+ id: "bulk-delete",
86
+ label: "Delete selected",
87
+ variant: "danger",
88
+ onClick: async () => { await onBulkDelete(selection.selectedIds); selection.clearSelection(); refetch?.(); },
89
+ }] : []),
90
+ ...(onBulkActivate ? [{
91
+ id: "bulk-activate",
92
+ label: "Activate",
93
+ onClick: async () => { await onBulkActivate(selection.selectedIds); selection.clearSelection(); refetch?.(); },
94
+ }] : []),
95
+ ...(onBulkDeactivate ? [{
96
+ id: "bulk-deactivate",
97
+ label: "Deactivate",
98
+ onClick: async () => { await onBulkDeactivate(selection.selectedIds); selection.clearSelection(); refetch?.(); },
99
+ }] : []),
100
+ ];
101
+ const handleNavigateNew = () => {
102
+ if (onCreateClick) {
103
+ onCreateClick();
104
+ return;
105
+ }
106
+ window.location.href = String(ROUTES.STORE.STORE_CATEGORIES_NEW);
107
+ };
108
+ return (_jsxs("div", { className: "min-h-screen", children: [_jsx(ListingToolbar, { filterCount: 0, searchValue: searchInput, searchPlaceholder: "Search categories by label...", 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: "table", onViewChange: () => { }, onResetAll: resetAll, hasActiveState: hasActiveState, extra: _jsxs(Button, { size: "sm", onClick: handleNavigateNew, className: "flex items-center gap-1.5", children: [_jsx(Plus, { className: "h-4 w-4" }), _jsx("span", { children: "New Category" })] }) }), 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 && (_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 categories yet \u2014 add your first storefront category" }) })) : (_jsx(DataTable, { columns: COLUMNS, data: rows, keyExtractor: (r) => r.id, selectable: bulkActions.length > 0, selectedIds: selection.selectedIds, onSelectionChange: (ids) => selection.setSelectedIds(ids), actions: (row) => (_jsx(RowActionMenu, { actions: [
109
+ {
110
+ label: "Edit",
111
+ onClick: () => onEditClick
112
+ ? onEditClick(row.id)
113
+ : (window.location.href = String(ROUTES.STORE.STORE_CATEGORIES_EDIT(row.id))),
114
+ },
115
+ ...(onDelete ? [{
116
+ label: "Delete",
117
+ destructive: true,
118
+ onClick: () => setDeleteTargetId(row.id),
119
+ disabled: deletingId === row.id,
120
+ }] : []),
121
+ ] })) }))] }), deleteTargetId && (_jsx(ConfirmDeleteModal, { isOpen: true, title: "Delete Category", message: "Are you sure you want to delete this category? This cannot be undone.", onConfirm: () => handleDelete(deleteTargetId), onClose: () => setDeleteTargetId(null), isDeleting: deletingId === deleteTargetId }))] }));
122
+ }
@@ -18,13 +18,6 @@ export interface StorefrontDraft {
18
18
  isVacationMode?: boolean;
19
19
  vacationMessage?: string;
20
20
  isPublic?: boolean;
21
- googleReviews?: {
22
- placeId: string;
23
- enabled: boolean;
24
- maxReviews?: number;
25
- minRating?: number;
26
- layout?: "grid" | "carousel";
27
- };
28
21
  }
29
22
  export interface SellerStorefrontViewProps {
30
23
  initialValues?: StorefrontDraft;
@@ -1,34 +1,22 @@
1
1
  "use client";
2
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useCallback, useState } from "react";
4
- import { Section, StackedViewShell } from "../../../ui";
5
- import { Alert, Button, FormField, FormGroup, Heading, Stack, Text, Toggle, } from "../../../ui";
4
+ import { StackedViewShell } from "../../../ui";
5
+ import { Alert, FormField, FormGroup, Heading, Stack, Text, Toggle, } from "../../../ui";
6
6
  import { ImageUpload, useMediaUpload } from "../../media";
7
- import { useFormShell } from "../../shell";
7
+ import { StepForm, useFormShell } from "../../shell";
8
8
  export function SellerStorefrontView({ initialValues, onSave, isLoading = false, storeSlug = "store", }) {
9
9
  const [draft, setDraft] = useState(initialValues ?? {});
10
10
  const [saving, setSaving] = useState(false);
11
11
  const [saved, setSaved] = useState(false);
12
- const { isDirty, markDirty, markClean } = useFormShell();
12
+ const [currentStep, setCurrentStep] = useState(0);
13
+ const { markDirty, markClean } = useFormShell();
13
14
  const { upload } = useMediaUpload();
14
15
  const update = useCallback((partial) => {
15
16
  setDraft((prev) => ({ ...prev, ...partial }));
16
17
  markDirty();
17
18
  setSaved(false);
18
19
  }, [markDirty]);
19
- const updateSocial = (key, value) => {
20
- update({ socialLinks: { ...draft.socialLinks, [key]: value } });
21
- };
22
- const updateGoogleReviews = (patch) => {
23
- update({
24
- googleReviews: {
25
- placeId: draft.googleReviews?.placeId ?? "",
26
- enabled: draft.googleReviews?.enabled ?? false,
27
- ...draft.googleReviews,
28
- ...patch,
29
- },
30
- });
31
- };
32
20
  const handleSave = async () => {
33
21
  setSaving(true);
34
22
  setSaved(false);
@@ -42,17 +30,26 @@ export function SellerStorefrontView({ initialValues, onSave, isLoading = false,
42
30
  }
43
31
  };
44
32
  const busy = saving || isLoading;
33
+ const steps = [
34
+ {
35
+ label: "Store Identity",
36
+ validate: (values) => !values.storeName?.trim() ? "Store name is required" : null,
37
+ render: ({ values, onChange }) => (_jsxs(Stack, { gap: "md", children: [_jsx(Heading, { level: 3, className: "mb-2", children: "Store Identity" }), _jsx(FormField, { name: "storeName", label: "Store Name", type: "text", value: values.storeName ?? "", onChange: (v) => onChange({ storeName: v }), placeholder: "e.g. Pok\u00E9mon Palace", disabled: busy }), _jsx(FormField, { name: "storeCategory", label: "Store Category", type: "text", value: values.storeCategory ?? "", onChange: (v) => onChange({ storeCategory: v }), placeholder: "e.g. Trading Cards, Action Figures", disabled: busy }), _jsx(FormField, { name: "bio", label: "Short Bio (shown in search results)", type: "textarea", value: values.bio ?? "", onChange: (v) => onChange({ bio: v }), placeholder: "One-liner about your store (max 300 chars)", disabled: busy }), _jsx(FormField, { name: "storeDescription", label: "Full Description", type: "textarea", value: values.storeDescription ?? "", onChange: (v) => onChange({ storeDescription: v }), placeholder: "Detailed store description shown on your public store page\u2026", disabled: busy })] })),
38
+ },
39
+ {
40
+ label: "Branding",
41
+ render: ({ values, onChange }) => (_jsxs(Stack, { gap: "md", children: [_jsx(Heading, { level: 3, className: "mb-2", children: "Branding" }), _jsxs(FormGroup, { columns: 2, children: [_jsx(ImageUpload, { label: "Store Logo", currentImage: values.storeLogoURL, onUpload: (file) => upload(file, "stores", true, { type: "store-logo", store: storeSlug }), onChange: (url) => onChange({ storeLogoURL: url }), helperText: "Square image, min 200\u00D7200px" }), _jsx(ImageUpload, { label: "Store Banner", currentImage: values.storeBannerURL, onUpload: (file) => upload(file, "stores", true, { type: "store-banner", store: storeSlug }), onChange: (url) => onChange({ storeBannerURL: url }), helperText: "Recommended: 1200\u00D7300px" })] })] })),
42
+ },
43
+ {
44
+ label: "Policies",
45
+ render: ({ values, onChange }) => (_jsxs(Stack, { gap: "md", children: [_jsx(Heading, { level: 3, className: "mb-2", children: "Policies" }), _jsx(FormField, { name: "returnPolicy", label: "Return Policy", type: "textarea", value: values.returnPolicy ?? "", onChange: (v) => onChange({ returnPolicy: v }), placeholder: "Describe your return policy\u2026", disabled: busy }), _jsx(FormField, { name: "shippingPolicy", label: "Shipping Policy", type: "textarea", value: values.shippingPolicy ?? "", onChange: (v) => onChange({ shippingPolicy: v }), placeholder: "How and when you ship orders\u2026", disabled: busy })] })),
46
+ },
47
+ {
48
+ label: "Contact & Visibility",
49
+ render: ({ values, onChange }) => (_jsxs(Stack, { gap: "md", children: [_jsx(Heading, { level: 3, className: "mb-2", children: "Contact & Social" }), _jsxs(FormGroup, { columns: 2, children: [_jsx(FormField, { name: "website", label: "Website", type: "text", value: values.website ?? "", onChange: (v) => onChange({ website: v }), placeholder: "https://example.com", disabled: busy }), _jsx(FormField, { name: "location", label: "Location", type: "text", value: values.location ?? "", onChange: (v) => onChange({ location: v }), placeholder: "e.g. Mumbai, India", disabled: busy })] }), _jsxs(FormGroup, { columns: 2, children: [_jsx(FormField, { name: "twitter", label: "Twitter / X URL", type: "text", value: values.socialLinks?.twitter ?? "", onChange: (v) => onChange({ socialLinks: { ...values.socialLinks, twitter: v } }), placeholder: "https://twitter.com/...", disabled: busy }), _jsx(FormField, { name: "instagram", label: "Instagram URL", type: "text", value: values.socialLinks?.instagram ?? "", onChange: (v) => onChange({ socialLinks: { ...values.socialLinks, instagram: v } }), placeholder: "https://instagram.com/...", disabled: busy })] }), _jsxs(FormGroup, { columns: 2, children: [_jsx(FormField, { name: "facebook", label: "Facebook URL", type: "text", value: values.socialLinks?.facebook ?? "", onChange: (v) => onChange({ socialLinks: { ...values.socialLinks, facebook: v } }), placeholder: "https://facebook.com/...", disabled: busy }), _jsx(FormField, { name: "linkedin", label: "LinkedIn URL", type: "text", value: values.socialLinks?.linkedin ?? "", onChange: (v) => onChange({ socialLinks: { ...values.socialLinks, linkedin: v } }), placeholder: "https://linkedin.com/...", disabled: busy })] }), _jsx(Heading, { level: 4, className: "mt-4 mb-2", children: "Visibility" }), _jsx(Toggle, { checked: values.isPublic !== false, onChange: (checked) => onChange({ isPublic: checked }), label: "Make store public \u2014 visible to all buyers", disabled: busy }), values.isPublic === false && (_jsx(Text, { className: "text-sm text-[var(--appkit-color-text-muted)]", children: "Your store is hidden. Existing orders are unaffected." })), _jsx(Heading, { level: 4, className: "mt-4 mb-2", children: "Vacation Mode" }), _jsx(Toggle, { checked: !!values.isVacationMode, onChange: (checked) => onChange({ isVacationMode: checked }), label: "Enable vacation mode \u2014 your store will show a notice to buyers", disabled: busy }), values.isVacationMode && (_jsx(FormField, { name: "vacationMessage", label: "Vacation Message", type: "textarea", value: values.vacationMessage ?? "", onChange: (v) => onChange({ vacationMessage: v }), placeholder: "I'm away until\u2026 Orders placed now will ship when I return.", disabled: busy }))] })),
50
+ },
51
+ ];
45
52
  return (_jsx(StackedViewShell, { portal: "seller", title: "Storefront Settings", sections: [
46
- _jsxs(Stack, { gap: "lg", children: [saved && (_jsx(Alert, { variant: "success", children: "Changes saved successfully." })), _jsxs(Section, { children: [_jsx(Heading, { level: 3, className: "mb-4", children: "Store Profile" }), _jsxs(Stack, { gap: "md", children: [_jsx(FormField, { name: "storeName", label: "Store Name", type: "text", value: draft.storeName ?? "", onChange: (v) => update({ storeName: v }), placeholder: "e.g. Pok\u00E9mon Palace", disabled: busy }), _jsx(FormField, { name: "bio", label: "Short Bio (shown in search results)", type: "textarea", value: draft.bio ?? "", onChange: (v) => update({ bio: v }), placeholder: "One-liner about your store (max 300 chars)", disabled: busy }), _jsxs(FormGroup, { columns: 2, children: [_jsx(ImageUpload, { label: "Store Logo", currentImage: draft.storeLogoURL, onUpload: (file) => {
47
- return upload(file, "stores", true, {
48
- type: "store-logo",
49
- store: storeSlug,
50
- });
51
- }, onChange: (url) => update({ storeLogoURL: url }), helperText: "Square image, min 200\u00D7200px" }), _jsx(ImageUpload, { label: "Store Banner", currentImage: draft.storeBannerURL, onUpload: (file) => {
52
- return upload(file, "stores", true, {
53
- type: "store-banner",
54
- store: storeSlug,
55
- });
56
- }, onChange: (url) => update({ storeBannerURL: url }), helperText: "Recommended: 1200\u00D7300px" })] })] })] }), _jsxs(Section, { children: [_jsx(Heading, { level: 3, className: "mb-4", children: "Store Details" }), _jsxs(Stack, { gap: "md", children: [_jsx(FormField, { name: "storeCategory", label: "Store Category", type: "text", value: draft.storeCategory ?? "", onChange: (v) => update({ storeCategory: v }), placeholder: "e.g. Trading Cards, Action Figures", disabled: busy }), _jsx(FormField, { name: "storeDescription", label: "Full Description", type: "textarea", value: draft.storeDescription ?? "", onChange: (v) => update({ storeDescription: v }), placeholder: "Detailed store description shown on your public store page\u2026", disabled: busy })] })] }), _jsxs(Section, { children: [_jsx(Heading, { level: 3, className: "mb-4", children: "Policies" }), _jsxs(Stack, { gap: "md", children: [_jsx(FormField, { name: "returnPolicy", label: "Return Policy", type: "textarea", value: draft.returnPolicy ?? "", onChange: (v) => update({ returnPolicy: v }), placeholder: "Describe your return policy\u2026", disabled: busy }), _jsx(FormField, { name: "shippingPolicy", label: "Shipping Policy", type: "textarea", value: draft.shippingPolicy ?? "", onChange: (v) => update({ shippingPolicy: v }), placeholder: "How and when you ship orders\u2026", disabled: busy })] })] }), _jsxs(Section, { children: [_jsx(Heading, { level: 3, className: "mb-4", children: "Contact & Social" }), _jsxs(Stack, { gap: "md", children: [_jsxs(FormGroup, { columns: 2, children: [_jsx(FormField, { name: "website", label: "Website", type: "text", value: draft.website ?? "", onChange: (v) => update({ website: v }), placeholder: "https://example.com", disabled: busy }), _jsx(FormField, { name: "location", label: "Location", type: "text", value: draft.location ?? "", onChange: (v) => update({ location: v }), placeholder: "e.g. Mumbai, India", disabled: busy })] }), _jsxs(FormGroup, { columns: 2, children: [_jsx(FormField, { name: "twitter", label: "Twitter / X URL", type: "text", value: draft.socialLinks?.twitter ?? "", onChange: (v) => updateSocial("twitter", v), placeholder: "https://twitter.com/...", disabled: busy }), _jsx(FormField, { name: "instagram", label: "Instagram URL", type: "text", value: draft.socialLinks?.instagram ?? "", onChange: (v) => updateSocial("instagram", v), placeholder: "https://instagram.com/...", disabled: busy })] }), _jsxs(FormGroup, { columns: 2, children: [_jsx(FormField, { name: "facebook", label: "Facebook URL", type: "text", value: draft.socialLinks?.facebook ?? "", onChange: (v) => updateSocial("facebook", v), placeholder: "https://facebook.com/...", disabled: busy }), _jsx(FormField, { name: "linkedin", label: "LinkedIn URL", type: "text", value: draft.socialLinks?.linkedin ?? "", onChange: (v) => updateSocial("linkedin", v), placeholder: "https://linkedin.com/...", disabled: busy })] })] })] }), _jsxs(Section, { children: [_jsx(Heading, { level: 3, className: "mb-4", children: "Vacation Mode" }), _jsxs(Stack, { gap: "md", children: [_jsx(Toggle, { checked: !!draft.isVacationMode, onChange: (checked) => update({ isVacationMode: checked }), label: "Enable vacation mode \u2014 your store will show a notice to buyers", disabled: busy }), draft.isVacationMode && (_jsx(FormField, { name: "vacationMessage", label: "Vacation Message", type: "textarea", value: draft.vacationMessage ?? "", onChange: (v) => update({ vacationMessage: v }), placeholder: "I'm away until\u2026 Orders placed now will ship when I return.", disabled: busy }))] })] }), _jsxs(Section, { children: [_jsx(Heading, { level: 3, className: "mb-4", children: "Visibility" }), _jsx(Toggle, { checked: draft.isPublic !== false, onChange: (checked) => update({ isPublic: checked }), label: "Make store public \u2014 visible to all buyers", disabled: busy }), draft.isPublic === false && (_jsx(Text, { className: "mt-2 text-sm text-[var(--appkit-color-text-muted)]", children: "Your store is hidden. Existing orders are unaffected." }))] }), _jsxs(Section, { children: [_jsx(Heading, { level: 3, className: "mb-1", children: "Google Business Reviews" }), _jsx(Text, { className: "text-sm text-[var(--appkit-color-text-muted)] mb-4", children: "Display real Google reviews on your store About page. Requires a Google Place ID." }), _jsxs(Stack, { gap: "md", children: [_jsx(Toggle, { checked: !!draft.googleReviews?.enabled, onChange: (checked) => updateGoogleReviews({ enabled: checked }), label: "Show Google reviews on my store About page", disabled: busy }), draft.googleReviews?.enabled && (_jsxs(_Fragment, { children: [_jsx(FormField, { name: "googlePlaceId", label: "Google Place ID", type: "text", value: draft.googleReviews.placeId ?? "", onChange: (v) => updateGoogleReviews({ placeId: v }), placeholder: "ChIJ...", helpText: "Find your Place ID at developers.google.com/maps/documentation/places/web-service/place-id", disabled: busy }), _jsxs(FormGroup, { columns: 2, children: [_jsx(FormField, { name: "googleMaxReviews", label: "Max reviews to show", type: "number", value: String(draft.googleReviews.maxReviews ?? 6), onChange: (v) => updateGoogleReviews({ maxReviews: Number(v) }), disabled: busy }), _jsx(FormField, { name: "googleMinRating", label: "Minimum star rating (1\u20135)", type: "number", value: String(draft.googleReviews.minRating ?? 0), onChange: (v) => updateGoogleReviews({ minRating: Number(v) }), disabled: busy })] })] }))] })] }), _jsxs("div", { className: "flex items-center justify-end gap-3 pt-2 border-t border-[var(--appkit-color-border)]", children: [isDirty && !saving && (_jsx(Text, { className: "text-sm text-[var(--appkit-color-text-muted)]", children: "You have unsaved changes." })), _jsx(Button, { variant: "primary", onClick: handleSave, disabled: busy || !isDirty, isLoading: saving, children: "Save Changes" })] })] }, "profile"),
53
+ _jsxs("div", { children: [saved && (_jsx(Alert, { variant: "success", className: "mb-6", children: "Changes saved successfully." })), _jsx(StepForm, { steps: steps, values: draft, onChange: update, onComplete: handleSave, formId: "seller-storefront", currentStep: currentStep, onStepChange: setCurrentStep, completeLabel: "Save Changes", isLoading: busy })] }, "stepform"),
57
54
  ] }));
58
55
  }
@@ -0,0 +1,10 @@
1
+ export interface SellerTemplatesViewProps {
2
+ onDelete?: (id: string) => Promise<void>;
3
+ onBulkDelete?: (ids: string[]) => Promise<void>;
4
+ onDuplicate?: (row: {
5
+ id: string;
6
+ name: string;
7
+ raw: Record<string, unknown>;
8
+ }) => Promise<void>;
9
+ }
10
+ export declare function SellerTemplatesView({ onDelete, onBulkDelete, onDuplicate, }: SellerTemplatesViewProps): import("react/jsx-runtime").JSX.Element;