@mohasinac/appkit 4.1.1 → 4.2.0

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 (225) hide show
  1. package/dist/_internal/client/features/maintenance/index.d.ts +2 -0
  2. package/dist/_internal/client/features/maintenance/index.js +1 -0
  3. package/dist/_internal/client/features/maintenance/views/CloudLogsListView.d.ts +9 -0
  4. package/dist/_internal/client/features/maintenance/views/CloudLogsListView.js +55 -0
  5. package/dist/_internal/server/features/auctions/index.d.ts +1 -1
  6. package/dist/_internal/server/features/auctions/index.js +1 -1
  7. package/dist/_internal/server/features/auctions/service.js +2 -2
  8. package/dist/_internal/server/features/checkout/actions.d.ts +15 -0
  9. package/dist/_internal/server/features/checkout/actions.js +245 -182
  10. package/dist/_internal/server/features/maintenance/cloud-logs-data.d.ts +50 -0
  11. package/dist/_internal/server/features/maintenance/cloud-logs-data.js +152 -0
  12. package/dist/_internal/server/functions/scheduled.d.ts +2 -1
  13. package/dist/_internal/server/functions/scheduled.js +9 -1
  14. package/dist/_internal/server/jobs/core/jobRunners.js +10 -0
  15. package/dist/_internal/server/jobs/core/newsletterExport.d.ts +15 -0
  16. package/dist/_internal/server/jobs/core/newsletterExport.js +43 -0
  17. package/dist/_internal/server/jobs/core/onOrderCreate.d.ts +4 -12
  18. package/dist/_internal/server/jobs/core/onOrderCreate.js +3 -3
  19. package/dist/_internal/server/jobs/core/onOrderStatusChange.d.ts +2 -0
  20. package/dist/_internal/server/jobs/core/onOrderStatusChange.js +1 -0
  21. package/dist/_internal/server/jobs/core/onProductWrite.js +14 -2
  22. package/dist/_internal/server/jobs/core/paymentWindowTimeout.js +1 -0
  23. package/dist/_internal/server/jobs/core/pendingOrderTimeout.js +1 -0
  24. package/dist/_internal/server/jobs/core/revenueRollup.d.ts +13 -0
  25. package/dist/_internal/server/jobs/core/revenueRollup.js +22 -0
  26. package/dist/_internal/server/jobs/core/whatsappNotify.d.ts +35 -0
  27. package/dist/_internal/server/jobs/core/whatsappNotify.js +82 -0
  28. package/dist/_internal/server/jobs/handlers/index.d.ts +1 -0
  29. package/dist/_internal/server/jobs/handlers/index.js +1 -0
  30. package/dist/_internal/server/jobs/handlers/revenueRollup.d.ts +2 -0
  31. package/dist/_internal/server/jobs/handlers/revenueRollup.js +2 -0
  32. package/dist/_internal/shared/features/auctions/config.d.ts +1 -1
  33. package/dist/_internal/shared/features/auctions/config.js +1 -1
  34. package/dist/_internal/shared/features/auctions/schema.js +1 -1
  35. package/dist/_internal/shared/features/cart/schema.js +2 -2
  36. package/dist/_internal/shared/features/checkout/config.d.ts +7 -0
  37. package/dist/_internal/shared/features/checkout/config.js +7 -0
  38. package/dist/_internal/shared/features/events/schema.js +1 -1
  39. package/dist/_internal/shared/features/orders/schema.js +1 -1
  40. package/dist/_internal/shared/features/products/schema.js +3 -3
  41. package/dist/_internal/shared/features/promotions/schema.js +3 -3
  42. package/dist/_internal/shared/fees/calculator.d.ts +32 -7
  43. package/dist/_internal/shared/fees/calculator.js +25 -0
  44. package/dist/client.d.ts +4 -4
  45. package/dist/client.js +4 -2
  46. package/dist/constants/api-endpoints.d.ts +9 -6
  47. package/dist/constants/api-endpoints.js +3 -2
  48. package/dist/contracts/client-payment-gateway.d.ts +1 -2
  49. package/dist/features/about/components/AboutView.d.ts +6 -16
  50. package/dist/features/about/components/AboutView.js +3 -3
  51. package/dist/features/about/components/FeesView.js +18 -0
  52. package/dist/features/about/index.d.ts +2 -1
  53. package/dist/features/about/schemas/firestore.d.ts +47 -0
  54. package/dist/features/about/schemas/firestore.js +6 -0
  55. package/dist/features/about/schemas/index.d.ts +210 -0
  56. package/dist/features/about/schemas/index.js +45 -0
  57. package/dist/features/account/hooks/useProfile.js +3 -0
  58. package/dist/features/admin/actions/notification-actions.d.ts +4 -1
  59. package/dist/features/admin/actions/notification-actions.js +56 -10
  60. package/dist/features/admin/components/AdminAdsView.js +1 -1
  61. package/dist/features/admin/components/AdminCarouselGroupEditorView.d.ts +6 -0
  62. package/dist/features/admin/components/AdminCarouselGroupEditorView.js +50 -0
  63. package/dist/features/admin/components/AdminCartsView.js +16 -3
  64. package/dist/features/admin/components/AdminCouponEditorView.js +2 -2
  65. package/dist/features/admin/components/AdminCouponsView.js +14 -4
  66. package/dist/features/admin/components/AdminEmployeeEditorView.js +1 -42
  67. package/dist/features/admin/components/AdminMediaView.js +1 -1
  68. package/dist/features/admin/components/AdminNewsletterView.js +42 -11
  69. package/dist/features/admin/components/AdminNotificationsView.js +31 -19
  70. package/dist/features/admin/components/AdminOrdersView.js +7 -0
  71. package/dist/features/admin/components/AdminPayoutsView.js +18 -3
  72. package/dist/features/admin/components/AdminProductsView.js +17 -2
  73. package/dist/features/admin/components/AdminReviewsView.js +16 -2
  74. package/dist/features/admin/components/AdminScammersView.js +7 -0
  75. package/dist/features/admin/components/AdminSectionsView.js +4 -0
  76. package/dist/features/admin/components/AdminSiteConfigGuideView.js +1 -1
  77. package/dist/features/admin/components/AdminSiteSettingsView.js +127 -8
  78. package/dist/features/admin/components/AdminStoreEditorView.d.ts +2 -1
  79. package/dist/features/admin/components/AdminStoreEditorView.js +4 -4
  80. package/dist/features/admin/components/AdminStoresView.js +1 -1
  81. package/dist/features/admin/components/AdminSupportTicketDetailView.js +23 -5
  82. package/dist/features/admin/components/AdminSupportTicketsView.js +20 -2
  83. package/dist/features/admin/components/AdminTesterChecklistItemEditorView.js +4 -1
  84. package/dist/features/admin/components/AdminTesterChecklistView.js +8 -0
  85. package/dist/features/admin/components/index.d.ts +2 -0
  86. package/dist/features/admin/components/index.js +1 -0
  87. package/dist/features/admin/constants/filter-tabs.d.ts +55 -41
  88. package/dist/features/admin/constants/filter-tabs.js +55 -27
  89. package/dist/features/admin/repository/analytics-rollup.repository.d.ts +25 -0
  90. package/dist/features/admin/repository/analytics-rollup.repository.js +31 -0
  91. package/dist/features/admin/repository/site-settings.repository.js +8 -1
  92. package/dist/features/admin/schemas/firestore.d.ts +46 -0
  93. package/dist/features/admin/schemas/firestore.js +62 -24
  94. package/dist/features/auctions/actions/bid-actions.js +1 -1
  95. package/dist/features/auctions/components/AuctionDetailPageView.js +2 -2
  96. package/dist/features/auctions/components/AuctionsListView.js +8 -1
  97. package/dist/features/auth/components/LoginForm.js +2 -2
  98. package/dist/features/auth/components/RegisterForm.js +2 -2
  99. package/dist/features/auth/permissions/constants.d.ts +16 -0
  100. package/dist/features/auth/permissions/constants.js +53 -0
  101. package/dist/features/auth/schemas/firestore.js +1 -0
  102. package/dist/features/blog/components/BlogFilters.js +1 -1
  103. package/dist/features/cart/schemas/firestore.d.ts +1 -1
  104. package/dist/features/categories/schemas/firestore.d.ts +1 -1
  105. package/dist/features/consultation/components/ConsultationForm.js +1 -1
  106. package/dist/features/events/components/EventFilters.js +2 -0
  107. package/dist/features/homepage/components/WelcomeSection.js +2 -2
  108. package/dist/features/layout/BackToTop.d.ts +9 -5
  109. package/dist/features/layout/BackToTop.js +17 -21
  110. package/dist/features/layout/TitleBarLayout.d.ts +2 -2
  111. package/dist/features/layout/TitleBarLayout.js +4 -4
  112. package/dist/features/media/AvatarUpload.js +7 -3
  113. package/dist/features/media/MediaVideo.js +1 -1
  114. package/dist/features/media/finalize.d.ts +9 -13
  115. package/dist/features/media/finalize.js +23 -74
  116. package/dist/features/media/server.d.ts +1 -1
  117. package/dist/features/media/server.js +1 -1
  118. package/dist/features/orders/actions/refund-actions.js +1 -0
  119. package/dist/features/orders/hooks/useOrders.js +16 -4
  120. package/dist/features/orders/schemas/firestore.d.ts +19 -5
  121. package/dist/features/payments/schemas/firestore.d.ts +2 -2
  122. package/dist/features/pre-orders/components/PreOrdersListView.js +7 -0
  123. package/dist/features/products/components/ArtStickersListView.js +5 -0
  124. package/dist/features/products/components/ProductDetailPageView.d.ts +7 -1
  125. package/dist/features/products/components/ProductForm.js +14 -1
  126. package/dist/features/products/components/ProductsIndexPageView.js +7 -0
  127. package/dist/features/products/constants/action-defs.d.ts +29 -3
  128. package/dist/features/products/constants/action-defs.js +77 -1
  129. package/dist/features/products/schemas/firestore.d.ts +1 -1
  130. package/dist/features/products/schemas/product-templates.d.ts +1 -1
  131. package/dist/features/products/types/index.d.ts +4 -0
  132. package/dist/features/scams/schemas/index.js +2 -2
  133. package/dist/features/search/components/Search.js +3 -3
  134. package/dist/features/seller/components/SellerAuctionsView.js +27 -2
  135. package/dist/features/seller/components/SellerOrdersView.js +2 -2
  136. package/dist/features/seller/components/SellerPayoutsView.js +24 -10
  137. package/dist/features/seller/components/SellerPreOrdersView.js +12 -4
  138. package/dist/features/seller/components/SellerPrizeDrawsView.js +23 -5
  139. package/dist/features/seller/components/SellerProductShell.d.ts +2 -0
  140. package/dist/features/seller/components/SellerProductShell.js +1 -1
  141. package/dist/features/seller/components/SellerProductsView.js +8 -6
  142. package/dist/features/seller/components/SellerReviewsView.js +27 -6
  143. package/dist/features/seller/components/index.d.ts +0 -2
  144. package/dist/features/seller/components/index.js +0 -1
  145. package/dist/features/stores/components/StoreListingsGuideView.js +2 -1
  146. package/dist/features/stores/components/StoreProductsView.js +1 -1
  147. package/dist/features/stores/schemas/firestore.d.ts +11 -0
  148. package/dist/features/stores/schemas/firestore.js +5 -0
  149. package/dist/features/stores/schemas/index.d.ts +2 -2
  150. package/dist/features/tester/actions/checklist-item-actions.d.ts +6 -0
  151. package/dist/features/tester/actions/checklist-item-actions.js +2 -0
  152. package/dist/features/tester/components/AdminTesterFeedbackIssuesView.js +13 -2
  153. package/dist/features/tester/components/AdminTesterFeedbackListView.js +2 -1
  154. package/dist/features/tester/components/AdminTesterFeedbackReportView.js +9 -5
  155. package/dist/features/tester/components/TesterHubView.js +34 -21
  156. package/dist/features/tester/repository/tester-checklist-item.repository.js +1 -0
  157. package/dist/features/tester/repository/tester-checklist-response.repository.d.ts +18 -4
  158. package/dist/features/tester/repository/tester-checklist-response.repository.js +43 -8
  159. package/dist/features/tester/schemas/firestore.d.ts +8 -3
  160. package/dist/features/tester/schemas/firestore.js +6 -0
  161. package/dist/features/tester/seed-data/tester-checklist-seed-data.js +21 -9
  162. package/dist/features/tester/utils/phases.d.ts +31 -0
  163. package/dist/features/tester/utils/phases.js +46 -0
  164. package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.js +1 -1
  165. package/dist/features/whatsapp-bot/helpers/whatsapp.d.ts +10 -1
  166. package/dist/features/whatsapp-bot/helpers/whatsapp.js +47 -0
  167. package/dist/features/whatsapp-bot/types/index.d.ts +20 -1
  168. package/dist/features/wishlist/types/index.d.ts +3 -0
  169. package/dist/index.d.ts +15 -6
  170. package/dist/index.js +19 -9
  171. package/dist/next/components/NotFoundView.js +2 -1
  172. package/dist/next/routing/route-map.d.ts +6 -12
  173. package/dist/next/routing/route-map.js +3 -4
  174. package/dist/providers/db-firebase/admin.d.ts +1 -0
  175. package/dist/providers/db-firebase/admin.js +1 -1
  176. package/dist/repositories/index.d.ts +2 -0
  177. package/dist/repositories/index.js +1 -0
  178. package/dist/schemas/registry.d.ts +2 -2
  179. package/dist/seed/addresses-seed-data.js +18 -18
  180. package/dist/seed/bids-seed-data.js +4 -4
  181. package/dist/seed/blog-posts-seed-data.js +82 -82
  182. package/dist/seed/carousel-slides-seed-data.js +14 -10
  183. package/dist/seed/carousels-seed-data.js +3 -3
  184. package/dist/seed/cart-seed-data.js +92 -92
  185. package/dist/seed/claimed-coupons-seed-data.js +10 -10
  186. package/dist/seed/conversations-seed-data.js +75 -75
  187. package/dist/seed/coupon-usage-seed-data.js +12 -12
  188. package/dist/seed/coupons-seed-data.js +41 -41
  189. package/dist/seed/events-seed-data.js +105 -105
  190. package/dist/seed/grouped-listings-seed-data.d.ts +2 -137
  191. package/dist/seed/grouped-listings-seed-data.js +79 -143
  192. package/dist/seed/history-seed-data.js +38 -38
  193. package/dist/seed/homepage-sections-seed-data.js +9 -9
  194. package/dist/seed/notifications-seed-data.js +56 -56
  195. package/dist/seed/offers-seed-data.js +91 -91
  196. package/dist/seed/orders-seed-data.js +121 -106
  197. package/dist/seed/payouts-seed-data.js +42 -42
  198. package/dist/seed/products-auctions-seed-data.js +10 -2
  199. package/dist/seed/products-standard-seed-data.js +40 -8
  200. package/dist/seed/reviews-seed-data.js +42 -23
  201. package/dist/seed/scammers-seed-data.js +22 -22
  202. package/dist/seed/sessions-seed-data.js +7 -7
  203. package/dist/seed/shipments-seed-data.js +10 -10
  204. package/dist/seed/site-settings-seed-data.js +89 -0
  205. package/dist/seed/store-addresses-seed-data.js +2 -2
  206. package/dist/seed/store-extensions-seed-data.js +93 -93
  207. package/dist/seed/stores-seed-data.js +2 -0
  208. package/dist/seed/support-tickets-seed-data.js +47 -47
  209. package/dist/seed/users-seed-data.js +55 -89
  210. package/dist/seed/wishlists-seed-data.js +22 -22
  211. package/dist/server.d.ts +4 -3
  212. package/dist/server.js +7 -7
  213. package/dist/styles.css +1 -1
  214. package/dist/tailwind-utilities.css +1 -1
  215. package/dist/ui/components/PageLoader.js +8 -3
  216. package/dist/ui/components/Select.d.ts +8 -1
  217. package/dist/ui/components/Select.js +2 -2
  218. package/dist/ui/components/SiteMark.d.ts +23 -0
  219. package/dist/ui/components/SiteMark.js +76 -0
  220. package/dist/ui/index.d.ts +2 -0
  221. package/dist/ui/index.js +1 -0
  222. package/dist/validation/schemas.d.ts +0 -2
  223. package/dist/validation/schemas.js +0 -2
  224. package/package.json +1 -1
  225. package/scripts/seed-cli.mjs +17 -15
@@ -3,13 +3,15 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
3
3
  import { useApiMutation } from "@mohasinac/appkit/client";
4
4
  import React from "react";
5
5
  import { useQuery, useQueryClient } from "@tanstack/react-query";
6
- import { Alert, BackgroundRenderer, Button, Div, Form, FormActions, Grid, Input, Row, Select, Slider, Span, Stack, StackedViewShell, Tabs, TabsContent, TabsList, TabsTrigger, Text, Textarea, Toggle, useToast } from "../../../ui";
6
+ import { Alert, BackgroundRenderer, Button, Div, Form, FormActions, Grid, Input, PaginatedSelect, Row, Select, Slider, Span, Stack, StackedViewShell, Tabs, TabsContent, TabsList, TabsTrigger, Text, Textarea, Toggle, useToast } from "../../../ui";
7
7
  import { ImageUpload } from "../../media/upload/ImageUpload";
8
8
  import { MediaUploadField } from "../../media/upload/MediaUploadField";
9
9
  import { useMediaUpload } from "../../media";
10
10
  import { apiClient } from "../../../http";
11
11
  import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
12
12
  import { ROUTES } from "../../../next/routing/route-map";
13
+ import { FEATURE_FLAG_META } from "../schemas/firestore";
14
+ import { NOTIFICATION_TYPE_TABS } from "../../../constants/notification-types";
13
15
  import { ThemeManagerView, } from "../../site-settings/components/ThemeManagerView";
14
16
  import { DEFAULT_LIGHT_THEME, DEFAULT_DARK_THEME } from "../../../tokens/themes";
15
17
  const __O = {
@@ -136,6 +138,17 @@ export function AdminSiteSettingsView({ labels = {}, ...rest }) {
136
138
  const [preOrderListingFee, setPreOrderListingFee] = React.useState(0);
137
139
  const [featuredSlotFee, setFeaturedSlotFee] = React.useState(999);
138
140
  const [promotedSlotFee, setPromotedSlotFee] = React.useState(499);
141
+ const [whatsappNotifyFeeEnabled, setWhatsappNotifyFeeEnabled] = React.useState(false);
142
+ const [whatsappNotifyFee, setWhatsappNotifyFee] = React.useState(10);
143
+ const [giftWrapFeeEnabled, setGiftWrapFeeEnabled] = React.useState(false);
144
+ const [giftWrapFee, setGiftWrapFee] = React.useState(49);
145
+ const [shipmentProtectionFeeEnabled, setShipmentProtectionFeeEnabled] = React.useState(false);
146
+ const [shipmentProtectionFeePercent, setShipmentProtectionFeePercent] = React.useState(2);
147
+ const [shipmentProtectionFeeMin, setShipmentProtectionFeeMin] = React.useState(30);
148
+ const [codDepositPercent, setCodDepositPercent] = React.useState(10);
149
+ const [sellerShippingFixed, setSellerShippingFixed] = React.useState(0);
150
+ const [platformShippingPercent, setPlatformShippingPercent] = React.useState(10);
151
+ const [platformShippingFixedMin, setPlatformShippingFixedMin] = React.useState(0);
139
152
  // ⑧ Integrations
140
153
  const [razorpayKeyId, setRazorpayKeyId] = React.useState("");
141
154
  const [razorpaySecret, setRazorpaySecret] = React.useState("");
@@ -163,6 +176,15 @@ export function AdminSiteSettingsView({ labels = {}, ...rest }) {
163
176
  const [razorpayEnabled, setRazorpayEnabled] = React.useState(false);
164
177
  const [upiManualEnabled, setUpiManualEnabled] = React.useState(true);
165
178
  const [codEnabled, setCodEnabled] = React.useState(true);
179
+ const [otpCheckoutThreshold, setOtpCheckoutThreshold] = React.useState(5000);
180
+ // Feature flags — generic, data-driven off FEATURE_FLAG_META (12 boolean platform flags).
181
+ const [featureFlags, setFeatureFlags] = React.useState({});
182
+ // Per-listing-type / per-category-type visibility flags.
183
+ const [listingTypeFlags, setListingTypeFlags] = React.useState({});
184
+ const [categoryTypeFlags, setCategoryTypeFlags] = React.useState({});
185
+ // Per-channel notification-type allowlists — empty array means "all types".
186
+ const [notifEmailTypes, setNotifEmailTypes] = React.useState([]);
187
+ const [notifWhatsappTypes, setNotifWhatsappTypes] = React.useState([]);
166
188
  // ⑩ Auction
167
189
  const [minBidIncrement, setMinBidIncrement] = React.useState(50);
168
190
  const [autoExtendWindow, setAutoExtendWindow] = React.useState(5);
@@ -184,12 +206,30 @@ export function AdminSiteSettingsView({ labels = {}, ...rest }) {
184
206
  const [waPhoneNumberId, setWaPhoneNumberId] = React.useState("");
185
207
  const [waCloudApiToken, setWaCloudApiToken] = React.useState("");
186
208
  const [waAdminNotifyNumbers, setWaAdminNotifyNumbers] = React.useState("");
209
+ const [waTemplateLanguage, setWaTemplateLanguage] = React.useState("en");
210
+ const [waTemplateOrderPlaced, setWaTemplateOrderPlaced] = React.useState("");
211
+ const [waTemplateOrderConfirmed, setWaTemplateOrderConfirmed] = React.useState("");
212
+ const [waTemplateOrderShipped, setWaTemplateOrderShipped] = React.useState("");
213
+ const [waTemplateOrderDelivered, setWaTemplateOrderDelivered] = React.useState("");
214
+ const [waTemplateOrderCancelled, setWaTemplateOrderCancelled] = React.useState("");
215
+ const [waTemplateRefundInitiated, setWaTemplateRefundInitiated] = React.useState("");
187
216
  // ⓪ About
188
217
  const [aboutTitle, setAboutTitle] = React.useState("");
189
218
  const [aboutSubtitle, setAboutSubtitle] = React.useState("");
190
219
  const [aboutMissionTitle, setAboutMissionTitle] = React.useState("");
191
220
  const [aboutMissionText, setAboutMissionText] = React.useState("");
221
+ const [aboutHowItWorksTitle, setAboutHowItWorksTitle] = React.useState("");
222
+ const [aboutHowItems, setAboutHowItems] = React.useState([]);
223
+ const [aboutValuesTitle, setAboutValuesTitle] = React.useState("");
224
+ const [aboutValueItems, setAboutValueItems] = React.useState([]);
225
+ const [aboutMilestonesTitle, setAboutMilestonesTitle] = React.useState("");
226
+ const [aboutMilestones, setAboutMilestones] = React.useState([]);
227
+ const [aboutTeamTitle, setAboutTeamTitle] = React.useState("");
228
+ const [aboutTeamSubtitle, setAboutTeamSubtitle] = React.useState("");
229
+ const [aboutTeamMembers, setAboutTeamMembers] = React.useState([]);
192
230
  const [aboutCtaTitle, setAboutCtaTitle] = React.useState("");
231
+ const [aboutCtaSell, setAboutCtaSell] = React.useState("");
232
+ const [aboutCtaShop, setAboutCtaShop] = React.useState("");
193
233
  // ⑭ Notification channels
194
234
  const [notifEmailEnabled, setNotifEmailEnabled] = React.useState(false);
195
235
  const [notifEmailMinPriority, setNotifEmailMinPriority] = React.useState("normal");
@@ -272,6 +312,17 @@ export function AdminSiteSettingsView({ labels = {}, ...rest }) {
272
312
  setPreOrderListingFee(s.commissions?.preOrderListingFee ?? 0);
273
313
  setFeaturedSlotFee(s.commissions?.featuredSlotFee ?? 999);
274
314
  setPromotedSlotFee(s.commissions?.promotedSlotFee ?? 499);
315
+ setWhatsappNotifyFeeEnabled(s.commissions?.whatsappNotifyFeeEnabled ?? false);
316
+ setWhatsappNotifyFee(s.commissions?.whatsappNotifyFee ?? 10);
317
+ setGiftWrapFeeEnabled(s.commissions?.giftWrapFeeEnabled ?? false);
318
+ setGiftWrapFee(s.commissions?.giftWrapFee ?? 49);
319
+ setShipmentProtectionFeeEnabled(s.commissions?.shipmentProtectionFeeEnabled ?? false);
320
+ setShipmentProtectionFeePercent(s.commissions?.shipmentProtectionFeePercent ?? 2);
321
+ setShipmentProtectionFeeMin(s.commissions?.shipmentProtectionFeeMin ?? 30);
322
+ setCodDepositPercent(s.commissions?.codDepositPercent ?? 10);
323
+ setSellerShippingFixed(s.commissions?.sellerShippingFixed ?? 0);
324
+ setPlatformShippingPercent(s.commissions?.platformShippingPercent ?? 10);
325
+ setPlatformShippingFixedMin(s.commissions?.platformShippingFixedMin ?? 0);
275
326
  setLaborHourlyRate(s.laborRate?.hourlyRate ?? 200);
276
327
  setLaborMaxHoursPerDay(s.laborRate?.maxHoursPerDay ?? 6);
277
328
  setEmiEnabled(s.emi?.enabled ?? false);
@@ -308,6 +359,12 @@ export function AdminSiteSettingsView({ labels = {}, ...rest }) {
308
359
  setRazorpayEnabled(s.payment?.razorpayEnabled ?? false);
309
360
  setUpiManualEnabled(s.payment?.upiManualEnabled ?? true);
310
361
  setCodEnabled(s.payment?.codEnabled ?? true);
362
+ setOtpCheckoutThreshold(s.payment?.otpCheckoutThreshold ?? 5000);
363
+ setFeatureFlags(s.featureFlags ?? {});
364
+ setListingTypeFlags(s.featureFlags?.listingTypes ?? {});
365
+ setCategoryTypeFlags(s.featureFlags?.categoryTypes ?? {});
366
+ setNotifEmailTypes(s.notificationChannels?.email?.types ?? []);
367
+ setNotifWhatsappTypes(s.notificationChannels?.whatsapp?.types ?? []);
311
368
  setMinBidIncrement(s.auctionConfig?.minBidIncrement ?? 50);
312
369
  setAutoExtendWindow(s.auctionConfig?.autoExtendWindowMinutes ?? 5);
313
370
  setSettlementGrace(s.auctionConfig?.settlementGracePeriodHours ?? 24);
@@ -326,10 +383,28 @@ export function AdminSiteSettingsView({ labels = {}, ...rest }) {
326
383
  setAboutSubtitle(s.aboutContent?.subtitle ?? "");
327
384
  setAboutMissionTitle(s.aboutContent?.missionTitle ?? "");
328
385
  setAboutMissionText(s.aboutContent?.missionText ?? "");
386
+ setAboutHowItWorksTitle(s.aboutContent?.howItWorksTitle ?? "");
387
+ setAboutHowItems(s.aboutContent?.howItems ?? []);
388
+ setAboutValuesTitle(s.aboutContent?.valuesTitle ?? "");
389
+ setAboutValueItems(s.aboutContent?.valueItems ?? []);
390
+ setAboutMilestonesTitle(s.aboutContent?.milestonesTitle ?? "");
391
+ setAboutMilestones(s.aboutContent?.milestones ?? []);
392
+ setAboutTeamTitle(s.aboutContent?.teamTitle ?? "");
393
+ setAboutTeamSubtitle(s.aboutContent?.teamSubtitle ?? "");
394
+ setAboutTeamMembers(s.aboutContent?.teamMembers ?? []);
329
395
  setAboutCtaTitle(s.aboutContent?.ctaTitle ?? "");
396
+ setAboutCtaSell(s.aboutContent?.ctaSell ?? "");
397
+ setAboutCtaShop(s.aboutContent?.ctaShop ?? "");
330
398
  setWaPhoneNumberId(s.credentialsMasked?.whatsappPhoneNumberId ?? "");
331
399
  setWaCloudApiToken(s.credentialsMasked?.whatsappCloudApiToken ?? "");
332
400
  setWaAdminNotifyNumbers(s.credentialsMasked?.whatsappAdminNotifyNumbers ?? "");
401
+ setWaTemplateLanguage(s.credentialsMasked?.whatsappTemplateLanguage ?? "en");
402
+ setWaTemplateOrderPlaced(s.credentialsMasked?.whatsappTemplateOrderPlaced ?? "");
403
+ setWaTemplateOrderConfirmed(s.credentialsMasked?.whatsappTemplateOrderConfirmed ?? "");
404
+ setWaTemplateOrderShipped(s.credentialsMasked?.whatsappTemplateOrderShipped ?? "");
405
+ setWaTemplateOrderDelivered(s.credentialsMasked?.whatsappTemplateOrderDelivered ?? "");
406
+ setWaTemplateOrderCancelled(s.credentialsMasked?.whatsappTemplateOrderCancelled ?? "");
407
+ setWaTemplateRefundInitiated(s.credentialsMasked?.whatsappTemplateRefundInitiated ?? "");
333
408
  setNotifEmailEnabled(s.notificationChannels?.email?.enabled ?? false);
334
409
  setNotifEmailMinPriority(s.notificationChannels?.email?.minPriority ?? "normal");
335
410
  setNotifWhatsappEnabled(s.notificationChannels?.whatsapp?.enabled ?? false);
@@ -354,6 +429,13 @@ export function AdminSiteSettingsView({ labels = {}, ...rest }) {
354
429
  whatsappPhoneNumberId: s.credentialsMasked?.whatsappPhoneNumberId ?? "",
355
430
  whatsappCloudApiToken: s.credentialsMasked?.whatsappCloudApiToken ?? "",
356
431
  whatsappAdminNotifyNumbers: s.credentialsMasked?.whatsappAdminNotifyNumbers ?? "",
432
+ whatsappTemplateLanguage: s.credentialsMasked?.whatsappTemplateLanguage ?? "en",
433
+ whatsappTemplateOrderPlaced: s.credentialsMasked?.whatsappTemplateOrderPlaced ?? "",
434
+ whatsappTemplateOrderConfirmed: s.credentialsMasked?.whatsappTemplateOrderConfirmed ?? "",
435
+ whatsappTemplateOrderShipped: s.credentialsMasked?.whatsappTemplateOrderShipped ?? "",
436
+ whatsappTemplateOrderDelivered: s.credentialsMasked?.whatsappTemplateOrderDelivered ?? "",
437
+ whatsappTemplateOrderCancelled: s.credentialsMasked?.whatsappTemplateOrderCancelled ?? "",
438
+ whatsappTemplateRefundInitiated: s.credentialsMasked?.whatsappTemplateRefundInitiated ?? "",
357
439
  resendApiKey: s.credentialsMasked?.resendApiKey ?? "",
358
440
  };
359
441
  }, [data]);
@@ -362,7 +444,24 @@ export function AdminSiteSettingsView({ labels = {}, ...rest }) {
362
444
  // save action for the whole form, not 19 per-tab mutations.
363
445
  function buildFullPayload() {
364
446
  return {
365
- aboutContent: { title: aboutTitle, subtitle: aboutSubtitle, missionTitle: aboutMissionTitle, missionText: aboutMissionText, ctaTitle: aboutCtaTitle },
447
+ aboutContent: {
448
+ title: aboutTitle,
449
+ subtitle: aboutSubtitle,
450
+ missionTitle: aboutMissionTitle,
451
+ missionText: aboutMissionText,
452
+ howItWorksTitle: aboutHowItWorksTitle,
453
+ howItems: aboutHowItems,
454
+ valuesTitle: aboutValuesTitle,
455
+ valueItems: aboutValueItems,
456
+ milestonesTitle: aboutMilestonesTitle,
457
+ milestones: aboutMilestones,
458
+ teamTitle: aboutTeamTitle,
459
+ teamSubtitle: aboutTeamSubtitle,
460
+ teamMembers: aboutTeamMembers,
461
+ ctaTitle: aboutCtaTitle,
462
+ ctaSell: aboutCtaSell,
463
+ ctaShop: aboutCtaShop,
464
+ },
366
465
  siteName, tagline, logo: logoUrl, favicon: faviconUrl,
367
466
  maintenance: { enabled: maintenanceMode, message: maintenanceMessage },
368
467
  background: {
@@ -387,7 +486,7 @@ export function AdminSiteSettingsView({ labels = {}, ...rest }) {
387
486
  contact: { email: supportEmail, phone: supportPhone, address: supportAddress, supportHours, whatsappNumber: whatsapp },
388
487
  socialLinks: { instagram, twitter, facebook, youtube, linkedin, pinterest },
389
488
  watermark: { type: watermarkType, text: watermarkText, imageUrl: watermarkImageUrl, size: watermarkSize, opacity: watermarkOpacity },
390
- commissions: { platformFeePercent, gstPercent, minimumTransactionFee, gatewayFeePercent, payoutHoldDays, minPayoutAmount, auctionListingFee, preOrderListingFee, featuredSlotFee, promotedSlotFee },
489
+ commissions: { platformFeePercent, gstPercent, minimumTransactionFee, gatewayFeePercent, payoutHoldDays, minPayoutAmount, auctionListingFee, preOrderListingFee, featuredSlotFee, promotedSlotFee, whatsappNotifyFeeEnabled, whatsappNotifyFee, giftWrapFeeEnabled, giftWrapFee, shipmentProtectionFeeEnabled, shipmentProtectionFeePercent, shipmentProtectionFeeMin, codDepositPercent, sellerShippingFixed, platformShippingPercent, platformShippingFixedMin },
391
490
  laborRate: { hourlyRate: laborHourlyRate, maxHoursPerDay: laborMaxHoursPerDay },
392
491
  emi: {
393
492
  enabled: emiEnabled,
@@ -425,6 +524,13 @@ export function AdminSiteSettingsView({ labels = {}, ...rest }) {
425
524
  whatsappPhoneNumberId: maskedOrReal("whatsappPhoneNumberId", waPhoneNumberId),
426
525
  whatsappCloudApiToken: maskedOrReal("whatsappCloudApiToken", waCloudApiToken),
427
526
  whatsappAdminNotifyNumbers: maskedOrReal("whatsappAdminNotifyNumbers", waAdminNotifyNumbers),
527
+ whatsappTemplateLanguage: maskedOrReal("whatsappTemplateLanguage", waTemplateLanguage),
528
+ whatsappTemplateOrderPlaced: maskedOrReal("whatsappTemplateOrderPlaced", waTemplateOrderPlaced),
529
+ whatsappTemplateOrderConfirmed: maskedOrReal("whatsappTemplateOrderConfirmed", waTemplateOrderConfirmed),
530
+ whatsappTemplateOrderShipped: maskedOrReal("whatsappTemplateOrderShipped", waTemplateOrderShipped),
531
+ whatsappTemplateOrderDelivered: maskedOrReal("whatsappTemplateOrderDelivered", waTemplateOrderDelivered),
532
+ whatsappTemplateOrderCancelled: maskedOrReal("whatsappTemplateOrderCancelled", waTemplateOrderCancelled),
533
+ whatsappTemplateRefundInitiated: maskedOrReal("whatsappTemplateRefundInitiated", waTemplateRefundInitiated),
428
534
  resendApiKey: maskedOrReal("resendApiKey", resendApiKey),
429
535
  },
430
536
  emailSettings: {
@@ -433,14 +539,20 @@ export function AdminSiteSettingsView({ labels = {}, ...rest }) {
433
539
  },
434
540
  integrations: { googleAnalyticsId: gaMeasurementId, facebookPixelId: fbPixelId, gtmContainerId },
435
541
  shipping: { freeShippingThreshold, defaultCarrier, maxDeliveryRadius },
436
- payment: { razorpayEnabled, upiManualEnabled, codEnabled },
542
+ payment: { razorpayEnabled, upiManualEnabled, codEnabled, otpCheckoutThreshold },
437
543
  auctionConfig: { minBidIncrement, autoExtendWindowMinutes: autoExtendWindow, settlementGracePeriodHours: settlementGrace },
438
544
  platformLimits: { maxProductsPerStore, maxImagesPerProduct, maxVideoSizeMb, maxCustomFieldsPerProduct: maxCustomFields, maxCustomSectionsPerProduct: maxCustomSections, orderCancellationWindowHours: orderCancelWindow },
439
545
  legalPages: { terms: termsHtml, privacy: privacyHtml, refundPolicy: refundHtml, shipping: shippingPolicyHtml, cookies: cookieHtml },
546
+ // Spreading the raw `featureFlags` object captured at load (not hand-picking keys)
547
+ // preserves `adminCheckoutBypass` through this save even though it's not editable
548
+ // here — Firestore's update() replaces nested maps wholesale, so omitting a key
549
+ // here would silently wipe it (it's edited exclusively via its own dedicated,
550
+ // audit-logged route — see the note above the Feature Flags tab).
551
+ featureFlags: { ...featureFlags, listingTypes: listingTypeFlags, categoryTypes: categoryTypeFlags },
440
552
  notificationChannels: {
441
553
  inApp: { enabled: true, readOnly: true },
442
- email: { enabled: notifEmailEnabled, minPriority: notifEmailMinPriority },
443
- whatsapp: { enabled: notifWhatsappEnabled, minPriority: notifWhatsappMinPriority, otpEnabled: notifWhatsappOtpEnabled },
554
+ email: { enabled: notifEmailEnabled, minPriority: notifEmailMinPriority, types: notifEmailTypes },
555
+ whatsapp: { enabled: notifWhatsappEnabled, minPriority: notifWhatsappMinPriority, otpEnabled: notifWhatsappOtpEnabled, types: notifWhatsappTypes },
444
556
  sms: { enabled: notifSmsEnabled, minPriority: notifSmsMinPriority },
445
557
  },
446
558
  };
@@ -452,6 +564,9 @@ export function AdminSiteSettingsView({ labels = {}, ...rest }) {
452
564
  onSuccess: () => {
453
565
  showToast("Site settings saved.", "success");
454
566
  queryClient.invalidateQueries({ queryKey: ["admin", "site-settings"] });
567
+ // Public-facing consumers (Navbar, checkout, watermark, etc.) read via the
568
+ // shared useSiteSettings() hook under a different key — must invalidate both.
569
+ queryClient.invalidateQueries({ queryKey: ["site-settings"] });
455
570
  },
456
571
  onError: (err) => showToast(err?.message ?? "Failed to save site settings.", "error"),
457
572
  });
@@ -468,6 +583,9 @@ export function AdminSiteSettingsView({ labels = {}, ...rest }) {
468
583
  { label: "Bluedart", value: "bluedart" },
469
584
  { label: "FedEx", value: "fedex" },
470
585
  ];
586
+ const LISTING_TYPE_KEYS = ["standard", "auction", "pre-order", "prize-draw", "bundle", "classified", "digital-code", "live"];
587
+ const CATEGORY_TYPE_KEYS = ["category", "sublisting", "brand", "bundle"];
588
+ const NOTIF_TYPE_OPTIONS = NOTIFICATION_TYPE_TABS.filter((t) => t.id !== "All").map((t) => ({ value: t.id, label: t.label }));
471
589
  return (_jsx(StackedViewShell, { portal: "admin", ...rest, title: labels.title ?? "Site Settings", sections: [
472
590
  isLoading ? (_jsx(Alert, { variant: "info", title: "Loading", children: "Fetching site settings\u2026" }, "loading")) : null,
473
591
  error ? (_jsx(Alert, { variant: "error", title: "Load failed", children: error instanceof Error ? error.message : "Unknown error" }, "error")) : null,
@@ -491,7 +609,8 @@ export function AdminSiteSettingsView({ labels = {}, ...rest }) {
491
609
  ["procurement", "⑮ Procurement"],
492
610
  ["emi", "⑯ EMI"],
493
611
  ["gst", "⑰ GST"],
494
- ].map(([value, label]) => (_jsx(TabsTrigger, { value: value, children: label }, value))) }), _jsx(TabsContent, { value: "about", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); saveAllMutation.mutate(); }, className: "pt-[var(--appkit-space-4)]", spacing: "md", children: [_jsx(Text, { size: "xs", color: "muted", children: "Override the About page hero and mission text. Leave blank to use the platform defaults." }), _jsx(Input, { label: "Hero title", value: aboutTitle, onChange: (e) => setAboutTitle(e.target.value), placeholder: "About LetItRip" }), _jsx(Input, { label: "Hero subtitle", value: aboutSubtitle, onChange: (e) => setAboutSubtitle(e.target.value), placeholder: "Connecting buyers, sellers, and bidders in one vibrant marketplace" }), _jsx(Input, { label: "Mission section title", value: aboutMissionTitle, onChange: (e) => setAboutMissionTitle(e.target.value), placeholder: "Our Mission" }), _jsxs(_Fragment, { children: [_jsx(Text, { className: "mb-1", color: "muted", size: "sm", weight: "medium", children: "Mission text" }), _jsx(Textarea, { value: aboutMissionText, onChange: (e) => setAboutMissionText(e.target.value), placeholder: "LetItRip was built to democratise commerce\u2026", rows: 4 })] }), _jsx(Input, { label: "CTA banner title", value: aboutCtaTitle, onChange: (e) => setAboutCtaTitle(e.target.value), placeholder: "Ready to get started?" })] }) }), _jsx(TabsContent, { value: "branding", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); saveAllMutation.mutate(); }, className: "pt-[var(--appkit-space-4)]", spacing: "md", children: [_jsx(Input, { label: "Site name", value: siteName, onChange: (e) => setSiteName(e.target.value), placeholder: "LetItRip" }), _jsx(Input, { label: "Tagline", value: tagline, onChange: (e) => setTagline(e.target.value), placeholder: "India's Largest Collectibles Marketplace" }), _jsx(ImageUpload, { label: "Logo", currentImage: logoUrl, onUpload: (file) => upload(file, "store"), onChange: setLogoUrl }), _jsx(ImageUpload, { label: "Favicon", currentImage: faviconUrl, onUpload: (file) => upload(file, "store"), onChange: setFaviconUrl }), _jsxs(Stack, { gap: "sm", rounded: "lg", border: "default", padding: "md", children: [_jsx(Toggle, { label: "Maintenance mode", checked: maintenanceMode, onChange: setMaintenanceMode }), _jsx(Input, { label: "Maintenance message", value: maintenanceMessage, onChange: (e) => setMaintenanceMessage(e.target.value), placeholder: "We're back soon.", disabled: !maintenanceMode })] })] }) }), _jsx(TabsContent, { value: "appearance", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); saveAllMutation.mutate(); }, className: "pt-[var(--appkit-space-4)]", spacing: "md", children: [_jsx(Text, { size: "xs", color: "muted", children: "Sets the background behind the public shell, dashboard sidebars, and any Section/Card that opts into it. Leave the value blank for a plain surface." }), _jsxs(Grid, { cols: 2, gap: "lg", children: [_jsxs(Stack, { gap: "sm", rounded: "lg", border: "default", padding: "md", children: [_jsx(Text, { size: "sm", weight: "semibold", children: "Light mode" }), _jsx(Select, { label: "Type", options: BG_TYPE_OPTIONS, value: lightBgType, onValueChange: (v) => setLightBgType(v) }), lightBgType === "color" ? (_jsx(Input, { type: "color", label: "Color", value: lightBgValue || "#ffffff", onChange: (e) => setLightBgValue(e.target.value), className: "h-10 w-full cursor-pointer", bare: true }) /* audit-hex-tokens-ok: native color picker requires literal hex string fallback */) : lightBgType === "gradient" ? (_jsx(Textarea, { label: "CSS gradient expression", rows: 2, value: lightBgValue, onChange: (e) => setLightBgValue(e.target.value), placeholder: "linear-gradient(...)" })) : (_jsx(MediaUploadField, { label: lightBgType === "video" ? "Background video" : "Background image", kind: lightBgType === "video" ? "video" : "image", value: lightBgValue, onChange: setLightBgValue, onUpload: (file) => upload(file, "store") })), _jsx(Toggle, { label: "Dim overlay", checked: lightBgOverlayEnabled, onChange: setLightBgOverlayEnabled }), lightBgOverlayEnabled && (_jsxs(_Fragment, { children: [_jsx(Input, { type: "color", label: "Overlay color", value: lightBgOverlayColor, onChange: (e) => setLightBgOverlayColor(e.target.value), className: "h-10 w-full cursor-pointer", bare: true }), " ", _jsx(Slider, { label: "Overlay opacity", min: 0, max: 100, value: lightBgOverlayOpacity, onChange: setLightBgOverlayOpacity })] })), _jsx(Text, { size: "xs", color: "muted", children: "Preview" }), _jsx(Div, { className: "relative h-24 w-full", overflow: "hidden", rounded: "md", border: "default", children: _jsx(BackgroundRenderer, { mode: "light", lightMode: {
612
+ ["featureflags", " Feature Flags"],
613
+ ].map(([value, label]) => (_jsx(TabsTrigger, { value: value, children: label }, value))) }), _jsx(TabsContent, { value: "about", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); saveAllMutation.mutate(); }, className: "pt-[var(--appkit-space-4)]", spacing: "md", children: [_jsx(Text, { size: "xs", color: "muted", children: "Override the About page content. Leave blank to use the platform defaults." }), _jsx(Input, { label: "Hero title", value: aboutTitle, onChange: (e) => setAboutTitle(e.target.value), placeholder: "About LetItRip" }), _jsx(Input, { label: "Hero subtitle", value: aboutSubtitle, onChange: (e) => setAboutSubtitle(e.target.value), placeholder: "Connecting buyers, sellers, and bidders in one vibrant marketplace" }), _jsx(Input, { label: "Mission section title", value: aboutMissionTitle, onChange: (e) => setAboutMissionTitle(e.target.value), placeholder: "Our Mission" }), _jsxs(_Fragment, { children: [_jsx(Text, { className: "mb-1", color: "muted", size: "sm", weight: "medium", children: "Mission text" }), _jsx(Textarea, { value: aboutMissionText, onChange: (e) => setAboutMissionText(e.target.value), placeholder: "LetItRip was built to democratise commerce\u2026", rows: 4 })] }), _jsxs(Stack, { gap: "sm", rounded: "lg", border: "default", padding: "md", children: [_jsx(Input, { label: '"How it works" section title', value: aboutHowItWorksTitle, onChange: (e) => setAboutHowItWorksTitle(e.target.value), placeholder: "How It Works" }), aboutHowItems.map((item, i) => (_jsxs(Stack, { gap: "sm", rounded: "lg", border: "default", padding: "sm", children: [_jsxs(Row, { justify: "between", align: "center", children: [_jsxs(Text, { size: "xs", weight: "medium", color: "muted", children: ["Step ", i + 1] }), _jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => setAboutHowItems(aboutHowItems.filter((_, idx) => idx !== i)), children: "\u2715" })] }), _jsx(Input, { label: "Icon (emoji)", value: item.icon, onChange: (e) => { const next = [...aboutHowItems]; next[i] = { ...item, icon: e.target.value }; setAboutHowItems(next); }, placeholder: "\uD83D\uDED2" }), _jsx(Input, { label: "Title", value: item.title, onChange: (e) => { const next = [...aboutHowItems]; next[i] = { ...item, title: e.target.value }; setAboutHowItems(next); } }), _jsx(Textarea, { value: item.text, onChange: (e) => { const next = [...aboutHowItems]; next[i] = { ...item, text: e.target.value }; setAboutHowItems(next); }, rows: 2 })] }, i))), _jsx(Button, { type: "button", variant: "secondary", size: "sm", onClick: () => setAboutHowItems([...aboutHowItems, { title: "", text: "", icon: "✨", tone: "indigo" }]), children: "+ Add step" })] }), _jsxs(Stack, { gap: "sm", rounded: "lg", border: "default", padding: "md", children: [_jsx(Input, { label: "Values section title", value: aboutValuesTitle, onChange: (e) => setAboutValuesTitle(e.target.value), placeholder: "Our Values" }), aboutValueItems.map((item, i) => (_jsxs(Stack, { gap: "sm", rounded: "lg", border: "default", padding: "sm", children: [_jsxs(Row, { justify: "between", align: "center", children: [_jsxs(Text, { size: "xs", weight: "medium", color: "muted", children: ["Value ", i + 1] }), _jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => setAboutValueItems(aboutValueItems.filter((_, idx) => idx !== i)), children: "\u2715" })] }), _jsx(Input, { label: "Icon (emoji)", value: item.icon, onChange: (e) => { const next = [...aboutValueItems]; next[i] = { ...item, icon: e.target.value }; setAboutValueItems(next); }, placeholder: "\uD83D\uDEE1\uFE0F" }), _jsx(Input, { label: "Title", value: item.title, onChange: (e) => { const next = [...aboutValueItems]; next[i] = { ...item, title: e.target.value }; setAboutValueItems(next); } }), _jsx(Textarea, { value: item.text, onChange: (e) => { const next = [...aboutValueItems]; next[i] = { ...item, text: e.target.value }; setAboutValueItems(next); }, rows: 2 })] }, i))), _jsx(Button, { type: "button", variant: "secondary", size: "sm", onClick: () => setAboutValueItems([...aboutValueItems, { title: "", text: "", icon: "✨" }]), children: "+ Add value" })] }), _jsxs(Stack, { gap: "sm", rounded: "lg", border: "default", padding: "md", children: [_jsx(Input, { label: "Milestones section title", value: aboutMilestonesTitle, onChange: (e) => setAboutMilestonesTitle(e.target.value), placeholder: "Our Journey" }), aboutMilestones.map((item, i) => (_jsxs(Stack, { gap: "sm", rounded: "lg", border: "default", padding: "sm", children: [_jsxs(Row, { justify: "between", align: "center", children: [_jsxs(Text, { size: "xs", weight: "medium", color: "muted", children: ["Milestone ", i + 1] }), _jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => setAboutMilestones(aboutMilestones.filter((_, idx) => idx !== i)), children: "\u2715" })] }), _jsx(Input, { label: "Year", value: item.year, onChange: (e) => { const next = [...aboutMilestones]; next[i] = { ...item, year: e.target.value }; setAboutMilestones(next); }, placeholder: "2024" }), _jsx(Textarea, { value: item.text, onChange: (e) => { const next = [...aboutMilestones]; next[i] = { ...item, text: e.target.value }; setAboutMilestones(next); }, rows: 2 })] }, i))), _jsx(Button, { type: "button", variant: "secondary", size: "sm", onClick: () => setAboutMilestones([...aboutMilestones, { year: "", text: "" }]), children: "+ Add milestone" })] }), _jsxs(Stack, { gap: "sm", rounded: "lg", border: "default", padding: "md", children: [_jsx(Input, { label: "Team section title", value: aboutTeamTitle, onChange: (e) => setAboutTeamTitle(e.target.value), placeholder: "Meet the Team" }), _jsx(Input, { label: "Team section subtitle", value: aboutTeamSubtitle, onChange: (e) => setAboutTeamSubtitle(e.target.value), placeholder: "The people building LetItRip" }), aboutTeamMembers.map((member, i) => (_jsxs(Stack, { gap: "sm", rounded: "lg", border: "default", padding: "sm", children: [_jsxs(Row, { justify: "between", align: "center", children: [_jsxs(Text, { size: "xs", weight: "medium", color: "muted", children: ["Team member ", i + 1] }), _jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => setAboutTeamMembers(aboutTeamMembers.filter((_, idx) => idx !== i)), children: "\u2715" })] }), _jsx(ImageUpload, { label: "Photo", currentImage: member.photoUrl, onUpload: (file) => upload(file, "store"), onChange: (url) => { const next = [...aboutTeamMembers]; next[i] = { ...member, photoUrl: url }; setAboutTeamMembers(next); } }), _jsx(Input, { label: "Name", value: member.name, onChange: (e) => { const next = [...aboutTeamMembers]; next[i] = { ...member, name: e.target.value }; setAboutTeamMembers(next); } }), _jsx(Input, { label: "Role", value: member.role, onChange: (e) => { const next = [...aboutTeamMembers]; next[i] = { ...member, role: e.target.value }; setAboutTeamMembers(next); }, placeholder: "Founder & Developer" }), _jsx(Textarea, { value: member.bio, onChange: (e) => { const next = [...aboutTeamMembers]; next[i] = { ...member, bio: e.target.value }; setAboutTeamMembers(next); }, rows: 3 }), _jsxs(Row, { gap: "md", children: [_jsx(Toggle, { label: "Founder", checked: !!member.isFounder, onChange: (v) => { const next = [...aboutTeamMembers]; next[i] = { ...member, isFounder: v }; setAboutTeamMembers(next); } }), _jsx(Toggle, { label: "Developer", checked: !!member.isDeveloper, onChange: (v) => { const next = [...aboutTeamMembers]; next[i] = { ...member, isDeveloper: v }; setAboutTeamMembers(next); } })] })] }, i))), _jsx(Button, { type: "button", variant: "secondary", size: "sm", onClick: () => setAboutTeamMembers([...aboutTeamMembers, { name: "", role: "", bio: "" }]), children: "+ Add team member" })] }), _jsx(Input, { label: "CTA banner title", value: aboutCtaTitle, onChange: (e) => setAboutCtaTitle(e.target.value), placeholder: "Ready to get started?" }), _jsx(Input, { label: "Sell CTA copy", value: aboutCtaSell, onChange: (e) => setAboutCtaSell(e.target.value), placeholder: "Start selling in minutes" }), _jsx(Input, { label: "Shop CTA copy", value: aboutCtaShop, onChange: (e) => setAboutCtaShop(e.target.value), placeholder: "Browse the marketplace" })] }) }), _jsx(TabsContent, { value: "branding", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); saveAllMutation.mutate(); }, className: "pt-[var(--appkit-space-4)]", spacing: "md", children: [_jsx(Input, { label: "Site name", value: siteName, onChange: (e) => setSiteName(e.target.value), placeholder: "LetItRip" }), _jsx(Input, { label: "Tagline", value: tagline, onChange: (e) => setTagline(e.target.value), placeholder: "India's Largest Collectibles Marketplace" }), _jsx(ImageUpload, { label: "Logo", currentImage: logoUrl, onUpload: (file) => upload(file, "store"), onChange: setLogoUrl }), _jsx(ImageUpload, { label: "Favicon", currentImage: faviconUrl, onUpload: (file) => upload(file, "store"), onChange: setFaviconUrl }), _jsxs(Stack, { gap: "sm", rounded: "lg", border: "default", padding: "md", children: [_jsx(Toggle, { label: "Maintenance mode", checked: maintenanceMode, onChange: setMaintenanceMode }), _jsx(Input, { label: "Maintenance message", value: maintenanceMessage, onChange: (e) => setMaintenanceMessage(e.target.value), placeholder: "We're back soon.", disabled: !maintenanceMode })] })] }) }), _jsx(TabsContent, { value: "appearance", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); saveAllMutation.mutate(); }, className: "pt-[var(--appkit-space-4)]", spacing: "md", children: [_jsx(Text, { size: "xs", color: "muted", children: "Sets the background behind the public shell, dashboard sidebars, and any Section/Card that opts into it. Leave the value blank for a plain surface." }), _jsxs(Grid, { cols: 2, gap: "lg", children: [_jsxs(Stack, { gap: "sm", rounded: "lg", border: "default", padding: "md", children: [_jsx(Text, { size: "sm", weight: "semibold", children: "Light mode" }), _jsx(Select, { label: "Type", options: BG_TYPE_OPTIONS, value: lightBgType, onValueChange: (v) => setLightBgType(v) }), lightBgType === "color" ? (_jsx(Input, { type: "color", label: "Color", value: lightBgValue || "#ffffff", onChange: (e) => setLightBgValue(e.target.value), className: "h-10 w-full cursor-pointer", bare: true }) /* audit-hex-tokens-ok: native color picker requires literal hex string fallback */) : lightBgType === "gradient" ? (_jsx(Textarea, { label: "CSS gradient expression", rows: 2, value: lightBgValue, onChange: (e) => setLightBgValue(e.target.value), placeholder: "linear-gradient(...)" })) : (_jsx(MediaUploadField, { label: lightBgType === "video" ? "Background video" : "Background image", kind: lightBgType === "video" ? "video" : "image", value: lightBgValue, onChange: setLightBgValue, onUpload: (file) => upload(file, "store") })), _jsx(Toggle, { label: "Dim overlay", checked: lightBgOverlayEnabled, onChange: setLightBgOverlayEnabled }), lightBgOverlayEnabled && (_jsxs(_Fragment, { children: [_jsx(Input, { type: "color", label: "Overlay color", value: lightBgOverlayColor, onChange: (e) => setLightBgOverlayColor(e.target.value), className: "h-10 w-full cursor-pointer", bare: true }), " ", _jsx(Slider, { label: "Overlay opacity", min: 0, max: 100, value: lightBgOverlayOpacity, onChange: setLightBgOverlayOpacity })] })), _jsx(Text, { size: "xs", color: "muted", children: "Preview" }), _jsx(Div, { className: "relative h-24 w-full", overflow: "hidden", rounded: "md", border: "default", children: _jsx(BackgroundRenderer, { mode: "light", lightMode: {
495
614
  type: lightBgType,
496
615
  value: lightBgValue,
497
616
  overlay: { enabled: lightBgOverlayEnabled, color: lightBgOverlayColor, opacity: lightBgOverlayOpacity / 100 },
@@ -502,7 +621,7 @@ export function AdminSiteSettingsView({ labels = {}, ...rest }) {
502
621
  } }) })] })] })] }) }), _jsx(TabsContent, { value: "themes", children: _jsx(Form, { onSubmit: (e) => {
503
622
  e.preventDefault();
504
623
  saveAllMutation.mutate();
505
- }, className: "pt-[var(--appkit-space-4)]", spacing: "md", children: _jsx(ThemeManagerView, { value: themeRegistry, onChange: setThemeRegistry, previewOrigin: "/" }) }) }), _jsx(TabsContent, { value: "announcement", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); saveAllMutation.mutate(); }, className: "pt-[var(--appkit-space-4)]", spacing: "md", children: [_jsx(Toggle, { label: "Show announcement bar", checked: announcementEnabled, onChange: setAnnouncementEnabled }), _jsx(Input, { label: "Announcement text", value: announcementText, onChange: (e) => setAnnouncementText(e.target.value), placeholder: "\uD83C\uDF89 Free shipping on orders \u20B9999+", disabled: !announcementEnabled }), _jsx(Input, { label: "Link URL (optional)", value: announcementLink, onChange: (e) => setAnnouncementLink(e.target.value), placeholder: String(ROUTES.PUBLIC.PRODUCTS), disabled: !announcementEnabled }), _jsxs(Stack, { gap: "none", children: [_jsx(Text, { size: "sm", weight: "medium", color: "muted", className: "mb-1", children: "Background color" }), _jsx(Input, { type: "color", value: announcementBg || "#1d4ed8", onChange: (e) => setAnnouncementBg(e.target.value), className: "h-10 w-32 cursor-pointer", bare: true, disabled: !announcementEnabled }), " "] })] }) }), _jsx(TabsContent, { value: "seo", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); saveAllMutation.mutate(); }, className: "pt-[var(--appkit-space-4)]", spacing: "md", children: [_jsx(Input, { label: "Default meta title", value: seoTitle, onChange: (e) => setSeoTitle(e.target.value), placeholder: "LetItRip \u2014 Buy, Sell & Auction Collectibles in India", maxLength: 60, helperText: "Max 60 chars. Use {page} token for dynamic insertion." }), _jsx(Input, { label: "Default meta description", value: seoDescription, onChange: (e) => setSeoDescription(e.target.value), placeholder: "India's largest collectibles marketplace\u2026", maxLength: 160, helperText: "Max 160 chars." }), _jsx(ImageUpload, { label: "Default OG image", currentImage: seoOgImage, onUpload: (file) => upload(file, "store"), onChange: setSeoOgImage }), _jsx(Input, { label: "Canonical base URL", value: canonicalUrl, onChange: (e) => setCanonicalUrl(e.target.value), placeholder: "https://letitrip.in" }), _jsx(Toggle, { label: "Robots noindex (disables search indexing \u2014 use carefully)", checked: seoNoIndex, onChange: setSeoNoIndex })] }) }), _jsx(TabsContent, { value: "contact", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); saveAllMutation.mutate(); }, className: "pt-[var(--appkit-space-4)]", spacing: "md", children: [_jsxs(Grid, { cols: 2, gap: "md", children: [_jsx(Input, { label: "Support email", value: supportEmail, onChange: (e) => setSupportEmail(e.target.value), type: "email", placeholder: "support@letitrip.in" }), _jsx(Input, { label: "Support phone", value: supportPhone, onChange: (e) => setSupportPhone(e.target.value), placeholder: "+91 XXXXX XXXXX" })] }), _jsx(Input, { label: "Physical address", value: supportAddress, onChange: (e) => setSupportAddress(e.target.value), placeholder: "Mumbai, Maharashtra, India" }), _jsx(Input, { label: "Support hours", value: supportHours, onChange: (e) => setSupportHours(e.target.value), placeholder: "Mon\u2013Fri, 10 AM \u2013 6 PM IST" }), _jsx(Text, { className: "pt-[0.5rem]", color: "muted", size: "sm", weight: "medium", children: "Social links" }), _jsxs(Grid, { cols: 2, gap: "md", children: [_jsx(Input, { label: "Instagram URL", value: instagram, onChange: (e) => setInstagram(e.target.value), placeholder: "https://instagram.com/letitrip" }), _jsx(Input, { label: "Twitter / X URL", value: twitter, onChange: (e) => setTwitter(e.target.value), placeholder: "https://twitter.com/letitrip" }), _jsx(Input, { label: "Facebook URL", value: facebook, onChange: (e) => setFacebook(e.target.value), placeholder: "https://facebook.com/letitrip" }), _jsx(Input, { label: "YouTube URL", value: youtube, onChange: (e) => setYoutube(e.target.value), placeholder: "https://youtube.com/@letitrip" }), _jsx(Input, { label: "WhatsApp number", value: whatsapp, onChange: (e) => setWhatsapp(e.target.value), placeholder: "+91XXXXXXXXXX" }), _jsx(Input, { label: "LinkedIn URL", value: linkedin, onChange: (e) => setLinkedin(e.target.value), placeholder: "https://linkedin.com/company/letitrip" }), _jsx(Input, { label: "Pinterest URL", value: pinterest, onChange: (e) => setPinterest(e.target.value), placeholder: "https://pinterest.com/letitrip" })] })] }) }), _jsx(TabsContent, { value: "watermark", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); saveAllMutation.mutate(); }, className: "pt-[var(--appkit-space-4)]", spacing: "md", children: [_jsx(Select, { label: "Watermark type", options: [{ label: "Text", value: "text" }, { label: "Image", value: "image" }], value: watermarkType, onValueChange: (v) => setWatermarkType(v) }), watermarkType === "text" ? (_jsx(Input, { label: "Watermark text", value: watermarkText, onChange: (e) => setWatermarkText(e.target.value), placeholder: "letitrip.in" })) : (_jsx(ImageUpload, { label: "Watermark image", currentImage: watermarkImageUrl, onUpload: (file) => upload(file, "store"), onChange: setWatermarkImageUrl })), _jsx(Slider, { label: `Size — ${watermarkSize}% of image width`, value: watermarkSize, onChange: setWatermarkSize, min: 5, max: 100, step: 5 }), _jsx(Slider, { label: `Opacity — ${watermarkOpacity}%`, value: watermarkOpacity, onChange: setWatermarkOpacity, min: 5, max: 100, step: 5 }), _jsxs(Stack, { gap: "xs", surface: "muted", rounded: "lg", border: "default", padding: "md", children: [_jsx(Text, { size: "xs", color: "muted", children: "Preview (text watermark only)" }), _jsx(Row, { surface: "default", justify: "end", align: "end", className: `relative h-32 ${__O.hidden}`, rounded: "default", children: _jsx(Span, { ref: watermarkPreviewRef, weight: "medium", color: "faint", padding: "1", className: "select-none", children: watermarkText }) })] })] }) }), _jsx(TabsContent, { value: "fees", children: _jsx(Form, { onSubmit: (e) => { e.preventDefault(); saveAllMutation.mutate(); }, className: "pt-[var(--appkit-space-4)]", spacing: "md", children: _jsxs(Grid, { cols: 2, gap: "md", children: [_jsx(Input, { label: "Platform fee \u2014 our cut (%)", helperText: "% charged on order value. Buyer pays this.", value: String(platformFeePercent), onChange: (e) => setPlatformFeePercent(parseFloat(e.target.value) || 0), type: "number", min: 0, max: 100, step: 0.1 }), _jsx(Input, { label: "GST on platform fee (%)", helperText: "Applied to our fee only (not full order). Usually 18%.", value: String(gstPercent), onChange: (e) => setGstPercent(parseFloat(e.target.value) || 0), type: "number", min: 0, max: 100, step: 0.1 }), _jsx(Input, { label: "Razorpay gateway cost (%)", helperText: "Gateway's own fee \u2014 absorbed by platform, not passed through.", value: String(gatewayFeePercent), onChange: (e) => setGatewayFeePercent(parseFloat(e.target.value) || 0), type: "number", min: 0, max: 10, step: 0.01 }), _jsx(Input, { label: "Minimum transaction fee (\u20B9)", helperText: "Per-transaction floor. Total charge will never be below base + this.", value: String(minimumTransactionFee), onChange: (e) => setMinimumTransactionFee(parseFloat(e.target.value) || 0), type: "number", min: 0, step: 0.01 }), _jsx(Input, { label: "Seller payout hold (days)", value: String(payoutHoldDays), onChange: (e) => setPayoutHoldDays(parseInt(e.target.value) || 0), type: "number", min: 0 }), _jsx(Input, { label: "Minimum payout amount (\u20B9)", value: String(minPayoutAmount), onChange: (e) => setMinPayoutAmount(parseInt(e.target.value) || 0), type: "number", min: 0 }), _jsx(Input, { label: "Auction listing fee (\u20B9)", value: String(auctionListingFee), onChange: (e) => setAuctionListingFee(parseInt(e.target.value) || 0), type: "number", min: 0 }), _jsx(Input, { label: "Pre-order listing fee (\u20B9)", value: String(preOrderListingFee), onChange: (e) => setPreOrderListingFee(parseInt(e.target.value) || 0), type: "number", min: 0 }), _jsx(Input, { label: "Featured slot fee (\u20B9)", value: String(featuredSlotFee), onChange: (e) => setFeaturedSlotFee(parseInt(e.target.value) || 0), type: "number", min: 0 }), _jsx(Input, { label: "Promoted slot fee (\u20B9)", value: String(promotedSlotFee), onChange: (e) => setPromotedSlotFee(parseInt(e.target.value) || 0), type: "number", min: 0 })] }) }) }), _jsx(TabsContent, { value: "procurement", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); saveAllMutation.mutate(); }, className: "pt-[var(--appkit-space-4)]", spacing: "md", children: [_jsx(Text, { size: "xs", color: "muted", children: "Used to compute each procurement shipment's labor cost (hours spent \u00D7 hourly rate) and its estimated processing time (hours spent \u00F7 max hours/day)." }), _jsxs(Grid, { cols: 2, gap: "md", children: [_jsx(Input, { label: "Hourly rate (\u20B9)", helperText: "Your effective hourly wage for sorting/categorizing/listing a shipment.", value: String(laborHourlyRate), onChange: (e) => setLaborHourlyRate(Math.round((parseFloat(e.target.value) || 0) * 100) / 100), type: "number", min: 0 }), _jsx(Input, { label: "Max hours per day", helperText: "Used only to project how many days a shipment's tracked hours will take.", value: String(laborMaxHoursPerDay), onChange: (e) => setLaborMaxHoursPerDay(parseFloat(e.target.value) || 0), type: "number", min: 0, max: 24 })] })] }) }), _jsx(TabsContent, { value: "emi", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); saveAllMutation.mutate(); }, className: "pt-[var(--appkit-space-4)]", spacing: "md", children: [_jsx(Text, { size: "xs", color: "muted", children: "A seller must also opt in via their own Payout Settings for EMI to appear at checkout on their items. See the \"How EMI Works\" public page for buyer-facing copy." }), _jsx(Toggle, { checked: emiEnabled, onChange: setEmiEnabled, label: "Enable EMI platform-wide" }), _jsxs(Grid, { cols: 2, gap: "md", children: [_jsx(Input, { label: "Minimum order value (\u20B9)", helperText: "A seller's cart subtotal must exceed this for EMI to appear as an option.", value: String(emiMinOrderValue), onChange: (e) => setEmiMinOrderValue(Math.round((parseFloat(e.target.value) || 0) * 100) / 100), type: "number", min: 0 }), _jsx(Input, { label: "Tenure options (months, comma-separated)", helperText: "e.g. 2,3,4,5,6", value: emiTenureOptionsText, onChange: (e) => setEmiTenureOptionsText(e.target.value) }), _jsx(Input, { label: "Token / down-payment (%)", helperText: "Collected upfront at checkout.", value: String(emiTokenPercent), onChange: (e) => setEmiTokenPercent(parseFloat(e.target.value) || 0), type: "number", min: 0, max: 100 }), _jsx(Input, { label: "Billing day (1\u201310)", helperText: "Day of month each installment is due.", value: String(emiBillingDay), onChange: (e) => setEmiBillingDay(parseFloat(e.target.value) || 1), type: "number", min: 1, max: 10 }), _jsx(Input, { label: "Surcharge (% of principal per month)", helperText: "The 'excess EMI fee' the buyer pays for spreading payment.", value: String(emiSurchargePercentPerMonth), onChange: (e) => setEmiSurchargePercentPerMonth(parseFloat(e.target.value) || 0), type: "number", min: 0 }), _jsx(Input, { label: "Seller's share of surcharge (%)", helperText: "The rest of the surcharge goes to the platform.", value: String(emiSurchargeSellerSharePercent), onChange: (e) => setEmiSurchargeSellerSharePercent(parseFloat(e.target.value) || 0), type: "number", min: 0, max: 100 })] })] }) }), _jsx(TabsContent, { value: "gst", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); saveAllMutation.mutate(); }, className: "pt-[var(--appkit-space-4)]", spacing: "md", children: [_jsx(Text, { size: "xs", color: "muted", children: "Required before enabling GST-inclusive checkout (P-8). Also set a GST rate + HSN code on each taxable product for the tax breakdown to appear." }), _jsx(Toggle, { checked: gstEnabled, onChange: setGstEnabled, label: "Enable GST on checkout" }), _jsxs(Grid, { cols: 2, gap: "md", children: [_jsx(Input, { label: "GSTIN", helperText: "15-character GST Identification Number.", value: gstin, onChange: (e) => setGstin(e.target.value), placeholder: "29AAAAA0000A1Z5", maxLength: 15 }), _jsx(Input, { label: "Legal name", helperText: "Registered business name for invoices.", value: gstLegalName, onChange: (e) => setGstLegalName(e.target.value), placeholder: "LetItRip Collectibles Pvt Ltd" })] }), _jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "sm", weight: "semibold", children: "Registered address" }), _jsx(Textarea, { value: gstAddress, onChange: (e) => setGstAddress(e.target.value), placeholder: "Registered business address for GST invoices\u2026", rows: 3 })] })] }) }), _jsx(TabsContent, { value: "integrations", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); saveAllMutation.mutate(); }, className: "pt-[var(--appkit-space-4)]", spacing: "md", children: [_jsx(Text, { size: "xs", color: "muted", children: "Keys are masked in transit and stored encrypted. Click Reveal to view." }), _jsxs(Stack, { gap: "sm", children: [_jsx(Text, { size: "sm", weight: "medium", color: "muted", children: "Razorpay" }), _jsxs(Grid, { cols: 2, gap: "md", children: [_jsx(MaskedInput, { label: "Razorpay Key ID", value: razorpayKeyId, onChange: setRazorpayKeyId, placeholder: "rzp_live_\u2026" }), _jsx(MaskedInput, { label: "Razorpay Secret", value: razorpaySecret, onChange: setRazorpaySecret, placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" })] })] }), _jsxs(Stack, { gap: "sm", children: [_jsx(Text, { size: "sm", weight: "medium", color: "muted", children: "SMTP / Email" }), _jsxs(Grid, { cols: 2, gap: "md", children: [_jsx(Input, { label: "SMTP host", value: smtpHost, onChange: (e) => setSmtpHost(e.target.value), placeholder: "smtp.sendgrid.net" }), _jsx(Input, { label: "SMTP port", value: smtpPort, onChange: (e) => setSmtpPort(e.target.value), type: "number", placeholder: "587" }), _jsx(Input, { label: "SMTP user", value: smtpUser, onChange: (e) => setSmtpUser(e.target.value), placeholder: "apikey" }), _jsx(MaskedInput, { label: "SMTP password", value: smtpPassword, onChange: setSmtpPassword, placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" })] }), _jsx(Input, { label: "From address", value: smtpFrom, onChange: (e) => setSmtpFrom(e.target.value), placeholder: "noreply@letitrip.in", type: "email" })] }), _jsxs(Stack, { gap: "sm", children: [_jsx(Text, { size: "sm", weight: "medium", color: "muted", children: "Analytics & Tracking" }), _jsxs(Grid, { cols: 2, gap: "md", children: [_jsx(Input, { label: "Google Analytics ID", value: gaMeasurementId, onChange: (e) => setGaMeasurementId(e.target.value), placeholder: "G-XXXXXXXXXX" }), _jsx(Input, { label: "Facebook Pixel ID", value: fbPixelId, onChange: (e) => setFbPixelId(e.target.value), placeholder: "XXXXXXXXXXXXXXXX" }), _jsx(Input, { label: "GTM Container ID", value: gtmContainerId, onChange: (e) => setGtmContainerId(e.target.value), placeholder: "GTM-XXXXXXX" })] })] }), _jsxs(Stack, { gap: "sm", children: [_jsx(Text, { size: "sm", weight: "medium", color: "muted", children: "Meta (Instagram & Facebook Social Feed)" }), _jsx(Text, { size: "xs", color: "muted", children: "Used by the Social Feed section to fetch Instagram and Facebook posts via Meta Graph API v19." }), _jsxs(Grid, { cols: 2, gap: "md", children: [_jsx(MaskedInput, { label: "Page Access Token", value: metaPageAccessToken, onChange: setMetaPageAccessToken, placeholder: "EAAxxxxxxx\u2026" }), _jsx(Input, { label: "Page ID (or handle)", value: metaPageId, onChange: (e) => setMetaPageId(e.target.value), placeholder: "letitrip" })] })] }), _jsxs(Stack, { gap: "sm", children: [_jsx(Text, { size: "sm", weight: "medium", color: "muted", children: "TikTok for Developers (Social Feed)" }), _jsx(Text, { size: "xs", color: "muted", children: "Client credentials + long-lived access token from TikTok for Developers. Used to list your account's public videos." }), _jsxs(Grid, { cols: 2, gap: "md", children: [_jsx(MaskedInput, { label: "Client Key", value: tiktokClientKey, onChange: setTiktokClientKey, placeholder: "aw\u2026" }), _jsx(MaskedInput, { label: "Client Secret", value: tiktokClientSecret, onChange: setTiktokClientSecret, placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" }), _jsx(MaskedInput, { label: "Access Token (long-lived)", value: tiktokAccessToken, onChange: setTiktokAccessToken, placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" })] })] }), _jsxs(Stack, { gap: "sm", children: [_jsx(Text, { size: "sm", weight: "medium", color: "muted", children: "DeviantArt OAuth2 (Social Feed)" }), _jsx(Text, { size: "xs", color: "muted", children: "Client credentials for DeviantArt gallery fetching (client-credentials OAuth2 flow \u2014 no user login required)." }), _jsxs(Grid, { cols: 2, gap: "md", children: [_jsx(MaskedInput, { label: "Client ID", value: deviantartClientId, onChange: setDeviantartClientId, placeholder: "1234" }), _jsx(MaskedInput, { label: "Client Secret", value: deviantartClientSecret, onChange: setDeviantartClientSecret, placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" })] })] })] }) }), _jsx(TabsContent, { value: "shipping", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); saveAllMutation.mutate(); }, className: "pt-[var(--appkit-space-4)]", spacing: "md", children: [_jsx(Text, { size: "sm", weight: "medium", color: "muted", children: "Payment methods" }), _jsx(Toggle, { label: "Razorpay (online card/UPI) enabled \u2014 disabled by default, manual payment is the default", checked: razorpayEnabled, onChange: setRazorpayEnabled }), _jsx(Toggle, { label: "Manual UPI/bank transfer enabled", checked: upiManualEnabled, onChange: setUpiManualEnabled }), _jsx(Toggle, { label: "Cash on delivery (COD) enabled", checked: codEnabled, onChange: setCodEnabled }), _jsx(Input, { label: "Free shipping threshold (\u20B9)", value: String(freeShippingThreshold), onChange: (e) => setFreeShippingThreshold(parseInt(e.target.value) || 0), type: "number", min: 0, helperText: "Orders above this amount get free shipping." }), _jsx(Select, { label: "Default carrier", options: CARRIER_OPTIONS, value: defaultCarrier, onValueChange: setDefaultCarrier }), _jsx(Input, { label: "Max delivery radius (km, 0 = no limit)", value: String(maxDeliveryRadius), onChange: (e) => setMaxDeliveryRadius(parseInt(e.target.value) || 0), type: "number", min: 0 })] }) }), _jsx(TabsContent, { value: "auction", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); saveAllMutation.mutate(); }, className: "pt-[var(--appkit-space-4)]", spacing: "md", children: [_jsx(Input, { label: "Minimum bid increment (\u20B9)", value: String(minBidIncrement), onChange: (e) => setMinBidIncrement(parseInt(e.target.value) || 0), type: "number", min: 1, helperText: "Global default \u2014 individual auctions may override." }), _jsx(Input, { label: "Auto-extend window (minutes before end)", value: String(autoExtendWindow), onChange: (e) => setAutoExtendWindow(parseInt(e.target.value) || 0), type: "number", min: 0, helperText: "Extend auction end time if a bid arrives within this window." }), _jsx(Input, { label: "Settlement grace period (hours)", value: String(settlementGrace), onChange: (e) => setSettlementGrace(parseInt(e.target.value) || 0), type: "number", min: 1, helperText: "Time winner has to pay before the auction is re-listed." })] }) }), _jsx(TabsContent, { value: "limits", children: _jsx(Form, { onSubmit: (e) => { e.preventDefault(); saveAllMutation.mutate(); }, className: "pt-[var(--appkit-space-4)]", spacing: "md", children: _jsxs(Grid, { cols: 2, gap: "md", children: [_jsx(Input, { label: "Max products per store", value: String(maxProductsPerStore), onChange: (e) => setMaxProductsPerStore(parseInt(e.target.value) || 0), type: "number", min: 1 }), _jsx(Input, { label: "Max images per product", value: String(maxImagesPerProduct), onChange: (e) => setMaxImagesPerProduct(parseInt(e.target.value) || 0), type: "number", min: 1 }), _jsx(Input, { label: "Max video size (MB)", value: String(maxVideoSizeMb), onChange: (e) => setMaxVideoSizeMb(parseInt(e.target.value) || 0), type: "number", min: 1 }), _jsx(Input, { label: "Max custom fields per product", value: String(maxCustomFields), onChange: (e) => setMaxCustomFields(parseInt(e.target.value) || 0), type: "number", min: 0 }), _jsx(Input, { label: "Max custom sections per product", value: String(maxCustomSections), onChange: (e) => setMaxCustomSections(parseInt(e.target.value) || 0), type: "number", min: 0 }), _jsx(Input, { label: "Order cancellation window (hours)", value: String(orderCancelWindow), onChange: (e) => setOrderCancelWindow(parseInt(e.target.value) || 0), type: "number", min: 0 })] }) }) }), _jsx(TabsContent, { value: "whatsapp", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); saveAllMutation.mutate(); }, className: "pt-[var(--appkit-space-4)]", spacing: "md", children: [_jsx(Text, { size: "xs", color: "muted", children: "Platform-level WhatsApp Business Cloud API credentials. Used for automated purchase announcements to admin numbers when orders are placed. Store owners configure their own credentials in Store \u2192 WhatsApp." }), _jsx(Input, { label: "Phone Number ID", value: waPhoneNumberId, onChange: (e) => setWaPhoneNumberId(e.target.value), placeholder: "987654321098765", helperText: "From Meta for Developers \u2192 App \u2192 WhatsApp \u2192 API Setup" }), _jsx(MaskedInput, { label: "Cloud API System User Token", value: waCloudApiToken, onChange: setWaCloudApiToken, placeholder: "EAAxxxxxxxx\u2026", helperText: "Long-lived system user access token with WhatsApp Business permissions" }), _jsx(Input, { label: "Admin Notify Numbers", value: waAdminNotifyNumbers, onChange: (e) => setWaAdminNotifyNumbers(e.target.value), placeholder: "919876543210,918765432109", helperText: "Comma-separated, digits-only, include country code. These receive a WhatsApp message when any order is placed." })] }) }), _jsx(TabsContent, { value: "notifications", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); saveAllMutation.mutate(); }, className: "pt-[var(--appkit-space-4)]", spacing: "lg", children: [_jsx(Text, { size: "xs", color: "muted", children: "In-app notifications are always on. Enable external channels below to let the platform fan out to email, WhatsApp, or SMS. Users can further restrict which types they receive." }), _jsxs(Stack, { gap: "xs", surface: "muted", rounded: "lg", border: "default", padding: "md", children: [_jsxs(Row, { justify: "between", gap: "sm", children: [_jsx(Text, { size: "sm", weight: "medium", color: "muted", children: "In-app (notification bell)" }), _jsx(Span, { color: "success", surface: "success-surface", size: "xs", weight: "semibold", rounded: "full", padding: "pill-xs", children: "Always on" })] }), _jsx(Text, { size: "xs", color: "muted", children: "Displayed in the notification bell and inbox. Cannot be disabled." })] }), _jsxs(Stack, { gap: "md", rounded: "lg", border: "default", padding: "md", children: [_jsx(Toggle, { label: "Email notifications", checked: notifEmailEnabled, onChange: setNotifEmailEnabled }), notifEmailEnabled && (_jsxs(Stack, { gap: "md", className: NOTIF_CHANNEL_INDENT, children: [_jsx(Select, { label: "Minimum priority to send email", options: PRIORITY_OPTIONS, value: notifEmailMinPriority, onValueChange: setNotifEmailMinPriority }), _jsx(Text, { size: "xs", weight: "medium", color: "muted", className: "pt-[0.25rem]", children: "Resend API (for transactional email)" }), _jsx(MaskedInput, { label: "Resend API Key", value: resendApiKey, onChange: setResendApiKey, placeholder: "re_live_\u2026", helperText: "Get your key at resend.com \u2014 used for all transactional notifications." }), _jsxs(Grid, { cols: 2, gap: "md", children: [_jsx(Input, { label: "From email", value: notifFromEmail, onChange: (e) => setNotifFromEmail(e.target.value), placeholder: "noreply@letitrip.in", type: "email" }), _jsx(Input, { label: "From name", value: notifFromName, onChange: (e) => setNotifFromName(e.target.value), placeholder: "LetItRip" })] })] }))] }), _jsxs(Stack, { gap: "md", rounded: "lg", border: "default", padding: "md", children: [_jsx(Toggle, { label: "WhatsApp notifications", checked: notifWhatsappEnabled, onChange: setNotifWhatsappEnabled }), notifWhatsappEnabled && (_jsxs(Stack, { gap: "md", className: NOTIF_CHANNEL_INDENT, children: [_jsx(Select, { label: "Minimum priority to send WhatsApp", options: PRIORITY_OPTIONS, value: notifWhatsappMinPriority, onValueChange: setNotifWhatsappMinPriority }), _jsx(Toggle, { label: "Enable WhatsApp OTP (for login and verification)", checked: notifWhatsappOtpEnabled, onChange: setNotifWhatsappOtpEnabled }), _jsx(Text, { size: "xs", color: "muted", children: "WhatsApp credentials are configured in the WhatsApp tab (\u246C). OTP messages use the same phone number." })] }))] }), _jsxs(Stack, { gap: "md", rounded: "lg", border: "default", padding: "md", children: [_jsx(Toggle, { label: "SMS notifications", checked: notifSmsEnabled, onChange: setNotifSmsEnabled }), notifSmsEnabled && (_jsxs(Stack, { gap: "md", className: NOTIF_CHANNEL_INDENT, children: [_jsx(Select, { label: "Minimum priority to send SMS", options: PRIORITY_OPTIONS, value: notifSmsMinPriority, onValueChange: setNotifSmsMinPriority }), _jsx(Text, { size: "xs", color: "muted", children: "SMS gateway credentials (e.g. Twilio, MSG91) can be configured in the Integrations tab once an SMS provider is connected." })] }))] })] }) }), _jsx(TabsContent, { value: "legal", children: _jsx(Form, { onSubmit: (e) => { e.preventDefault(); saveAllMutation.mutate(); }, className: "pt-[var(--appkit-space-4)]", spacing: "md", children: [
624
+ }, className: "pt-[var(--appkit-space-4)]", spacing: "md", children: _jsx(ThemeManagerView, { value: themeRegistry, onChange: setThemeRegistry, previewOrigin: "/" }) }) }), _jsx(TabsContent, { value: "announcement", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); saveAllMutation.mutate(); }, className: "pt-[var(--appkit-space-4)]", spacing: "md", children: [_jsx(Toggle, { label: "Show announcement bar", checked: announcementEnabled, onChange: setAnnouncementEnabled }), _jsx(Input, { label: "Announcement text", value: announcementText, onChange: (e) => setAnnouncementText(e.target.value), placeholder: "\uD83C\uDF89 Free shipping on orders \u20B9999+", disabled: !announcementEnabled }), _jsx(Input, { label: "Link URL (optional)", value: announcementLink, onChange: (e) => setAnnouncementLink(e.target.value), placeholder: String(ROUTES.PUBLIC.PRODUCTS), disabled: !announcementEnabled }), _jsxs(Stack, { gap: "none", children: [_jsx(Text, { size: "sm", weight: "medium", color: "muted", className: "mb-1", children: "Background color" }), _jsx(Input, { type: "color", value: announcementBg || "#1d4ed8", onChange: (e) => setAnnouncementBg(e.target.value), className: "h-10 w-32 cursor-pointer", bare: true, disabled: !announcementEnabled }), " "] })] }) }), _jsx(TabsContent, { value: "seo", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); saveAllMutation.mutate(); }, className: "pt-[var(--appkit-space-4)]", spacing: "md", children: [_jsx(Input, { label: "Default meta title", value: seoTitle, onChange: (e) => setSeoTitle(e.target.value), placeholder: "LetItRip \u2014 Buy, Sell & Auction Collectibles in India", maxLength: 60, helperText: "Max 60 chars. Use {page} token for dynamic insertion." }), _jsx(Input, { label: "Default meta description", value: seoDescription, onChange: (e) => setSeoDescription(e.target.value), placeholder: "India's largest collectibles marketplace\u2026", maxLength: 160, helperText: "Max 160 chars." }), _jsx(ImageUpload, { label: "Default OG image", currentImage: seoOgImage, onUpload: (file) => upload(file, "store"), onChange: setSeoOgImage }), _jsx(Input, { label: "Canonical base URL", value: canonicalUrl, onChange: (e) => setCanonicalUrl(e.target.value), placeholder: "https://letitrip.in" }), _jsx(Toggle, { label: "Robots noindex (disables search indexing \u2014 use carefully)", checked: seoNoIndex, onChange: setSeoNoIndex })] }) }), _jsx(TabsContent, { value: "contact", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); saveAllMutation.mutate(); }, className: "pt-[var(--appkit-space-4)]", spacing: "md", children: [_jsxs(Grid, { cols: 2, gap: "md", children: [_jsx(Input, { label: "Support email", value: supportEmail, onChange: (e) => setSupportEmail(e.target.value), type: "email", placeholder: "support@letitrip.in" }), _jsx(Input, { label: "Support phone", value: supportPhone, onChange: (e) => setSupportPhone(e.target.value), placeholder: "+91 XXXXX XXXXX" })] }), _jsx(Input, { label: "Physical address", value: supportAddress, onChange: (e) => setSupportAddress(e.target.value), placeholder: "Mumbai, Maharashtra, India" }), _jsx(Input, { label: "Support hours", value: supportHours, onChange: (e) => setSupportHours(e.target.value), placeholder: "Mon\u2013Fri, 10 AM \u2013 6 PM IST" }), _jsx(Text, { className: "pt-[0.5rem]", color: "muted", size: "sm", weight: "medium", children: "Social links" }), _jsxs(Grid, { cols: 2, gap: "md", children: [_jsx(Input, { label: "Instagram URL", value: instagram, onChange: (e) => setInstagram(e.target.value), placeholder: "https://instagram.com/letitrip" }), _jsx(Input, { label: "Twitter / X URL", value: twitter, onChange: (e) => setTwitter(e.target.value), placeholder: "https://twitter.com/letitrip" }), _jsx(Input, { label: "Facebook URL", value: facebook, onChange: (e) => setFacebook(e.target.value), placeholder: "https://facebook.com/letitrip" }), _jsx(Input, { label: "YouTube URL", value: youtube, onChange: (e) => setYoutube(e.target.value), placeholder: "https://youtube.com/@letitrip" }), _jsx(Input, { label: "WhatsApp number", value: whatsapp, onChange: (e) => setWhatsapp(e.target.value), placeholder: "+91XXXXXXXXXX" }), _jsx(Input, { label: "LinkedIn URL", value: linkedin, onChange: (e) => setLinkedin(e.target.value), placeholder: "https://linkedin.com/company/letitrip" }), _jsx(Input, { label: "Pinterest URL", value: pinterest, onChange: (e) => setPinterest(e.target.value), placeholder: "https://pinterest.com/letitrip" })] })] }) }), _jsx(TabsContent, { value: "watermark", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); saveAllMutation.mutate(); }, className: "pt-[var(--appkit-space-4)]", spacing: "md", children: [_jsx(Select, { label: "Watermark type", options: [{ label: "Text", value: "text" }, { label: "Image", value: "image" }], value: watermarkType, onValueChange: (v) => setWatermarkType(v) }), watermarkType === "text" ? (_jsx(Input, { label: "Watermark text", value: watermarkText, onChange: (e) => setWatermarkText(e.target.value), placeholder: "letitrip.in" })) : (_jsx(ImageUpload, { label: "Watermark image", currentImage: watermarkImageUrl, onUpload: (file) => upload(file, "store"), onChange: setWatermarkImageUrl })), _jsx(Slider, { label: `Size — ${watermarkSize}% of image width`, value: watermarkSize, onChange: setWatermarkSize, min: 5, max: 100, step: 5 }), _jsx(Slider, { label: `Opacity — ${watermarkOpacity}%`, value: watermarkOpacity, onChange: setWatermarkOpacity, min: 5, max: 100, step: 5 }), _jsxs(Stack, { gap: "xs", surface: "muted", rounded: "lg", border: "default", padding: "md", children: [_jsx(Text, { size: "xs", color: "muted", children: "Preview (text watermark only)" }), _jsx(Row, { surface: "default", justify: "end", align: "end", className: `relative h-32 ${__O.hidden}`, rounded: "default", children: _jsx(Span, { ref: watermarkPreviewRef, weight: "medium", color: "faint", padding: "1", className: "select-none", children: watermarkText }) })] })] }) }), _jsx(TabsContent, { value: "fees", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); saveAllMutation.mutate(); }, className: "pt-[var(--appkit-space-4)]", spacing: "md", children: [_jsxs(Grid, { cols: 2, gap: "md", children: [_jsx(Input, { label: "Platform fee \u2014 our cut (%)", helperText: "% charged on order value. Buyer pays this.", value: String(platformFeePercent), onChange: (e) => setPlatformFeePercent(parseFloat(e.target.value) || 0), type: "number", min: 0, max: 100, step: 0.1 }), _jsx(Input, { label: "GST on platform fee (%)", helperText: "Applied to our fee only (not full order). Usually 18%.", value: String(gstPercent), onChange: (e) => setGstPercent(parseFloat(e.target.value) || 0), type: "number", min: 0, max: 100, step: 0.1 }), _jsx(Input, { label: "Razorpay gateway cost (%)", helperText: "Gateway's own fee \u2014 absorbed by platform, not passed through.", value: String(gatewayFeePercent), onChange: (e) => setGatewayFeePercent(parseFloat(e.target.value) || 0), type: "number", min: 0, max: 10, step: 0.01 }), _jsx(Input, { label: "Minimum transaction fee (\u20B9)", helperText: "Per-transaction floor. Total charge will never be below base + this.", value: String(minimumTransactionFee), onChange: (e) => setMinimumTransactionFee(parseFloat(e.target.value) || 0), type: "number", min: 0, step: 0.01 }), _jsx(Input, { label: "Seller payout hold (days)", value: String(payoutHoldDays), onChange: (e) => setPayoutHoldDays(parseInt(e.target.value) || 0), type: "number", min: 0 }), _jsx(Input, { label: "Minimum payout amount (\u20B9)", value: String(minPayoutAmount), onChange: (e) => setMinPayoutAmount(parseInt(e.target.value) || 0), type: "number", min: 0 }), _jsx(Input, { label: "Auction listing fee (\u20B9)", value: String(auctionListingFee), onChange: (e) => setAuctionListingFee(parseInt(e.target.value) || 0), type: "number", min: 0 }), _jsx(Input, { label: "Pre-order listing fee (\u20B9)", value: String(preOrderListingFee), onChange: (e) => setPreOrderListingFee(parseInt(e.target.value) || 0), type: "number", min: 0 }), _jsx(Input, { label: "Featured slot fee (\u20B9)", value: String(featuredSlotFee), onChange: (e) => setFeaturedSlotFee(parseInt(e.target.value) || 0), type: "number", min: 0 }), _jsx(Input, { label: "Promoted slot fee (\u20B9)", value: String(promotedSlotFee), onChange: (e) => setPromotedSlotFee(parseInt(e.target.value) || 0), type: "number", min: 0 }), _jsx(Input, { label: "COD deposit (%)", helperText: "% of order collected upfront on COD orders; remainder paid on delivery.", value: String(codDepositPercent), onChange: (e) => setCodDepositPercent(parseFloat(e.target.value) || 0), type: "number", min: 0, max: 100, step: 0.1 })] }), _jsx(Toggle, { checked: whatsappNotifyFeeEnabled, onChange: setWhatsappNotifyFeeEnabled, label: "Offer the WhatsApp order-updates addon at checkout" }), _jsx(Grid, { cols: 2, gap: "md", children: _jsx(Input, { label: "WhatsApp addon fee (\u20B9)", helperText: "Flat fee charged to the buyer when they opt in. Requires WhatsApp credentials + at least one approved template \u2014 see the WhatsApp tab.", value: String(whatsappNotifyFee), onChange: (e) => setWhatsappNotifyFee(parseFloat(e.target.value) || 0), type: "number", min: 0, disabled: !whatsappNotifyFeeEnabled }) }), _jsx(Toggle, { checked: giftWrapFeeEnabled, onChange: setGiftWrapFeeEnabled, label: "Offer the gift-wrap addon at checkout" }), _jsx(Grid, { cols: 2, gap: "md", children: _jsx(Input, { label: "Gift wrap fee (\u20B9)", helperText: "Flat fee charged to the buyer when they opt in.", value: String(giftWrapFee), onChange: (e) => setGiftWrapFee(parseFloat(e.target.value) || 0), type: "number", min: 0, disabled: !giftWrapFeeEnabled }) }), _jsx(Toggle, { checked: shipmentProtectionFeeEnabled, onChange: setShipmentProtectionFeeEnabled, label: "Offer the shipment-protection addon at checkout" }), _jsxs(Grid, { cols: 2, gap: "md", children: [_jsx(Input, { label: "Shipment protection (%)", helperText: "% of order subtotal, charged when the buyer opts in.", value: String(shipmentProtectionFeePercent), onChange: (e) => setShipmentProtectionFeePercent(parseFloat(e.target.value) || 0), type: "number", min: 0, max: 100, step: 0.1, disabled: !shipmentProtectionFeeEnabled }), _jsx(Input, { label: "Shipment protection minimum (\u20B9)", helperText: "Floor for the shipment-protection fee.", value: String(shipmentProtectionFeeMin), onChange: (e) => setShipmentProtectionFeeMin(parseFloat(e.target.value) || 0), type: "number", min: 0, disabled: !shipmentProtectionFeeEnabled })] })] }) }), _jsx(TabsContent, { value: "procurement", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); saveAllMutation.mutate(); }, className: "pt-[var(--appkit-space-4)]", spacing: "md", children: [_jsx(Text, { size: "xs", color: "muted", children: "Used to compute each procurement shipment's labor cost (hours spent \u00D7 hourly rate) and its estimated processing time (hours spent \u00F7 max hours/day)." }), _jsxs(Grid, { cols: 2, gap: "md", children: [_jsx(Input, { label: "Hourly rate (\u20B9)", helperText: "Your effective hourly wage for sorting/categorizing/listing a shipment.", value: String(laborHourlyRate), onChange: (e) => setLaborHourlyRate(Math.round((parseFloat(e.target.value) || 0) * 100) / 100), type: "number", min: 0 }), _jsx(Input, { label: "Max hours per day", helperText: "Used only to project how many days a shipment's tracked hours will take.", value: String(laborMaxHoursPerDay), onChange: (e) => setLaborMaxHoursPerDay(parseFloat(e.target.value) || 0), type: "number", min: 0, max: 24 })] })] }) }), _jsx(TabsContent, { value: "emi", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); saveAllMutation.mutate(); }, className: "pt-[var(--appkit-space-4)]", spacing: "md", children: [_jsx(Text, { size: "xs", color: "muted", children: "A seller must also opt in via their own Payout Settings for EMI to appear at checkout on their items. See the \"How EMI Works\" public page for buyer-facing copy." }), _jsx(Toggle, { checked: emiEnabled, onChange: setEmiEnabled, label: "Enable EMI platform-wide" }), _jsxs(Grid, { cols: 2, gap: "md", children: [_jsx(Input, { label: "Minimum order value (\u20B9)", helperText: "A seller's cart subtotal must exceed this for EMI to appear as an option.", value: String(emiMinOrderValue), onChange: (e) => setEmiMinOrderValue(Math.round((parseFloat(e.target.value) || 0) * 100) / 100), type: "number", min: 0 }), _jsx(Input, { label: "Tenure options (months, comma-separated)", helperText: "e.g. 2,3,4,5,6", value: emiTenureOptionsText, onChange: (e) => setEmiTenureOptionsText(e.target.value) }), _jsx(Input, { label: "Token / down-payment (%)", helperText: "Collected upfront at checkout.", value: String(emiTokenPercent), onChange: (e) => setEmiTokenPercent(parseFloat(e.target.value) || 0), type: "number", min: 0, max: 100 }), _jsx(Input, { label: "Billing day (1\u201310)", helperText: "Day of month each installment is due.", value: String(emiBillingDay), onChange: (e) => setEmiBillingDay(parseFloat(e.target.value) || 1), type: "number", min: 1, max: 10 }), _jsx(Input, { label: "Surcharge (% of principal per month)", helperText: "The 'excess EMI fee' the buyer pays for spreading payment.", value: String(emiSurchargePercentPerMonth), onChange: (e) => setEmiSurchargePercentPerMonth(parseFloat(e.target.value) || 0), type: "number", min: 0 }), _jsx(Input, { label: "Seller's share of surcharge (%)", helperText: "The rest of the surcharge goes to the platform.", value: String(emiSurchargeSellerSharePercent), onChange: (e) => setEmiSurchargeSellerSharePercent(parseFloat(e.target.value) || 0), type: "number", min: 0, max: 100 })] })] }) }), _jsx(TabsContent, { value: "gst", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); saveAllMutation.mutate(); }, className: "pt-[var(--appkit-space-4)]", spacing: "md", children: [_jsx(Text, { size: "xs", color: "muted", children: "Required before enabling GST-inclusive checkout (P-8). Also set a GST rate + HSN code on each taxable product for the tax breakdown to appear." }), _jsx(Toggle, { checked: gstEnabled, onChange: setGstEnabled, label: "Enable GST on checkout" }), _jsxs(Grid, { cols: 2, gap: "md", children: [_jsx(Input, { label: "GSTIN", helperText: "15-character GST Identification Number.", value: gstin, onChange: (e) => setGstin(e.target.value), placeholder: "29AAAAA0000A1Z5", maxLength: 15 }), _jsx(Input, { label: "Legal name", helperText: "Registered business name for invoices.", value: gstLegalName, onChange: (e) => setGstLegalName(e.target.value), placeholder: "LetItRip Collectibles Pvt Ltd" })] }), _jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "sm", weight: "semibold", children: "Registered address" }), _jsx(Textarea, { value: gstAddress, onChange: (e) => setGstAddress(e.target.value), placeholder: "Registered business address for GST invoices\u2026", rows: 3 })] })] }) }), _jsx(TabsContent, { value: "featureflags", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); saveAllMutation.mutate(); }, className: "pt-[var(--appkit-space-4)]", spacing: "lg", children: [_jsx(Text, { size: "xs", color: "muted", children: "Site-wide platform feature toggles. Disabling a flag hides that feature's nav entries and pages \u2014 existing data is untouched, it just becomes unreachable until re-enabled." }), _jsx(Grid, { cols: 2, gap: "md", children: FEATURE_FLAG_META.map((flag) => (_jsxs(Stack, { gap: "xs", children: [_jsx(Toggle, { label: `${flag.icon} ${flag.labelKey}`, checked: featureFlags[flag.key] ?? false, onChange: (v) => setFeatureFlags((prev) => ({ ...prev, [flag.key]: v })) }), _jsx(Text, { size: "xs", color: "muted", children: flag.descKey })] }, flag.key))) }), _jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "sm", weight: "semibold", children: "Listing types" }), _jsx(Text, { size: "xs", color: "muted", children: "Disabled types are hidden from listings and reject create/add-to-cart." }), _jsx(Grid, { cols: 2, gap: "sm", children: LISTING_TYPE_KEYS.map((key) => (_jsx(Toggle, { label: key, checked: listingTypeFlags[key] ?? true, onChange: (v) => setListingTypeFlags((prev) => ({ ...prev, [key]: v })) }, key))) })] }), _jsxs(Stack, { gap: "xs", children: [_jsx(Text, { size: "sm", weight: "semibold", children: "Category types" }), _jsx(Grid, { cols: 2, gap: "sm", children: CATEGORY_TYPE_KEYS.map((key) => (_jsx(Toggle, { label: key, checked: categoryTypeFlags[key] ?? true, onChange: (v) => setCategoryTypeFlags((prev) => ({ ...prev, [key]: v })) }, key))) })] })] }) }), _jsx(TabsContent, { value: "integrations", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); saveAllMutation.mutate(); }, className: "pt-[var(--appkit-space-4)]", spacing: "md", children: [_jsx(Text, { size: "xs", color: "muted", children: "Keys are masked in transit and stored encrypted. Click Reveal to view." }), _jsxs(Stack, { gap: "sm", children: [_jsx(Text, { size: "sm", weight: "medium", color: "muted", children: "Razorpay" }), _jsxs(Grid, { cols: 2, gap: "md", children: [_jsx(MaskedInput, { label: "Razorpay Key ID", value: razorpayKeyId, onChange: setRazorpayKeyId, placeholder: "rzp_live_\u2026" }), _jsx(MaskedInput, { label: "Razorpay Secret", value: razorpaySecret, onChange: setRazorpaySecret, placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" })] })] }), _jsxs(Stack, { gap: "sm", children: [_jsx(Text, { size: "sm", weight: "medium", color: "muted", children: "SMTP / Email" }), _jsxs(Grid, { cols: 2, gap: "md", children: [_jsx(Input, { label: "SMTP host", value: smtpHost, onChange: (e) => setSmtpHost(e.target.value), placeholder: "smtp.sendgrid.net" }), _jsx(Input, { label: "SMTP port", value: smtpPort, onChange: (e) => setSmtpPort(e.target.value), type: "number", placeholder: "587" }), _jsx(Input, { label: "SMTP user", value: smtpUser, onChange: (e) => setSmtpUser(e.target.value), placeholder: "apikey" }), _jsx(MaskedInput, { label: "SMTP password", value: smtpPassword, onChange: setSmtpPassword, placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" })] }), _jsx(Input, { label: "From address", value: smtpFrom, onChange: (e) => setSmtpFrom(e.target.value), placeholder: "noreply@letitrip.in", type: "email" })] }), _jsxs(Stack, { gap: "sm", children: [_jsx(Text, { size: "sm", weight: "medium", color: "muted", children: "Analytics & Tracking" }), _jsxs(Grid, { cols: 2, gap: "md", children: [_jsx(Input, { label: "Google Analytics ID", value: gaMeasurementId, onChange: (e) => setGaMeasurementId(e.target.value), placeholder: "G-XXXXXXXXXX" }), _jsx(Input, { label: "Facebook Pixel ID", value: fbPixelId, onChange: (e) => setFbPixelId(e.target.value), placeholder: "XXXXXXXXXXXXXXXX" }), _jsx(Input, { label: "GTM Container ID", value: gtmContainerId, onChange: (e) => setGtmContainerId(e.target.value), placeholder: "GTM-XXXXXXX" })] })] }), _jsxs(Stack, { gap: "sm", children: [_jsx(Text, { size: "sm", weight: "medium", color: "muted", children: "Meta (Instagram & Facebook Social Feed)" }), _jsx(Text, { size: "xs", color: "muted", children: "Used by the Social Feed section to fetch Instagram and Facebook posts via Meta Graph API v19." }), _jsxs(Grid, { cols: 2, gap: "md", children: [_jsx(MaskedInput, { label: "Page Access Token", value: metaPageAccessToken, onChange: setMetaPageAccessToken, placeholder: "EAAxxxxxxx\u2026" }), _jsx(Input, { label: "Page ID (or handle)", value: metaPageId, onChange: (e) => setMetaPageId(e.target.value), placeholder: "letitrip" })] })] }), _jsxs(Stack, { gap: "sm", children: [_jsx(Text, { size: "sm", weight: "medium", color: "muted", children: "TikTok for Developers (Social Feed)" }), _jsx(Text, { size: "xs", color: "muted", children: "Client credentials + long-lived access token from TikTok for Developers. Used to list your account's public videos." }), _jsxs(Grid, { cols: 2, gap: "md", children: [_jsx(MaskedInput, { label: "Client Key", value: tiktokClientKey, onChange: setTiktokClientKey, placeholder: "aw\u2026" }), _jsx(MaskedInput, { label: "Client Secret", value: tiktokClientSecret, onChange: setTiktokClientSecret, placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" }), _jsx(MaskedInput, { label: "Access Token (long-lived)", value: tiktokAccessToken, onChange: setTiktokAccessToken, placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" })] })] }), _jsxs(Stack, { gap: "sm", children: [_jsx(Text, { size: "sm", weight: "medium", color: "muted", children: "DeviantArt OAuth2 (Social Feed)" }), _jsx(Text, { size: "xs", color: "muted", children: "Client credentials for DeviantArt gallery fetching (client-credentials OAuth2 flow \u2014 no user login required)." }), _jsxs(Grid, { cols: 2, gap: "md", children: [_jsx(MaskedInput, { label: "Client ID", value: deviantartClientId, onChange: setDeviantartClientId, placeholder: "1234" }), _jsx(MaskedInput, { label: "Client Secret", value: deviantartClientSecret, onChange: setDeviantartClientSecret, placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" })] })] })] }) }), _jsx(TabsContent, { value: "shipping", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); saveAllMutation.mutate(); }, className: "pt-[var(--appkit-space-4)]", spacing: "md", children: [_jsx(Text, { size: "sm", weight: "medium", color: "muted", children: "Payment methods" }), _jsx(Toggle, { label: "Razorpay (online card/UPI) enabled \u2014 disabled by default, manual payment is the default", checked: razorpayEnabled, onChange: setRazorpayEnabled }), _jsx(Toggle, { label: "Manual UPI/bank transfer enabled", checked: upiManualEnabled, onChange: setUpiManualEnabled }), _jsx(Toggle, { label: "Cash on delivery (COD) enabled", checked: codEnabled, onChange: setCodEnabled }), _jsx(Input, { label: "Free shipping threshold (\u20B9)", value: String(freeShippingThreshold), onChange: (e) => setFreeShippingThreshold(parseInt(e.target.value) || 0), type: "number", min: 0, helperText: "Orders above this amount get free shipping." }), _jsx(Select, { label: "Default carrier", options: CARRIER_OPTIONS, value: defaultCarrier, onValueChange: setDefaultCarrier }), _jsx(Input, { label: "Max delivery radius (km, 0 = no limit)", value: String(maxDeliveryRadius), onChange: (e) => setMaxDeliveryRadius(parseInt(e.target.value) || 0), type: "number", min: 0 }), _jsx(Input, { label: "High-value checkout OTP threshold (\u20B9)", helperText: "Carts at or above this subtotal require an extra OTP verification step before payment (0 = disabled).", value: String(otpCheckoutThreshold), onChange: (e) => setOtpCheckoutThreshold(parseInt(e.target.value) || 0), type: "number", min: 0 }), _jsx(Text, { size: "sm", weight: "medium", color: "muted", className: "pt-[var(--appkit-space-2)]", children: "Seller shipping charge defaults" }), _jsxs(Grid, { cols: 2, gap: "md", children: [_jsx(Input, { label: "Seller shipping fixed (\u20B9)", helperText: "Flat shipping charge collected on the seller's behalf.", value: String(sellerShippingFixed), onChange: (e) => setSellerShippingFixed(parseFloat(e.target.value) || 0), type: "number", min: 0 }), _jsx(Input, { label: "Platform shipping (%)", helperText: "Platform's own shipping markup, as a % of order value.", value: String(platformShippingPercent), onChange: (e) => setPlatformShippingPercent(parseFloat(e.target.value) || 0), type: "number", min: 0, max: 100, step: 0.1 }), _jsx(Input, { label: "Platform shipping minimum (\u20B9)", helperText: "Floor for the platform shipping markup.", value: String(platformShippingFixedMin), onChange: (e) => setPlatformShippingFixedMin(parseFloat(e.target.value) || 0), type: "number", min: 0 })] })] }) }), _jsx(TabsContent, { value: "auction", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); saveAllMutation.mutate(); }, className: "pt-[var(--appkit-space-4)]", spacing: "md", children: [_jsx(Input, { label: "Minimum bid increment (\u20B9)", value: String(minBidIncrement), onChange: (e) => setMinBidIncrement(parseInt(e.target.value) || 0), type: "number", min: 1, helperText: "Global default \u2014 individual auctions may override." }), _jsx(Input, { label: "Auto-extend window (minutes before end)", value: String(autoExtendWindow), onChange: (e) => setAutoExtendWindow(parseInt(e.target.value) || 0), type: "number", min: 0, helperText: "Extend auction end time if a bid arrives within this window." }), _jsx(Input, { label: "Settlement grace period (hours)", value: String(settlementGrace), onChange: (e) => setSettlementGrace(parseInt(e.target.value) || 0), type: "number", min: 1, helperText: "Time winner has to pay before the auction is re-listed." })] }) }), _jsx(TabsContent, { value: "limits", children: _jsx(Form, { onSubmit: (e) => { e.preventDefault(); saveAllMutation.mutate(); }, className: "pt-[var(--appkit-space-4)]", spacing: "md", children: _jsxs(Grid, { cols: 2, gap: "md", children: [_jsx(Input, { label: "Max products per store", value: String(maxProductsPerStore), onChange: (e) => setMaxProductsPerStore(parseInt(e.target.value) || 0), type: "number", min: 1 }), _jsx(Input, { label: "Max images per product", value: String(maxImagesPerProduct), onChange: (e) => setMaxImagesPerProduct(parseInt(e.target.value) || 0), type: "number", min: 1 }), _jsx(Input, { label: "Max video size (MB)", value: String(maxVideoSizeMb), onChange: (e) => setMaxVideoSizeMb(parseInt(e.target.value) || 0), type: "number", min: 1 }), _jsx(Input, { label: "Max custom fields per product", value: String(maxCustomFields), onChange: (e) => setMaxCustomFields(parseInt(e.target.value) || 0), type: "number", min: 0 }), _jsx(Input, { label: "Max custom sections per product", value: String(maxCustomSections), onChange: (e) => setMaxCustomSections(parseInt(e.target.value) || 0), type: "number", min: 0 }), _jsx(Input, { label: "Order cancellation window (hours)", value: String(orderCancelWindow), onChange: (e) => setOrderCancelWindow(parseInt(e.target.value) || 0), type: "number", min: 0 })] }) }) }), _jsx(TabsContent, { value: "whatsapp", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); saveAllMutation.mutate(); }, className: "pt-[var(--appkit-space-4)]", spacing: "md", children: [_jsx(Text, { size: "xs", color: "muted", children: "Platform-level WhatsApp Business Cloud API credentials. Used for automated purchase announcements to admin numbers when orders are placed. Store owners configure their own credentials in Store \u2192 WhatsApp." }), _jsx(Input, { label: "Phone Number ID", value: waPhoneNumberId, onChange: (e) => setWaPhoneNumberId(e.target.value), placeholder: "987654321098765", helperText: "From Meta for Developers \u2192 App \u2192 WhatsApp \u2192 API Setup" }), _jsx(MaskedInput, { label: "Cloud API System User Token", value: waCloudApiToken, onChange: setWaCloudApiToken, placeholder: "EAAxxxxxxxx\u2026", helperText: "Long-lived system user access token with WhatsApp Business permissions" }), _jsx(Input, { label: "Admin Notify Numbers", value: waAdminNotifyNumbers, onChange: (e) => setWaAdminNotifyNumbers(e.target.value), placeholder: "919876543210,918765432109", helperText: "Comma-separated, digits-only, include country code. These receive a WhatsApp message when any order is placed." }), _jsx(Text, { size: "xs", color: "muted", children: "Approved Meta message templates for the buyer-facing WhatsApp order-updates addon (Fees tab). Meta rejects business-initiated free-text WhatsApp messages outside a 24h customer-service window \u2014 a real template name here is required for that notification type to actually deliver. Leave blank to skip WhatsApp for that type (in-app + email still fire)." }), _jsx(Input, { label: "Template language code", value: waTemplateLanguage, onChange: (e) => setWaTemplateLanguage(e.target.value), placeholder: "en", helperText: "BCP-47 code the templates below were approved in, e.g. en or en_US." }), _jsxs(Grid, { cols: 2, gap: "md", children: [_jsx(Input, { label: "Order placed template name", value: waTemplateOrderPlaced, onChange: (e) => setWaTemplateOrderPlaced(e.target.value), placeholder: "order_placed_update" }), _jsx(Input, { label: "Order confirmed template name", value: waTemplateOrderConfirmed, onChange: (e) => setWaTemplateOrderConfirmed(e.target.value), placeholder: "order_confirmed_update" }), _jsx(Input, { label: "Order shipped template name", value: waTemplateOrderShipped, onChange: (e) => setWaTemplateOrderShipped(e.target.value), placeholder: "order_shipped_update" }), _jsx(Input, { label: "Order delivered template name", value: waTemplateOrderDelivered, onChange: (e) => setWaTemplateOrderDelivered(e.target.value), placeholder: "order_delivered_update" }), _jsx(Input, { label: "Order cancelled template name", value: waTemplateOrderCancelled, onChange: (e) => setWaTemplateOrderCancelled(e.target.value), placeholder: "order_cancelled_update" }), _jsx(Input, { label: "Refund initiated template name", value: waTemplateRefundInitiated, onChange: (e) => setWaTemplateRefundInitiated(e.target.value), placeholder: "refund_initiated_update" })] })] }) }), _jsx(TabsContent, { value: "notifications", children: _jsxs(Form, { onSubmit: (e) => { e.preventDefault(); saveAllMutation.mutate(); }, className: "pt-[var(--appkit-space-4)]", spacing: "lg", children: [_jsx(Text, { size: "xs", color: "muted", children: "In-app notifications are always on. Enable external channels below to let the platform fan out to email, WhatsApp, or SMS. Users can further restrict which types they receive." }), _jsxs(Stack, { gap: "xs", surface: "muted", rounded: "lg", border: "default", padding: "md", children: [_jsxs(Row, { justify: "between", gap: "sm", children: [_jsx(Text, { size: "sm", weight: "medium", color: "muted", children: "In-app (notification bell)" }), _jsx(Span, { color: "success", surface: "success-surface", size: "xs", weight: "semibold", rounded: "full", padding: "pill-xs", children: "Always on" })] }), _jsx(Text, { size: "xs", color: "muted", children: "Displayed in the notification bell and inbox. Cannot be disabled." })] }), _jsxs(Stack, { gap: "md", rounded: "lg", border: "default", padding: "md", children: [_jsx(Toggle, { label: "Email notifications", checked: notifEmailEnabled, onChange: setNotifEmailEnabled }), notifEmailEnabled && (_jsxs(Stack, { gap: "md", className: NOTIF_CHANNEL_INDENT, children: [_jsx(Select, { label: "Minimum priority to send email", options: PRIORITY_OPTIONS, value: notifEmailMinPriority, onValueChange: setNotifEmailMinPriority }), _jsx(Text, { size: "xs", weight: "medium", color: "muted", className: "pt-[0.25rem]", children: "Resend API (for transactional email)" }), _jsx(MaskedInput, { label: "Resend API Key", value: resendApiKey, onChange: setResendApiKey, placeholder: "re_live_\u2026", helperText: "Get your key at resend.com \u2014 used for all transactional notifications." }), _jsxs(Grid, { cols: 2, gap: "md", children: [_jsx(Input, { label: "From email", value: notifFromEmail, onChange: (e) => setNotifFromEmail(e.target.value), placeholder: "noreply@letitrip.in", type: "email" }), _jsx(Input, { label: "From name", value: notifFromName, onChange: (e) => setNotifFromName(e.target.value), placeholder: "LetItRip" })] }), _jsx(Text, { size: "xs", weight: "medium", color: "muted", className: "pt-[0.25rem]", children: "Notification types (leave empty to send all types)" }), _jsx(PaginatedSelect, { multiple: true, options: NOTIF_TYPE_OPTIONS, value: notifEmailTypes, onChange: (values) => setNotifEmailTypes(values), placeholder: "All notification types" })] }))] }), _jsxs(Stack, { gap: "md", rounded: "lg", border: "default", padding: "md", children: [_jsx(Toggle, { label: "WhatsApp notifications", checked: notifWhatsappEnabled, onChange: setNotifWhatsappEnabled }), notifWhatsappEnabled && (_jsxs(Stack, { gap: "md", className: NOTIF_CHANNEL_INDENT, children: [_jsx(Select, { label: "Minimum priority to send WhatsApp", options: PRIORITY_OPTIONS, value: notifWhatsappMinPriority, onValueChange: setNotifWhatsappMinPriority }), _jsx(Toggle, { label: "Enable WhatsApp OTP (for login and verification)", checked: notifWhatsappOtpEnabled, onChange: setNotifWhatsappOtpEnabled }), _jsx(Text, { size: "xs", color: "muted", children: "WhatsApp credentials are configured in the WhatsApp tab (\u246C). OTP messages use the same phone number." }), _jsx(Text, { size: "xs", weight: "medium", color: "muted", className: "pt-[0.25rem]", children: "Notification types (leave empty to send all types)" }), _jsx(PaginatedSelect, { multiple: true, options: NOTIF_TYPE_OPTIONS, value: notifWhatsappTypes, onChange: (values) => setNotifWhatsappTypes(values), placeholder: "All notification types" })] }))] }), _jsxs(Stack, { gap: "md", rounded: "lg", border: "default", padding: "md", children: [_jsx(Toggle, { label: "SMS notifications", checked: notifSmsEnabled, onChange: setNotifSmsEnabled }), notifSmsEnabled && (_jsxs(Stack, { gap: "md", className: NOTIF_CHANNEL_INDENT, children: [_jsx(Select, { label: "Minimum priority to send SMS", options: PRIORITY_OPTIONS, value: notifSmsMinPriority, onValueChange: setNotifSmsMinPriority }), _jsx(Text, { size: "xs", color: "muted", children: "SMS gateway credentials (e.g. Twilio, MSG91) can be configured in the Integrations tab once an SMS provider is connected." })] }))] })] }) }), _jsx(TabsContent, { value: "legal", children: _jsx(Form, { onSubmit: (e) => { e.preventDefault(); saveAllMutation.mutate(); }, className: "pt-[var(--appkit-space-4)]", spacing: "md", children: [
506
625
  ["Terms of Service", termsHtml, setTermsHtml],
507
626
  ["Privacy Policy", privacyHtml, setPrivacyHtml],
508
627
  ["Refund Policy", refundHtml, setRefundHtml],
@@ -6,6 +6,7 @@ export interface AdminStoreEditorViewProps {
6
6
  storeName?: string;
7
7
  currentStatus?: string;
8
8
  currentIsVerified?: boolean;
9
+ currentIsFeatured?: boolean;
9
10
  currentCapabilities?: string[];
10
11
  }
11
- export declare function AdminStoreEditorView({ open, onClose, storeId, storeName, currentStatus, currentIsVerified, currentCapabilities, }: AdminStoreEditorViewProps): React.JSX.Element;
12
+ export declare function AdminStoreEditorView({ open, onClose, storeId, storeName, currentStatus, currentIsVerified, currentIsFeatured, currentCapabilities, }: AdminStoreEditorViewProps): React.JSX.Element;
@@ -48,12 +48,12 @@ const STATUS_OPTIONS = [
48
48
  { label: "Rejected", value: "rejected" },
49
49
  ];
50
50
  // --- Component ---------------------------------------------------------------
51
- export function AdminStoreEditorView({ open, onClose, storeId, storeName, currentStatus, currentIsVerified, currentCapabilities, }) {
51
+ export function AdminStoreEditorView({ open, onClose, storeId, storeName, currentStatus, currentIsVerified, currentIsFeatured, currentCapabilities, }) {
52
52
  const queryClient = useQueryClient();
53
53
  const { showToast } = useToast();
54
54
  const [storeStatus, setStoreStatus] = React.useState(currentStatus ?? "pending");
55
55
  const [adminNotes, setAdminNotes] = React.useState("");
56
- const [isFeatured, setIsFeatured] = React.useState(false);
56
+ const [isFeatured, setIsFeatured] = React.useState(currentIsFeatured ?? false);
57
57
  const [isVerified, setIsVerified] = React.useState(currentIsVerified ?? false);
58
58
  const [suspensionReason, setSuspensionReason] = React.useState("");
59
59
  const [capabilities, setCapabilities] = React.useState(new Set(currentCapabilities ?? ["suggest_brands", "create_coupons"]));
@@ -71,12 +71,12 @@ export function AdminStoreEditorView({ open, onClose, storeId, storeName, curren
71
71
  if (open) {
72
72
  setStoreStatus(currentStatus ?? "pending");
73
73
  setAdminNotes("");
74
- setIsFeatured(false);
74
+ setIsFeatured(currentIsFeatured ?? false);
75
75
  setIsVerified(currentIsVerified ?? false);
76
76
  setSuspensionReason("");
77
77
  setCapabilities(new Set(currentCapabilities ?? ["suggest_brands", "create_coupons"]));
78
78
  }
79
- }, [open, currentStatus, currentIsVerified, currentCapabilities]);
79
+ }, [open, currentStatus, currentIsVerified, currentIsFeatured, currentCapabilities]);
80
80
  const saveMutation = useApiMutation({
81
81
  mutationFn: async () => {
82
82
  await apiClient.patch(ADMIN_ENDPOINTS.STORE_BY_ID(storeId), {
@@ -109,7 +109,7 @@ export function AdminStoresView({ children, ...props }) {
109
109
  },
110
110
  renderFilterPanel: ({ pendingFilters, setPendingFilters }) => (_jsx(FilterChipGroup, { label: "Status", tabs: ADMIN_STORE_STATUS_TABS, value: pendingFilters.status ?? "", onChange: (id) => setPendingFilters((p) => ({ ...p, status: id })) })),
111
111
  };
112
- return (_jsxs(_Fragment, { children: [_jsx(DataListingView, { config: config }), _jsx(AdminStoreEditorView, { open: Boolean(editorRow), onClose: () => setEditorRow(null), storeId: editorRow?.id, storeName: editorRow?.primary, currentStatus: editorRow?.status?.toLowerCase(), currentIsVerified: Boolean(editorRow?._raw?.isVerified), currentCapabilities: Array.isArray(editorRow?._raw?.capabilities)
112
+ return (_jsxs(_Fragment, { children: [_jsx(DataListingView, { config: config }), _jsx(AdminStoreEditorView, { open: Boolean(editorRow), onClose: () => setEditorRow(null), storeId: editorRow?.id, storeName: editorRow?.primary, currentStatus: editorRow?.status?.toLowerCase(), currentIsVerified: Boolean(editorRow?._raw?.isVerified), currentIsFeatured: Boolean(editorRow?._raw?.isFeatured), currentCapabilities: Array.isArray(editorRow?._raw?.capabilities)
113
113
  ? editorRow._raw.capabilities
114
114
  : undefined })] }));
115
115
  }
@@ -2,7 +2,7 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { Code, useApiMutation } from "@mohasinac/appkit/client";
4
4
  import React from "react";
5
- import { useQueryClient } from "@tanstack/react-query";
5
+ import { useQuery, useQueryClient } from "@tanstack/react-query";
6
6
  import { Button, Div, FormActions, HorizontalRule, Input, Label, Row, Select, SideDrawer, Span, Stack, Text, Textarea, Toggle, useToast } from "../../../ui";
7
7
  import { apiClient } from "../../../http";
8
8
  import { ADMIN_ENDPOINTS, SUPPORT_ENDPOINTS } from "../../../constants/api-endpoints";
@@ -109,6 +109,24 @@ export function AdminSupportTicketDetailView({ open, onClose, ticketId, subject,
109
109
  const [storeIsFeatured, setStoreIsFeatured] = React.useState(false);
110
110
  const linkedStoreId = parties.storeId?.trim();
111
111
  const isStoreChangeRequest = category === "store_change_request";
112
+ // Seed the panel from the store's REAL current values, not hardcoded
113
+ // defaults — applyStoreChange below sends all three fields unconditionally,
114
+ // so an unseeded default would silently reset a real verified/featured
115
+ // store back to false/"active" on the very first unrelated save.
116
+ const storeQuery = useQuery({
117
+ queryKey: ["admin", "support-ticket-store-change", linkedStoreId],
118
+ queryFn: async () => {
119
+ const res = await apiClient.get(ADMIN_ENDPOINTS.STORE_BY_ID(linkedStoreId));
120
+ return (res?.data ?? res);
121
+ },
122
+ enabled: open && isStoreChangeRequest && !!linkedStoreId,
123
+ select: (data) => {
124
+ setStoreStatus(data.status ?? "active");
125
+ setStoreIsVerified(Boolean(data.isVerified));
126
+ setStoreIsFeatured(Boolean(data.isFeatured));
127
+ return data;
128
+ },
129
+ });
112
130
  const applyStoreChange = useApiMutation({
113
131
  mutationFn: async () => {
114
132
  if (!linkedStoreId)
@@ -247,7 +265,7 @@ export function AdminSupportTicketDetailView({ open, onClose, ticketId, subject,
247
265
  ["orderId", "Order ID"],
248
266
  ["productId", "Product slug"],
249
267
  ["bidId", "Bid ID"],
250
- ].map(([key, label]) => (_jsx(Input, { label: label, type: "text", value: parties[key] ?? "", onChange: (e) => setParties((p) => ({ ...p, [key]: e.target.value })), placeholder: label }, key)))] }), isOrderModificationRequest && (_jsx(OrderItemsPanel, { linkedOrderId: linkedOrderId, orderItemsOpen: orderItemsOpen, setOrderItemsOpen: setOrderItemsOpen, orderItems: orderItems, setOrderItems: setOrderItems, loadOrderItems: loadOrderItems, applyOrderItems: applyOrderItems })), isStoreChangeRequest && (_jsx(StoreChangePanel, { linkedStoreId: linkedStoreId, storeStatus: storeStatus, setStoreStatus: setStoreStatus, storeIsVerified: storeIsVerified, setStoreIsVerified: setStoreIsVerified, storeIsFeatured: storeIsFeatured, setStoreIsFeatured: setStoreIsFeatured, applyStoreChange: applyStoreChange })), isUnbanRequest && (_jsx(UnbanRequestPanel, { linkedUserId: linkedUserId, liftHardBan: liftHardBan, liftSoftBanTickets: liftSoftBanTickets })), _jsxs(FormActions, { align: "right", children: [_jsx(Button, { type: "button", variant: "secondary", onClick: onClose, children: "Cancel" }), _jsx(Button, { type: "button", isLoading: updateMutation.isPending, disabled: !ticketId || updateMutation.isPending, onClick: () => updateMutation.mutate(), children: "Save changes" })] })] }) }));
268
+ ].map(([key, label]) => (_jsx(Input, { label: label, type: "text", value: parties[key] ?? "", onChange: (e) => setParties((p) => ({ ...p, [key]: e.target.value })), placeholder: label }, key)))] }), isOrderModificationRequest && (_jsx(OrderItemsPanel, { linkedOrderId: linkedOrderId, orderItemsOpen: orderItemsOpen, setOrderItemsOpen: setOrderItemsOpen, orderItems: orderItems, setOrderItems: setOrderItems, loadOrderItems: loadOrderItems, applyOrderItems: applyOrderItems })), isStoreChangeRequest && (_jsx(StoreChangePanel, { linkedStoreId: linkedStoreId, storeStatus: storeStatus, setStoreStatus: setStoreStatus, storeIsVerified: storeIsVerified, setStoreIsVerified: setStoreIsVerified, storeIsFeatured: storeIsFeatured, setStoreIsFeatured: setStoreIsFeatured, applyStoreChange: applyStoreChange, isLoadingStore: storeQuery.isLoading })), isUnbanRequest && (_jsx(UnbanRequestPanel, { linkedUserId: linkedUserId, liftHardBan: liftHardBan, liftSoftBanTickets: liftSoftBanTickets })), _jsxs(FormActions, { align: "right", children: [_jsx(Button, { type: "button", variant: "secondary", onClick: onClose, children: "Cancel" }), _jsx(Button, { type: "button", isLoading: updateMutation.isPending, disabled: !ticketId || updateMutation.isPending, onClick: () => updateMutation.mutate(), children: "Save changes" })] })] }) }));
251
269
  }
252
270
  function OrderItemsPanel(props) {
253
271
  const { linkedOrderId, orderItemsOpen, setOrderItemsOpen, orderItems, setOrderItems, loadOrderItems, applyOrderItems, } = props;
@@ -258,13 +276,13 @@ function OrderItemsPanel(props) {
258
276
  return (_jsxs(Stack, { padding: "sm", className: "border border-info/40 bg-[var(--appkit-color-info-surface)]/40", gap: "sm", rounded: "lg", children: [_jsx(Text, { className: "text-info tracking-wide", size: "xs", weight: "semibold", transform: "uppercase", children: "Modify order items" }), linkedOrderId ? (_jsxs(_Fragment, { children: [_jsxs(Text, { size: "xs", color: "muted", children: ["Editing order: ", _jsx(Code, { className: "font-mono", children: linkedOrderId })] }), !orderItemsOpen ? (_jsx(Button, { type: "button", variant: "secondary", size: "sm", isLoading: loadOrderItems.isPending, disabled: loadOrderItems.isPending, onClick: () => loadOrderItems.mutate(), children: "Load current items" })) : (_jsxs(_Fragment, { children: [orderItems.length === 0 ? (_jsx(Text, { size: "xs", color: "muted", children: "Order has no items." })) : (_jsx(Stack, { gap: "sm", children: orderItems.map((it, idx) => (_jsxs(Row, { paddingY: "y-2xs", padding: "x-xs", rounded: "default", align: "center", gap: "sm", border: "default", children: [_jsxs(Div, { className: "flex-1 min-w-0", children: [_jsx(Text, { className: "truncate", size: "xs", weight: "medium", children: it.productTitle }), _jsxs(Text, { size: "xs", color: "muted", children: [it.productId, " \u00B7 \u20B9", it.unitPrice.toFixed(2), "/ea"] })] }), _jsx(Input, { bare: true, type: "number", min: "0", value: it.quantity, onChange: (e) => updateQty(idx, e.target.value), className: "w-16 rounded border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] px-[var(--appkit-space-2)] py-[var(--appkit-space-1)] text-[length:var(--appkit-text-xs)]" })] }, `${it.productId}-${idx}`))) })), _jsxs(Row, { gap: "sm", children: [_jsx(Button, { type: "button", variant: "secondary", size: "sm", onClick: () => setOrderItemsOpen(false), children: "Cancel" }), _jsx(Button, { type: "button", variant: "primary", size: "sm", isLoading: applyOrderItems.isPending, disabled: applyOrderItems.isPending, onClick: () => applyOrderItems.mutate(), children: "Apply changes" })] })] }))] })) : (_jsxs(Text, { size: "xs", color: "muted", children: ["Set the", " ", _jsx(Text, { as: "span", weight: "semibold", children: "Order ID" }), " ", "field in the Linked parties panel above to enable this action."] }))] }));
259
277
  }
260
278
  function StoreChangePanel(props) {
261
- const { linkedStoreId, storeStatus, setStoreStatus, storeIsVerified, setStoreIsVerified, storeIsFeatured, setStoreIsFeatured, applyStoreChange, } = props;
262
- return (_jsxs(Stack, { padding: "sm", className: "border border-warning/40 bg-[var(--appkit-color-warning-surface)]/40", gap: "sm", rounded: "lg", children: [_jsx(Text, { className: "text-warning tracking-wide", size: "xs", weight: "semibold", transform: "uppercase", children: "Apply store change" }), linkedStoreId ? (_jsxs(_Fragment, { children: [_jsxs(Text, { size: "xs", color: "muted", children: ["Editing store: ", _jsx(Code, { className: "font-mono", children: linkedStoreId })] }), _jsx(Select, { label: "Store status", options: [
279
+ const { linkedStoreId, storeStatus, setStoreStatus, storeIsVerified, setStoreIsVerified, storeIsFeatured, setStoreIsFeatured, applyStoreChange, isLoadingStore, } = props;
280
+ return (_jsxs(Stack, { padding: "sm", className: "border border-warning/40 bg-[var(--appkit-color-warning-surface)]/40", gap: "sm", rounded: "lg", children: [_jsx(Text, { className: "text-warning tracking-wide", size: "xs", weight: "semibold", transform: "uppercase", children: "Apply store change" }), linkedStoreId ? (_jsxs(_Fragment, { children: [_jsxs(Text, { size: "xs", color: "muted", children: ["Editing store: ", _jsx(Code, { className: "font-mono", children: linkedStoreId })] }), isLoadingStore && (_jsx(Text, { size: "xs", color: "muted", children: "Loading current store state\u2026" })), _jsx(Select, { label: "Store status", options: [
263
281
  { label: "Active", value: "active" },
264
282
  { label: "Pending", value: "pending" },
265
283
  { label: "Suspended", value: "suspended" },
266
284
  { label: "Rejected", value: "rejected" },
267
- ], value: storeStatus, onValueChange: setStoreStatus }), _jsx(Toggle, { label: "Verified badge", checked: storeIsVerified, onChange: setStoreIsVerified }), _jsx(Toggle, { label: "Featured store", checked: storeIsFeatured, onChange: setStoreIsFeatured }), _jsx(Button, { type: "button", variant: "primary", size: "sm", isLoading: applyStoreChange.isPending, disabled: applyStoreChange.isPending, onClick: () => applyStoreChange.mutate(), children: "Apply store change" })] })) : (_jsxs(Text, { size: "xs", color: "muted", children: ["Set the", " ", _jsx(Text, { as: "span", weight: "semibold", children: "Store slug" }), " ", "field in the Linked parties panel above to enable this action."] }))] }));
285
+ ], value: storeStatus, onValueChange: setStoreStatus, disabled: isLoadingStore }), _jsx(Toggle, { label: "Verified badge", checked: storeIsVerified, onChange: setStoreIsVerified, disabled: isLoadingStore }), _jsx(Toggle, { label: "Featured store", checked: storeIsFeatured, onChange: setStoreIsFeatured, disabled: isLoadingStore }), _jsx(Button, { type: "button", variant: "primary", size: "sm", isLoading: applyStoreChange.isPending, disabled: applyStoreChange.isPending || isLoadingStore, onClick: () => applyStoreChange.mutate(), children: "Apply store change" })] })) : (_jsxs(Text, { size: "xs", color: "muted", children: ["Set the", " ", _jsx(Text, { as: "span", weight: "semibold", children: "Store slug" }), " ", "field in the Linked parties panel above to enable this action."] }))] }));
268
286
  }
269
287
  function UnbanRequestPanel(props) {
270
288
  const { linkedUserId, liftHardBan, liftSoftBanTickets } = props;