@mohasinac/appkit 4.63.4 → 4.64.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 (232) hide show
  1. package/dist/.build-stamp.json +3 -3
  2. package/dist/_internal/server/features/categories/adapters.d.ts +1 -1
  3. package/dist/_internal/server/features/categories/adapters.js +13 -0
  4. package/dist/_internal/server/features/checkout/actions.d.ts +2 -0
  5. package/dist/_internal/server/features/checkout/actions.js +22 -5
  6. package/dist/_internal/server/features/events/like-actions.d.ts +25 -0
  7. package/dist/_internal/server/features/events/like-actions.js +67 -0
  8. package/dist/_internal/server/features/events/likes.d.ts +65 -0
  9. package/dist/_internal/server/features/events/likes.js +146 -0
  10. package/dist/_internal/server/features/orders/adapters.js +3 -1
  11. package/dist/_internal/server/features/seo/index.d.ts +3 -0
  12. package/dist/_internal/server/features/seo/index.js +2 -0
  13. package/dist/_internal/server/features/seo/product-detail-types.d.ts +1 -0
  14. package/dist/_internal/server/features/seo/product-detail-types.js +26 -0
  15. package/dist/_internal/server/features/seo/robots.js +20 -1
  16. package/dist/_internal/server/features/seo/sitemap.js +125 -27
  17. package/dist/_internal/server/features/seo/static-params.d.ts +107 -0
  18. package/dist/_internal/server/features/seo/static-params.js +228 -0
  19. package/dist/_internal/server/features/seo/taxonomy-links.d.ts +44 -0
  20. package/dist/_internal/server/features/seo/taxonomy-links.js +85 -0
  21. package/dist/_internal/server/features/site-settings/adapters.js +20 -2
  22. package/dist/_internal/server/features/stores/adapters.d.ts +2 -2
  23. package/dist/_internal/server/features/stores/adapters.js +88 -1
  24. package/dist/_internal/server/functions/scheduled.d.ts +16 -1
  25. package/dist/_internal/server/functions/scheduled.js +23 -1
  26. package/dist/_internal/server/jobs/core/analyticsAlertEvaluate.js +5 -2
  27. package/dist/_internal/server/jobs/core/jobRunners.js +5 -0
  28. package/dist/_internal/server/jobs/core/onOrderCreate.js +104 -10
  29. package/dist/_internal/server/jobs/core/onOrderStatusChange.d.ts +2 -0
  30. package/dist/_internal/server/jobs/core/onOrderStatusChange.js +1 -0
  31. package/dist/_internal/server/jobs/core/onScamReportCreate.js +1 -0
  32. package/dist/_internal/server/jobs/core/onScamReportRejected.js +1 -0
  33. package/dist/_internal/server/jobs/core/onScamReportVerified.js +1 -0
  34. package/dist/_internal/server/jobs/core/paymentWindowTimeout.js +1 -0
  35. package/dist/_internal/server/jobs/core/pendingOrderTimeout.js +1 -0
  36. package/dist/_internal/server/jobs/core/sellerStandingRollup.d.ts +63 -0
  37. package/dist/_internal/server/jobs/core/sellerStandingRollup.js +412 -0
  38. package/dist/_internal/server/jobs/core/whatsappNotify.d.ts +35 -0
  39. package/dist/_internal/server/jobs/core/whatsappNotify.js +140 -0
  40. package/dist/_internal/server/jobs/handlers/index.d.ts +1 -0
  41. package/dist/_internal/server/jobs/handlers/index.js +1 -0
  42. package/dist/_internal/server/jobs/handlers/sellerStandingRollup.d.ts +12 -0
  43. package/dist/_internal/server/jobs/handlers/sellerStandingRollup.js +14 -0
  44. package/dist/_internal/server/notifications/channel-health.d.ts +8 -6
  45. package/dist/_internal/server/notifications/channel-health.js +2 -2
  46. package/dist/_internal/server/notifications/send-guard.d.ts +1 -1
  47. package/dist/_internal/server/notifications/send-guard.js +4 -2
  48. package/dist/_internal/shared/actions/action-registry.js +89 -0
  49. package/dist/_internal/shared/checkout/order-math.d.ts +1 -1
  50. package/dist/_internal/shared/checkout/order-math.js +1 -1
  51. package/dist/_internal/shared/features/checkout/config.d.ts +2 -0
  52. package/dist/_internal/shared/features/checkout/config.js +2 -0
  53. package/dist/_internal/shared/features/messaging/config.d.ts +5 -7
  54. package/dist/_internal/shared/features/messaging/config.js +4 -1
  55. package/dist/_internal/shared/features/seller-standing/config.d.ts +130 -0
  56. package/dist/_internal/shared/features/seller-standing/config.js +153 -0
  57. package/dist/_internal/shared/features/site-settings/fees.d.ts +2 -0
  58. package/dist/_internal/shared/features/site-settings/fees.js +2 -0
  59. package/dist/_internal/shared/features/site-settings/types.d.ts +27 -2
  60. package/dist/_internal/shared/fees/calculator.d.ts +8 -0
  61. package/dist/_internal/shared/fees/calculator.js +7 -0
  62. package/dist/cli/index.js +2 -0
  63. package/dist/client.d.ts +2 -2
  64. package/dist/client.js +1 -1
  65. package/dist/constants/api-endpoints.d.ts +39 -0
  66. package/dist/constants/api-endpoints.js +16 -0
  67. package/dist/constants/notification-types.d.ts +1 -1
  68. package/dist/constants/notification-types.js +1 -1
  69. package/dist/core/integration-keys.d.ts +5 -0
  70. package/dist/core/integration-keys.js +10 -0
  71. package/dist/features/about/components/FeesView.js +6 -0
  72. package/dist/features/about/components/HelpPageView.js +9 -1
  73. package/dist/features/account/components/BecomeSellerView.d.ts +15 -3
  74. package/dist/features/account/components/BecomeSellerView.js +2 -2
  75. package/dist/features/account/components/BuyerShoppingGuideView.js +1 -1
  76. package/dist/features/account/components/NotificationPreferencesPanel.js +4 -3
  77. package/dist/features/account/types/index.d.ts +2 -0
  78. package/dist/features/admin/actions/notification-actions.d.ts +17 -2
  79. package/dist/features/admin/actions/notification-actions.js +154 -9
  80. package/dist/features/admin/components/AdminOrderEditorView.d.ts +1 -1
  81. package/dist/features/admin/components/AdminOrdersView.js +2 -0
  82. package/dist/features/admin/components/AdminSiteSettingsView.js +66 -6
  83. package/dist/features/admin/components/AdminStoreEditorView.d.ts +12 -1
  84. package/dist/features/admin/components/AdminStoreEditorView.js +31 -2
  85. package/dist/features/admin/components/AdminStoresGuideView.js +1 -1
  86. package/dist/features/admin/components/AdminStoresView.js +59 -2
  87. package/dist/features/admin/components/AdminTrustGuideView.js +10 -0
  88. package/dist/features/admin/constants/site-settings-tabs.d.ts +12 -7
  89. package/dist/features/admin/constants/site-settings-tabs.js +12 -6
  90. package/dist/features/admin/repository/site-settings.repository.js +1 -1
  91. package/dist/features/admin/schemas/admin-editor-forms.d.ts +10 -0
  92. package/dist/features/admin/schemas/admin-editor-forms.js +34 -0
  93. package/dist/features/admin/schemas/admin-user-form.d.ts +61 -0
  94. package/dist/features/admin/schemas/admin-user-form.js +44 -3
  95. package/dist/features/admin/schemas/firestore.d.ts +73 -0
  96. package/dist/features/admin/schemas/firestore.js +8 -3
  97. package/dist/features/auth/checkout-value-otp.d.ts +1 -1
  98. package/dist/features/auth/checkout-value-otp.js +1 -1
  99. package/dist/features/auth/permissions/constants.d.ts +2 -2
  100. package/dist/features/auth/permissions/constants.js +2 -1
  101. package/dist/features/blog/components/BlogIndexPageView.js +2 -2
  102. package/dist/features/blog/components/BlogListView.js +2 -1
  103. package/dist/features/blog/components/BlogPostView.js +2 -1
  104. package/dist/features/blog/constants/category-badge.d.ts +33 -0
  105. package/dist/features/blog/constants/category-badge.js +40 -0
  106. package/dist/features/cart/components/CartPriceBreakdown.d.ts +2 -0
  107. package/dist/features/cart/components/CartPriceBreakdown.js +1 -1
  108. package/dist/features/cart/components/StoreAddonsPicker.d.ts +5 -2
  109. package/dist/features/cart/components/StoreAddonsPicker.js +5 -4
  110. package/dist/features/cart/repository/cart.repository.js +2 -1
  111. package/dist/features/cart/schemas/firestore.d.ts +2 -1
  112. package/dist/features/categories/components/TaxonomyLinkIndex.d.ts +39 -0
  113. package/dist/features/categories/components/TaxonomyLinkIndex.js +11 -0
  114. package/dist/features/categories/schemas/firestore.d.ts +25 -0
  115. package/dist/features/categories/utils/load-category-options.d.ts +33 -0
  116. package/dist/features/categories/utils/load-category-options.js +50 -0
  117. package/dist/features/checkout/actions/checkout-value-otp-actions.d.ts +5 -10
  118. package/dist/features/checkout/actions/checkout-value-otp-actions.js +88 -2
  119. package/dist/features/events/components/EventCard.js +4 -12
  120. package/dist/features/events/components/EventInsights.d.ts +27 -0
  121. package/dist/features/events/components/EventInsights.js +10 -0
  122. package/dist/features/events/components/EventLikeButton.d.ts +21 -0
  123. package/dist/features/events/components/EventLikeButton.js +59 -0
  124. package/dist/features/events/components/EventLikersRail.d.ts +23 -0
  125. package/dist/features/events/components/EventLikersRail.js +54 -0
  126. package/dist/features/events/components/EventTypeBadge.d.ts +26 -0
  127. package/dist/features/events/components/EventTypeBadge.js +7 -0
  128. package/dist/features/events/components/EventsListPageView.js +2 -2
  129. package/dist/features/events/components/SpinWheel.d.ts +41 -0
  130. package/dist/features/events/components/SpinWheel.js +128 -0
  131. package/dist/features/events/components/SpinWheelView.js +36 -15
  132. package/dist/features/events/constants/event-type-meta.d.ts +54 -0
  133. package/dist/features/events/constants/event-type-meta.js +109 -0
  134. package/dist/features/events/repository/event-likes.repository.d.ts +57 -0
  135. package/dist/features/events/repository/event-likes.repository.js +151 -0
  136. package/dist/features/events/schemas/firestore.d.ts +111 -0
  137. package/dist/features/events/schemas/likes.d.ts +81 -0
  138. package/dist/features/events/schemas/likes.js +59 -0
  139. package/dist/features/events/types/index.d.ts +7 -0
  140. package/dist/features/events/utils/carousel-slide.d.ts +42 -0
  141. package/dist/features/events/utils/carousel-slide.js +174 -0
  142. package/dist/features/events/utils/event-charts.d.ts +65 -0
  143. package/dist/features/events/utils/event-charts.js +172 -0
  144. package/dist/features/faq/constants/help-guides.js +9 -0
  145. package/dist/features/faq/schemas/firestore.js +1 -0
  146. package/dist/features/faq/types/index.d.ts +19 -0
  147. package/dist/features/homepage/components/BrandsSection.js +25 -1
  148. package/dist/features/homepage/components/HeroCarousel.js +47 -10
  149. package/dist/features/homepage/lib/section-renderer.js +1 -1
  150. package/dist/features/homepage/types/index.d.ts +7 -0
  151. package/dist/features/orders/actions/refund-actions.js +1 -0
  152. package/dist/features/orders/components/OrderAddonBadges.d.ts +3 -1
  153. package/dist/features/orders/components/OrderAddonBadges.js +4 -3
  154. package/dist/features/orders/repository/orders.repository.d.ts +8 -0
  155. package/dist/features/orders/repository/orders.repository.js +2 -0
  156. package/dist/features/orders/schemas/firestore.d.ts +4 -0
  157. package/dist/features/orders/types/index.d.ts +5 -2
  158. package/dist/features/search/action-index/settings-entries.js +9 -0
  159. package/dist/features/store-extensions/repository/store-extensions.repositories.d.ts +6 -1
  160. package/dist/features/store-extensions/repository/store-extensions.repositories.js +10 -1
  161. package/dist/features/store-extensions/schemas/firestore.d.ts +17 -1
  162. package/dist/features/store-extensions/schemas/firestore.js +10 -0
  163. package/dist/features/stores/components/InteractiveStoreCard.js +2 -1
  164. package/dist/features/stores/components/SellerStandingPanel.d.ts +31 -0
  165. package/dist/features/stores/components/SellerStandingPanel.js +25 -0
  166. package/dist/features/stores/components/SellerTierBadge.d.ts +57 -0
  167. package/dist/features/stores/components/SellerTierBadge.js +19 -0
  168. package/dist/features/stores/components/StoreCapabilitiesGuideView.js +33 -2
  169. package/dist/features/stores/components/StoreCreateForm.d.ts +46 -0
  170. package/dist/features/stores/components/StoreCreateForm.js +107 -0
  171. package/dist/features/stores/components/StoreGuideHubView.js +18 -5
  172. package/dist/features/stores/components/StoreHeader.js +2 -1
  173. package/dist/features/stores/components/StoreSettingsGuideView.js +6 -2
  174. package/dist/features/stores/repository/store.repository.d.ts +23 -1
  175. package/dist/features/stores/repository/store.repository.js +52 -1
  176. package/dist/features/stores/schemas/firestore.d.ts +76 -7
  177. package/dist/features/stores/schemas/firestore.js +21 -6
  178. package/dist/features/stores/schemas/index.d.ts +88 -2
  179. package/dist/features/stores/schemas/index.js +14 -0
  180. package/dist/features/stores/schemas/store-create.d.ts +47 -0
  181. package/dist/features/stores/schemas/store-create.js +86 -0
  182. package/dist/features/stores/types/index.d.ts +42 -0
  183. package/dist/features/whatsapp-bot/api/send-status/route.d.ts +12 -0
  184. package/dist/features/whatsapp-bot/api/send-status/route.js +38 -0
  185. package/dist/features/whatsapp-bot/api/webhook/route.d.ts +12 -0
  186. package/dist/features/whatsapp-bot/api/webhook/route.js +43 -0
  187. package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.d.ts +57 -0
  188. package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.js +76 -0
  189. package/dist/features/whatsapp-bot/components/WhatsAppChatButton.d.ts +9 -0
  190. package/dist/features/whatsapp-bot/components/WhatsAppChatButton.js +7 -0
  191. package/dist/features/whatsapp-bot/components/index.d.ts +3 -0
  192. package/dist/features/whatsapp-bot/components/index.js +2 -0
  193. package/dist/features/whatsapp-bot/helpers/whatsapp.d.ts +52 -0
  194. package/dist/features/whatsapp-bot/helpers/whatsapp.js +288 -0
  195. package/dist/features/whatsapp-bot/index.d.ts +3 -0
  196. package/dist/features/whatsapp-bot/index.js +3 -0
  197. package/dist/features/whatsapp-bot/manifest.d.ts +2 -0
  198. package/dist/features/whatsapp-bot/manifest.js +13 -0
  199. package/dist/features/whatsapp-bot/messages/en.json +7 -0
  200. package/dist/features/whatsapp-bot/server.d.ts +7 -0
  201. package/dist/features/whatsapp-bot/server.js +7 -0
  202. package/dist/features/whatsapp-bot/types/index.d.ts +126 -0
  203. package/dist/features/whatsapp-bot/types/index.js +1 -0
  204. package/dist/index.d.ts +23 -6
  205. package/dist/index.js +38 -12
  206. package/dist/next/routing/route-map.d.ts +6 -1
  207. package/dist/next/routing/route-map.js +14 -0
  208. package/dist/providers/db-firebase/base.repository.d.ts +1 -1
  209. package/dist/providers/db-firebase/base.repository.js +1 -1
  210. package/dist/repositories/index.d.ts +1 -1
  211. package/dist/repositories/index.js +1 -1
  212. package/dist/schemas/registry.d.ts +115 -0
  213. package/dist/schemas/registry.js +2 -1
  214. package/dist/security/pii-encrypt.js +1 -1
  215. package/dist/server.d.ts +15 -2
  216. package/dist/server.js +32 -2
  217. package/dist/styles.css +36 -1
  218. package/dist/tailwind-utilities.css +1 -1
  219. package/dist/ui/components/HorizontalScroller.js +15 -2
  220. package/dist/ui/components/NavigationLoader.d.ts +14 -1
  221. package/dist/ui/components/NavigationLoader.js +79 -30
  222. package/dist/ui/components/PageHeroHeading.d.ts +40 -0
  223. package/dist/ui/components/PageHeroHeading.js +15 -0
  224. package/dist/ui/components/Typography.d.ts +3 -3
  225. package/dist/ui/components/Typography.js +59 -31
  226. package/dist/ui/components/Typography.style.css +35 -0
  227. package/dist/ui/index.d.ts +2 -0
  228. package/dist/ui/index.js +1 -0
  229. package/package.json +1 -1
  230. package/scripts/seed-cli.mjs +4 -2
  231. package/dist/features/orders/utils/order-announcement-message.d.ts +0 -18
  232. package/dist/features/orders/utils/order-announcement-message.js +0 -16
@@ -12,8 +12,20 @@
12
12
  * `scripts/audit-public-projection-parity.mjs`. Adding a field here without a
13
13
  * proven client reader is how the endpoint drifted in the first place.
14
14
  */
15
- import type { NotificationChannelConfig, SiteSettingsDocument } from "../../../../features/admin/schemas/firestore";
15
+ import type { SiteSettingsDocument } from "../../../../features/admin/schemas/firestore";
16
16
  import type { MediaVideoWatermark } from "../../../../features/media/MediaVideo";
17
+ /** The only notification-channel facts a browser is given: is each channel on. */
18
+ export interface PublicNotificationChannels {
19
+ email: {
20
+ enabled: boolean;
21
+ };
22
+ whatsapp: {
23
+ enabled: boolean;
24
+ };
25
+ sms: {
26
+ enabled: boolean;
27
+ };
28
+ }
17
29
  export interface PublicSiteSettings {
18
30
  /** Support channels shown to buyers. Deliberately NOT the full `contact` — `address` and `upiVpa` stay server-side. */
19
31
  contact: {
@@ -64,7 +76,20 @@ export interface PublicSiteSettings {
64
76
  search?: {
65
77
  indexEnabled: boolean;
66
78
  };
67
- notificationChannels?: NotificationChannelConfig;
79
+ /**
80
+ * 🛑 NARROWER than `NotificationChannelConfig` on purpose, and it must stay
81
+ * that way. The full config carries `minPriority` and a `types[]` allow-list
82
+ * naming exactly which notification types each channel carries — operational
83
+ * routing detail that no browser reads and that an anonymous caller has no
84
+ * business enumerating.
85
+ *
86
+ * `inApp` is deliberately absent too: it is always on and nothing renders a
87
+ * toggle for it.
88
+ *
89
+ * Widening this back to `NotificationChannelConfig` re-publishes the lot by
90
+ * the act of widening, which is the failure Root Cause #70 records.
91
+ */
92
+ notificationChannels?: PublicNotificationChannels;
68
93
  announcementBar?: SiteSettingsDocument["announcementBar"];
69
94
  navConfig?: SiteSettingsDocument["navConfig"];
70
95
  actionConfig?: SiteSettingsDocument["actionConfig"];
@@ -175,6 +175,14 @@ export interface CodHandlingFeeRates {
175
175
  * changes no number on its own.
176
176
  */
177
177
  export declare function computeCodHandlingFee(subtotal: number, rates: CodHandlingFeeRates): number;
178
+ export interface WhatsAppNotifyFeeRates {
179
+ /** Admin master toggle — the addon isn't charged (even if the buyer selected it) unless this is true. */
180
+ whatsappNotifyFeeEnabled?: boolean;
181
+ /** Flat rupee fee charged when the buyer opts in. Falls back to ₹10. */
182
+ whatsappNotifyFee?: number;
183
+ }
184
+ /** Flat WhatsApp order-updates addon fee — charged only when the buyer opted in AND the admin has the addon enabled. */
185
+ export declare function computeWhatsAppNotifyFee(addonSelected: boolean, rates: WhatsAppNotifyFeeRates): number;
178
186
  export interface GiftWrapFeeRates {
179
187
  /** Admin master toggle — the addon isn't charged (even if the buyer selected it) unless this is true. */
180
188
  giftWrapFeeEnabled?: boolean;
@@ -202,6 +202,13 @@ export function computeCodHandlingFee(subtotal, rates) {
202
202
  const percentFee = roundRupees(subtotal * (percent / 100));
203
203
  return Math.min(percentFee, cap);
204
204
  }
205
+ const DEFAULT_WHATSAPP_NOTIFY_FEE = 10;
206
+ /** Flat WhatsApp order-updates addon fee — charged only when the buyer opted in AND the admin has the addon enabled. */
207
+ export function computeWhatsAppNotifyFee(addonSelected, rates) {
208
+ if (!addonSelected || !rates.whatsappNotifyFeeEnabled)
209
+ return 0;
210
+ return rates.whatsappNotifyFee ?? DEFAULT_WHATSAPP_NOTIFY_FEE;
211
+ }
205
212
  const DEFAULT_GIFT_WRAP_FEE = 49;
206
213
  /** Flat gift-wrap addon fee — charged only when the buyer opted in AND the admin has the addon enabled. */
207
214
  export function computeGiftWrapFee(addonSelected, rates) {
package/dist/cli/index.js CHANGED
@@ -59,6 +59,7 @@ export const FEATURE_SUBPATH_MAP = {
59
59
  "before-after": "@mohasinac/appkit/features/before-after",
60
60
  collections: "@mohasinac/appkit/features/collections",
61
61
  preorders: "@mohasinac/appkit/features/pre-orders",
62
+ "whatsapp-bot": "@mohasinac/appkit/features/whatsapp-bot",
62
63
  };
63
64
  /**
64
65
  * Wraps a Next.js config object. With appkit, only `@mohasinac/appkit` needs to
@@ -109,6 +110,7 @@ const FEATURE_NAMESPACE_MAP = {
109
110
  corporate: "corporate",
110
111
  "before-after": "beforeAfter",
111
112
  collections: "collections",
113
+ "whatsapp-bot": "whatsappBot",
112
114
  };
113
115
  // Opaque dynamic import — prevents bundlers from statically analysing the path
114
116
  const _dynamicImport = new Function("modulePath", "return import(modulePath)");
package/dist/client.d.ts CHANGED
@@ -545,7 +545,7 @@ export type { FeeDerivation, FeeDerivations } from "./_internal/shared/fees/expl
545
545
  export type { BuyerFacingFees, BuyerEmiSettings, } from "./_internal/shared/features/site-settings/fees";
546
546
  export type { PublicSiteSettings } from "./_internal/shared/features/site-settings/types";
547
547
  export { computeCodHandlingFee } from "./_internal/shared/fees/calculator";
548
- export type { CodHandlingFeeRates, GiftWrapFeeRates, ShipmentProtectionFeeRates, } from "./_internal/shared/fees/calculator";
548
+ export type { CodHandlingFeeRates, WhatsAppNotifyFeeRates, GiftWrapFeeRates, ShipmentProtectionFeeRates, } from "./_internal/shared/fees/calculator";
549
549
  export { FAQPageContent } from "./features/faq/index";
550
550
  export type { FAQCategory, FAQCategoryItem, FAQSortOption } from "./features/faq/index";
551
551
  export { CategoryInlineSelect } from "./features/seller/components/CategoryInlineSelect";
@@ -571,7 +571,7 @@ export type { AdCreativeFormValues } from "./features/ads/schemas/creative-form"
571
571
  export { adminStoreUpdateSchema, announcementBarSchema, } from "./features/admin/schemas/admin-editor-forms";
572
572
  export { adminOrderUpdateSchema, employeeInviteSchema, hardBanReasonSchema, featureFlagsUpdateSchema, adminAdFormSchema, } from "./features/admin/schemas/admin-ops-forms";
573
573
  export { changeEmailSchema } from "./features/account/schemas/index";
574
- export { adminUserUpdateSchema, lotteryPullSchema, } from "./features/admin/schemas/admin-user-form";
574
+ export { adminUserUpdateSchema, whatsappSettingsSchema, lotteryPullSchema, } from "./features/admin/schemas/admin-user-form";
575
575
  export { siteSettingsFormSchema } from "./features/admin/schemas/site-settings-form";
576
576
  export { refineAddressPostal, addressFormSchema, addressUpdateSchema, adminAddressCreateSchema, adminAddressUpdateSchema, addressUnbanRequestSchema, } from "./features/addresses/schemas/address-form";
577
577
  export type { AddressFormValues, AddressUpdateValues, AdminAddressCreateValues, } from "./features/addresses/schemas/address-form";
package/dist/client.js CHANGED
@@ -619,7 +619,7 @@ export { adCreativeFormSchema } from "./features/ads/schemas/creative-form.js";
619
619
  export { adminStoreUpdateSchema, announcementBarSchema, } from "./features/admin/schemas/admin-editor-forms.js";
620
620
  export { adminOrderUpdateSchema, employeeInviteSchema, hardBanReasonSchema, featureFlagsUpdateSchema, adminAdFormSchema, } from "./features/admin/schemas/admin-ops-forms.js";
621
621
  export { changeEmailSchema } from "./features/account/schemas/index.js";
622
- export { adminUserUpdateSchema, lotteryPullSchema, } from "./features/admin/schemas/admin-user-form.js";
622
+ export { adminUserUpdateSchema, whatsappSettingsSchema, lotteryPullSchema, } from "./features/admin/schemas/admin-user-form.js";
623
623
  export { siteSettingsFormSchema } from "./features/admin/schemas/site-settings-form.js";
624
624
  // The ONE address shape and the ONE postal rule (W5 / D19). Eleven field
625
625
  // shapes and fifteen disagreeing postal rules collapsed to these.
@@ -438,6 +438,14 @@ export declare const EVENT_ENDPOINTS: {
438
438
  readonly ENTRIES: (id: string) => string;
439
439
  readonly LEADERBOARD: (id: string, limit?: number) => string;
440
440
  readonly SPIN: (id: string) => string;
441
+ /**
442
+ * Likes. POST toggles the viewer's; GET pages the "liked by" list.
443
+ *
444
+ * `id` may be a slug — public event URLs link by slug — and the route
445
+ * resolves it to the canonical document id before keying anything.
446
+ */
447
+ readonly LIKES: (id: string) => string;
448
+ readonly LIKERS: (id: string, offset: number) => string;
441
449
  readonly LOTTERY_PULL: (id: string) => string;
442
450
  readonly LOTTERY_ENTRIES: (id: string) => string;
443
451
  };
@@ -626,6 +634,11 @@ export declare const SCAMMER_ENDPOINTS: {
626
634
  export declare const BEFORE_AFTER_ENDPOINTS: {
627
635
  readonly LIST: "/api/before-after";
628
636
  };
637
+ export declare const WHATSAPP_SELLER_ENDPOINTS: {
638
+ readonly SETTINGS: "/api/store/whatsapp-settings";
639
+ readonly CATALOG_SYNC: "/api/store/whatsapp-settings/catalog-sync";
640
+ readonly CATALOG_IMPORT: "/api/store/whatsapp-settings/catalog-import";
641
+ };
629
642
  export declare const API_ENDPOINTS: {
630
643
  readonly CONFIG: {};
631
644
  readonly LOGS: {
@@ -1006,6 +1019,14 @@ export declare const API_ENDPOINTS: {
1006
1019
  readonly ENTRIES: (id: string) => string;
1007
1020
  readonly LEADERBOARD: (id: string, limit?: number) => string;
1008
1021
  readonly SPIN: (id: string) => string;
1022
+ /**
1023
+ * Likes. POST toggles the viewer's; GET pages the "liked by" list.
1024
+ *
1025
+ * `id` may be a slug — public event URLs link by slug — and the route
1026
+ * resolves it to the canonical document id before keying anything.
1027
+ */
1028
+ readonly LIKES: (id: string) => string;
1029
+ readonly LIKERS: (id: string, offset: number) => string;
1009
1030
  readonly LOTTERY_PULL: (id: string) => string;
1010
1031
  readonly LOTTERY_ENTRIES: (id: string) => string;
1011
1032
  };
@@ -1178,6 +1199,11 @@ export declare const API_ENDPOINTS: {
1178
1199
  readonly PRODUCTS: (sellerId: string) => string;
1179
1200
  readonly REVIEWS: (userId: string) => string;
1180
1201
  };
1202
+ readonly WHATSAPP_SELLER: {
1203
+ readonly SETTINGS: "/api/store/whatsapp-settings";
1204
+ readonly CATALOG_SYNC: "/api/store/whatsapp-settings/catalog-sync";
1205
+ readonly CATALOG_IMPORT: "/api/store/whatsapp-settings/catalog-import";
1206
+ };
1181
1207
  readonly SUPPORT: {
1182
1208
  readonly TICKETS: "/api/support/tickets";
1183
1209
  readonly TICKET_BY_ID: (id: string) => string;
@@ -1592,6 +1618,14 @@ export declare const API_ROUTES: {
1592
1618
  readonly ENTRIES: (id: string) => string;
1593
1619
  readonly LEADERBOARD: (id: string, limit?: number) => string;
1594
1620
  readonly SPIN: (id: string) => string;
1621
+ /**
1622
+ * Likes. POST toggles the viewer's; GET pages the "liked by" list.
1623
+ *
1624
+ * `id` may be a slug — public event URLs link by slug — and the route
1625
+ * resolves it to the canonical document id before keying anything.
1626
+ */
1627
+ readonly LIKES: (id: string) => string;
1628
+ readonly LIKERS: (id: string, offset: number) => string;
1595
1629
  readonly LOTTERY_PULL: (id: string) => string;
1596
1630
  readonly LOTTERY_ENTRIES: (id: string) => string;
1597
1631
  };
@@ -1764,6 +1798,11 @@ export declare const API_ROUTES: {
1764
1798
  readonly PRODUCTS: (sellerId: string) => string;
1765
1799
  readonly REVIEWS: (userId: string) => string;
1766
1800
  };
1801
+ readonly WHATSAPP_SELLER: {
1802
+ readonly SETTINGS: "/api/store/whatsapp-settings";
1803
+ readonly CATALOG_SYNC: "/api/store/whatsapp-settings/catalog-sync";
1804
+ readonly CATALOG_IMPORT: "/api/store/whatsapp-settings/catalog-import";
1805
+ };
1767
1806
  readonly SUPPORT: {
1768
1807
  readonly TICKETS: "/api/support/tickets";
1769
1808
  readonly TICKET_BY_ID: (id: string) => string;
@@ -541,6 +541,14 @@ export const EVENT_ENDPOINTS = {
541
541
  LEADERBOARD: (id, limit) => `/api/events/${id}/leaderboard${limit !== undefined ? `?limit=${limit}` : ""}`,
542
542
  // SB9-E user spin assignment
543
543
  SPIN: (id) => `/api/events/${id}/spin`,
544
+ /**
545
+ * Likes. POST toggles the viewer's; GET pages the "liked by" list.
546
+ *
547
+ * `id` may be a slug — public event URLs link by slug — and the route
548
+ * resolves it to the canonical document id before keying anything.
549
+ */
550
+ LIKES: (id) => `/api/events/${id}/likes`,
551
+ LIKERS: (id, offset) => `/api/events/${id}/likes?offset=${offset}`,
544
552
  // Lottery: user self-pull (draw happens immediately on submit)
545
553
  LOTTERY_PULL: (id) => `/api/events/${id}/lottery-pull`,
546
554
  LOTTERY_ENTRIES: (id) => `/api/events/${id}/lottery-entries`,
@@ -829,6 +837,13 @@ export const BEFORE_AFTER_ENDPOINTS = {
829
837
  LIST: "/api/before-after",
830
838
  };
831
839
  // ---------------------------------------------------------------------------
840
+ // WhatsApp Business (store-level settings + catalog sync)
841
+ // ---------------------------------------------------------------------------
842
+ export const WHATSAPP_SELLER_ENDPOINTS = {
843
+ SETTINGS: "/api/store/whatsapp-settings",
844
+ CATALOG_SYNC: "/api/store/whatsapp-settings/catalog-sync",
845
+ CATALOG_IMPORT: "/api/store/whatsapp-settings/catalog-import",
846
+ };
832
847
  // ---------------------------------------------------------------------------
833
848
  // Aggregate namespace export
834
849
  // ---------------------------------------------------------------------------
@@ -873,6 +888,7 @@ export const API_ENDPOINTS = {
873
888
  SUBLISTING_CATEGORIES: SUBLISTING_CATEGORY_ENDPOINTS,
874
889
  WISHLIST: WISHLIST_ENDPOINTS,
875
890
  PROFILE_STATS: PROFILE_STATS_ENDPOINTS,
891
+ WHATSAPP_SELLER: WHATSAPP_SELLER_ENDPOINTS,
876
892
  SUPPORT: SUPPORT_ENDPOINTS,
877
893
  SCAMMERS: SCAMMER_ENDPOINTS,
878
894
  REPORTS: REPORT_ENDPOINTS,
@@ -12,7 +12,7 @@
12
12
  * **18 of the 27 real types** and was offered two that never appear.
13
13
  * · `AdminSiteSettingsView`'s per-channel allow-list, so an admin literally
14
14
  * **could not allow-list `offer_received` or `payment_review`** for email
15
- * — the toggle did not exist.
15
+ * or WhatsApp — the toggle did not exist.
16
16
  *
17
17
  * Everything here now derives from `NOTIFICATION_TYPE_VALUES`, so a new
18
18
  * notification type is one edit and cannot be missing from either surface.
@@ -12,7 +12,7 @@
12
12
  * **18 of the 27 real types** and was offered two that never appear.
13
13
  * · `AdminSiteSettingsView`'s per-channel allow-list, so an admin literally
14
14
  * **could not allow-list `offer_received` or `payment_review`** for email
15
- * — the toggle did not exist.
15
+ * or WhatsApp — the toggle did not exist.
16
16
  *
17
17
  * Everything here now derives from `NOTIFICATION_TYPE_VALUES`, so a new
18
18
  * notification type is one edit and cannot be missing from either surface.
@@ -12,6 +12,11 @@ export interface ResolvedKeys {
12
12
  /** Webhook signing secret. Optional in practice: without it `verifyWebhook()` fails closed and the buyer-present /verify path still works. */
13
13
  razorpayWebhookSecret: string;
14
14
  resendApiKey: string;
15
+ whatsappApiKey: string;
16
+ whatsappPhoneNumberId: string;
17
+ whatsappCloudApiToken: string;
18
+ /** Comma-separated digits-only numbers, e.g. "919876543210,918765432109" */
19
+ whatsappAdminNotifyNumbers: string;
15
20
  }
16
21
  /** Drops the in-process cache. Call this after admin saves new credentials. */
17
22
  export declare function invalidateIntegrationKeysCache(): void;
@@ -32,6 +32,10 @@ const EMPTY_KEYS = {
32
32
  razorpayKeySecret: "",
33
33
  razorpayWebhookSecret: "",
34
34
  resendApiKey: "",
35
+ whatsappApiKey: "",
36
+ whatsappPhoneNumberId: "",
37
+ whatsappCloudApiToken: "",
38
+ whatsappAdminNotifyNumbers: "",
35
39
  };
36
40
  let _cache = null;
37
41
  const CACHE_TTL_MS = 60000; // 1 minute
@@ -79,6 +83,12 @@ export async function resolveKeys() {
79
83
  phonepeWebhookUsername: db.phonepeWebhookUsername || process.env.PHONEPE_WEBHOOK_USERNAME || "",
80
84
  phonepeWebhookPassword: db.phonepeWebhookPassword || process.env.PHONEPE_WEBHOOK_PASSWORD || "",
81
85
  resendApiKey: db.resendApiKey || process.env.RESEND_API_KEY || "",
86
+ whatsappApiKey: db.whatsappApiKey || process.env.WHATSAPP_API_KEY || "",
87
+ whatsappPhoneNumberId: db.whatsappPhoneNumberId || process.env.WHATSAPP_PHONE_NUMBER_ID || "",
88
+ whatsappCloudApiToken: db.whatsappCloudApiToken || process.env.WHATSAPP_CLOUD_API_TOKEN || "",
89
+ whatsappAdminNotifyNumbers: db.whatsappAdminNotifyNumbers ||
90
+ process.env.WHATSAPP_ADMIN_NOTIFY_NUMBERS ||
91
+ "",
82
92
  };
83
93
  _cache = { value, expiresAt: Date.now() + CACHE_TTL_MS };
84
94
  return value;
@@ -66,6 +66,12 @@ export async function FeesView({} = {}) {
66
66
  who: t("paidByBuyer"),
67
67
  note: t("codHandlingFeeNote"),
68
68
  },
69
+ {
70
+ category: t("whatsappNotifyFeeTitle"),
71
+ rate: t("whatsappNotifyFeeRate"),
72
+ who: t("paidByBuyer"),
73
+ note: t("whatsappNotifyFeeNote"),
74
+ },
69
75
  {
70
76
  category: t("giftWrapFeeTitle"),
71
77
  rate: t("giftWrapFeeRate"),
@@ -5,7 +5,7 @@ import { ProseHero } from "./ProseHero.js";
5
5
  import { FLEX_ROW } from "../../../_internal/shared/styles/themed.js";
6
6
  import { Alert, Div, Heading, Row, Section, Stack, Text } from "../../../ui/index.js";
7
7
  import { TextLink } from "../../../ui/index.js";
8
- import { BookOpen, MessageCircle, ShoppingBag, Gavel, PackageCheck, UserCheck, Store, ChevronRight, } from "lucide-react";
8
+ import { BookOpen, MessageCircle, ShoppingBag, Gavel, PackageCheck, UserCheck, Store, ShieldCheck, ChevronRight, } from "lucide-react";
9
9
  const __P = {
10
10
  p6: "p-[var(--appkit-space-6)]",
11
11
  p8: "p-[var(--appkit-space-8)]",
@@ -48,6 +48,14 @@ export async function HelpPageView({} = {}) {
48
48
  color: "bg-violet-50 border-violet-200 dark:bg-violet-900/20 dark:border-violet-700",
49
49
  iconColor: "text-violet-600 dark:text-violet-400",
50
50
  },
51
+ {
52
+ icon: ShieldCheck,
53
+ title: t("topicSellerBadges"),
54
+ desc: t("topicSellerBadgesDesc"),
55
+ href: String(ROUTES.PUBLIC.HELP_SELLER_BADGES),
56
+ color: "bg-teal-50 border-teal-200 dark:bg-teal-900/20 dark:border-teal-700",
57
+ iconColor: "text-teal-600 dark:text-teal-400",
58
+ },
51
59
  {
52
60
  icon: BookOpen,
53
61
  title: t("topicFAQs"),
@@ -4,13 +4,25 @@ export interface BecomeSellerViewLabels {
4
4
  applyButton?: string;
5
5
  alreadySeller?: string;
6
6
  }
7
+ /**
8
+ * 🛑 `create-store` is a real state, not a variant of `already-seller`.
9
+ *
10
+ * Applying and owning a storefront are two different things, and the gap
11
+ * between them was invisible: a user who applied became `role: "seller"` with
12
+ * no store, and this shell's `already-seller` slot told them to "head over to
13
+ * your Store Dashboard" — a dashboard with no store behind it. There was no
14
+ * step anywhere in the product that created one. This state is that step.
15
+ */
16
+ export type BecomeSellerState = "guide" | "success" | "create-store" | "already-seller";
7
17
  export interface BecomeSellerViewProps {
8
18
  labels?: BecomeSellerViewLabels;
9
19
  renderGuide?: () => React.ReactNode;
10
20
  renderSuccess?: () => React.ReactNode;
21
+ /** Seller with no store yet — renders the store-creation form. */
22
+ renderCreateStore?: () => React.ReactNode;
11
23
  renderAlreadySeller?: () => React.ReactNode;
12
- /** Which state to render. Shell exposes all three slots; consumer controls which is active. */
13
- state?: "guide" | "success" | "already-seller";
24
+ /** Which state to render. Shell exposes all four slots; consumer controls which is active. */
25
+ state?: BecomeSellerState;
14
26
  className?: string;
15
27
  }
16
- export declare function BecomeSellerView({ labels, renderGuide, renderSuccess, renderAlreadySeller, state, className, }: BecomeSellerViewProps): React.JSX.Element;
28
+ export declare function BecomeSellerView({ labels, renderGuide, renderSuccess, renderCreateStore, renderAlreadySeller, state, className, }: BecomeSellerViewProps): React.JSX.Element;
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Div, Heading } from "../../../ui/index.js";
3
- export function BecomeSellerView({ labels = {}, renderGuide, renderSuccess, renderAlreadySeller, state = "guide", className = "", }) {
4
- return (_jsxs(Div, { className: className, children: [labels.title && state === "guide" && (_jsx(Heading, { level: 1, className: "mb-6", size: "2xl", weight: "bold", children: labels.title })), state === "guide" && renderGuide?.(), state === "success" && renderSuccess?.(), state === "already-seller" && renderAlreadySeller?.()] }));
3
+ export function BecomeSellerView({ labels = {}, renderGuide, renderSuccess, renderCreateStore, renderAlreadySeller, state = "guide", className = "", }) {
4
+ return (_jsxs(Div, { className: className, children: [labels.title && state === "guide" && (_jsx(Heading, { level: 1, className: "mb-6", size: "2xl", weight: "bold", children: labels.title })), state === "guide" && renderGuide?.(), state === "success" && renderSuccess?.(), state === "create-store" && renderCreateStore?.(), state === "already-seller" && renderAlreadySeller?.()] }));
5
5
  }
@@ -25,7 +25,7 @@ const SECTIONS = [
25
25
  },
26
26
  {
27
27
  Icon: CheckCircle, title: "Order Confirmation",
28
- content: (_jsxs(_Fragment, { children: [_jsx(Text, { className: GC.textMuted, children: "After a successful payment you'll see an on-screen confirmation with your order ID. You'll also receive:" }), _jsxs(Ul, { className: `${GC.listDiscMuted} mt-3`, children: [_jsx(Li, { children: "An email confirmation to your registered address" }), _jsx(Li, { children: "An in-app notification you can read any time from the bell in the header" })] }), _jsxs(Text, { className: `${GC.textMuted} mt-3`, children: ["View all your orders at any time under ", _jsx(Span, { weight: "bold", children: "My Account \u2192 My Orders" }), "."] })] })),
28
+ content: (_jsxs(_Fragment, { children: [_jsx(Text, { className: GC.textMuted, children: "After a successful payment you'll see an on-screen confirmation with your order ID. You'll also receive:" }), _jsxs(Ul, { className: `${GC.listDiscMuted} mt-3`, children: [_jsx(Li, { children: "An email confirmation to your registered address" }), _jsx(Li, { children: "A WhatsApp message if you've added and verified your phone number" })] }), _jsxs(Text, { className: `${GC.textMuted} mt-3`, children: ["View all your orders at any time under ", _jsx(Span, { weight: "bold", children: "My Account \u2192 My Orders" }), "."] })] })),
29
29
  },
30
30
  {
31
31
  Icon: UserX, title: "Guest Limitations",
@@ -30,7 +30,7 @@ export function NotificationPreferencesPanel({ fetchUrl = ACCOUNT_ENDPOINTS.NOTI
30
30
  const { showToast } = useToast();
31
31
  const { data: settings } = useSiteSettings();
32
32
  const adminChannels = settings?.notificationChannels;
33
- const [channels, setChannels] = useState({ email: true, sms: true });
33
+ const [channels, setChannels] = useState({ email: true, whatsapp: true, sms: true });
34
34
  const [types, setTypes] = useState({
35
35
  orderUpdates: true, bids: true, promotions: true,
36
36
  system: true, reviews: true, messages: true, offers: true,
@@ -92,7 +92,8 @@ export function NotificationPreferencesPanel({ fetchUrl = ACCOUNT_ENDPOINTS.NOTI
92
92
  }
93
93
  // Which channels are admin-enabled (only show those toggles to the user)
94
94
  const emailAdminEnabled = adminChannels?.email?.enabled ?? false;
95
+ const whatsappAdminEnabled = adminChannels?.whatsapp?.enabled ?? false;
95
96
  const smsAdminEnabled = adminChannels?.sms?.enabled ?? false;
96
- const anyChannelEnabled = emailAdminEnabled || smsAdminEnabled;
97
- return (_jsxs(Stack, { gap: "lg", children: [_jsx(SectionCard, { title: "In-app notifications", children: _jsxs(Row, { align: "center", justify: "between", gap: "md", padding: "y-sm", children: [_jsxs(Div, { children: [_jsx(Text, { className: "text-[var(--appkit-color-text)]", size: "sm", weight: "medium", children: "In-app notifications" }), _jsx(Text, { variant: "secondary", className: "mt-0.5", size: "xs", children: "Always on \u2014 displayed in the notification bell and inbox" })] }), _jsx(Row, { className: "h-5 w-9 bg-[var(--appkit-color-primary)] px-[0.125rem]", align: "center", justify: "end", rounded: "full", "aria-label": "Always on", children: _jsx(Span, { className: "h-4 w-4", rounded: "full", surface: "default", shadow: "default" }) })] }) }), anyChannelEnabled && (_jsxs(SectionCard, { title: "Notification channels", children: [emailAdminEnabled && (_jsx(ToggleRow, { label: "Email", description: "Receive notifications by email", checked: channels.email !== false, onChange: (v) => setChannel("email", v) })), smsAdminEnabled && (_jsx(ToggleRow, { label: "SMS", description: "Receive SMS text notifications", checked: channels.sms !== false, onChange: (v) => setChannel("sms", v) }))] })), _jsx(SectionCard, { title: "Notification types", children: TYPE_ROWS.map((row) => (_jsx(ToggleRow, { label: row.label, description: row.description, checked: types[row.key] !== false, onChange: (v) => setType(row.key, v) }, row.key))) }), _jsxs(Row, { justify: "end", gap: "sm", children: [saved && (_jsx(Text, { className: "text-[var(--appkit-color-success)] self-center", size: "sm", children: "Preferences saved \u2713" })), _jsx(Button, { onClick: handleSave, isLoading: saving, size: "sm", children: "Save preferences" })] })] }));
97
+ const anyChannelEnabled = emailAdminEnabled || whatsappAdminEnabled || smsAdminEnabled;
98
+ return (_jsxs(Stack, { gap: "lg", children: [_jsx(SectionCard, { title: "In-app notifications", children: _jsxs(Row, { align: "center", justify: "between", gap: "md", padding: "y-sm", children: [_jsxs(Div, { children: [_jsx(Text, { className: "text-[var(--appkit-color-text)]", size: "sm", weight: "medium", children: "In-app notifications" }), _jsx(Text, { variant: "secondary", className: "mt-0.5", size: "xs", children: "Always on \u2014 displayed in the notification bell and inbox" })] }), _jsx(Row, { className: "h-5 w-9 bg-[var(--appkit-color-primary)] px-[0.125rem]", align: "center", justify: "end", rounded: "full", "aria-label": "Always on", children: _jsx(Span, { className: "h-4 w-4", rounded: "full", surface: "default", shadow: "default" }) })] }) }), anyChannelEnabled && (_jsxs(SectionCard, { title: "Notification channels", children: [emailAdminEnabled && (_jsx(ToggleRow, { label: "Email", description: "Receive notifications by email", checked: channels.email !== false, onChange: (v) => setChannel("email", v) })), whatsappAdminEnabled && (_jsx(ToggleRow, { label: "WhatsApp", description: "Receive notifications on WhatsApp", checked: channels.whatsapp !== false, onChange: (v) => setChannel("whatsapp", v) })), smsAdminEnabled && (_jsx(ToggleRow, { label: "SMS", description: "Receive SMS text notifications", checked: channels.sms !== false, onChange: (v) => setChannel("sms", v) }))] })), _jsx(SectionCard, { title: "Notification types", children: TYPE_ROWS.map((row) => (_jsx(ToggleRow, { label: row.label, description: row.description, checked: types[row.key] !== false, onChange: (v) => setType(row.key, v) }, row.key))) }), _jsxs(Row, { justify: "end", gap: "sm", children: [saved && (_jsx(Text, { className: "text-[var(--appkit-color-success)] self-center", size: "sm", children: "Preferences saved \u2713" })), _jsx(Button, { onClick: handleSave, isLoading: saving, size: "sm", children: "Save preferences" })] })] }));
98
99
  }
@@ -75,6 +75,8 @@ export interface UserAddress {
75
75
  export interface NotificationChannelPrefs {
76
76
  /** Disable all email notifications for this user (default: true = enabled). */
77
77
  email?: boolean;
78
+ /** Disable all WhatsApp notifications for this user. */
79
+ whatsapp?: boolean;
78
80
  /** Disable all SMS notifications for this user. */
79
81
  sms?: boolean;
80
82
  }
@@ -11,8 +11,21 @@ export declare function getUnreadNotificationCount(userId: string): Promise<numb
11
11
  export interface SendNotificationInput extends NotificationCreateInput {
12
12
  /** User's email — used by the email channel when enabled. */
13
13
  userEmail?: string;
14
+ /** User's phone with country code, digits only — used by WhatsApp channel. */
15
+ userPhone?: string;
14
16
  /** Pre-rendered email HTML — falls back to a plain-text <p> when absent. */
15
17
  emailHtml?: string;
18
+ /**
19
+ * The store this notification is about, for the order-lifecycle types in
20
+ * `ORDER_GATED_TYPES`. Its WhatsApp subscription decides whether the
21
+ * WhatsApp arm runs; absent, those types fall back to in-app + email.
22
+ *
23
+ * Resolved HERE rather than by each caller: six call sites would otherwise
24
+ * each do their own store read and each be a place the rule could drift
25
+ * (Root Cause #75). The read only happens when the type is gated AND
26
+ * WhatsApp is otherwise eligible, so the common path costs nothing.
27
+ */
28
+ storeId?: string;
16
29
  /**
17
30
  * Which portal the recipient reads this in — decides where `actionUrl`
18
31
  * points when the caller does not supply one.
@@ -48,15 +61,17 @@ export interface SendNotificationInput extends NotificationCreateInput {
48
61
  export interface SendNotificationResult {
49
62
  notification: NotificationDocument;
50
63
  email: "sent" | "skipped" | "failed";
64
+ /** WhatsApp dispatch is now async (enqueued as a `whatsappNotify` job) — "queued" replaces "sent" as the immediate outcome; the real delivery result lands on `notification.whatsappStatus`. */
65
+ whatsapp: "queued" | "skipped" | "failed";
51
66
  }
52
67
  /**
53
68
  * Create an in-app notification and fan out to enabled external channels.
54
69
  *
55
- * In-app is always written. Email is sent only when:
70
+ * In-app is always written. Email / WhatsApp are sent only when:
56
71
  * 1. The channel is enabled in siteSettings.notificationChannels
57
72
  * 2. Notification priority meets the channel's minPriority threshold
58
73
  * 3. The optional `types` filter includes this notification type (or is absent)
59
- * 4. The contact field (userEmail) is supplied by the caller
74
+ * 4. The contact field (userEmail / userPhone) is supplied by the caller
60
75
  * 5. The required credentials are set in siteSettings.credentials
61
76
  */
62
77
  export declare function sendNotification(input: SendNotificationInput): Promise<SendNotificationResult>;