@mohasinac/appkit 4.18.0 → 4.19.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/_internal/client/features/lottery/LotteryAdminEditView.js +3 -1
- package/dist/_internal/client/features/lottery/LotteryPullForm.js +3 -1
- package/dist/_internal/shared/features/lottery/config-form.d.ts +58 -0
- package/dist/_internal/shared/features/lottery/config-form.js +71 -0
- package/dist/client.d.ts +3 -0
- package/dist/client.js +3 -0
- package/dist/features/account/schemas/index.d.ts +23 -0
- package/dist/features/account/schemas/index.js +21 -0
- package/dist/features/admin/components/AdminSiteSettingsView.js +8 -6
- package/dist/features/admin/components/AdminUserEditorView.js +14 -12
- package/dist/features/admin/schemas/admin-user-form.d.ts +82 -0
- package/dist/features/admin/schemas/admin-user-form.js +102 -0
- package/dist/features/admin/schemas/site-settings-form.d.ts +309 -0
- package/dist/features/admin/schemas/site-settings-form.js +159 -0
- package/dist/features/auctions/components/PlaceBidFormClient.js +3 -2
- package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.js +4 -2
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/schemas/registry.d.ts +682 -0
- package/dist/schemas/registry.js +22 -0
- package/package.json +1 -1
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* WHY: `AdminSiteSettingsView` is 1826 lines with **21 `<Form>` tags and no
|
|
3
|
+
* schema on any of them**. All 21 are tabs over one document and save
|
|
4
|
+
* through a single `buildFullPayload()` → one PUT, so this is one form
|
|
5
|
+
* wearing twenty-one hats, entirely unvalidated.
|
|
6
|
+
*
|
|
7
|
+
* Live consequences already documented for this exact payload:
|
|
8
|
+
* · `announcementBar` was saved under the key `text` until 2026-08-24 —
|
|
9
|
+
* a key no renderer has ever read — so admin-authored announcements
|
|
10
|
+
* saved successfully and never appeared.
|
|
11
|
+
* · `adSettings`, `integrations`, `platformLimits`, `tagline` and
|
|
12
|
+
* `favicon` were written here while undeclared on
|
|
13
|
+
* `SiteSettingsDocument`, which is how an unmasked ad-credentials
|
|
14
|
+
* blob reached anonymous callers (Recurrent Root Cause #70).
|
|
15
|
+
*
|
|
16
|
+
* WHAT: A schema that validates the fields with real rules and **passes the
|
|
17
|
+
* rest through untouched**.
|
|
18
|
+
*
|
|
19
|
+
* ## 🛑 This one is `.passthrough()`, deliberately, and that is the whole point
|
|
20
|
+
*
|
|
21
|
+
* Everywhere else in this rework an update schema is `.strict()`. Here that
|
|
22
|
+
* would be actively dangerous. `buildFullPayload()` demonstrably writes keys
|
|
23
|
+
* the TypeScript interface does not declare, and a closed schema would SILENTLY
|
|
24
|
+
* STRIP every one of them on the next save — turning a validation improvement
|
|
25
|
+
* into the largest single act of data loss in the codebase. That is the
|
|
26
|
+
* `productBaseSchema` failure, aimed at the site's entire configuration.
|
|
27
|
+
*
|
|
28
|
+
* So: constrain what can be reasoned about (percentages that must be 0–100,
|
|
29
|
+
* money that must be non-negative, a contact email that must be an email), and
|
|
30
|
+
* let the rest pass. Tightening any group is a separate, evidence-led change —
|
|
31
|
+
* per the data-integrity protocol, only after a full-collection round-trip
|
|
32
|
+
* diff proves the schema is a superset of what is stored.
|
|
33
|
+
*
|
|
34
|
+
* EXPORTS: siteSettingsFormSchema, type SiteSettingsFormValues
|
|
35
|
+
*
|
|
36
|
+
* @tag domain:admin
|
|
37
|
+
* @tag layer:schema
|
|
38
|
+
* @tag pattern:none
|
|
39
|
+
* @tag access:isomorphic
|
|
40
|
+
* @tag consumers:AdminSiteSettingsView
|
|
41
|
+
* @tag sideEffects:none
|
|
42
|
+
*/
|
|
43
|
+
import { z } from "zod";
|
|
44
|
+
/** A percentage a human types into a settings box. */
|
|
45
|
+
const percent = (label) => z.coerce
|
|
46
|
+
.number({ invalid_type_error: `${label} must be a number.` })
|
|
47
|
+
.min(0, `${label} cannot be negative.`)
|
|
48
|
+
.max(100, `${label} cannot exceed 100%.`)
|
|
49
|
+
.optional();
|
|
50
|
+
/** A non-negative rupee amount. */
|
|
51
|
+
const money = (label) => z.coerce
|
|
52
|
+
.number({ invalid_type_error: `${label} must be a number.` })
|
|
53
|
+
.min(0, `${label} cannot be negative.`)
|
|
54
|
+
.optional();
|
|
55
|
+
/** An optional email box — blank is allowed, malformed is not. */
|
|
56
|
+
const optionalEmail = z
|
|
57
|
+
.string()
|
|
58
|
+
.trim()
|
|
59
|
+
.toLowerCase()
|
|
60
|
+
.email("That doesn't look like an email address.")
|
|
61
|
+
.optional()
|
|
62
|
+
.or(z.literal(""));
|
|
63
|
+
/** An optional URL box — blank is allowed, malformed is not. */
|
|
64
|
+
const optionalUrl = z
|
|
65
|
+
.string()
|
|
66
|
+
.trim()
|
|
67
|
+
.url("Enter a full URL, including https://.")
|
|
68
|
+
.optional()
|
|
69
|
+
.or(z.literal(""));
|
|
70
|
+
export const siteSettingsFormSchema = z
|
|
71
|
+
.object({
|
|
72
|
+
/*
|
|
73
|
+
* 🛑 `message` is the canonical key. Naming it here is what stops the
|
|
74
|
+
* `text` mistake recurring: a payload carrying `text` still passes (the
|
|
75
|
+
* schema is open), but the one key a renderer reads is now declared, and
|
|
76
|
+
* the form is typed against it.
|
|
77
|
+
*/
|
|
78
|
+
announcementBar: z
|
|
79
|
+
.object({
|
|
80
|
+
message: z.string().trim().max(300, "Keep the announcement under 300 characters.").optional(),
|
|
81
|
+
enabled: z.boolean().optional(),
|
|
82
|
+
link: optionalUrl,
|
|
83
|
+
})
|
|
84
|
+
.passthrough()
|
|
85
|
+
.optional(),
|
|
86
|
+
contact: z
|
|
87
|
+
.object({
|
|
88
|
+
email: optionalEmail,
|
|
89
|
+
supportEmail: optionalEmail,
|
|
90
|
+
phone: z.string().trim().max(40).optional(),
|
|
91
|
+
})
|
|
92
|
+
.passthrough()
|
|
93
|
+
.optional(),
|
|
94
|
+
/*
|
|
95
|
+
* The commission block. Every one of these is a percentage or an amount
|
|
96
|
+
* that multiplies against real orders, and all were free text — a stray
|
|
97
|
+
* keystroke in `platformFeePercent` changes what every seller is charged.
|
|
98
|
+
*/
|
|
99
|
+
commissions: z
|
|
100
|
+
.object({
|
|
101
|
+
platformFeePercent: percent("Platform fee"),
|
|
102
|
+
gatewayFeePercent: percent("Gateway fee"),
|
|
103
|
+
platformFeeMax: money("Platform fee cap"),
|
|
104
|
+
minPayoutAmount: money("Minimum payout"),
|
|
105
|
+
payoutHoldDays: z.coerce.number().int().min(0).max(365).optional(),
|
|
106
|
+
codHandlingFee: money("COD handling fee"),
|
|
107
|
+
codDepositPercent: percent("COD deposit"),
|
|
108
|
+
})
|
|
109
|
+
.passthrough()
|
|
110
|
+
.optional(),
|
|
111
|
+
laborRate: z
|
|
112
|
+
.object({ hourlyRate: money("Hourly rate") })
|
|
113
|
+
.passthrough()
|
|
114
|
+
.optional(),
|
|
115
|
+
emi: z
|
|
116
|
+
.object({
|
|
117
|
+
surchargePercent: percent("EMI surcharge"),
|
|
118
|
+
surchargeSellerSharePercent: percent("Seller share"),
|
|
119
|
+
minOrderAmount: money("Minimum EMI order"),
|
|
120
|
+
})
|
|
121
|
+
.passthrough()
|
|
122
|
+
.optional(),
|
|
123
|
+
gst: z
|
|
124
|
+
.object({
|
|
125
|
+
// 15 characters, the statutory format. A wrong GSTIN appears on every
|
|
126
|
+
// invoice the platform issues.
|
|
127
|
+
gstin: z
|
|
128
|
+
.string()
|
|
129
|
+
.trim()
|
|
130
|
+
.toUpperCase()
|
|
131
|
+
.regex(/^\d{2}[A-Z]{5}\d{4}[A-Z]\d[A-Z\d][A-Z\d]$/, "That is not a valid 15-character GSTIN.")
|
|
132
|
+
.optional()
|
|
133
|
+
.or(z.literal("")),
|
|
134
|
+
ratePercent: percent("GST rate"),
|
|
135
|
+
})
|
|
136
|
+
.passthrough()
|
|
137
|
+
.optional(),
|
|
138
|
+
auctionConfig: z
|
|
139
|
+
.object({
|
|
140
|
+
minBidIncrement: money("Minimum bid increment"),
|
|
141
|
+
extensionMinutes: z.coerce.number().int().min(0).max(1440).optional(),
|
|
142
|
+
})
|
|
143
|
+
.passthrough()
|
|
144
|
+
.optional(),
|
|
145
|
+
seo: z
|
|
146
|
+
.object({
|
|
147
|
+
title: z.string().trim().max(70, "Search engines truncate titles past ~70 characters.").optional(),
|
|
148
|
+
description: z
|
|
149
|
+
.string()
|
|
150
|
+
.trim()
|
|
151
|
+
.max(160, "Search engines truncate descriptions past ~160 characters.")
|
|
152
|
+
.optional(),
|
|
153
|
+
})
|
|
154
|
+
.passthrough()
|
|
155
|
+
.optional(),
|
|
156
|
+
})
|
|
157
|
+
// See the header: OPEN on purpose. `buildFullPayload()` writes keys the
|
|
158
|
+
// document interface does not declare, and closing this would delete them.
|
|
159
|
+
.passthrough();
|
|
@@ -13,6 +13,7 @@ import { useLiveAuctionBid } from "../hooks/useLiveAuctionBid";
|
|
|
13
13
|
import { AUCTION_BUYOUT_WINDOW_MINUTES } from "../../../_internal/shared/checkout/lanes";
|
|
14
14
|
import { BID_PRESET_MULTIPLIERS, isBuyNowAvailable, resolveMinBid, resolveMinBidIncrement, } from "../../../_internal/shared/features/auctions/config";
|
|
15
15
|
import { normalizeError } from "../../../errors/normalize";
|
|
16
|
+
import { FormErrorSummary } from "../../../ui/forms/FormErrorSummary";
|
|
16
17
|
const __P = {
|
|
17
18
|
p5: "p-[var(--appkit-space-5)]",
|
|
18
19
|
};
|
|
@@ -179,10 +180,10 @@ export function PlaceBidFormClient({ productId, currentBid: ssrCurrentBid, start
|
|
|
179
180
|
}
|
|
180
181
|
});
|
|
181
182
|
}
|
|
182
|
-
return (_jsxs(Stack, { className: `${__P.p5}`, border: "subtle", gap: "md", rounded: "xl", surface: "muted", children: [_jsxs(Stack, { gap: "xs", children: [_jsxs(Row, { justify: "between", align: "center", children: [_jsx(Text, { size: "xs", color: "muted", children: hasBids ? "Current bid" : "Starting bid" }), _jsx(Text, { size: "xs", color: "muted", children: hasBids ? "Starting bid" : "Minimum bid" })] }), _jsxs(Row, { justify: "between", align: "baseline", children: [_jsx(Span, { size: "xl", weight: "bold", className: "text-primary-600 dark:text-primary-400", children: formatCurrency(currentBid, currency) }), _jsx(Span, { size: "sm", color: "muted", children: formatCurrency(hasBids ? startingBid : minBid, currency) })] }), _jsxs(Text, { size: "xs", color: "faint", children: [bidCount, " ", bidCount === 1 ? "bid" : "bids", " \u00B7 min increment", " ", formatCurrency(minBidIncrement, currency)] })] }), _jsx(LoginRequiredModal, { isOpen: showLoginModal, onClose: () => setShowLoginModal(false), message: "You need to be signed in to place a bid. Please log in or create an account to continue." }), _jsx(Form, { onSubmit: (e) => {
|
|
183
|
+
return (_jsxs(Stack, { className: `${__P.p5}`, border: "subtle", gap: "md", rounded: "xl", surface: "muted", children: [_jsxs(Stack, { gap: "xs", children: [_jsxs(Row, { justify: "between", align: "center", children: [_jsx(Text, { size: "xs", color: "muted", children: hasBids ? "Current bid" : "Starting bid" }), _jsx(Text, { size: "xs", color: "muted", children: hasBids ? "Starting bid" : "Minimum bid" })] }), _jsxs(Row, { justify: "between", align: "baseline", children: [_jsx(Span, { size: "xl", weight: "bold", className: "text-primary-600 dark:text-primary-400", children: formatCurrency(currentBid, currency) }), _jsx(Span, { size: "sm", color: "muted", children: formatCurrency(hasBids ? startingBid : minBid, currency) })] }), _jsxs(Text, { size: "xs", color: "faint", children: [bidCount, " ", bidCount === 1 ? "bid" : "bids", " \u00B7 min increment", " ", formatCurrency(minBidIncrement, currency)] })] }), _jsx(LoginRequiredModal, { isOpen: showLoginModal, onClose: () => setShowLoginModal(false), message: "You need to be signed in to place a bid. Please log in or create an account to continue." }), _jsx(Form, { schema: schema, onSubmit: (e) => {
|
|
183
184
|
// handler wired through render-prop below — keeps setFieldError in scope
|
|
184
185
|
e.preventDefault();
|
|
185
|
-
}, children: ({ setFieldError, clearErrors }) => (_jsxs(Stack, { gap: "sm", children: [_jsxs(Row, { gap: "xs", wrap: true, role: "radiogroup", "aria-label": "Bid amount preset", children: [BID_PRESET_MULTIPLIERS.map((n) => {
|
|
186
|
+
}, children: ({ setFieldError, clearErrors }) => (_jsxs(Stack, { gap: "sm", children: [_jsx(FormErrorSummary, {}), _jsxs(Row, { gap: "xs", wrap: true, role: "radiogroup", "aria-label": "Bid amount preset", children: [BID_PRESET_MULTIPLIERS.map((n) => {
|
|
186
187
|
const amount = presetAmount(n);
|
|
187
188
|
const delta = amount - currentBid;
|
|
188
189
|
// `delta` is 0 only for the opening preset on a bid-free
|
|
@@ -16,6 +16,8 @@ import { apiClient } from "../../../http";
|
|
|
16
16
|
import { WHATSAPP_SELLER_ENDPOINTS } from "../../../constants/api-endpoints";
|
|
17
17
|
import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
|
|
18
18
|
import { buildPurchaseAnnouncementMessage } from "../helpers/whatsapp";
|
|
19
|
+
import { whatsappSettingsSchema } from "../../admin/schemas/admin-user-form";
|
|
20
|
+
import { FormErrorSummary } from "../../../ui/forms/FormErrorSummary";
|
|
19
21
|
// ---------------------------------------------------------------------------
|
|
20
22
|
// Sub-components
|
|
21
23
|
// ---------------------------------------------------------------------------
|
|
@@ -187,10 +189,10 @@ export function SellerWhatsAppSettingsView({ hasCapability }) {
|
|
|
187
189
|
? cfg?.connected === true
|
|
188
190
|
: Boolean(cfg?.[step.checkKey]);
|
|
189
191
|
return (_jsxs(Row, { gap: "sm", align: "start", children: [_jsx(Row, { textWeight: "bold", textSize: "xs", className: `flex-shrink-0 w-6 h-6 mt-0.5 ${done ? "bg-[var(--appkit-color-success)] text-white" : "bg-[var(--appkit-color-surface-elevated)] text-[var(--appkit-color-text-muted)] dark:text-[var(--appkit-color-text-faint)]"}`, align: "center", justify: "center", rounded: "full", children: done ? "✓" : step.n }), _jsxs(Div, { children: [_jsx(Text, { size: "sm", weight: "medium", color: "primary", children: step.title }), _jsx(Text, { className: "mt-0.5", color: "muted", size: "xs", children: step.body })] })] }, step.n));
|
|
190
|
-
}) })] }), _jsxs(Section, { className: CLS_SECTION_CARD, children: [_jsxs(Row, { justify: "between", align: "center", className: "mb-4", children: [_jsx(Heading, { level: 2, size: "sm", weight: "semibold", color: "primary", children: "Connection" }), isLoading ? null : cfg?.connected ? (_jsx(Badge, { variant: "success", children: "Connected" })) : (_jsx(Badge, { variant: "default", children: "Not configured" }))] }), _jsxs(Form, { onSubmit: (e) => {
|
|
192
|
+
}) })] }), _jsxs(Section, { className: CLS_SECTION_CARD, children: [_jsxs(Row, { justify: "between", align: "center", className: "mb-4", children: [_jsx(Heading, { level: 2, size: "sm", weight: "semibold", color: "primary", children: "Connection" }), isLoading ? null : cfg?.connected ? (_jsx(Badge, { variant: "success", children: "Connected" })) : (_jsx(Badge, { variant: "default", children: "Not configured" }))] }), _jsxs(Form, { schema: whatsappSettingsSchema, onSubmit: (e) => {
|
|
191
193
|
e.preventDefault();
|
|
192
194
|
saveMutation.mutate();
|
|
193
|
-
}, spacing: "md", children: [_jsx(Input, { label: "WhatsApp Business Phone Number", value: phoneNumber, onChange: (e) => setPhoneNumber(e.target.value), placeholder: "919876543210", helperText: "Digits only, include country code (e.g. 91 for India)" }), _jsx(Input, { label: "WABA ID (WhatsApp Business Account ID)", value: wabaId, onChange: (e) => setWabaId(e.target.value), placeholder: "123456789012345", helperText: "From Meta Business Manager \u2192 WhatsApp Accounts" }), _jsx(Input, { label: "Catalog ID", value: catalogId, onChange: (e) => setCatalogId(e.target.value), placeholder: "987654321098765", helperText: "From Meta Commerce Manager \u2192 Catalogs" }), _jsx(MaskedTokenInput, { label: "System User Access Token", value: accessToken, onChange: setAccessToken, placeholder: "EAAxxxxxxxx\u2026", helperText: "Long-lived token with WhatsApp Business permissions" }), _jsx(FormActions, { align: "right", children: _jsx(Button, { type: "submit", isLoading: saveMutation.isPending, disabled: saveMutation.isPending, children: saveMutation.isPending ? "Saving…" : ACTIONS.STORE["whatsapp-connect"].label }) })] })] }), _jsxs(Section, { className: CLS_SECTION_CARD, children: [_jsx(Heading, { level: 2, className: "mb-4", color: "primary", size: "sm", weight: "semibold", children: "Catalog Sync" }), _jsxs(Row, { justify: "between", align: "center", className: "mb-4", children: [_jsxs(Div, { children: [_jsx(Text, { size: "sm", color: "muted", children: "Enable catalog sync" }), _jsx(Text, { size: "xs", color: "muted", children: "When enabled, your published standard products can be synced to WhatsApp." })] }), _jsx(Toggle, { checked: syncEnabled, onChange: setSyncEnabled, disabled: !cfg?.connected })] }), cfg?.lastCatalogSyncAt && (_jsxs(Row, { color: "muted", textSize: "xs", gap: "sm", align: "center", className: "mb-3", children: [_jsxs(Text, { children: ["Last sync: ", new Date(cfg.lastCatalogSyncAt).toLocaleString("en-IN")] }), cfg.lastSyncCount !== undefined && _jsxs(Text, { children: ["\u00B7 ", cfg.lastSyncCount, " products"] }), cfg.lastSyncStatus && (_jsx(Badge, { variant: STATUS_VARIANT[cfg.lastSyncStatus] ?? "default", children: cfg.lastSyncStatus }))] })), _jsx(Text, { className: "mb-3", color: "faint", size: "xs", children: "Only published standard products are synced. Auctions and pre-orders are excluded. Batches of up to 50 products per call." }), _jsxs(Row, { gap: "3", children: [_jsx(Button, { onClick: () => syncMutation.mutate(), isLoading: syncMutation.isPending, disabled: !cfg?.connected || !syncEnabled || syncMutation.isPending, variant: "secondary", children: syncMutation.isPending ? "Syncing…" : ACTIONS.STORE["whatsapp-catalog-sync"].label }), _jsx(Button, { onClick: () => void startImport(), isLoading: importing, disabled: !cfg?.connected || !syncEnabled || importing, variant: "secondary", children: importing ? "Importing…" : ACTIONS.STORE["whatsapp-catalog-import"].label })] }), _jsxs(Text, { className: "mt-3", color: "faint", size: "xs", children: [_jsx(Span, { weight: "bold", children: "Push" }), " sends your published standard products to WhatsApp.", " ", _jsx(Span, { weight: "bold", children: "Import" }), " creates draft products from your WhatsApp catalog. Products are matched by slug in the description field."] })] }), _jsxs(Section, { className: CLS_SECTION_CARD, children: [_jsx(Heading, { level: 2, className: "mb-2", color: "primary", size: "sm", weight: "semibold", children: "Purchase Announcement Preview" }), _jsx(Text, { className: "mb-3", color: "muted", size: "xs", children: "This message is sent automatically to your phone and the platform admin when a new order is placed." }), _jsx(Div, { textSize: "sm", className: "font-mono", color: "primary", surface: "muted", padding: "inline", rounded: "lg", children: buildPurchaseAnnouncementMessage({
|
|
195
|
+
}, spacing: "md", children: [_jsx(FormErrorSummary, {}), _jsx(Input, { label: "WhatsApp Business Phone Number", value: phoneNumber, onChange: (e) => setPhoneNumber(e.target.value), placeholder: "919876543210", helperText: "Digits only, include country code (e.g. 91 for India)" }), _jsx(Input, { label: "WABA ID (WhatsApp Business Account ID)", value: wabaId, onChange: (e) => setWabaId(e.target.value), placeholder: "123456789012345", helperText: "From Meta Business Manager \u2192 WhatsApp Accounts" }), _jsx(Input, { label: "Catalog ID", value: catalogId, onChange: (e) => setCatalogId(e.target.value), placeholder: "987654321098765", helperText: "From Meta Commerce Manager \u2192 Catalogs" }), _jsx(MaskedTokenInput, { label: "System User Access Token", value: accessToken, onChange: setAccessToken, placeholder: "EAAxxxxxxxx\u2026", helperText: "Long-lived token with WhatsApp Business permissions" }), _jsx(FormActions, { align: "right", children: _jsx(Button, { type: "submit", isLoading: saveMutation.isPending, disabled: saveMutation.isPending, children: saveMutation.isPending ? "Saving…" : ACTIONS.STORE["whatsapp-connect"].label }) })] })] }), _jsxs(Section, { className: CLS_SECTION_CARD, children: [_jsx(Heading, { level: 2, className: "mb-4", color: "primary", size: "sm", weight: "semibold", children: "Catalog Sync" }), _jsxs(Row, { justify: "between", align: "center", className: "mb-4", children: [_jsxs(Div, { children: [_jsx(Text, { size: "sm", color: "muted", children: "Enable catalog sync" }), _jsx(Text, { size: "xs", color: "muted", children: "When enabled, your published standard products can be synced to WhatsApp." })] }), _jsx(Toggle, { checked: syncEnabled, onChange: setSyncEnabled, disabled: !cfg?.connected })] }), cfg?.lastCatalogSyncAt && (_jsxs(Row, { color: "muted", textSize: "xs", gap: "sm", align: "center", className: "mb-3", children: [_jsxs(Text, { children: ["Last sync: ", new Date(cfg.lastCatalogSyncAt).toLocaleString("en-IN")] }), cfg.lastSyncCount !== undefined && _jsxs(Text, { children: ["\u00B7 ", cfg.lastSyncCount, " products"] }), cfg.lastSyncStatus && (_jsx(Badge, { variant: STATUS_VARIANT[cfg.lastSyncStatus] ?? "default", children: cfg.lastSyncStatus }))] })), _jsx(Text, { className: "mb-3", color: "faint", size: "xs", children: "Only published standard products are synced. Auctions and pre-orders are excluded. Batches of up to 50 products per call." }), _jsxs(Row, { gap: "3", children: [_jsx(Button, { onClick: () => syncMutation.mutate(), isLoading: syncMutation.isPending, disabled: !cfg?.connected || !syncEnabled || syncMutation.isPending, variant: "secondary", children: syncMutation.isPending ? "Syncing…" : ACTIONS.STORE["whatsapp-catalog-sync"].label }), _jsx(Button, { onClick: () => void startImport(), isLoading: importing, disabled: !cfg?.connected || !syncEnabled || importing, variant: "secondary", children: importing ? "Importing…" : ACTIONS.STORE["whatsapp-catalog-import"].label })] }), _jsxs(Text, { className: "mt-3", color: "faint", size: "xs", children: [_jsx(Span, { weight: "bold", children: "Push" }), " sends your published standard products to WhatsApp.", " ", _jsx(Span, { weight: "bold", children: "Import" }), " creates draft products from your WhatsApp catalog. Products are matched by slug in the description field."] })] }), _jsxs(Section, { className: CLS_SECTION_CARD, children: [_jsx(Heading, { level: 2, className: "mb-2", color: "primary", size: "sm", weight: "semibold", children: "Purchase Announcement Preview" }), _jsx(Text, { className: "mb-3", color: "muted", size: "xs", children: "This message is sent automatically to your phone and the platform admin when a new order is placed." }), _jsx(Div, { textSize: "sm", className: "font-mono", color: "primary", surface: "muted", padding: "inline", rounded: "lg", children: buildPurchaseAnnouncementMessage({
|
|
194
196
|
buyerName: "Ravi K.",
|
|
195
197
|
firstItemName: "Charizard PSA 9",
|
|
196
198
|
additionalItemCount: 2,
|
package/dist/index.d.ts
CHANGED
|
@@ -3291,3 +3291,6 @@ export { scamReportFormSchema } from "./features/scams/schemas/report-form";
|
|
|
3291
3291
|
export { sublistingCategoryFormSchema } from "./features/store-extensions/schemas/sublisting-category-form";
|
|
3292
3292
|
export { adminAddressFormSchema, adminStoreUpdateSchema, announcementBarSchema, } from "./features/admin/schemas/admin-editor-forms";
|
|
3293
3293
|
export { adminOrderUpdateSchema, employeeInviteSchema, hardBanReasonSchema, featureFlagsUpdateSchema, adminAdFormSchema, } from "./features/admin/schemas/admin-ops-forms";
|
|
3294
|
+
export { changeEmailSchema } from "./features/account/schemas/index";
|
|
3295
|
+
export { adminUserUpdateSchema, whatsappSettingsSchema, lotteryPullSchema, } from "./features/admin/schemas/admin-user-form";
|
|
3296
|
+
export { siteSettingsFormSchema } from "./features/admin/schemas/site-settings-form";
|
package/dist/index.js
CHANGED
|
@@ -5700,3 +5700,6 @@ export { scamReportFormSchema } from "./features/scams/schemas/report-form";
|
|
|
5700
5700
|
export { sublistingCategoryFormSchema } from "./features/store-extensions/schemas/sublisting-category-form";
|
|
5701
5701
|
export { adminAddressFormSchema, adminStoreUpdateSchema, announcementBarSchema, } from "./features/admin/schemas/admin-editor-forms";
|
|
5702
5702
|
export { adminOrderUpdateSchema, employeeInviteSchema, hardBanReasonSchema, featureFlagsUpdateSchema, adminAdFormSchema, } from "./features/admin/schemas/admin-ops-forms";
|
|
5703
|
+
export { changeEmailSchema } from "./features/account/schemas/index";
|
|
5704
|
+
export { adminUserUpdateSchema, whatsappSettingsSchema, lotteryPullSchema, } from "./features/admin/schemas/admin-user-form";
|
|
5705
|
+
export { siteSettingsFormSchema } from "./features/admin/schemas/site-settings-form";
|