@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.
- package/dist/.build-stamp.json +3 -3
- package/dist/_internal/server/features/categories/adapters.d.ts +1 -1
- package/dist/_internal/server/features/categories/adapters.js +13 -0
- package/dist/_internal/server/features/checkout/actions.d.ts +2 -0
- package/dist/_internal/server/features/checkout/actions.js +22 -5
- package/dist/_internal/server/features/events/like-actions.d.ts +25 -0
- package/dist/_internal/server/features/events/like-actions.js +67 -0
- package/dist/_internal/server/features/events/likes.d.ts +65 -0
- package/dist/_internal/server/features/events/likes.js +146 -0
- package/dist/_internal/server/features/orders/adapters.js +3 -1
- package/dist/_internal/server/features/seo/index.d.ts +3 -0
- package/dist/_internal/server/features/seo/index.js +2 -0
- package/dist/_internal/server/features/seo/product-detail-types.d.ts +1 -0
- package/dist/_internal/server/features/seo/product-detail-types.js +26 -0
- package/dist/_internal/server/features/seo/robots.js +20 -1
- package/dist/_internal/server/features/seo/sitemap.js +125 -27
- package/dist/_internal/server/features/seo/static-params.d.ts +107 -0
- package/dist/_internal/server/features/seo/static-params.js +228 -0
- package/dist/_internal/server/features/seo/taxonomy-links.d.ts +44 -0
- package/dist/_internal/server/features/seo/taxonomy-links.js +85 -0
- package/dist/_internal/server/features/site-settings/adapters.js +20 -2
- package/dist/_internal/server/features/stores/adapters.d.ts +2 -2
- package/dist/_internal/server/features/stores/adapters.js +88 -1
- package/dist/_internal/server/functions/scheduled.d.ts +16 -1
- package/dist/_internal/server/functions/scheduled.js +23 -1
- package/dist/_internal/server/jobs/core/analyticsAlertEvaluate.js +5 -2
- package/dist/_internal/server/jobs/core/jobRunners.js +5 -0
- package/dist/_internal/server/jobs/core/onOrderCreate.js +104 -10
- package/dist/_internal/server/jobs/core/onOrderStatusChange.d.ts +2 -0
- package/dist/_internal/server/jobs/core/onOrderStatusChange.js +1 -0
- package/dist/_internal/server/jobs/core/onScamReportCreate.js +1 -0
- package/dist/_internal/server/jobs/core/onScamReportRejected.js +1 -0
- package/dist/_internal/server/jobs/core/onScamReportVerified.js +1 -0
- package/dist/_internal/server/jobs/core/paymentWindowTimeout.js +1 -0
- package/dist/_internal/server/jobs/core/pendingOrderTimeout.js +1 -0
- package/dist/_internal/server/jobs/core/sellerStandingRollup.d.ts +63 -0
- package/dist/_internal/server/jobs/core/sellerStandingRollup.js +412 -0
- package/dist/_internal/server/jobs/core/whatsappNotify.d.ts +35 -0
- package/dist/_internal/server/jobs/core/whatsappNotify.js +140 -0
- package/dist/_internal/server/jobs/handlers/index.d.ts +1 -0
- package/dist/_internal/server/jobs/handlers/index.js +1 -0
- package/dist/_internal/server/jobs/handlers/sellerStandingRollup.d.ts +12 -0
- package/dist/_internal/server/jobs/handlers/sellerStandingRollup.js +14 -0
- package/dist/_internal/server/notifications/channel-health.d.ts +8 -6
- package/dist/_internal/server/notifications/channel-health.js +2 -2
- package/dist/_internal/server/notifications/send-guard.d.ts +1 -1
- package/dist/_internal/server/notifications/send-guard.js +4 -2
- package/dist/_internal/shared/actions/action-registry.js +89 -0
- package/dist/_internal/shared/checkout/order-math.d.ts +1 -1
- package/dist/_internal/shared/checkout/order-math.js +1 -1
- package/dist/_internal/shared/features/checkout/config.d.ts +2 -0
- package/dist/_internal/shared/features/checkout/config.js +2 -0
- package/dist/_internal/shared/features/messaging/config.d.ts +5 -7
- package/dist/_internal/shared/features/messaging/config.js +4 -1
- package/dist/_internal/shared/features/seller-standing/config.d.ts +130 -0
- package/dist/_internal/shared/features/seller-standing/config.js +153 -0
- package/dist/_internal/shared/features/site-settings/fees.d.ts +2 -0
- package/dist/_internal/shared/features/site-settings/fees.js +2 -0
- package/dist/_internal/shared/features/site-settings/types.d.ts +27 -2
- package/dist/_internal/shared/fees/calculator.d.ts +8 -0
- package/dist/_internal/shared/fees/calculator.js +7 -0
- package/dist/cli/index.js +2 -0
- package/dist/client.d.ts +2 -2
- package/dist/client.js +1 -1
- package/dist/constants/api-endpoints.d.ts +39 -0
- package/dist/constants/api-endpoints.js +16 -0
- package/dist/constants/notification-types.d.ts +1 -1
- package/dist/constants/notification-types.js +1 -1
- package/dist/core/integration-keys.d.ts +5 -0
- package/dist/core/integration-keys.js +10 -0
- package/dist/features/about/components/FeesView.js +6 -0
- package/dist/features/about/components/HelpPageView.js +9 -1
- package/dist/features/account/components/BecomeSellerView.d.ts +15 -3
- package/dist/features/account/components/BecomeSellerView.js +2 -2
- package/dist/features/account/components/BuyerShoppingGuideView.js +1 -1
- package/dist/features/account/components/NotificationPreferencesPanel.js +4 -3
- package/dist/features/account/types/index.d.ts +2 -0
- package/dist/features/admin/actions/notification-actions.d.ts +17 -2
- package/dist/features/admin/actions/notification-actions.js +154 -9
- package/dist/features/admin/components/AdminOrderEditorView.d.ts +1 -1
- package/dist/features/admin/components/AdminOrdersView.js +2 -0
- package/dist/features/admin/components/AdminSiteSettingsView.js +66 -6
- package/dist/features/admin/components/AdminStoreEditorView.d.ts +12 -1
- package/dist/features/admin/components/AdminStoreEditorView.js +31 -2
- package/dist/features/admin/components/AdminStoresGuideView.js +1 -1
- package/dist/features/admin/components/AdminStoresView.js +59 -2
- package/dist/features/admin/components/AdminTrustGuideView.js +10 -0
- package/dist/features/admin/constants/site-settings-tabs.d.ts +12 -7
- package/dist/features/admin/constants/site-settings-tabs.js +12 -6
- package/dist/features/admin/repository/site-settings.repository.js +1 -1
- package/dist/features/admin/schemas/admin-editor-forms.d.ts +10 -0
- package/dist/features/admin/schemas/admin-editor-forms.js +34 -0
- package/dist/features/admin/schemas/admin-user-form.d.ts +61 -0
- package/dist/features/admin/schemas/admin-user-form.js +44 -3
- package/dist/features/admin/schemas/firestore.d.ts +73 -0
- package/dist/features/admin/schemas/firestore.js +8 -3
- package/dist/features/auth/checkout-value-otp.d.ts +1 -1
- package/dist/features/auth/checkout-value-otp.js +1 -1
- package/dist/features/auth/permissions/constants.d.ts +2 -2
- package/dist/features/auth/permissions/constants.js +2 -1
- package/dist/features/blog/components/BlogIndexPageView.js +2 -2
- package/dist/features/blog/components/BlogListView.js +2 -1
- package/dist/features/blog/components/BlogPostView.js +2 -1
- package/dist/features/blog/constants/category-badge.d.ts +33 -0
- package/dist/features/blog/constants/category-badge.js +40 -0
- package/dist/features/cart/components/CartPriceBreakdown.d.ts +2 -0
- package/dist/features/cart/components/CartPriceBreakdown.js +1 -1
- package/dist/features/cart/components/StoreAddonsPicker.d.ts +5 -2
- package/dist/features/cart/components/StoreAddonsPicker.js +5 -4
- package/dist/features/cart/repository/cart.repository.js +2 -1
- package/dist/features/cart/schemas/firestore.d.ts +2 -1
- package/dist/features/categories/components/TaxonomyLinkIndex.d.ts +39 -0
- package/dist/features/categories/components/TaxonomyLinkIndex.js +11 -0
- package/dist/features/categories/schemas/firestore.d.ts +25 -0
- package/dist/features/categories/utils/load-category-options.d.ts +33 -0
- package/dist/features/categories/utils/load-category-options.js +50 -0
- package/dist/features/checkout/actions/checkout-value-otp-actions.d.ts +5 -10
- package/dist/features/checkout/actions/checkout-value-otp-actions.js +88 -2
- package/dist/features/events/components/EventCard.js +4 -12
- package/dist/features/events/components/EventInsights.d.ts +27 -0
- package/dist/features/events/components/EventInsights.js +10 -0
- package/dist/features/events/components/EventLikeButton.d.ts +21 -0
- package/dist/features/events/components/EventLikeButton.js +59 -0
- package/dist/features/events/components/EventLikersRail.d.ts +23 -0
- package/dist/features/events/components/EventLikersRail.js +54 -0
- package/dist/features/events/components/EventTypeBadge.d.ts +26 -0
- package/dist/features/events/components/EventTypeBadge.js +7 -0
- package/dist/features/events/components/EventsListPageView.js +2 -2
- package/dist/features/events/components/SpinWheel.d.ts +41 -0
- package/dist/features/events/components/SpinWheel.js +128 -0
- package/dist/features/events/components/SpinWheelView.js +36 -15
- package/dist/features/events/constants/event-type-meta.d.ts +54 -0
- package/dist/features/events/constants/event-type-meta.js +109 -0
- package/dist/features/events/repository/event-likes.repository.d.ts +57 -0
- package/dist/features/events/repository/event-likes.repository.js +151 -0
- package/dist/features/events/schemas/firestore.d.ts +111 -0
- package/dist/features/events/schemas/likes.d.ts +81 -0
- package/dist/features/events/schemas/likes.js +59 -0
- package/dist/features/events/types/index.d.ts +7 -0
- package/dist/features/events/utils/carousel-slide.d.ts +42 -0
- package/dist/features/events/utils/carousel-slide.js +174 -0
- package/dist/features/events/utils/event-charts.d.ts +65 -0
- package/dist/features/events/utils/event-charts.js +172 -0
- package/dist/features/faq/constants/help-guides.js +9 -0
- package/dist/features/faq/schemas/firestore.js +1 -0
- package/dist/features/faq/types/index.d.ts +19 -0
- package/dist/features/homepage/components/BrandsSection.js +25 -1
- package/dist/features/homepage/components/HeroCarousel.js +47 -10
- package/dist/features/homepage/lib/section-renderer.js +1 -1
- package/dist/features/homepage/types/index.d.ts +7 -0
- package/dist/features/orders/actions/refund-actions.js +1 -0
- package/dist/features/orders/components/OrderAddonBadges.d.ts +3 -1
- package/dist/features/orders/components/OrderAddonBadges.js +4 -3
- package/dist/features/orders/repository/orders.repository.d.ts +8 -0
- package/dist/features/orders/repository/orders.repository.js +2 -0
- package/dist/features/orders/schemas/firestore.d.ts +4 -0
- package/dist/features/orders/types/index.d.ts +5 -2
- package/dist/features/search/action-index/settings-entries.js +9 -0
- package/dist/features/store-extensions/repository/store-extensions.repositories.d.ts +6 -1
- package/dist/features/store-extensions/repository/store-extensions.repositories.js +10 -1
- package/dist/features/store-extensions/schemas/firestore.d.ts +17 -1
- package/dist/features/store-extensions/schemas/firestore.js +10 -0
- package/dist/features/stores/components/InteractiveStoreCard.js +2 -1
- package/dist/features/stores/components/SellerStandingPanel.d.ts +31 -0
- package/dist/features/stores/components/SellerStandingPanel.js +25 -0
- package/dist/features/stores/components/SellerTierBadge.d.ts +57 -0
- package/dist/features/stores/components/SellerTierBadge.js +19 -0
- package/dist/features/stores/components/StoreCapabilitiesGuideView.js +33 -2
- package/dist/features/stores/components/StoreCreateForm.d.ts +46 -0
- package/dist/features/stores/components/StoreCreateForm.js +107 -0
- package/dist/features/stores/components/StoreGuideHubView.js +18 -5
- package/dist/features/stores/components/StoreHeader.js +2 -1
- package/dist/features/stores/components/StoreSettingsGuideView.js +6 -2
- package/dist/features/stores/repository/store.repository.d.ts +23 -1
- package/dist/features/stores/repository/store.repository.js +52 -1
- package/dist/features/stores/schemas/firestore.d.ts +76 -7
- package/dist/features/stores/schemas/firestore.js +21 -6
- package/dist/features/stores/schemas/index.d.ts +88 -2
- package/dist/features/stores/schemas/index.js +14 -0
- package/dist/features/stores/schemas/store-create.d.ts +47 -0
- package/dist/features/stores/schemas/store-create.js +86 -0
- package/dist/features/stores/types/index.d.ts +42 -0
- package/dist/features/whatsapp-bot/api/send-status/route.d.ts +12 -0
- package/dist/features/whatsapp-bot/api/send-status/route.js +38 -0
- package/dist/features/whatsapp-bot/api/webhook/route.d.ts +12 -0
- package/dist/features/whatsapp-bot/api/webhook/route.js +43 -0
- package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.d.ts +57 -0
- package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.js +76 -0
- package/dist/features/whatsapp-bot/components/WhatsAppChatButton.d.ts +9 -0
- package/dist/features/whatsapp-bot/components/WhatsAppChatButton.js +7 -0
- package/dist/features/whatsapp-bot/components/index.d.ts +3 -0
- package/dist/features/whatsapp-bot/components/index.js +2 -0
- package/dist/features/whatsapp-bot/helpers/whatsapp.d.ts +52 -0
- package/dist/features/whatsapp-bot/helpers/whatsapp.js +288 -0
- package/dist/features/whatsapp-bot/index.d.ts +3 -0
- package/dist/features/whatsapp-bot/index.js +3 -0
- package/dist/features/whatsapp-bot/manifest.d.ts +2 -0
- package/dist/features/whatsapp-bot/manifest.js +13 -0
- package/dist/features/whatsapp-bot/messages/en.json +7 -0
- package/dist/features/whatsapp-bot/server.d.ts +7 -0
- package/dist/features/whatsapp-bot/server.js +7 -0
- package/dist/features/whatsapp-bot/types/index.d.ts +126 -0
- package/dist/features/whatsapp-bot/types/index.js +1 -0
- package/dist/index.d.ts +23 -6
- package/dist/index.js +38 -12
- package/dist/next/routing/route-map.d.ts +6 -1
- package/dist/next/routing/route-map.js +14 -0
- package/dist/providers/db-firebase/base.repository.d.ts +1 -1
- package/dist/providers/db-firebase/base.repository.js +1 -1
- package/dist/repositories/index.d.ts +1 -1
- package/dist/repositories/index.js +1 -1
- package/dist/schemas/registry.d.ts +115 -0
- package/dist/schemas/registry.js +2 -1
- package/dist/security/pii-encrypt.js +1 -1
- package/dist/server.d.ts +15 -2
- package/dist/server.js +32 -2
- package/dist/styles.css +36 -1
- package/dist/tailwind-utilities.css +1 -1
- package/dist/ui/components/HorizontalScroller.js +15 -2
- package/dist/ui/components/NavigationLoader.d.ts +14 -1
- package/dist/ui/components/NavigationLoader.js +79 -30
- package/dist/ui/components/PageHeroHeading.d.ts +40 -0
- package/dist/ui/components/PageHeroHeading.js +15 -0
- package/dist/ui/components/Typography.d.ts +3 -3
- package/dist/ui/components/Typography.js +59 -31
- package/dist/ui/components/Typography.style.css +35 -0
- package/dist/ui/index.d.ts +2 -0
- package/dist/ui/index.js +1 -0
- package/package.json +1 -1
- package/scripts/seed-cli.mjs +4 -2
- package/dist/features/orders/utils/order-announcement-message.d.ts +0 -18
- 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 {
|
|
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
|
-
|
|
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
|
|
13
|
-
state?:
|
|
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: "
|
|
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.
|
|
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>;
|