@mohasinac/appkit 4.53.1 → 4.54.0-next.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 (220) hide show
  1. package/dist/.build-stamp.json +5 -5
  2. package/dist/_internal/client/theme/ThemeProvider.js +15 -1
  3. package/dist/_internal/server/features/auth/capabilities.js +7 -5
  4. package/dist/_internal/server/features/categories/price-guidance-resolve.d.ts +66 -0
  5. package/dist/_internal/server/features/categories/price-guidance-resolve.js +138 -0
  6. package/dist/_internal/server/features/checkout/supplier-identity.js +28 -6
  7. package/dist/_internal/server/features/price-index/market.d.ts +57 -0
  8. package/dist/_internal/server/features/price-index/market.js +120 -0
  9. package/dist/_internal/server/features/products/list-public.d.ts +12 -0
  10. package/dist/_internal/server/features/products/list-public.js +10 -1
  11. package/dist/_internal/server/features/products/listing-tab-counts.d.ts +25 -1
  12. package/dist/_internal/server/features/products/listing-tab-counts.js +184 -10
  13. package/dist/_internal/server/features/search/index-build/sources.js +43 -2
  14. package/dist/_internal/server/features/stores/tabs.d.ts +7 -2
  15. package/dist/_internal/server/features/stores/tabs.js +5 -3
  16. package/dist/_internal/server/jobs/core/jobRunners.js +0 -10
  17. package/dist/_internal/server/jobs/core/onOrderCreate.js +10 -104
  18. package/dist/_internal/shared/actions/action-registry.d.ts +1 -1
  19. package/dist/_internal/shared/actions/action-registry.js +128 -0
  20. package/dist/_internal/shared/features/categories/bundle-copy.d.ts +1 -1
  21. package/dist/_internal/shared/features/site-settings/supplier-of-record.d.ts +56 -0
  22. package/dist/_internal/shared/features/site-settings/supplier-of-record.js +57 -0
  23. package/dist/_internal/shared/listing-types/tiers.d.ts +94 -0
  24. package/dist/_internal/shared/listing-types/tiers.js +150 -0
  25. package/dist/_internal/shared/search/match.js +28 -2
  26. package/dist/cli/index.js +0 -2
  27. package/dist/client.d.ts +21 -2
  28. package/dist/client.js +23 -4
  29. package/dist/constants/api-endpoints.d.ts +28 -0
  30. package/dist/constants/api-endpoints.js +14 -0
  31. package/dist/features/account/components/UserOrdersView.js +26 -7
  32. package/dist/features/addresses/utils/postal-autofill.d.ts +39 -0
  33. package/dist/features/addresses/utils/postal-autofill.js +54 -0
  34. package/dist/features/admin/components/AdminStoreEditorView.js +73 -34
  35. package/dist/features/admin/components/OwnerQuickActions.d.ts +29 -0
  36. package/dist/features/admin/components/OwnerQuickActions.js +142 -0
  37. package/dist/features/admin/schemas/admin-editor-forms.d.ts +1 -1
  38. package/dist/features/admin/schemas/admin-editor-forms.js +4 -1
  39. package/dist/features/auctions/components/AuctionDetailPageView.js +8 -7
  40. package/dist/features/auctions/components/MarketplaceAuctionCard.d.ts +11 -1
  41. package/dist/features/auctions/components/MarketplaceAuctionCard.js +9 -2
  42. package/dist/features/auth/permissions/constants.d.ts +29 -2
  43. package/dist/features/auth/permissions/constants.js +68 -1
  44. package/dist/features/blog/components/BlogFeaturedCard.d.ts +11 -1
  45. package/dist/features/blog/components/BlogFeaturedCard.js +9 -2
  46. package/dist/features/cart/components/CartDrawer.js +3 -2
  47. package/dist/features/cart/components/CartGroupLineRow.js +2 -1
  48. package/dist/features/cart/hooks/useAddToCart.js +10 -5
  49. package/dist/features/cart/utils/pending-ops.d.ts +11 -1
  50. package/dist/features/cart/utils/pending-ops.js +14 -2
  51. package/dist/features/categories/api/[id]/price-guidance/route.js +1 -24
  52. package/dist/features/categories/components/BrandDetailPageView.js +15 -6
  53. package/dist/features/categories/components/BrandDetailTabs.d.ts +7 -1
  54. package/dist/features/categories/components/BrandDetailTabs.js +18 -3
  55. package/dist/features/categories/components/BundleCollage.js +3 -2
  56. package/dist/features/categories/components/BundleItemsPicker.js +3 -4
  57. package/dist/features/categories/components/CategoryDetailPageView.js +19 -8
  58. package/dist/features/categories/components/CategoryDetailTabs.d.ts +7 -1
  59. package/dist/features/categories/components/CategoryDetailTabs.js +29 -7
  60. package/dist/features/categories/components/CategoryGrid.d.ts +11 -1
  61. package/dist/features/categories/components/CategoryGrid.js +9 -2
  62. package/dist/features/checkout/actions/checkout-value-otp-actions.d.ts +10 -5
  63. package/dist/features/checkout/actions/checkout-value-otp-actions.js +2 -88
  64. package/dist/features/classified/components/ClassifiedDetailPageView.js +10 -1
  65. package/dist/features/digital-codes/components/DigitalCodeDetailPageView.js +10 -1
  66. package/dist/features/events/components/EventCard.d.ts +11 -1
  67. package/dist/features/events/components/EventCard.js +9 -2
  68. package/dist/features/layout/AppLayoutShell.js +2 -1
  69. package/dist/features/layout/BottomActions.d.ts +1 -0
  70. package/dist/features/layout/BottomActions.js +330 -0
  71. package/dist/features/layout/BottomChrome.d.ts +45 -0
  72. package/dist/features/layout/BottomChrome.js +5 -17
  73. package/dist/features/layout/SideActionDock.js +36 -13
  74. package/dist/features/layout/index.d.ts +2 -7
  75. package/dist/features/layout/index.js +7 -7
  76. package/dist/features/layout/useIsDesktop.d.ts +36 -0
  77. package/dist/features/layout/useIsDesktop.js +48 -0
  78. package/dist/features/live/components/LiveItemDetailPageView.js +10 -1
  79. package/dist/features/media/messages/en.json +67 -67
  80. package/dist/features/orders/components/YourPurchaseStrip.d.ts +24 -0
  81. package/dist/features/orders/components/YourPurchaseStrip.js +77 -0
  82. package/dist/features/orders/components/index.d.ts +2 -1
  83. package/dist/features/orders/components/index.js +1 -1
  84. package/dist/features/orders/utils/order-announcement-message.d.ts +18 -0
  85. package/dist/features/orders/utils/order-announcement-message.js +16 -0
  86. package/dist/features/orders/utils/payment-proof-message.d.ts +20 -0
  87. package/dist/features/orders/utils/payment-proof-message.js +17 -0
  88. package/dist/features/parts/schemas/firestore.d.ts +227 -0
  89. package/dist/features/parts/schemas/firestore.js +6 -6
  90. package/dist/features/pre-orders/components/MarketplacePreorderCard.d.ts +11 -1
  91. package/dist/features/pre-orders/components/MarketplacePreorderCard.js +10 -3
  92. package/dist/features/pre-orders/components/PreOrderDetailPageView.js +8 -7
  93. package/dist/features/price-index/components/PriceIndexToolView.d.ts +21 -0
  94. package/dist/features/price-index/components/PriceIndexToolView.js +230 -27
  95. package/dist/features/price-index/lookup-target.d.ts +48 -0
  96. package/dist/features/price-index/lookup-target.js +107 -0
  97. package/dist/features/products/api/[id]/route.js +8 -1
  98. package/dist/features/products/api/route.js +16 -4
  99. package/dist/features/products/components/AvailabilityScopeHint.d.ts +22 -0
  100. package/dist/features/products/components/AvailabilityScopeHint.js +27 -0
  101. package/dist/features/products/components/CompareOverlay.d.ts +2 -1
  102. package/dist/features/products/components/CompareOverlay.js +2 -1
  103. package/dist/features/products/components/GroupSettingsPanel.js +2 -1
  104. package/dist/features/products/components/InteractiveProductCard.d.ts +7 -1
  105. package/dist/features/products/components/InteractiveProductCard.js +16 -4
  106. package/dist/features/products/components/MarketplaceBundleCard.d.ts +11 -1
  107. package/dist/features/products/components/MarketplaceBundleCard.js +9 -2
  108. package/dist/features/products/components/MarketplacePrizeDrawCard.d.ts +11 -1
  109. package/dist/features/products/components/MarketplacePrizeDrawCard.js +9 -2
  110. package/dist/features/products/components/ProductDetailPageView.js +34 -4
  111. package/dist/features/products/components/ProductGrid.d.ts +14 -1
  112. package/dist/features/products/components/ProductGrid.js +22 -5
  113. package/dist/features/products/components/ProductsIndexListing.js +2 -2
  114. package/dist/features/products/components/SublistingCarouselSection.js +2 -1
  115. package/dist/features/products/repository/products.repository.d.ts +1 -0
  116. package/dist/features/products/repository/products.repository.js +5 -1
  117. package/dist/features/products/utils/group-member-image.d.ts +9 -2
  118. package/dist/features/products/utils/group-member-image.js +2 -1
  119. package/dist/features/reviews/api/[id]/route.js +83 -23
  120. package/dist/features/reviews/components/PurchaseReviewAffordance.d.ts +6 -0
  121. package/dist/features/reviews/components/PurchaseReviewAffordance.js +42 -0
  122. package/dist/features/reviews/components/ReviewFormDrawer.d.ts +34 -0
  123. package/dist/features/reviews/components/ReviewFormDrawer.js +127 -0
  124. package/dist/features/reviews/components/index.d.ts +4 -0
  125. package/dist/features/reviews/components/index.js +2 -0
  126. package/dist/features/seller/actions/seller-actions.d.ts +1 -1
  127. package/dist/features/seller/actions/seller-actions.js +49 -3
  128. package/dist/features/seller/components/SellerPayoutSettingsView.js +30 -2
  129. package/dist/features/seller/components/SellerProductShell.d.ts +17 -1
  130. package/dist/features/seller/components/SellerProductsView.js +3 -2
  131. package/dist/features/seller/hooks/useStoreListingEntitlements.d.ts +8 -0
  132. package/dist/features/seller/hooks/useStoreListingEntitlements.js +70 -0
  133. package/dist/features/stores/components/InteractiveStoreCard.d.ts +11 -1
  134. package/dist/features/stores/components/InteractiveStoreCard.js +9 -2
  135. package/dist/features/stores/components/StoreAuctionsListing.js +2 -1
  136. package/dist/features/stores/components/index.d.ts +0 -2
  137. package/dist/features/stores/components/index.js +0 -1
  138. package/dist/features/stores/schemas/index.d.ts +1 -1
  139. package/dist/features/stores/schemas/index.js +10 -1
  140. package/dist/features/tester/seed-data/authored/content-discovery__authenticity-checker.js +114 -2
  141. package/dist/features/tester/seed-data/tester-checklist-seed-data.js +415 -0
  142. package/dist/index.d.ts +8 -27
  143. package/dist/index.js +14 -35
  144. package/dist/next/routing/route-map.d.ts +2 -0
  145. package/dist/next/routing/route-map.js +9 -0
  146. package/dist/providers/shipping-shiprocket/index.d.ts +98 -0
  147. package/dist/providers/shipping-shiprocket/index.js +353 -0
  148. package/dist/schemas/registry.d.ts +2 -2
  149. package/dist/security/csp.d.ts +16 -1
  150. package/dist/security/csp.js +5 -3
  151. package/dist/seed/_helpers/category-forest.js +27 -0
  152. package/dist/seed/_helpers/category-parts-glossary-map.js +1816 -86
  153. package/dist/seed/_helpers/category-parts.d.ts +1 -1
  154. package/dist/seed/_helpers/category-parts.js +13412 -3020
  155. package/dist/seed/categories-seed-data.js +48 -6
  156. package/dist/seed/homepage-sections-seed-data.js +41 -28
  157. package/dist/seed/model-composition-seed-data.js +6 -8
  158. package/dist/seed/part-glossary/chunk0.d.ts +9 -0
  159. package/dist/seed/part-glossary/chunk0.js +35044 -0
  160. package/dist/seed/part-glossary/chunk1.d.ts +9 -0
  161. package/dist/seed/part-glossary/chunk1.js +39955 -0
  162. package/dist/seed/part-glossary/chunk2.d.ts +9 -0
  163. package/dist/seed/part-glossary/chunk2.js +50335 -0
  164. package/dist/seed/part-glossary/chunk3.d.ts +9 -0
  165. package/dist/seed/part-glossary/chunk3.js +52386 -0
  166. package/dist/seed/part-glossary/chunk4.d.ts +9 -0
  167. package/dist/seed/part-glossary/chunk4.js +50549 -0
  168. package/dist/seed/part-glossary-seed-data.d.ts +1 -1
  169. package/dist/seed/part-glossary-seed-data.js +23 -47483
  170. package/dist/seed/products-beyblade-x-seed-data.js +36 -1
  171. package/dist/server.d.ts +6 -8
  172. package/dist/server.js +16 -20
  173. package/dist/styles.css +516 -358
  174. package/dist/tailwind-utilities.css +1 -1
  175. package/dist/tokens/themes/index.d.ts +3 -1
  176. package/dist/tokens/themes/index.js +11 -1
  177. package/dist/tokens/themes/technical-dark.d.ts +30 -0
  178. package/dist/tokens/themes/technical-dark.js +103 -0
  179. package/dist/tokens/themes/technical-light.d.ts +22 -0
  180. package/dist/tokens/themes/technical-light.js +89 -0
  181. package/dist/tokens/tokens.css +155 -0
  182. package/dist/ui/components/GatedPrice.js +30 -3
  183. package/dist/ui/components/GatedPrice.style.css +22 -19
  184. package/dist/ui/components/QuickCreateModal.style.css +78 -78
  185. package/dist/ui/forms/FormShell.style.css +260 -260
  186. package/package.json +1 -1
  187. package/scripts/seed-cli.mjs +133 -27
  188. package/dist/_internal/server/jobs/core/whatsappCatalogImport.d.ts +0 -27
  189. package/dist/_internal/server/jobs/core/whatsappCatalogImport.js +0 -172
  190. package/dist/_internal/server/jobs/core/whatsappNotify.d.ts +0 -35
  191. package/dist/_internal/server/jobs/core/whatsappNotify.js +0 -140
  192. package/dist/features/admin/components/AdminWhatsAppGuideView.d.ts +0 -2
  193. package/dist/features/admin/components/AdminWhatsAppGuideView.js +0 -35
  194. package/dist/features/orders/components/MarketplaceOrderCard.d.ts +0 -36
  195. package/dist/features/orders/components/MarketplaceOrderCard.js +0 -57
  196. package/dist/features/stores/components/StoreWhatsAppGuideView.d.ts +0 -3
  197. package/dist/features/stores/components/StoreWhatsAppGuideView.js +0 -12
  198. package/dist/features/whatsapp-bot/api/send-status/route.d.ts +0 -12
  199. package/dist/features/whatsapp-bot/api/send-status/route.js +0 -38
  200. package/dist/features/whatsapp-bot/api/webhook/route.d.ts +0 -12
  201. package/dist/features/whatsapp-bot/api/webhook/route.js +0 -43
  202. package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.d.ts +0 -6
  203. package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.js +0 -270
  204. package/dist/features/whatsapp-bot/components/WhatsAppChatButton.d.ts +0 -9
  205. package/dist/features/whatsapp-bot/components/WhatsAppChatButton.js +0 -7
  206. package/dist/features/whatsapp-bot/components/index.d.ts +0 -3
  207. package/dist/features/whatsapp-bot/components/index.js +0 -2
  208. package/dist/features/whatsapp-bot/helpers/payment-proof-message.d.ts +0 -14
  209. package/dist/features/whatsapp-bot/helpers/payment-proof-message.js +0 -17
  210. package/dist/features/whatsapp-bot/helpers/whatsapp.d.ts +0 -52
  211. package/dist/features/whatsapp-bot/helpers/whatsapp.js +0 -283
  212. package/dist/features/whatsapp-bot/index.d.ts +0 -3
  213. package/dist/features/whatsapp-bot/index.js +0 -3
  214. package/dist/features/whatsapp-bot/manifest.d.ts +0 -2
  215. package/dist/features/whatsapp-bot/manifest.js +0 -13
  216. package/dist/features/whatsapp-bot/messages/en.json +0 -7
  217. package/dist/features/whatsapp-bot/server.d.ts +0 -7
  218. package/dist/features/whatsapp-bot/server.js +0 -7
  219. package/dist/features/whatsapp-bot/types/index.d.ts +0 -126
  220. package/dist/features/whatsapp-bot/types/index.js +0 -1
@@ -1,57 +0,0 @@
1
- "use client";
2
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
- import { useCallback } from "react";
4
- import { Package } from "lucide-react";
5
- import { BaseListingCard, Button, Caption, Row, Span, Stack, StatusBadge, Text, TextLink, Div } from "../../../ui/index.js";
6
- import { formatCurrency, formatDate } from "../../../utils/index.js";
7
- import { OrderStatusValues } from "../schemas/index.js";
8
- import { useLongPress } from "../../../react/hooks/useLongPress.js";
9
- const CLS_ACTION_BUTTON = "min-w-0 flex-1 px-[var(--appkit-space-2)] text-[length:var(--appkit-text-xs)]";
10
- const STATUS_MAP = {
11
- pending: "pending",
12
- confirmed: "info",
13
- shipped: "info",
14
- delivered: "success",
15
- cancelled: "danger",
16
- returned: "danger",
17
- };
18
- const DEFAULT_LABELS = {
19
- orderNumber: "Order",
20
- placedOn: "Placed on",
21
- items: "Items",
22
- trackOrder: "Track",
23
- writeReview: "Review",
24
- viewOrder: "View",
25
- };
26
- function defaultNavigate(href) {
27
- if (typeof window !== "undefined") {
28
- window.location.assign(href);
29
- }
30
- }
31
- export function MarketplaceOrderCard({ order, links, labels, className = "", variant = "grid", selectable = false, isSelected = false, onSelect, onNavigate, }) {
32
- const mergedLabels = { ...DEFAULT_LABELS, ...labels };
33
- const navigate = onNavigate ?? defaultNavigate;
34
- const orderId = order.id ?? "";
35
- const shortId = `#${orderId.slice(0, 8).toUpperCase()}`;
36
- const status = STATUS_MAP[order.status] ?? "pending";
37
- const statusLabel = order.status.charAt(0).toUpperCase() + order.status.slice(1);
38
- const isDelivered = order.status === OrderStatusValues.DELIVERED;
39
- const isShipped = order.status === OrderStatusValues.SHIPPED;
40
- const detailHref = links?.detailHref(order) ?? `/orders/${order.id}`;
41
- const trackHref = links?.trackHref?.(order);
42
- const reviewHref = links?.reviewHref?.(order);
43
- const handleSelect = useCallback((event) => {
44
- event.preventDefault();
45
- event.stopPropagation();
46
- onSelect?.(orderId, !isSelected);
47
- }, [orderId, isSelected, onSelect]);
48
- const longPress = useLongPress(() => onSelect?.(orderId, !isSelected));
49
- const isListVariant = variant === "list";
50
- const itemCount = order.items?.length ?? 0;
51
- const infoBlock = (_jsxs(_Fragment, { children: [_jsx(Row, { className: "h-10 w-10 flex-shrink-0", surface: "subtle", align: "center", justify: "center", rounded: "lg", children: _jsx(Package, { className: "h-5 w-5 text-[var(--appkit-color-text-muted)] text-[var(--appkit-color-text-muted)]" }) }), _jsxs(Stack, { className: "min-w-0", gap: "xs", children: [_jsx(TextLink, { href: detailHref, className: "leading-tight", children: _jsx(Text, { weight: "semibold", className: "truncate", children: order.productTitle ?? shortId }) }), _jsxs(Caption, { className: "font-mono", children: [mergedLabels.orderNumber, " ", shortId] }), _jsxs(Caption, { children: [mergedLabels.placedOn, " ", formatDate(order.orderDate)] }), itemCount > 1 && (_jsxs(Caption, { children: [mergedLabels.items, ": ", _jsx(Span, { weight: "medium", children: itemCount })] }))] })] }));
52
- const statusPriceBlock = (_jsxs(_Fragment, { children: [_jsx(StatusBadge, { status: status, label: statusLabel }), _jsx(Text, { weight: "semibold", className: "tabular-nums", children: formatCurrency(order.totalPrice, order.currency) })] }));
53
- const actionsRow = (_jsxs(Row, { align: "center", gap: "sm", wrap: true, children: [(isShipped || isDelivered) &&
54
- trackHref &&
55
- order.trackingNumber && (_jsx(Button, { variant: "ghost", size: "sm", className: CLS_ACTION_BUTTON, onClick: () => navigate(trackHref), children: mergedLabels.trackOrder })), isDelivered && reviewHref && (_jsx(Button, { variant: "outline", size: "sm", className: CLS_ACTION_BUTTON, onClick: () => navigate(reviewHref), children: mergedLabels.writeReview })), _jsx(Button, { variant: "secondary", size: "sm", className: CLS_ACTION_BUTTON, onClick: () => navigate(detailHref), children: mergedLabels.viewOrder })] }));
56
- return (_jsxs(Div, { rounded: "xl", border: "subtle", shadow: "hover-md", className: `group relative overflow-hidden bg-[var(--appkit-color-surface)] transition-all duration-200 ${isSelected ? "ring-2 ring-primary-500 dark:ring-primary-400" : ""} ${className}`, onMouseDown: onSelect && !isSelected ? longPress.onMouseDown : undefined, onMouseUp: onSelect && !isSelected ? longPress.onMouseUp : undefined, onMouseLeave: onSelect && !isSelected ? longPress.onMouseLeave : undefined, onTouchStart: onSelect && !isSelected ? longPress.onTouchStart : undefined, onTouchEnd: onSelect && !isSelected ? longPress.onTouchEnd : undefined, onTouchCancel: onSelect && !isSelected ? longPress.onTouchCancel : undefined, "data-section": "marketplaceordercard-div-411", children: [onSelect && (_jsx(BaseListingCard.Checkbox, { selected: isSelected, onSelect: handleSelect, label: isSelected ? "Deselect order" : "Select order", position: "top-2 left-2", className: selectable || isSelected ? "opacity-100" : "opacity-0 pointer-events-none group-hover:opacity-100 group-hover:pointer-events-auto transition-opacity" })), isListVariant ? (_jsxs(Row, { align: "center", justify: "between", gap: "md", padding: "md", "data-section": "marketplaceordercard-div-412", children: [_jsx(Div, { layout: "flex", align: "start", gap: "3", paddingX: selectable ? "l-xl" : undefined, className: "min-w-0 flex-1", "data-section": "marketplaceordercard-div-413", children: infoBlock }), _jsxs(Row, { align: "center", gap: "md", className: "flex-shrink-0", "data-section": "marketplaceordercard-div-416", children: [_jsx(Row, { align: "center", gap: "md", "data-section": "marketplaceordercard-div-417", children: statusPriceBlock }), actionsRow] })] })) : (_jsxs(Stack, { gap: "md", padding: "md", "data-section": "marketplaceordercard-div-412", children: [_jsx(Div, { layout: "flex", align: "start", gap: "3", paddingX: selectable ? "l-xl" : undefined, "data-section": "marketplaceordercard-div-413", children: infoBlock }), _jsxs(Stack, { gap: "3", "data-section": "marketplaceordercard-div-416", children: [_jsx(Row, { wrap: true, align: "center", justify: "between", gap: "3", "data-section": "marketplaceordercard-div-417", children: statusPriceBlock }), actionsRow] })] }))] }));
57
- }
@@ -1,3 +0,0 @@
1
- import React from "react";
2
- export type StoreWhatsAppGuideViewProps = Record<string, never>;
3
- export declare function StoreWhatsAppGuideView(_props: StoreWhatsAppGuideViewProps): React.JSX.Element;
@@ -1,12 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { ArrowLeft } from "lucide-react";
3
- import { Alert, Code, Div, Heading, Li, Section, Span, Stack, Text, TextLink, Ul } from "../../../ui/index.js";
4
- import { ROUTES } from "../../../next/routing/route-map.js";
5
- function GuideSection({ title, children, }) {
6
- return (_jsxs(Section, { className: "border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)]", rounded: "xl", shadow: "sm", padding: "lg", children: [_jsx(Heading, { level: 2, className: "mb-4 text-[var(--appkit-color-text)]", size: "lg", weight: "semibold", children: title }), children] }));
7
- }
8
- const LIST_DISC = "list-disc leading-relaxed";
9
- const TEXT_MUTED = "leading-relaxed text-[var(--appkit-color-text-muted)]";
10
- export function StoreWhatsAppGuideView(_props) {
11
- return (_jsxs(Stack, { gap: "lg", padding: "b-2xl", children: [_jsxs(TextLink, { variant: "bare", href: String(ROUTES.STORE.GUIDE), size: "sm", layout: "inline-flex", align: "center", gap: "sm", className: "text-[var(--appkit-color-text-muted)] hover:text-[var(--appkit-color-text)] transition-colors", children: [_jsx(ArrowLeft, { className: "h-4 w-4" }), "Back to Seller Guide"] }), _jsxs(Div, { children: [_jsx(Heading, { level: 1, className: "text-[var(--appkit-color-text)]", size: "2xl", weight: "bold", children: "WhatsApp Catalog Sync" }), _jsx(Text, { className: "mt-1 text-[var(--appkit-color-text-muted)]", size: "sm", children: "Push your product catalog to Meta's Commerce Manager for WhatsApp catalog messages and Facebook/Instagram Shops \u2014 and import products back the other way." })] }), _jsx(GuideSection, { title: "1. Create a Commerce Manager catalog", children: _jsxs(Ul, { spacing: "tight", indent: "lg", children: [_jsxs(Li, { className: LIST_DISC, textSize: "sm", color: "muted", children: ["At ", _jsx(Span, { weight: "bold", children: "business.facebook.com/commerce" }), ", create a new catalog for the store (or use an existing one)."] }), _jsxs(Li, { className: LIST_DISC, textSize: "sm", color: "muted", children: ["Note the ", _jsx(Span, { weight: "bold", children: "Catalog ID" }), " shown in the catalog's settings."] })] }) }), _jsx(GuideSection, { title: "2. Generate a catalog-scoped access token", children: _jsxs(Text, { className: TEXT_MUTED, size: "sm", children: ["You need a Meta access token with ", _jsx(Code, { size: "xs", padding: "xs", rounded: "default", surface: "subtle", children: "catalog_management" }), " permission, scoped to that catalog. This is generated the same way as the platform-level WhatsApp System User token (ask your admin \u2014 Admin Guide \u2192 WhatsApp Integration, step 3) but assigned to the ", _jsx(Span, { weight: "bold", children: "catalog" }), " asset instead of the WhatsApp Business Account asset."] }) }), _jsxs(GuideSection, { title: "3. Enter credentials in the seller dashboard", children: [_jsxs(Text, { className: "mb-2 leading-relaxed text-[var(--appkit-color-text-muted)]", size: "sm", children: [_jsx(Span, { weight: "bold", children: "Store \u2192 WhatsApp" }), " settings page:"] }), _jsxs(Ul, { spacing: "tight", indent: "lg", children: [_jsx(Li, { className: LIST_DISC, textSize: "sm", color: "muted", children: "Catalog ID" }), _jsx(Li, { className: LIST_DISC, textSize: "sm", color: "muted", children: "Access Token" })] }), _jsxs(Text, { className: "mt-3 leading-relaxed text-[var(--appkit-color-text-muted)]", size: "sm", children: ["This is a store capability \u2014 it must be enabled for the store (", _jsx(Code, { size: "xs", padding: "xs", rounded: "default", surface: "subtle", children: "whatsapp_catalog_sync" }), " capability) before the settings page and sync actions are available."] })] }), _jsx(GuideSection, { title: "4. Push products to the catalog", children: _jsxs(Text, { className: TEXT_MUTED, size: "sm", children: ["Once connected, trigger a sync that batches published ", _jsx(Code, { size: "xs", padding: "xs", rounded: "default", surface: "subtle", children: "standard" }), "-listing products (up to 50 per API call) to the Meta catalog via the Commerce API ", _jsx(Code, { size: "xs", padding: "xs", rounded: "default", surface: "subtle", children: "items_batch" }), " endpoint \u2014 title, description, price, image, availability, and condition."] }) }), _jsx(GuideSection, { title: "5. Import products from the catalog", children: _jsxs(Text, { className: TEXT_MUTED, size: "sm", children: ["The reverse flow fetches products already in the Meta catalog and creates them as local ", _jsx(Span, { weight: "bold", children: "draft" }), " listings, deduplicating against existing products by slug/retailer-id matching."] }) }), _jsxs(Alert, { variant: "info", children: ["This is unrelated to the platform-level WhatsApp order-notification credentials \u2014 those are for sending order-status messages to buyers, not catalog sync. Only published ", _jsx(Span, { weight: "bold", children: "standard" }), " listings sync \u2014 auctions, pre-orders, and other listing types are not included."] })] }));
12
- }
@@ -1,12 +0,0 @@
1
- /**
2
- * feat-whatsapp-bot — POST /api/whatsapp/send-status
3
- *
4
- * WhatsApp message delivery status update.
5
- *
6
- * Consumer stub:
7
- * ```ts
8
- * export { whatsappSendStatusPOST as POST } from "@mohasinac/feat-whatsapp-bot";
9
- * ```
10
- */
11
- import { NextResponse } from "next/server.js";
12
- export declare function POST(request: Request): Promise<NextResponse>;
@@ -1,38 +0,0 @@
1
- /**
2
- * feat-whatsapp-bot — POST /api/whatsapp/send-status
3
- *
4
- * WhatsApp message delivery status update.
5
- *
6
- * Consumer stub:
7
- * ```ts
8
- * export { whatsappSendStatusPOST as POST } from "@mohasinac/feat-whatsapp-bot";
9
- * ```
10
- */
11
- import { NextResponse } from "next/server.js";
12
- import { getProviders } from "../../../../contracts/index.js";
13
- import { normalizeError } from "../../../../errors/normalize.js";
14
- export async function POST(request) {
15
- try {
16
- const body = await request.json();
17
- const { db } = getProviders();
18
- if (!db)
19
- return NextResponse.json({ success: false, error: "DB not configured" }, { status: 503 });
20
- // Update message status in database
21
- const repo = db.getRepository("whatsapp_message_status");
22
- const updated = await repo.create({
23
- ...body,
24
- updatedAt: new Date(),
25
- });
26
- return NextResponse.json({
27
- success: true,
28
- data: updated,
29
- });
30
- }
31
- catch (error) {
32
- void normalizeError(error);
33
- return NextResponse.json({
34
- success: false,
35
- error: error instanceof Error ? error.message : "Internal server error",
36
- }, { status: 500 });
37
- }
38
- }
@@ -1,12 +0,0 @@
1
- /**
2
- * feat-whatsapp-bot — POST /api/whatsapp/webhook
3
- *
4
- * WhatsApp webhook receiver for incoming messages.
5
- *
6
- * Consumer stub:
7
- * ```ts
8
- * export { whatsappWebhookPOST as POST } from "@mohasinac/feat-whatsapp-bot";
9
- * ```
10
- */
11
- import { NextResponse } from "next/server.js";
12
- export declare function POST(request: Request): Promise<NextResponse>;
@@ -1,43 +0,0 @@
1
- /**
2
- * feat-whatsapp-bot — POST /api/whatsapp/webhook
3
- *
4
- * WhatsApp webhook receiver for incoming messages.
5
- *
6
- * Consumer stub:
7
- * ```ts
8
- * export { whatsappWebhookPOST as POST } from "@mohasinac/feat-whatsapp-bot";
9
- * ```
10
- */
11
- import { NextResponse } from "next/server.js";
12
- import { getProviders } from "../../../../contracts/index.js";
13
- import { normalizeError } from "../../../../errors/normalize.js";
14
- export async function POST(request) {
15
- try {
16
- const body = await request.json();
17
- const { db, eventBus } = getProviders();
18
- if (!db)
19
- return NextResponse.json({ success: false, error: "DB not configured" }, { status: 503 });
20
- // Store webhook payload for processing
21
- const repo = db.getRepository("whatsapp_messages");
22
- const created = await repo.create({
23
- ...body,
24
- receivedAt: new Date(),
25
- processed: false,
26
- });
27
- // Emit event for async processing if eventBus available
28
- if (eventBus) {
29
- await eventBus.emit("whatsapp.message.received", created);
30
- }
31
- return NextResponse.json({
32
- success: true,
33
- data: created,
34
- }, { status: 201 });
35
- }
36
- catch (error) {
37
- void normalizeError(error);
38
- return NextResponse.json({
39
- success: false,
40
- error: error instanceof Error ? error.message : "Internal server error",
41
- }, { status: 500 });
42
- }
43
- }
@@ -1,6 +0,0 @@
1
- import React from "react";
2
- export interface SellerWhatsAppSettingsViewProps {
3
- /** Whether this store has the whatsapp_catalog_sync capability */
4
- hasCapability: boolean;
5
- }
6
- export declare function SellerWhatsAppSettingsView({ hasCapability }: SellerWhatsAppSettingsViewProps): React.JSX.Element;
@@ -1,270 +0,0 @@
1
- "use client";
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { useApiMutation, useBulkEvent, RTDB_PATHS } from "@mohasinac/appkit/client";
4
- import React from "react";
5
- import { normalizeError } from "../../../errors/normalize.js";
6
- import { toUserMessage } from "../../../errors/error-display-map.js";
7
- const __P = {
8
- p3: "p-[var(--appkit-space-3)]",
9
- };
10
- const __O = {
11
- hidden: "overflow-hidden",
12
- };
13
- const CLS_SECTION_CARD = "border border-[var(--appkit-color-border)] rounded-xl p-[var(--appkit-space-5)]";
14
- import { useQuery, useQueryClient } from "@tanstack/react-query";
15
- import { Alert, Badge, Button, Div, Heading, Input, Row, Section, Span, Stack, Text, Toggle, useToast } from "../../../ui/index.js";
16
- import { apiClient } from "../../../http/index.js";
17
- import { WHATSAPP_SELLER_ENDPOINTS } from "../../../constants/api-endpoints.js";
18
- import { ACTIONS } from "../../../_internal/shared/actions/action-registry.js";
19
- import { buildPurchaseAnnouncementMessage } from "../helpers/whatsapp.js";
20
- import { whatsappConnectionSchema, } from "../../admin/schemas/admin-user-form.js";
21
- import { SectionForm, useSectionFormNav, buildSectionsFromSchema, visibleValues, } from "../../shell/index.js";
22
- import { useFormShellState, FormShellContext } from "../../../ui/forms/index.js";
23
- import { applyZodIssues } from "../../../ui/forms/apply-zod-issues.js";
24
- import { FormErrorSummary } from "../../../ui/forms/FormErrorSummary.js";
25
- // ---------------------------------------------------------------------------
26
- // Sub-components
27
- // ---------------------------------------------------------------------------
28
- /**
29
- * What the server sends in place of a stored access token. It is a SENTINEL,
30
- * not a value — the real token never leaves the server.
31
- */
32
- const MASKED_TOKEN = "••••••";
33
- function MaskedTokenInput({ label, value, onChange, placeholder, helperText, }) {
34
- const [revealed, setRevealed] = React.useState(false);
35
- /*
36
- * There is nothing to reveal while the field still holds the sentinel: the
37
- * button used to un-mask six bullet characters, which reads as "the token is
38
- * literally ••••••". Offer it only once the seller has typed something, which
39
- * is the only case where the field contains a real value.
40
- */
41
- const isSentinel = value === MASKED_TOKEN;
42
- return (_jsxs(Div, { className: "relative", children: [_jsx(Input, { label: label, value: value, onChange: (e) => onChange(e.target.value), type: revealed && !isSentinel ? "text" : "password", placeholder: placeholder, helperText: isSentinel
43
- ? "A token is saved. Type a new one to replace it — the stored value is never sent back."
44
- : helperText }), !isSentinel && (_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => setRevealed((r) => !r), className: "absolute right-3 top-8 text-[length:var(--appkit-text-xs)]", children: revealed ? "Hide" : "Reveal" }))] }));
45
- }
46
- const STEPS = [
47
- {
48
- n: 1,
49
- title: "Create a Meta Business Account",
50
- body: "Go to business.facebook.com and create (or use) a Meta Business Manager account.",
51
- checkKey: undefined,
52
- },
53
- {
54
- n: 2,
55
- title: "Set up a WhatsApp Business App",
56
- body: "In Meta for Developers, create an App → add the WhatsApp product → note your Phone Number ID and WABA ID from the API Setup page.",
57
- checkKey: "wabaId",
58
- },
59
- {
60
- n: 3,
61
- title: "Generate a System User access token",
62
- body: 'In Meta Business Manager → System Users → create a System User → assign "WhatsApp Business Management" + "WhatsApp Business Messaging" permissions → generate a token.',
63
- checkKey: "accessToken",
64
- },
65
- {
66
- n: 4,
67
- title: "Create a WhatsApp Catalog",
68
- body: "In Meta Commerce Manager → Catalogs → create a catalog → copy the Catalog ID.",
69
- checkKey: "catalogId",
70
- },
71
- {
72
- n: 5,
73
- title: "Paste credentials below and save",
74
- body: "Fill the form below and click Save & Connect. Once connected, you can sync your products.",
75
- checkKey: "connected",
76
- },
77
- ];
78
- const STATUS_VARIANT = {
79
- success: "success",
80
- partial: "warning",
81
- failed: "danger",
82
- };
83
- // ---------------------------------------------------------------------------
84
- // Sample catalog items for preview
85
- // ---------------------------------------------------------------------------
86
- const SAMPLE_CATALOG_ITEMS = [
87
- { id: "1", emoji: "🃏", name: "Charizard PSA 9 Base Set", price: "₹4,500" },
88
- { id: "2", emoji: "🚗", name: "Hot Wheels Redline Vintage", price: "₹1,200" },
89
- { id: "3", emoji: "🤖", name: "Gundam HG RX-78-2 1/144", price: "₹2,800" },
90
- { id: "4", emoji: "🪀", name: "Beyblade Burst Storm Pegasus", price: "₹650" },
91
- ];
92
- // ---------------------------------------------------------------------------
93
- // Main component
94
- // ---------------------------------------------------------------------------
95
- export function SellerWhatsAppSettingsView({ hasCapability }) {
96
- const queryClient = useQueryClient();
97
- const { showToast } = useToast();
98
- const { data, isLoading } = useQuery({
99
- queryKey: ["store", "whatsapp-settings"],
100
- queryFn: async () => {
101
- const res = await apiClient.get(WHATSAPP_SELLER_ENDPOINTS.SETTINGS);
102
- return (res?.whatsappConfig ?? null);
103
- },
104
- });
105
- const cfg = data ?? null;
106
- // Connection form state
107
- const [draft, setDraft] = React.useState({
108
- phoneNumber: "",
109
- wabaId: "",
110
- catalogId: "",
111
- accessToken: "",
112
- });
113
- const [syncEnabled, setSyncEnabled] = React.useState(false);
114
- React.useEffect(() => {
115
- if (!cfg)
116
- return;
117
- setDraft({
118
- phoneNumber: cfg.phoneNumber ?? "",
119
- wabaId: cfg.wabaId ?? "",
120
- catalogId: cfg.catalogId ?? "",
121
- accessToken: cfg.accessToken ?? "",
122
- });
123
- setSyncEnabled(cfg.catalogSyncEnabled ?? false);
124
- }, [cfg]);
125
- /*
126
- * The access token needs a renderer: it is a `text` field to the schema, and
127
- * the control is a masked input with a reveal that must stay suppressed while
128
- * the field still holds the server's sentinel.
129
- */
130
- const sections = React.useMemo(() => buildSectionsFromSchema(whatsappConnectionSchema, {
131
- renderers: {
132
- accessToken: ({ values, onChange }) => (_jsx(MaskedTokenInput, { label: "System User Access Token", value: values.accessToken ?? "", onChange: (v) => onChange({ accessToken: v }), placeholder: "EAAxxxxxxxx\u2026", helperText: "Long-lived token with WhatsApp Business permissions" })),
133
- },
134
- }), []);
135
- const nav = useSectionFormNav(sections, draft, { scope: "store:whatsapp" });
136
- const form = useFormShellState(whatsappConnectionSchema, {
137
- sections: nav.sectionMeta,
138
- onGoToSection: nav.goToSection,
139
- fieldToSectionIndex: nav.fieldToSectionIndex,
140
- });
141
- /*
142
- * The CONNECTION form. Credentials only.
143
- *
144
- * 🛑 It used to also send `catalogSyncEnabled` — the one key it sent
145
- * unconditionally — while the toggle for it lives in Section 3, outside this
146
- * form and below its Save button. A seller flipped the sync toggle, saw it
147
- * move, pressed the Sync button beside it, and the setting was never
148
- * persisted: the only control that saved it was "Save & Connect", two cards
149
- * up and labelled for credentials.
150
- *
151
- * The toggle now owns its own write (`syncToggleMutation`), so the control
152
- * and the thing that persists it are in the same place.
153
- */
154
- const saveMutation = useApiMutation({
155
- errorMessage: "Failed to save settings.",
156
- mutationFn: async () => {
157
- const v = visibleValues(whatsappConnectionSchema, draft);
158
- const payload = {};
159
- if (v.phoneNumber)
160
- payload.phoneNumber = v.phoneNumber;
161
- if (v.wabaId)
162
- payload.wabaId = v.wabaId;
163
- if (v.catalogId)
164
- payload.catalogId = v.catalogId;
165
- // Only send accessToken if user has typed a new value (not the masked placeholder)
166
- if (v.accessToken && v.accessToken !== MASKED_TOKEN)
167
- payload.accessToken = v.accessToken;
168
- return apiClient.put(WHATSAPP_SELLER_ENDPOINTS.SETTINGS, payload);
169
- },
170
- onSuccess: () => {
171
- showToast("WhatsApp settings saved", "success");
172
- void queryClient.invalidateQueries({ queryKey: ["store", "whatsapp-settings"] });
173
- },
174
- });
175
- /** Persists the catalog-sync toggle on flip — see the note above. */
176
- const syncToggleMutation = useApiMutation({
177
- errorMessage: "Could not change the catalog-sync setting.",
178
- mutationFn: async (next) => apiClient.put(WHATSAPP_SELLER_ENDPOINTS.SETTINGS, { catalogSyncEnabled: next }),
179
- onSuccess: () => {
180
- void queryClient.invalidateQueries({ queryKey: ["store", "whatsapp-settings"] });
181
- },
182
- onError: () => {
183
- // Put the switch back where the server still has it.
184
- setSyncEnabled((prev) => !prev);
185
- },
186
- });
187
- const handleSyncToggle = (next) => {
188
- setSyncEnabled(next);
189
- syncToggleMutation.mutate(next);
190
- };
191
- // Catalog sync mutation (push: site → WhatsApp)
192
- const syncMutation = useApiMutation({
193
- errorMessage: "Catalog sync failed.",
194
- mutationFn: async () => apiClient.post(WHATSAPP_SELLER_ENDPOINTS.CATALOG_SYNC, {}),
195
- onSuccess: (res) => {
196
- const r = res ?? {};
197
- showToast(`Synced ${r.successCount ?? 0} product${(r.successCount ?? 0) !== 1 ? "s" : ""} to WhatsApp catalog`, "success");
198
- void queryClient.invalidateQueries({ queryKey: ["store", "whatsapp-settings"] });
199
- },
200
- });
201
- // Catalog import (pull: WhatsApp → site). Runs as the `whatsappCatalogImport`
202
- // async job — the route only enqueues, so the result arrives over the
203
- // useBulkEvent RTDB channel rather than in the POST response.
204
- const bulkEvent = useBulkEvent({ rtdbPath: RTDB_PATHS.BULK_EVENTS });
205
- const [importing, setImporting] = React.useState(false);
206
- const startImport = async () => {
207
- setImporting(true);
208
- try {
209
- const res = (await apiClient.post(WHATSAPP_SELLER_ENDPOINTS.CATALOG_IMPORT, {}));
210
- const { jobId, customToken } = res.data ?? {};
211
- if (jobId && customToken) {
212
- bulkEvent.subscribe(jobId, customToken);
213
- }
214
- else {
215
- setImporting(false);
216
- showToast("Failed to start catalog import.", "error");
217
- }
218
- }
219
- catch (err) {
220
- const e = normalizeError(err);
221
- setImporting(false);
222
- showToast(toUserMessage(e.code, undefined, { fallback: "Failed to start catalog import." }), "error");
223
- }
224
- };
225
- React.useEffect(() => {
226
- if (bulkEvent.status === "success") {
227
- setImporting(false);
228
- const summary = bulkEvent.result?.summary;
229
- const imported = summary?.succeeded ?? 0;
230
- const skipped = summary?.skipped ?? 0;
231
- showToast(`Imported ${imported} product${imported !== 1 ? "s" : ""} from WhatsApp (${skipped} already synced)`, "success");
232
- void queryClient.invalidateQueries({ queryKey: ["store", "whatsapp-settings"] });
233
- void queryClient.invalidateQueries({ queryKey: ["store", "products"] });
234
- }
235
- else if (bulkEvent.status === "failed" || bulkEvent.status === "timeout") {
236
- setImporting(false);
237
- showToast(bulkEvent.error ?? "Catalog import failed.", "error");
238
- }
239
- // eslint-disable-next-line react-hooks/exhaustive-deps
240
- }, [bulkEvent.status]);
241
- if (!hasCapability) {
242
- return (_jsx(Div, { className: "max-w-xl mx-auto", paddingY: "y-xl", paddingX: "x-md", children: _jsxs(Alert, { variant: "warning", children: [_jsx(Text, { weight: "medium", children: "WhatsApp catalog sync is not enabled for your store." }), _jsx(Text, { className: "mt-1", size: "sm", children: "Contact LetItRip support to request access to the WhatsApp Business integration." })] }) }));
243
- }
244
- return (_jsxs(Stack, { gap: "xl", className: "max-w-2xl mx-auto", paddingY: "y-lg", paddingX: "x-md", children: [_jsxs(Section, { children: [_jsx(Heading, { level: 2, className: "mb-4", color: "primary", size: "base", weight: "semibold", children: "How to connect your WhatsApp Business account" }), _jsx(Stack, { gap: "sm", children: STEPS.map((step) => {
245
- const done = step.checkKey === undefined
246
- ? false
247
- : step.checkKey === "connected"
248
- ? cfg?.connected === true
249
- : Boolean(cfg?.[step.checkKey]);
250
- return (_jsxs(Row, { gap: "sm", align: "start", children: [_jsx(Row, { textWeight: "bold", textSize: "xs", className: `flex-shrink-0 w-6 h-6 mt-0.5 ${done ? "bg-[var(--appkit-color-success)] text-white" : "bg-[var(--appkit-color-surface-elevated)] text-[var(--appkit-color-text-muted)] dark:text-[var(--appkit-color-text-faint)]"}`, align: "center", justify: "center", rounded: "full", children: done ? "✓" : step.n }), _jsxs(Div, { children: [_jsx(Text, { size: "sm", weight: "medium", color: "primary", children: step.title }), _jsx(Text, { className: "mt-0.5", color: "muted", size: "xs", children: step.body })] })] }, step.n));
251
- }) })] }), _jsxs(Section, { className: CLS_SECTION_CARD, children: [_jsxs(Row, { justify: "between", align: "center", className: "mb-4", children: [_jsx(Heading, { level: 2, size: "sm", weight: "semibold", color: "primary", children: "Connection" }), isLoading ? null : cfg?.connected ? (_jsx(Badge, { variant: "success", children: "Connected" })) : (_jsx(Badge, { variant: "default", children: "Not configured" }))] }), _jsxs(FormShellContext.Provider, { value: form.shellCtx, children: [_jsx(FormErrorSummary, {}), _jsx(SectionForm, { sections: sections, values: draft, onChange: (partial) => setDraft((d) => ({ ...d, ...partial })), onSubmit: () => {
252
- // SectionForm scrolls to the first bad section and then submits
253
- // regardless, so the guard lives here.
254
- form.clearErrors();
255
- const parsed = whatsappConnectionSchema.safeParse(visibleValues(whatsappConnectionSchema, draft));
256
- if (!parsed.success) {
257
- applyZodIssues(parsed.error.issues, form.setFieldError);
258
- return;
259
- }
260
- saveMutation.mutate();
261
- }, onValidationChange: () => form.validate(draft), schema: whatsappConnectionSchema, openIds: nav.openIds, onOpenChange: nav.setOpenIds, submitLabel: ACTIONS.STORE["whatsapp-connect"].label, isLoading: saveMutation.isPending })] })] }), _jsxs(Section, { className: CLS_SECTION_CARD, children: [_jsx(Heading, { level: 2, className: "mb-4", color: "primary", size: "sm", weight: "semibold", children: "Catalog Sync" }), _jsxs(Row, { justify: "between", align: "center", className: "mb-4", children: [_jsxs(Div, { children: [_jsx(Text, { size: "sm", color: "muted", children: "Enable catalog sync" }), _jsx(Text, { size: "xs", color: "muted", children: "When enabled, your published standard products can be synced to WhatsApp." })] }), _jsx(Toggle, { checked: syncEnabled, onChange: handleSyncToggle, disabled: !cfg?.connected || syncToggleMutation.isPending })] }), cfg?.lastCatalogSyncAt && (_jsxs(Row, { color: "muted", textSize: "xs", gap: "sm", align: "center", className: "mb-3", children: [_jsxs(Text, { children: ["Last sync: ", new Date(cfg.lastCatalogSyncAt).toLocaleString("en-IN")] }), cfg.lastSyncCount !== undefined && _jsxs(Text, { children: ["\u00B7 ", cfg.lastSyncCount, " products"] }), cfg.lastSyncStatus && (_jsx(Badge, { variant: STATUS_VARIANT[cfg.lastSyncStatus] ?? "default", children: cfg.lastSyncStatus }))] })), _jsx(Text, { className: "mb-3", color: "faint", size: "xs", children: "Only published standard products are synced. Auctions and pre-orders are excluded. Batches of up to 50 products per call." }), _jsxs(Row, { gap: "3", children: [_jsx(Button, { onClick: () => syncMutation.mutate(), isLoading: syncMutation.isPending, disabled: !cfg?.connected || !syncEnabled || syncMutation.isPending, variant: "secondary", children: syncMutation.isPending ? "Syncing…" : ACTIONS.STORE["whatsapp-catalog-sync"].label }), _jsx(Button, { onClick: () => void startImport(), isLoading: importing, disabled: !cfg?.connected || !syncEnabled || importing, variant: "secondary", children: importing ? "Importing…" : ACTIONS.STORE["whatsapp-catalog-import"].label })] }), _jsxs(Text, { className: "mt-3", color: "faint", size: "xs", children: [_jsx(Span, { weight: "bold", children: "Push" }), " sends your published standard products to WhatsApp.", " ", _jsx(Span, { weight: "bold", children: "Import" }), " creates draft products from your WhatsApp catalog. Products are matched by slug in the description field."] })] }), _jsxs(Section, { className: CLS_SECTION_CARD, children: [_jsx(Heading, { level: 2, className: "mb-2", color: "primary", size: "sm", weight: "semibold", children: "Purchase Announcement Preview" }), _jsx(Text, { className: "mb-3", color: "muted", size: "xs", children: "This message is sent automatically to your phone and the platform admin when a new order is placed." }), _jsx(Div, { textSize: "sm", className: "font-mono", color: "primary", surface: "muted", padding: "inline", rounded: "lg", children: buildPurchaseAnnouncementMessage({
262
- buyerName: "Ravi K.",
263
- firstItemName: "Charizard PSA 9",
264
- additionalItemCount: 2,
265
- totalAmount: 4500,
266
- orderId: "order-3-20260510-a1b2c3",
267
- }) })] }), _jsxs(Section, { className: CLS_SECTION_CARD, children: [_jsx(Heading, { level: 2, className: "mb-2", color: "primary", size: "sm", weight: "semibold", children: "Catalog Preview" }), _jsx(Text, { className: "mb-4", color: "muted", size: "xs", children: "This is how your products appear in the WhatsApp Catalog when a buyer taps \"View Catalog\" in the chat. Only published standard products are included." }), _jsxs(Div, { className: `${__O.hidden} bg-[var(--appkit-color-whatsapp-bg)] bg-[var(--appkit-color-surface-elevated)] ${__P.p3}`, rounded: "xl", border: "default", children: [_jsxs(Row, { gap: "sm", align: "center", className: "mb-3", children: [_jsx(Row, { className: "w-8 h-8 bg-[var(--appkit-color-whatsapp)]", align: "center", justify: "center", rounded: "full", children: _jsx(Text, { color: "inverse", size: "xs", weight: "bold", children: "W" }) }), _jsxs(Div, { children: [_jsx(Text, { size: "xs", weight: "semibold", color: "primary", children: cfg?.connected ? "Your Store" : "Store Name" }), _jsx(Text, { className: "text-[10px]", color: "muted", children: "WhatsApp Business" })] })] }), _jsx(Div, { layout: "grid", gap: "2", className: "grid-cols-2", children: SAMPLE_CATALOG_ITEMS.map((item) => (_jsxs(Div, { surface: "card", className: `${__O.hidden}`, children: [_jsx(Row, { className: "aspect-square", surface: "subtle", align: "center", justify: "center", children: _jsx(Text, { size: "2xl", children: item.emoji }) }), _jsxs(Div, { padding: "xs", children: [_jsx(Text, { className: "line-clamp-2 leading-tight", color: "primary", size: "xs", weight: "medium", children: item.name }), _jsx(Text, { className: "text-[var(--appkit-color-whatsapp)] mt-0.5", size: "xs", weight: "semibold", children: item.price })] })] }, item.id))) }), _jsx(Div, { className: "mt-3 text-center", children: _jsx(Text, { className: "text-[10px]", color: "muted", children: cfg?.lastSyncCount
268
- ? `${cfg.lastSyncCount} products synced to catalog`
269
- : "Sync your products to populate the catalog" }) })] }), !cfg?.connected && (_jsx(Text, { className: "text-warning mt-2", size: "xs", children: "Connect your WhatsApp Business account above to enable the catalog." }))] })] }));
270
- }
@@ -1,9 +0,0 @@
1
- import React from "react";
2
- interface WhatsAppChatButtonProps {
3
- waNumber: string;
4
- message?: string;
5
- label?: string;
6
- className?: string;
7
- }
8
- export declare function WhatsAppChatButton({ waNumber, message, label, className, }: WhatsAppChatButtonProps): React.JSX.Element;
9
- export {};
@@ -1,7 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import Link from "next/link.js";
3
- const CLS_WA_BTN = "inline-flex items-center gap-[var(--appkit-space-2)] rounded-lg bg-success-solid px-[var(--appkit-space-4)] py-[var(--appkit-space-2)] text-[length:var(--appkit-text-sm)] font-semibold text-success-on-solid transition-colors hover:brightness-110";
4
- export function WhatsAppChatButton({ waNumber, message = "Hi! I have a question.", label = "Chat on WhatsApp", className, }) {
5
- const href = `https://wa.me/${waNumber}?text=${encodeURIComponent(message)}`;
6
- return (_jsxs(Link, { href: href, target: "_blank", rel: "noopener noreferrer", className: `${CLS_WA_BTN} ${className ?? ""}`, children: [_jsx("svg", { className: "h-4 w-4", viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": "true", children: _jsx("path", { d: "M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413z" }) }), label] }));
7
- }
@@ -1,3 +0,0 @@
1
- export { WhatsAppChatButton } from "./WhatsAppChatButton";
2
- export { SellerWhatsAppSettingsView } from "./SellerWhatsAppSettingsView";
3
- export type { SellerWhatsAppSettingsViewProps } from "./SellerWhatsAppSettingsView";
@@ -1,2 +0,0 @@
1
- export { WhatsAppChatButton } from "./WhatsAppChatButton.js";
2
- export { SellerWhatsAppSettingsView } from "./SellerWhatsAppSettingsView.js";
@@ -1,14 +0,0 @@
1
- import type { PaymentProofReviewMessageInput } from "../types";
2
- /**
3
- * Tier PP — message for the payment-proof fast-review WhatsApp push (sent
4
- * to every `whatsappAdminNotifyNumbers` number when a buyer uploads proof)
5
- * and for the buyer/seller "share for review" wa.me link (same message,
6
- * routed through `buildGroupShareLink` instead of the Cloud API push).
7
- *
8
- * Pure string builder — deliberately kept in its own file, isolated from
9
- * `./whatsapp.ts` (which has a top-level `import { createHmac } from
10
- * "crypto"`), so it can be safely exported from the client-safe barrel.
11
- * The buyer/seller share-link caller (order payment page) needs this
12
- * client-side; the crypto-importing sibling functions never can be.
13
- */
14
- export declare function buildPaymentProofReviewMessage(input: PaymentProofReviewMessageInput): string;
@@ -1,17 +0,0 @@
1
- /**
2
- * Tier PP — message for the payment-proof fast-review WhatsApp push (sent
3
- * to every `whatsappAdminNotifyNumbers` number when a buyer uploads proof)
4
- * and for the buyer/seller "share for review" wa.me link (same message,
5
- * routed through `buildGroupShareLink` instead of the Cloud API push).
6
- *
7
- * Pure string builder — deliberately kept in its own file, isolated from
8
- * `./whatsapp.ts` (which has a top-level `import { createHmac } from
9
- * "crypto"`), so it can be safely exported from the client-safe barrel.
10
- * The buyer/seller share-link caller (order payment page) needs this
11
- * client-side; the crypto-importing sibling functions never can be.
12
- */
13
- export function buildPaymentProofReviewMessage(input) {
14
- const { orderId, buyerName, productTitle, totalAmount, reviewUrl } = input;
15
- const amount = totalAmount.toLocaleString("en-IN");
16
- return `💳 Payment proof submitted! ${buyerName} uploaded proof for "${productTitle}" (₹${amount}). Order #${orderId}. Please review within 2 hours or it auto-confirms: ${reviewUrl}`;
17
- }
@@ -1,52 +0,0 @@
1
- import type { CheckoutMessageInput, StatusNotificationInput, WebhookVerifyInput, IncomingWebhookPayload, SendWhatsAppInput, StatusMessageInput, WaBusinessSendInput, WaBusinessTemplateSendInput, CatalogSyncInput, CatalogSyncResult, PurchaseAnnouncementInput } from "../types";
2
- export declare function buildCheckoutMessageURL(input: CheckoutMessageInput): string;
3
- export declare function buildStatusNotificationURL(input: StatusNotificationInput): string;
4
- export declare function verifyWebhookSignature(input: WebhookVerifyInput): boolean;
5
- export declare function isAdminNumber(incomingNumber: string, adminBotNumber: string): boolean;
6
- /**
7
- * Parse an incoming WhatsApp webhook payload (Twilio form-encoded or Wati.io JSON).
8
- * Returns null if the payload cannot be parsed or is missing required fields.
9
- */
10
- export declare function parseIncomingWebhookPayload(rawBody: string, contentType: string): IncomingWebhookPayload | null;
11
- /**
12
- * Build a human-readable status notification message for an order.
13
- * Pass a custom `statusMessages` map to override the defaults.
14
- */
15
- export declare function buildStatusMessage(input: StatusMessageInput, statusMessages?: Record<string, string>): string;
16
- /**
17
- * Send a WhatsApp message via Meta WhatsApp Business Cloud API.
18
- * Distinct from the Twilio-based sendWhatsAppMessage — used for server-initiated
19
- * platform announcements. Returns true on success, false on any failure.
20
- */
21
- export declare function sendWhatsAppBusinessMessage(input: WaBusinessSendInput): Promise<boolean>;
22
- /**
23
- * Send a pre-approved Meta message TEMPLATE via WhatsApp Business Cloud API.
24
- * Required for business-initiated sends outside the 24h customer-service
25
- * window (proactive order/status notifications) — Meta rejects free-form
26
- * `sendWhatsAppBusinessMessage` `type: "text"` sends in that case. Returns
27
- * true on success, false on any failure (including a missing/unapproved
28
- * template — Meta returns a 4xx with an error body, not a network failure).
29
- */
30
- export declare function sendWhatsAppTemplateMessage(input: WaBusinessTemplateSendInput): Promise<boolean>;
31
- /**
32
- * Sync a store's products to a Meta Commerce Catalog via items_batch API.
33
- * Batches at 50 items per call (Meta limit). Returns aggregate results.
34
- */
35
- export declare function syncProductsToCatalog(input: CatalogSyncInput): Promise<CatalogSyncResult>;
36
- /**
37
- * Build a plain-text purchase announcement message for WhatsApp.
38
- * Sent to admin numbers and store owner when a new order is placed.
39
- */
40
- export declare function buildPurchaseAnnouncementMessage(input: PurchaseAnnouncementInput): string;
41
- /**
42
- * Build a wa.me share link with a pre-filled message.
43
- * Opens WhatsApp contact picker — user selects group manually.
44
- * This is the only API-compliant way to target a WhatsApp group.
45
- */
46
- export declare function buildGroupShareLink(message: string): string;
47
- export { buildPaymentProofReviewMessage } from "./payment-proof-message";
48
- /**
49
- * Send an outbound WhatsApp message via Twilio REST API.
50
- * Returns true on success, false on failure.
51
- */
52
- export declare function sendWhatsAppMessage(input: SendWhatsAppInput): Promise<boolean>;