@infuro/cms-core 1.0.47 → 1.0.50
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/README.md +30 -16
- package/dist/admin.cjs +1172 -38
- package/dist/admin.js +1173 -39
- package/dist/api.cjs +37 -37
- package/dist/api.js +5 -5
- package/dist/auth.cjs +52 -23
- package/dist/auth.d.cts +101 -2
- package/dist/auth.d.ts +101 -2
- package/dist/auth.js +3 -2
- package/dist/chunk-3EOM4V2M.cjs +452 -0
- package/dist/{chunk-2HU5R2JE.js → chunk-AYERBA7I.js} +1 -7
- package/dist/{chunk-YXH2UUEZ.js → chunk-IPDHT2UV.js} +257 -16
- package/dist/{chunk-XUCKZPML.cjs → chunk-JCMOOPNX.cjs} +2696 -2601
- package/dist/{chunk-W42UZLQO.js → chunk-LT2WOPKA.js} +2642 -2540
- package/dist/chunk-RK5ETF2I.js +434 -0
- package/dist/{chunk-4PMK3RNA.cjs → chunk-TJ2MIQUT.cjs} +1 -7
- package/dist/{chunk-LMJ7RKPF.cjs → chunk-UUWAUHUW.cjs} +279 -16
- package/dist/{chunk-YC4NUZCS.js → chunk-WRKV6MHB.js} +414 -2
- package/dist/{chunk-Q3HQEM4R.cjs → chunk-YV5PK4JW.cjs} +421 -1
- package/dist/cli.cjs +13 -22
- package/dist/cli.js +13 -22
- package/dist/{event-order-defaults-7Z3UZOEH.cjs → event-order-defaults-DU7V3YND.cjs} +9 -9
- package/dist/{event-order-defaults-XQ3IDPD7.js → event-order-defaults-H4RT7NMR.js} +1 -1
- package/dist/index.cjs +327 -291
- package/dist/index.d.cts +132 -5
- package/dist/index.d.ts +132 -5
- package/dist/index.js +8 -8
- package/dist/migrations/1782400000000-CreateUserDeviceTokens.ts +36 -0
- package/dist/migrations/1782500000000-AddPushToOrderNotificationBindingsChannelEnum.ts +15 -0
- package/dist/{order-notification-dispatcher-6WNG24NY.js → order-notification-dispatcher-3TA4ETYJ.js} +1 -1
- package/dist/{order-notification-dispatcher-6XSU3AR7.cjs → order-notification-dispatcher-ZEAZ5SHV.cjs} +7 -3
- package/package.json +1 -1
- package/dist/chunk-VUQFARRT.cjs +0 -182
- package/dist/chunk-ZF2RQWXB.js +0 -171
package/dist/admin.js
CHANGED
|
@@ -10,7 +10,7 @@ import { Slot } from '@radix-ui/react-slot';
|
|
|
10
10
|
import { cva } from 'class-variance-authority';
|
|
11
11
|
import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
|
|
12
12
|
import * as LucideIcons from 'lucide-react';
|
|
13
|
-
import { ChevronDown, User, Settings, LogOut, LayoutDashboard, Store, FolderTree, Layers, Building2, CalendarDays, ShoppingBag, Package, Receipt, BadgePercent, ShoppingCart, CreditCard, Users, Inbox, File, LinkIcon, ClipboardList, MessageSquare, Image as Image$1, Shield, FileText, Puzzle, X, Plus, MoreVertical, Upload, Download, Edit, Copy, RefreshCw, Trash2, Mail, Check, Save, Search, AlertCircle, MapPin, BarChart3, TrendingUp, UserCheck, Activity, Globe, Eye, MousePointer, ArrowLeftRight, RotateCcw, KeyRound, Loader2, CalendarClock, CheckSquare, Square, XSquare, Rss, ArrowLeft, Pencil, FolderPlus, LayoutGrid, List, Move, Archive, Edit2, ExternalLink, Power, Star, ChevronUp, Zap, Filter, CheckCircle2, ImageIcon, GripVertical, ChevronRight, ArrowRight, ArrowUpRight, IndianRupee, XCircle, Clock, Play, MessageCircle, Bot, FileUp, Tag, Box, SlidersHorizontal, Calculator, Link2 as Link2$1, Unlink, Gift, MoreHorizontal, ShieldCheck, QrCode, Car, Settings2, DollarSign, Hash, Circle, ChevronLeft, Bell, Share2,
|
|
13
|
+
import { ChevronDown, User, Settings, LogOut, LayoutDashboard, Store, FolderTree, Layers, Building2, CalendarDays, ShoppingBag, Package, Receipt, BadgePercent, ShoppingCart, CreditCard, Users, Inbox, File, LinkIcon, ClipboardList, MessageSquare, Image as Image$1, Shield, FileText, Puzzle, X, Plus, MoreVertical, Upload, Download, Edit, Copy, RefreshCw, Trash2, Mail, Check, Save, Search, AlertCircle, MapPin, BarChart3, TrendingUp, UserCheck, Activity, Globe, Eye, MousePointer, ArrowLeftRight, RotateCcw, KeyRound, Loader2, CalendarClock, CheckSquare, Square, XSquare, Rss, ArrowLeft, Pencil, FolderPlus, LayoutGrid, List, Move, Archive, Edit2, ExternalLink, Power, Star, ChevronUp, Zap, Filter, CheckCircle2, ImageIcon, GripVertical, ChevronRight, ArrowRight, ArrowUpRight, IndianRupee, XCircle, Clock, Play, MessageCircle, Bot, FileUp, Tag, Box, SlidersHorizontal, Calculator, Link2 as Link2$1, Unlink, Gift, MoreHorizontal, Smartphone, ShieldCheck, QrCode, Car, Send, Settings2, DollarSign, Hash, Circle, ChevronLeft, Bell, Share2, HardDrive, Folder, Film } from 'lucide-react';
|
|
14
14
|
import Image from 'next/image';
|
|
15
15
|
import Link2 from 'next/link';
|
|
16
16
|
import { usePathname, useSearchParams, useRouter } from 'next/navigation';
|
|
@@ -455,7 +455,7 @@ var init_admin_config_context = __esm({
|
|
|
455
455
|
var CMS_VERSION;
|
|
456
456
|
var init_cms_version = __esm({
|
|
457
457
|
"src/lib/cms-version.ts"() {
|
|
458
|
-
CMS_VERSION = "1.0.
|
|
458
|
+
CMS_VERSION = "1.0.50" ;
|
|
459
459
|
}
|
|
460
460
|
});
|
|
461
461
|
function useCatalogCategories(enabled = true) {
|
|
@@ -1146,6 +1146,15 @@ var init_builtin_plugin_descriptors = __esm({
|
|
|
1146
1146
|
enabled: true,
|
|
1147
1147
|
icon: "event_notifications",
|
|
1148
1148
|
settingsGroup: "event_notifications"
|
|
1149
|
+
},
|
|
1150
|
+
{
|
|
1151
|
+
name: "auth_providers",
|
|
1152
|
+
label: "Authentication Provider",
|
|
1153
|
+
version: "1.0.0",
|
|
1154
|
+
description: "Enable Google sign-in for admin and vendor users (existing accounts only).",
|
|
1155
|
+
enabled: true,
|
|
1156
|
+
icon: "auth_providers",
|
|
1157
|
+
settingsGroup: "auth_providers"
|
|
1149
1158
|
}
|
|
1150
1159
|
];
|
|
1151
1160
|
}
|
|
@@ -9140,28 +9149,75 @@ var init_AuthPageLayout = __esm({
|
|
|
9140
9149
|
}
|
|
9141
9150
|
});
|
|
9142
9151
|
|
|
9152
|
+
// src/auth/auth-providers-settings.ts
|
|
9153
|
+
function parseEnabled(raw) {
|
|
9154
|
+
if (typeof raw === "boolean") return raw;
|
|
9155
|
+
if (typeof raw === "number") return raw !== 0;
|
|
9156
|
+
if (typeof raw === "string") {
|
|
9157
|
+
const n = raw.trim().toLowerCase();
|
|
9158
|
+
return n === "true" || n === "1" || n === "yes" || n === "on";
|
|
9159
|
+
}
|
|
9160
|
+
return false;
|
|
9161
|
+
}
|
|
9162
|
+
function isGoogleAuthPubliclyEnabled(settings) {
|
|
9163
|
+
if (!settings) return false;
|
|
9164
|
+
if (settings.googleEnabled !== void 0 && settings.googleEnabled !== "") {
|
|
9165
|
+
return parseEnabled(settings.googleEnabled);
|
|
9166
|
+
}
|
|
9167
|
+
return parseEnabled(settings.enabled);
|
|
9168
|
+
}
|
|
9169
|
+
var init_auth_providers_settings = __esm({
|
|
9170
|
+
"src/auth/auth-providers-settings.ts"() {
|
|
9171
|
+
init_auth_debug();
|
|
9172
|
+
__name(parseEnabled, "parseEnabled");
|
|
9173
|
+
__name(isGoogleAuthPubliclyEnabled, "isGoogleAuthPubliclyEnabled");
|
|
9174
|
+
}
|
|
9175
|
+
});
|
|
9176
|
+
|
|
9143
9177
|
// src/admin/pages/SignInPage.tsx
|
|
9144
9178
|
var SignInPage_exports = {};
|
|
9145
9179
|
__export(SignInPage_exports, {
|
|
9146
9180
|
default: () => SignInPage_default
|
|
9147
9181
|
});
|
|
9182
|
+
function oauthErrorMessage(code) {
|
|
9183
|
+
if (!code) return "";
|
|
9184
|
+
const c = code.toLowerCase();
|
|
9185
|
+
if (c === "accessdenied" || c === "access_denied") {
|
|
9186
|
+
return "No account for this Google email. Ask an admin to invite you first.";
|
|
9187
|
+
}
|
|
9188
|
+
if (c === "oauthaccountnotlinked") {
|
|
9189
|
+
return "This Google account is not linked to an existing user. Sign in with email/password or ask an admin to invite you.";
|
|
9190
|
+
}
|
|
9191
|
+
if (c === "oauthcallback" || c === "oauthsignin" || c === "oauthcreateaccount") {
|
|
9192
|
+
return "Google sign-in failed. Check Authentication Provider settings and the redirect URI in Google Cloud Console.";
|
|
9193
|
+
}
|
|
9194
|
+
if (c === "configuration") {
|
|
9195
|
+
return "Google sign-in is not configured correctly.";
|
|
9196
|
+
}
|
|
9197
|
+
return "Invalid email or password";
|
|
9198
|
+
}
|
|
9148
9199
|
var SigninPage, SignInPage_default;
|
|
9149
9200
|
var init_SignInPage = __esm({
|
|
9150
9201
|
"src/admin/pages/SignInPage.tsx"() {
|
|
9151
9202
|
"use client";
|
|
9152
9203
|
init_AuthPageLayout();
|
|
9153
9204
|
init_auth_debug();
|
|
9205
|
+
init_auth_providers_settings();
|
|
9206
|
+
__name(oauthErrorMessage, "oauthErrorMessage");
|
|
9154
9207
|
SigninPage = /* @__PURE__ */ __name(() => {
|
|
9155
9208
|
const [email, setEmail] = useState("");
|
|
9156
9209
|
const [password, setPassword] = useState("");
|
|
9157
9210
|
const [error, setError] = useState("");
|
|
9158
9211
|
const [success, setSuccess] = useState("");
|
|
9159
9212
|
const [loading, setLoading] = useState(false);
|
|
9213
|
+
const [googleLoading, setGoogleLoading] = useState(false);
|
|
9214
|
+
const [googleEnabled, setGoogleEnabled] = useState(false);
|
|
9160
9215
|
const { status } = useSession();
|
|
9161
9216
|
const searchParams = useSearchParams();
|
|
9162
9217
|
useEffect(() => {
|
|
9163
|
-
|
|
9164
|
-
|
|
9218
|
+
const err = searchParams.get("error");
|
|
9219
|
+
if (err) {
|
|
9220
|
+
setError(oauthErrorMessage(err));
|
|
9165
9221
|
}
|
|
9166
9222
|
if (searchParams.get("activated") === "1") {
|
|
9167
9223
|
setSuccess("Account activated. Sign in with your new password.");
|
|
@@ -9172,6 +9228,23 @@ var init_SignInPage = __esm({
|
|
|
9172
9228
|
}, [
|
|
9173
9229
|
searchParams
|
|
9174
9230
|
]);
|
|
9231
|
+
useEffect(() => {
|
|
9232
|
+
let cancelled = false;
|
|
9233
|
+
(async () => {
|
|
9234
|
+
try {
|
|
9235
|
+
const res = await fetch("/api/settings/auth_providers", {
|
|
9236
|
+
cache: "no-store"
|
|
9237
|
+
});
|
|
9238
|
+
if (!res.ok) return;
|
|
9239
|
+
const data = await res.json();
|
|
9240
|
+
if (!cancelled) setGoogleEnabled(isGoogleAuthPubliclyEnabled(data));
|
|
9241
|
+
} catch {
|
|
9242
|
+
}
|
|
9243
|
+
})();
|
|
9244
|
+
return () => {
|
|
9245
|
+
cancelled = true;
|
|
9246
|
+
};
|
|
9247
|
+
}, []);
|
|
9175
9248
|
useEffect(() => {
|
|
9176
9249
|
logAuthClient("SignInPage session status", {
|
|
9177
9250
|
status
|
|
@@ -9229,6 +9302,19 @@ var init_SignInPage = __esm({
|
|
|
9229
9302
|
setLoading(false);
|
|
9230
9303
|
}
|
|
9231
9304
|
}, "handleSubmit");
|
|
9305
|
+
const handleGoogle = /* @__PURE__ */ __name(async () => {
|
|
9306
|
+
setGoogleLoading(true);
|
|
9307
|
+
setError("");
|
|
9308
|
+
try {
|
|
9309
|
+
logAuthClient("SignInPage Google signIn start");
|
|
9310
|
+
await signIn("google", {
|
|
9311
|
+
callbackUrl: "/admin/dashboard"
|
|
9312
|
+
});
|
|
9313
|
+
} catch {
|
|
9314
|
+
setError("Google sign-in failed. Please try again.");
|
|
9315
|
+
setGoogleLoading(false);
|
|
9316
|
+
}
|
|
9317
|
+
}, "handleGoogle");
|
|
9232
9318
|
return /* @__PURE__ */ React.createElement(AuthPageLayout, null, /* @__PURE__ */ React.createElement("div", {
|
|
9233
9319
|
className: "w-full shadow-md rounded-lg bg-white px-4 py-6 sm:px-6 sm:py-8"
|
|
9234
9320
|
}, /* @__PURE__ */ React.createElement("h3", {
|
|
@@ -9281,9 +9367,42 @@ var init_SignInPage = __esm({
|
|
|
9281
9367
|
className: "text-xs font-medium text-gray-600 hover:underline"
|
|
9282
9368
|
}, "Forgot password?")), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("button", {
|
|
9283
9369
|
type: "submit",
|
|
9284
|
-
disabled: loading,
|
|
9370
|
+
disabled: loading || googleLoading,
|
|
9285
9371
|
className: "w-full rounded bg-gray-900 px-4 py-2 text-sm font-medium text-white hover:bg-gray-800 disabled:opacity-50 disabled:cursor-not-allowed"
|
|
9286
|
-
}, loading ? "Signing in..." : "Sign in")))
|
|
9372
|
+
}, loading ? "Signing in..." : "Sign in"))), googleEnabled && /* @__PURE__ */ React.createElement("div", {
|
|
9373
|
+
className: "mt-6"
|
|
9374
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
9375
|
+
className: "relative mb-4"
|
|
9376
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
9377
|
+
className: "absolute inset-0 flex items-center"
|
|
9378
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
9379
|
+
className: "w-full border-t border-gray-200"
|
|
9380
|
+
})), /* @__PURE__ */ React.createElement("div", {
|
|
9381
|
+
className: "relative flex justify-center text-xs"
|
|
9382
|
+
}, /* @__PURE__ */ React.createElement("span", {
|
|
9383
|
+
className: "bg-white px-2 text-gray-500"
|
|
9384
|
+
}, "or"))), /* @__PURE__ */ React.createElement("button", {
|
|
9385
|
+
type: "button",
|
|
9386
|
+
onClick: handleGoogle,
|
|
9387
|
+
disabled: loading || googleLoading,
|
|
9388
|
+
className: "flex w-full items-center justify-center gap-2 rounded border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-800 hover:bg-gray-50 disabled:opacity-50 disabled:cursor-not-allowed"
|
|
9389
|
+
}, /* @__PURE__ */ React.createElement("svg", {
|
|
9390
|
+
className: "h-4 w-4",
|
|
9391
|
+
viewBox: "0 0 24 24",
|
|
9392
|
+
"aria-hidden": "true"
|
|
9393
|
+
}, /* @__PURE__ */ React.createElement("path", {
|
|
9394
|
+
fill: "#4285F4",
|
|
9395
|
+
d: "M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"
|
|
9396
|
+
}), /* @__PURE__ */ React.createElement("path", {
|
|
9397
|
+
fill: "#34A853",
|
|
9398
|
+
d: "M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"
|
|
9399
|
+
}), /* @__PURE__ */ React.createElement("path", {
|
|
9400
|
+
fill: "#FBBC05",
|
|
9401
|
+
d: "M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"
|
|
9402
|
+
}), /* @__PURE__ */ React.createElement("path", {
|
|
9403
|
+
fill: "#EA4335",
|
|
9404
|
+
d: "M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"
|
|
9405
|
+
})), googleLoading ? "Redirecting\u2026" : "Continue with Google"))));
|
|
9287
9406
|
}, "SigninPage");
|
|
9288
9407
|
SignInPage_default = SigninPage;
|
|
9289
9408
|
}
|
|
@@ -15407,6 +15526,30 @@ function getEmailTriggerDefaults(triggerKey, audience = "customer") {
|
|
|
15407
15526
|
bodyPlaceholder: "Hi {{customerName}},\n\nYour order {{orderNumber}} has been updated."
|
|
15408
15527
|
};
|
|
15409
15528
|
}
|
|
15529
|
+
function getPushTriggerDefaults(triggerKey, audience = "customer") {
|
|
15530
|
+
if (audience === "vendor") {
|
|
15531
|
+
return VENDOR_PUSH_TRIGGER_DEFAULTS[triggerKey] ?? {
|
|
15532
|
+
subject: "Vendor Push Update",
|
|
15533
|
+
body: "Hi {{vendorName}}, order {{orderNumber}} update.",
|
|
15534
|
+
subjectPlaceholder: "e.g. Vendor Push Update",
|
|
15535
|
+
bodyPlaceholder: "Hi {{vendorName}}, order {{orderNumber}} update."
|
|
15536
|
+
};
|
|
15537
|
+
}
|
|
15538
|
+
if (audience === "admin") {
|
|
15539
|
+
return ADMIN_PUSH_TRIGGER_DEFAULTS[triggerKey] ?? {
|
|
15540
|
+
subject: "Admin Push Alert",
|
|
15541
|
+
body: "Admin Alert: Order {{orderNumber}} update.",
|
|
15542
|
+
subjectPlaceholder: "e.g. Admin Push Alert",
|
|
15543
|
+
bodyPlaceholder: "Admin Alert: Order {{orderNumber}} update."
|
|
15544
|
+
};
|
|
15545
|
+
}
|
|
15546
|
+
return PUSH_TRIGGER_DEFAULTS[triggerKey] ?? {
|
|
15547
|
+
subject: "Order Update",
|
|
15548
|
+
body: "Hi {{customerName}}, order {{orderNumber}} update.",
|
|
15549
|
+
subjectPlaceholder: "e.g. Order Update",
|
|
15550
|
+
bodyPlaceholder: "Hi {{customerName}}, order {{orderNumber}} update."
|
|
15551
|
+
};
|
|
15552
|
+
}
|
|
15410
15553
|
async function jsonFetch(url, init) {
|
|
15411
15554
|
const res = await fetch(url, {
|
|
15412
15555
|
credentials: "include",
|
|
@@ -15498,7 +15641,7 @@ function useOrderNotificationTriggerBindings(channel, audienceType = "customers"
|
|
|
15498
15641
|
rebind
|
|
15499
15642
|
};
|
|
15500
15643
|
}
|
|
15501
|
-
var KNOWN_VARS, EMAIL_TRIGGER_DEFAULTS, VENDOR_EMAIL_TRIGGER_DEFAULTS, ADMIN_EMAIL_TRIGGER_DEFAULTS;
|
|
15644
|
+
var KNOWN_VARS, EMAIL_TRIGGER_DEFAULTS, VENDOR_EMAIL_TRIGGER_DEFAULTS, ADMIN_EMAIL_TRIGGER_DEFAULTS, PUSH_TRIGGER_DEFAULTS, VENDOR_PUSH_TRIGGER_DEFAULTS, ADMIN_PUSH_TRIGGER_DEFAULTS;
|
|
15502
15645
|
var init_order_notification_bindings_shared = __esm({
|
|
15503
15646
|
"src/admin/components/order-notification-bindings-shared.ts"() {
|
|
15504
15647
|
"use client";
|
|
@@ -15514,9 +15657,7 @@ var init_order_notification_bindings_shared = __esm({
|
|
|
15514
15657
|
"vendorId",
|
|
15515
15658
|
"refundAmount",
|
|
15516
15659
|
"invoiceNumber",
|
|
15517
|
-
"invoiceUrl"
|
|
15518
|
-
"ticketQr",
|
|
15519
|
-
"qrImageUrl"
|
|
15660
|
+
"invoiceUrl"
|
|
15520
15661
|
];
|
|
15521
15662
|
EMAIL_TRIGGER_DEFAULTS = {
|
|
15522
15663
|
order_placed: {
|
|
@@ -15595,7 +15736,7 @@ Order Summary:
|
|
|
15595
15736
|
Customer Name: {{customerName}}
|
|
15596
15737
|
Customer Email: {{customerEmail}}
|
|
15597
15738
|
Customer Phone: {{customerPhone}}`,
|
|
15598
|
-
bodyPlaceholder: "
|
|
15739
|
+
bodyPlaceholder: "New order {{orderNumber}} placed by {{customerName}}."
|
|
15599
15740
|
},
|
|
15600
15741
|
order_cancelled: {
|
|
15601
15742
|
subject: "Order {{orderNumber}} cancelled",
|
|
@@ -15611,6 +15752,66 @@ Refund Due: {{refundAmount}} {{currency}}`,
|
|
|
15611
15752
|
}
|
|
15612
15753
|
};
|
|
15613
15754
|
__name(getEmailTriggerDefaults, "getEmailTriggerDefaults");
|
|
15755
|
+
PUSH_TRIGGER_DEFAULTS = {
|
|
15756
|
+
order_placed: {
|
|
15757
|
+
subject: "Order {{orderNumber}} Confirmed!",
|
|
15758
|
+
subjectPlaceholder: "e.g. Order {{orderNumber}} Confirmed!",
|
|
15759
|
+
body: `Hi {{customerName}}, your order {{orderNumber}} for {{total}} {{currency}} is confirmed.`,
|
|
15760
|
+
bodyPlaceholder: "Hi {{customerName}}, your order {{orderNumber}} is confirmed."
|
|
15761
|
+
},
|
|
15762
|
+
order_cancelled: {
|
|
15763
|
+
subject: "Order {{orderNumber}} Cancelled",
|
|
15764
|
+
subjectPlaceholder: "e.g. Order {{orderNumber}} Cancelled",
|
|
15765
|
+
body: `Hi {{customerName}}, your order {{orderNumber}} for {{total}} {{currency}} has been cancelled.`,
|
|
15766
|
+
bodyPlaceholder: "Hi {{customerName}}, your order {{orderNumber}} has been cancelled."
|
|
15767
|
+
}
|
|
15768
|
+
};
|
|
15769
|
+
VENDOR_PUSH_TRIGGER_DEFAULTS = {
|
|
15770
|
+
order_placed: {
|
|
15771
|
+
subject: "New Order Received: {{orderNumber}}",
|
|
15772
|
+
subjectPlaceholder: "e.g. New Order Received: {{orderNumber}}",
|
|
15773
|
+
body: `Hi {{vendorName}}, you received a new order {{orderNumber}} for {{total}} {{currency}} from {{customerName}}.`,
|
|
15774
|
+
bodyPlaceholder: "Hi {{vendorName}}, you received a new order {{orderNumber}}."
|
|
15775
|
+
},
|
|
15776
|
+
order_cancelled: {
|
|
15777
|
+
subject: "Order {{orderNumber}} Cancelled",
|
|
15778
|
+
subjectPlaceholder: "e.g. Order {{orderNumber}} Cancelled",
|
|
15779
|
+
body: `Hi {{vendorName}}, order {{orderNumber}} from {{customerName}} has been cancelled.`,
|
|
15780
|
+
bodyPlaceholder: "Hi {{vendorName}}, order {{orderNumber}} was cancelled."
|
|
15781
|
+
}
|
|
15782
|
+
};
|
|
15783
|
+
ADMIN_PUSH_TRIGGER_DEFAULTS = {
|
|
15784
|
+
order_placed: {
|
|
15785
|
+
subject: "New Order {{orderNumber}} ({{total}} {{currency}})",
|
|
15786
|
+
subjectPlaceholder: "e.g. New Order {{orderNumber}} placed",
|
|
15787
|
+
body: `Hi Admin,
|
|
15788
|
+
|
|
15789
|
+
A new order {{orderNumber}} of {{total}} {{currency}} was placed.
|
|
15790
|
+
|
|
15791
|
+
Vendor: {{vendorName}}
|
|
15792
|
+
|
|
15793
|
+
Order Summary:
|
|
15794
|
+
{{orderDetails}}
|
|
15795
|
+
|
|
15796
|
+
Customer Name: {{customerName}}
|
|
15797
|
+
Customer Email: {{customerEmail}}
|
|
15798
|
+
Customer Phone: {{customerPhone}}`,
|
|
15799
|
+
bodyPlaceholder: "New order {{orderNumber}} placed by {{customerName}}."
|
|
15800
|
+
},
|
|
15801
|
+
order_cancelled: {
|
|
15802
|
+
subject: "Order {{orderNumber}} Cancelled",
|
|
15803
|
+
subjectPlaceholder: "e.g. Order {{orderNumber}} cancelled",
|
|
15804
|
+
body: `Hi Admin,
|
|
15805
|
+
|
|
15806
|
+
Order {{orderNumber}} has been cancelled.
|
|
15807
|
+
|
|
15808
|
+
Customer: {{customerName}}
|
|
15809
|
+
Vendor: {{vendorName}}
|
|
15810
|
+
Refund Due: {{refundAmount}} {{currency}}`,
|
|
15811
|
+
bodyPlaceholder: "Hi Admin,\n\nOrder {{orderNumber}} cancelled."
|
|
15812
|
+
}
|
|
15813
|
+
};
|
|
15814
|
+
__name(getPushTriggerDefaults, "getPushTriggerDefaults");
|
|
15614
15815
|
__name(jsonFetch, "jsonFetch");
|
|
15615
15816
|
__name(useOrderNotificationTriggerBindings, "useOrderNotificationTriggerBindings");
|
|
15616
15817
|
}
|
|
@@ -16261,14 +16462,582 @@ var init_emailTriggersBindingsPage = __esm({
|
|
|
16261
16462
|
vendorId: "Vendor / store ID",
|
|
16262
16463
|
refundAmount: "Refund amount (refund triggers)",
|
|
16263
16464
|
invoiceNumber: "Generated invoice number",
|
|
16264
|
-
invoiceUrl: "Link to download invoice PDF"
|
|
16265
|
-
ticketQr: "Embedded ticket QR code image",
|
|
16266
|
-
qrImageUrl: "Direct QR code image URL"
|
|
16465
|
+
invoiceUrl: "Link to download invoice PDF"
|
|
16267
16466
|
};
|
|
16268
16467
|
__name(EmailTriggerBindings, "EmailTriggerBindings");
|
|
16269
16468
|
__name(TriggerEmailEditor, "TriggerEmailEditor");
|
|
16270
16469
|
}
|
|
16271
16470
|
});
|
|
16471
|
+
function PushTriggerBindings({ audience = "customer" }) {
|
|
16472
|
+
const audienceType = audience === "vendor" ? "vendors" : audience === "admin" ? "admin" : "customers";
|
|
16473
|
+
const { triggers, bindings, loading, reload, rebind } = useOrderNotificationTriggerBindings("mobile", audienceType);
|
|
16474
|
+
const [selectedKey, setSelectedKey] = useState("");
|
|
16475
|
+
const [templates, setTemplates] = useState([]);
|
|
16476
|
+
const [loadingTpl, setLoadingTpl] = useState(true);
|
|
16477
|
+
const [title, setTitle] = useState("");
|
|
16478
|
+
const [body, setBody] = useState("");
|
|
16479
|
+
const [saving, setSaving] = useState(false);
|
|
16480
|
+
const bodyRef = useRef(null);
|
|
16481
|
+
const subjectRef = useRef(null);
|
|
16482
|
+
const lastFocused = useRef("body");
|
|
16483
|
+
useEffect(() => {
|
|
16484
|
+
let cancelled = false;
|
|
16485
|
+
(async () => {
|
|
16486
|
+
try {
|
|
16487
|
+
setLoadingTpl(true);
|
|
16488
|
+
const res = await fetch("/api/message-templates/email", {
|
|
16489
|
+
cache: "no-store"
|
|
16490
|
+
});
|
|
16491
|
+
if (!res.ok) throw new Error("Failed to load message templates");
|
|
16492
|
+
const data = await res.json();
|
|
16493
|
+
if (!cancelled) setTemplates(Array.isArray(data.items) ? data.items : []);
|
|
16494
|
+
} catch {
|
|
16495
|
+
if (!cancelled) toast.error("Could not load message templates");
|
|
16496
|
+
} finally {
|
|
16497
|
+
if (!cancelled) setLoadingTpl(false);
|
|
16498
|
+
}
|
|
16499
|
+
})();
|
|
16500
|
+
return () => {
|
|
16501
|
+
cancelled = true;
|
|
16502
|
+
};
|
|
16503
|
+
}, []);
|
|
16504
|
+
useEffect(() => {
|
|
16505
|
+
if (triggers.length > 0 && !selectedKey) {
|
|
16506
|
+
setSelectedKey(triggers[0].triggerKey);
|
|
16507
|
+
}
|
|
16508
|
+
}, [
|
|
16509
|
+
triggers,
|
|
16510
|
+
selectedKey
|
|
16511
|
+
]);
|
|
16512
|
+
const activeTrigger = useMemo(() => triggers.find((t) => t.triggerKey === selectedKey), [
|
|
16513
|
+
triggers,
|
|
16514
|
+
selectedKey
|
|
16515
|
+
]);
|
|
16516
|
+
const bindingMap = useMemo(() => {
|
|
16517
|
+
const m = /* @__PURE__ */ new Map();
|
|
16518
|
+
for (const b of bindings) {
|
|
16519
|
+
if (b.messageTemplateId != null) m.set(b.triggerKey, b.messageTemplateId);
|
|
16520
|
+
}
|
|
16521
|
+
return m;
|
|
16522
|
+
}, [
|
|
16523
|
+
bindings
|
|
16524
|
+
]);
|
|
16525
|
+
const activeBindingTplId = selectedKey ? bindingMap.get(selectedKey) ?? null : null;
|
|
16526
|
+
const activeTemplate = useMemo(() => {
|
|
16527
|
+
if (!activeBindingTplId) return null;
|
|
16528
|
+
return templates.find((t) => t.id === activeBindingTplId) ?? null;
|
|
16529
|
+
}, [
|
|
16530
|
+
activeBindingTplId,
|
|
16531
|
+
templates
|
|
16532
|
+
]);
|
|
16533
|
+
const defaults = useMemo(() => {
|
|
16534
|
+
if (!selectedKey) return {
|
|
16535
|
+
subject: "",
|
|
16536
|
+
body: "",
|
|
16537
|
+
subjectPlaceholder: "",
|
|
16538
|
+
bodyPlaceholder: ""
|
|
16539
|
+
};
|
|
16540
|
+
return getPushTriggerDefaults(selectedKey, audience);
|
|
16541
|
+
}, [
|
|
16542
|
+
selectedKey,
|
|
16543
|
+
audience
|
|
16544
|
+
]);
|
|
16545
|
+
useEffect(() => {
|
|
16546
|
+
if (activeTemplate) {
|
|
16547
|
+
setTitle(activeTemplate.subject ?? "");
|
|
16548
|
+
setBody(activeTemplate.body ?? "");
|
|
16549
|
+
} else {
|
|
16550
|
+
setTitle(defaults.subject);
|
|
16551
|
+
setBody(defaults.body);
|
|
16552
|
+
}
|
|
16553
|
+
}, [
|
|
16554
|
+
activeTemplate,
|
|
16555
|
+
defaults,
|
|
16556
|
+
selectedKey
|
|
16557
|
+
]);
|
|
16558
|
+
const insertVariable = /* @__PURE__ */ __name((varName) => {
|
|
16559
|
+
const token = `{{${varName}}}`;
|
|
16560
|
+
if (lastFocused.current === "subject" && subjectRef.current) {
|
|
16561
|
+
const el = subjectRef.current;
|
|
16562
|
+
const start = el.selectionStart ?? title.length;
|
|
16563
|
+
const end = el.selectionEnd ?? title.length;
|
|
16564
|
+
const next = title.slice(0, start) + token + title.slice(end);
|
|
16565
|
+
setTitle(next);
|
|
16566
|
+
setTimeout(() => {
|
|
16567
|
+
el.focus();
|
|
16568
|
+
el.setSelectionRange(start + token.length, start + token.length);
|
|
16569
|
+
}, 0);
|
|
16570
|
+
return;
|
|
16571
|
+
}
|
|
16572
|
+
if (bodyRef.current) {
|
|
16573
|
+
const el = bodyRef.current;
|
|
16574
|
+
const start = el.selectionStart ?? body.length;
|
|
16575
|
+
const end = el.selectionEnd ?? body.length;
|
|
16576
|
+
const next = body.slice(0, start) + token + body.slice(end);
|
|
16577
|
+
setBody(next);
|
|
16578
|
+
setTimeout(() => {
|
|
16579
|
+
el.focus();
|
|
16580
|
+
el.setSelectionRange(start + token.length, start + token.length);
|
|
16581
|
+
}, 0);
|
|
16582
|
+
} else {
|
|
16583
|
+
setBody((prev) => prev + token);
|
|
16584
|
+
}
|
|
16585
|
+
}, "insertVariable");
|
|
16586
|
+
const handleSave = /* @__PURE__ */ __name(async () => {
|
|
16587
|
+
if (!selectedKey) return;
|
|
16588
|
+
setSaving(true);
|
|
16589
|
+
try {
|
|
16590
|
+
let tplId = activeBindingTplId;
|
|
16591
|
+
if (tplId) {
|
|
16592
|
+
const res = await jsonFetch(`/api/message-templates/email/${tplId}`, {
|
|
16593
|
+
method: "PATCH",
|
|
16594
|
+
headers: {
|
|
16595
|
+
"Content-Type": "application/json"
|
|
16596
|
+
},
|
|
16597
|
+
body: JSON.stringify({
|
|
16598
|
+
name: `${audienceType}_push_${selectedKey}`,
|
|
16599
|
+
subject: title,
|
|
16600
|
+
body
|
|
16601
|
+
})
|
|
16602
|
+
});
|
|
16603
|
+
if (res.item) {
|
|
16604
|
+
setTemplates((prev) => prev.map((t) => t.id === res.item.id ? res.item : t));
|
|
16605
|
+
}
|
|
16606
|
+
} else {
|
|
16607
|
+
const res = await jsonFetch("/api/message-templates/email", {
|
|
16608
|
+
method: "POST",
|
|
16609
|
+
headers: {
|
|
16610
|
+
"Content-Type": "application/json"
|
|
16611
|
+
},
|
|
16612
|
+
body: JSON.stringify({
|
|
16613
|
+
name: `${audienceType}_push_${selectedKey}`,
|
|
16614
|
+
subject: title,
|
|
16615
|
+
body
|
|
16616
|
+
})
|
|
16617
|
+
});
|
|
16618
|
+
const createdItem = res.item || res;
|
|
16619
|
+
tplId = createdItem.id;
|
|
16620
|
+
if (createdItem) {
|
|
16621
|
+
setTemplates((prev) => [
|
|
16622
|
+
createdItem,
|
|
16623
|
+
...prev
|
|
16624
|
+
]);
|
|
16625
|
+
}
|
|
16626
|
+
}
|
|
16627
|
+
await rebind(selectedKey, tplId, `${audienceType}_push_${selectedKey}`);
|
|
16628
|
+
toast.success("Push notification template saved");
|
|
16629
|
+
await reload();
|
|
16630
|
+
} catch (e) {
|
|
16631
|
+
const msg = e instanceof Error ? e.message : "Save failed";
|
|
16632
|
+
toast.error(msg);
|
|
16633
|
+
} finally {
|
|
16634
|
+
setSaving(false);
|
|
16635
|
+
}
|
|
16636
|
+
}, "handleSave");
|
|
16637
|
+
if (loading || loadingTpl) {
|
|
16638
|
+
return /* @__PURE__ */ React.createElement("div", {
|
|
16639
|
+
className: "flex items-center gap-2 p-6 text-sm text-gray-500"
|
|
16640
|
+
}, /* @__PURE__ */ React.createElement(Loader2, {
|
|
16641
|
+
className: "h-4 w-4 animate-spin"
|
|
16642
|
+
}), " Loading push notification triggers\u2026");
|
|
16643
|
+
}
|
|
16644
|
+
return /* @__PURE__ */ React.createElement("div", {
|
|
16645
|
+
className: "space-y-6"
|
|
16646
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
16647
|
+
className: "flex flex-col sm:flex-row sm:items-center justify-between gap-4"
|
|
16648
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
16649
|
+
className: "space-y-1"
|
|
16650
|
+
}, /* @__PURE__ */ React.createElement("h3", {
|
|
16651
|
+
className: "text-base font-semibold text-gray-900 dark:text-gray-100 flex items-center gap-2"
|
|
16652
|
+
}, /* @__PURE__ */ React.createElement(Smartphone, {
|
|
16653
|
+
className: "h-5 w-5 text-gray-700 dark:text-gray-300"
|
|
16654
|
+
}), "Mobile Push Notification Templates"), /* @__PURE__ */ React.createElement("p", {
|
|
16655
|
+
className: "text-xs text-gray-500"
|
|
16656
|
+
}, "Configure push notification title and message body per trigger for", " ", /* @__PURE__ */ React.createElement("span", {
|
|
16657
|
+
className: "font-semibold capitalize text-gray-700 dark:text-gray-300"
|
|
16658
|
+
}, audience, "s"), ".")), /* @__PURE__ */ React.createElement(Button, {
|
|
16659
|
+
type: "button",
|
|
16660
|
+
onClick: handleSave,
|
|
16661
|
+
disabled: saving || !selectedKey,
|
|
16662
|
+
className: "gap-2 shrink-0"
|
|
16663
|
+
}, saving ? /* @__PURE__ */ React.createElement(Loader2, {
|
|
16664
|
+
className: "h-4 w-4 animate-spin"
|
|
16665
|
+
}) : /* @__PURE__ */ React.createElement(Save, {
|
|
16666
|
+
className: "h-4 w-4"
|
|
16667
|
+
}), "Save Template")), /* @__PURE__ */ React.createElement("div", {
|
|
16668
|
+
className: "grid grid-cols-1 md:grid-cols-4 gap-6"
|
|
16669
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
16670
|
+
className: "md:col-span-1 space-y-2"
|
|
16671
|
+
}, /* @__PURE__ */ React.createElement(Label3, {
|
|
16672
|
+
className: "text-xs font-semibold text-gray-500 uppercase tracking-wider"
|
|
16673
|
+
}, "Triggers"), /* @__PURE__ */ React.createElement("div", {
|
|
16674
|
+
className: "flex flex-col gap-1"
|
|
16675
|
+
}, triggers.map((t) => {
|
|
16676
|
+
const isBound = bindingMap.has(t.triggerKey);
|
|
16677
|
+
const isSelected = t.triggerKey === selectedKey;
|
|
16678
|
+
return /* @__PURE__ */ React.createElement("button", {
|
|
16679
|
+
key: t.triggerKey,
|
|
16680
|
+
type: "button",
|
|
16681
|
+
onClick: /* @__PURE__ */ __name(() => setSelectedKey(t.triggerKey), "onClick"),
|
|
16682
|
+
className: `flex flex-col items-start p-3 rounded-lg border text-left transition-all ${isSelected ? "border-gray-900 bg-gray-900 text-white dark:border-gray-100 dark:bg-gray-100 dark:text-gray-900 shadow-sm" : "border-gray-200 bg-white hover:bg-gray-50 text-gray-700 dark:border-gray-800 dark:bg-gray-900 dark:text-gray-300"}`
|
|
16683
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
16684
|
+
className: "flex items-center justify-between w-full"
|
|
16685
|
+
}, /* @__PURE__ */ React.createElement("span", {
|
|
16686
|
+
className: "font-medium text-sm"
|
|
16687
|
+
}, t.label), isBound && /* @__PURE__ */ React.createElement("span", {
|
|
16688
|
+
className: `text-[10px] px-1.5 py-0.5 rounded font-mono ${isSelected ? "bg-white/20 text-white dark:bg-black/20 dark:text-gray-900" : "bg-green-100 text-green-700 dark:bg-green-950 dark:text-green-300"}`
|
|
16689
|
+
}, "Configured")), /* @__PURE__ */ React.createElement("span", {
|
|
16690
|
+
className: `text-xs mt-1 ${isSelected ? "text-gray-300 dark:text-gray-600" : "text-gray-500 dark:text-gray-400"}`
|
|
16691
|
+
}, t.triggerKey));
|
|
16692
|
+
}))), /* @__PURE__ */ React.createElement("div", {
|
|
16693
|
+
className: "md:col-span-3 space-y-5 bg-white dark:bg-gray-900 p-5 rounded-xl border border-gray-200 dark:border-gray-800 shadow-sm"
|
|
16694
|
+
}, activeTrigger ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("h4", {
|
|
16695
|
+
className: "text-sm font-semibold text-gray-900 dark:text-gray-100"
|
|
16696
|
+
}, activeTrigger.label, " (", activeTrigger.triggerKey, ")"), activeTrigger.description && /* @__PURE__ */ React.createElement("p", {
|
|
16697
|
+
className: "text-xs text-gray-500 mt-0.5"
|
|
16698
|
+
}, activeTrigger.description)), /* @__PURE__ */ React.createElement("div", {
|
|
16699
|
+
className: "space-y-1.5"
|
|
16700
|
+
}, /* @__PURE__ */ React.createElement(Label3, {
|
|
16701
|
+
className: "text-xs font-medium text-gray-700 dark:text-gray-300"
|
|
16702
|
+
}, "Insert Variables"), /* @__PURE__ */ React.createElement("div", {
|
|
16703
|
+
className: "flex flex-wrap gap-1.5"
|
|
16704
|
+
}, KNOWN_VARS.map((v) => /* @__PURE__ */ React.createElement("button", {
|
|
16705
|
+
key: v,
|
|
16706
|
+
type: "button",
|
|
16707
|
+
onClick: /* @__PURE__ */ __name(() => insertVariable(v), "onClick"),
|
|
16708
|
+
title: VAR_HINTS2[v],
|
|
16709
|
+
className: "px-2 py-1 bg-gray-100 hover:bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-700 text-gray-700 dark:text-gray-300 rounded text-xs font-mono border border-gray-200 dark:border-gray-700 transition-colors"
|
|
16710
|
+
}, `{{${v}}}`)))), /* @__PURE__ */ React.createElement("div", {
|
|
16711
|
+
className: "space-y-1.5"
|
|
16712
|
+
}, /* @__PURE__ */ React.createElement(Label3, {
|
|
16713
|
+
htmlFor: "push-title",
|
|
16714
|
+
className: "text-xs font-medium"
|
|
16715
|
+
}, "Notification Title"), /* @__PURE__ */ React.createElement(Input, {
|
|
16716
|
+
id: "push-title",
|
|
16717
|
+
ref: subjectRef,
|
|
16718
|
+
value: title,
|
|
16719
|
+
onFocus: /* @__PURE__ */ __name(() => {
|
|
16720
|
+
lastFocused.current = "subject";
|
|
16721
|
+
}, "onFocus"),
|
|
16722
|
+
onChange: /* @__PURE__ */ __name((e) => setTitle(e.target.value), "onChange"),
|
|
16723
|
+
placeholder: defaults.subjectPlaceholder
|
|
16724
|
+
})), /* @__PURE__ */ React.createElement("div", {
|
|
16725
|
+
className: "space-y-1.5"
|
|
16726
|
+
}, /* @__PURE__ */ React.createElement(Label3, {
|
|
16727
|
+
htmlFor: "push-body",
|
|
16728
|
+
className: "text-xs font-medium"
|
|
16729
|
+
}, "Notification Body"), /* @__PURE__ */ React.createElement(Textarea, {
|
|
16730
|
+
id: "push-body",
|
|
16731
|
+
ref: bodyRef,
|
|
16732
|
+
value: body,
|
|
16733
|
+
onFocus: /* @__PURE__ */ __name(() => {
|
|
16734
|
+
lastFocused.current = "body";
|
|
16735
|
+
}, "onFocus"),
|
|
16736
|
+
onChange: /* @__PURE__ */ __name((e) => setBody(e.target.value), "onChange"),
|
|
16737
|
+
placeholder: defaults.bodyPlaceholder,
|
|
16738
|
+
className: "h-36 font-mono text-xs"
|
|
16739
|
+
}))) : /* @__PURE__ */ React.createElement("div", {
|
|
16740
|
+
className: "p-12 text-center text-sm text-gray-500"
|
|
16741
|
+
}, "Select a trigger from the left to configure push notification template."))));
|
|
16742
|
+
}
|
|
16743
|
+
var VAR_HINTS2;
|
|
16744
|
+
var init_pushTriggersBindingsPage = __esm({
|
|
16745
|
+
"src/admin/pages/pushTriggersBindingsPage.tsx"() {
|
|
16746
|
+
"use client";
|
|
16747
|
+
init_button();
|
|
16748
|
+
init_input();
|
|
16749
|
+
init_textarea();
|
|
16750
|
+
init_label();
|
|
16751
|
+
init_order_notification_bindings_shared();
|
|
16752
|
+
VAR_HINTS2 = {
|
|
16753
|
+
orderId: "Internal order ID",
|
|
16754
|
+
orderNumber: "Display order number",
|
|
16755
|
+
customerName: "Customer full name",
|
|
16756
|
+
customerPhone: "Customer phone",
|
|
16757
|
+
eventName: "Event title / product name",
|
|
16758
|
+
vendorName: "Vendor / store name",
|
|
16759
|
+
total: "Order total amount",
|
|
16760
|
+
currency: "Currency code (e.g. INR)",
|
|
16761
|
+
vendorId: "Vendor / store ID",
|
|
16762
|
+
refundAmount: "Refund amount (refund triggers)",
|
|
16763
|
+
invoiceNumber: "Generated invoice number",
|
|
16764
|
+
invoiceUrl: "Link to download invoice PDF"
|
|
16765
|
+
};
|
|
16766
|
+
__name(PushTriggerBindings, "PushTriggerBindings");
|
|
16767
|
+
}
|
|
16768
|
+
});
|
|
16769
|
+
function PushConfigModal({ open, onOpenChange }) {
|
|
16770
|
+
const [loading, setLoading] = useState(false);
|
|
16771
|
+
const [saving, setSaving] = useState(false);
|
|
16772
|
+
const [testing, setTesting] = useState(false);
|
|
16773
|
+
const [serviceAccountJson, setServiceAccountJson] = useState("");
|
|
16774
|
+
const [projectId, setProjectId] = useState("");
|
|
16775
|
+
const [clientEmail, setClientEmail] = useState("");
|
|
16776
|
+
const [privateKey, setPrivateKey] = useState("");
|
|
16777
|
+
const [isValidJson, setIsValidJson] = useState(false);
|
|
16778
|
+
const [testToken, setTestToken] = useState("");
|
|
16779
|
+
const [testTitle, setTestTitle] = useState("Test Push Notification");
|
|
16780
|
+
const [testBody, setTestBody] = useState("Firebase Push Notification setup is working!");
|
|
16781
|
+
useEffect(() => {
|
|
16782
|
+
if (!open) return;
|
|
16783
|
+
let cancelled = false;
|
|
16784
|
+
(async () => {
|
|
16785
|
+
try {
|
|
16786
|
+
setLoading(true);
|
|
16787
|
+
const res = await fetch("/api/settings/push", {
|
|
16788
|
+
cache: "no-store"
|
|
16789
|
+
});
|
|
16790
|
+
if (res.ok) {
|
|
16791
|
+
const data = await res.json();
|
|
16792
|
+
if (!cancelled && data) {
|
|
16793
|
+
const rawJson = data.firebase_service_account_json || "";
|
|
16794
|
+
setServiceAccountJson(rawJson);
|
|
16795
|
+
if (rawJson.trim()) {
|
|
16796
|
+
parseAndExtract(rawJson, false);
|
|
16797
|
+
} else {
|
|
16798
|
+
setProjectId(data.firebase_project_id || "");
|
|
16799
|
+
setClientEmail(data.firebase_client_email || "");
|
|
16800
|
+
setPrivateKey(data.firebase_private_key || "");
|
|
16801
|
+
}
|
|
16802
|
+
}
|
|
16803
|
+
}
|
|
16804
|
+
} catch {
|
|
16805
|
+
toast.error("Failed to load push configuration");
|
|
16806
|
+
} finally {
|
|
16807
|
+
if (!cancelled) setLoading(false);
|
|
16808
|
+
}
|
|
16809
|
+
})();
|
|
16810
|
+
return () => {
|
|
16811
|
+
cancelled = true;
|
|
16812
|
+
};
|
|
16813
|
+
}, [
|
|
16814
|
+
open
|
|
16815
|
+
]);
|
|
16816
|
+
const parseAndExtract = /* @__PURE__ */ __name((input, showToast = true) => {
|
|
16817
|
+
if (!input.trim()) {
|
|
16818
|
+
setIsValidJson(false);
|
|
16819
|
+
return;
|
|
16820
|
+
}
|
|
16821
|
+
try {
|
|
16822
|
+
const parsed = JSON.parse(input);
|
|
16823
|
+
if (parsed.project_id) setProjectId(parsed.project_id);
|
|
16824
|
+
if (parsed.client_email) setClientEmail(parsed.client_email);
|
|
16825
|
+
if (parsed.private_key) setPrivateKey(parsed.private_key);
|
|
16826
|
+
setIsValidJson(true);
|
|
16827
|
+
if (showToast) {
|
|
16828
|
+
toast.success("Valid Service Account JSON loaded");
|
|
16829
|
+
}
|
|
16830
|
+
} catch {
|
|
16831
|
+
setIsValidJson(false);
|
|
16832
|
+
if (showToast) {
|
|
16833
|
+
toast.error("Invalid Service Account JSON format");
|
|
16834
|
+
}
|
|
16835
|
+
}
|
|
16836
|
+
}, "parseAndExtract");
|
|
16837
|
+
const handleJsonChange = /* @__PURE__ */ __name((val) => {
|
|
16838
|
+
setServiceAccountJson(val);
|
|
16839
|
+
if (val.trim()) {
|
|
16840
|
+
parseAndExtract(val, false);
|
|
16841
|
+
} else {
|
|
16842
|
+
setIsValidJson(false);
|
|
16843
|
+
}
|
|
16844
|
+
}, "handleJsonChange");
|
|
16845
|
+
const handleSaveConfig = /* @__PURE__ */ __name(async () => {
|
|
16846
|
+
if (serviceAccountJson.trim() && !isValidJson) {
|
|
16847
|
+
toast.error("Please enter a valid Firebase Service Account JSON file");
|
|
16848
|
+
return;
|
|
16849
|
+
}
|
|
16850
|
+
setSaving(true);
|
|
16851
|
+
try {
|
|
16852
|
+
const res = await fetch("/api/settings/push", {
|
|
16853
|
+
method: "PUT",
|
|
16854
|
+
headers: {
|
|
16855
|
+
"Content-Type": "application/json"
|
|
16856
|
+
},
|
|
16857
|
+
body: JSON.stringify({
|
|
16858
|
+
firebase_service_account_json: {
|
|
16859
|
+
value: serviceAccountJson.trim(),
|
|
16860
|
+
type: "secret"
|
|
16861
|
+
},
|
|
16862
|
+
firebase_project_id: {
|
|
16863
|
+
value: projectId.trim(),
|
|
16864
|
+
type: "secret"
|
|
16865
|
+
},
|
|
16866
|
+
firebase_client_email: {
|
|
16867
|
+
value: clientEmail.trim(),
|
|
16868
|
+
type: "secret"
|
|
16869
|
+
},
|
|
16870
|
+
firebase_private_key: {
|
|
16871
|
+
value: privateKey.trim(),
|
|
16872
|
+
type: "secret"
|
|
16873
|
+
}
|
|
16874
|
+
})
|
|
16875
|
+
});
|
|
16876
|
+
if (!res.ok) {
|
|
16877
|
+
toast.error("Failed to save push configuration");
|
|
16878
|
+
return;
|
|
16879
|
+
}
|
|
16880
|
+
toast.success("Firebase Service Account JSON saved successfully");
|
|
16881
|
+
onOpenChange(false);
|
|
16882
|
+
} catch {
|
|
16883
|
+
toast.error("Failed to save push configuration");
|
|
16884
|
+
} finally {
|
|
16885
|
+
setSaving(false);
|
|
16886
|
+
}
|
|
16887
|
+
}, "handleSaveConfig");
|
|
16888
|
+
const handleSendTestPush = /* @__PURE__ */ __name(async () => {
|
|
16889
|
+
if (!testToken.trim()) {
|
|
16890
|
+
toast.error("Please enter a target FCM device token to test");
|
|
16891
|
+
return;
|
|
16892
|
+
}
|
|
16893
|
+
setTesting(true);
|
|
16894
|
+
try {
|
|
16895
|
+
const res = await fetch("/api/settings/push/test", {
|
|
16896
|
+
method: "POST",
|
|
16897
|
+
headers: {
|
|
16898
|
+
"Content-Type": "application/json"
|
|
16899
|
+
},
|
|
16900
|
+
body: JSON.stringify({
|
|
16901
|
+
token: testToken.trim(),
|
|
16902
|
+
title: testTitle.trim(),
|
|
16903
|
+
body: testBody.trim()
|
|
16904
|
+
})
|
|
16905
|
+
});
|
|
16906
|
+
const data = await res.json();
|
|
16907
|
+
if (!res.ok || !data.success) {
|
|
16908
|
+
toast.error(data.error || "Failed to send test push notification");
|
|
16909
|
+
return;
|
|
16910
|
+
}
|
|
16911
|
+
toast.success("Test push notification sent successfully!");
|
|
16912
|
+
} catch {
|
|
16913
|
+
toast.error("Failed to send test push notification");
|
|
16914
|
+
} finally {
|
|
16915
|
+
setTesting(false);
|
|
16916
|
+
}
|
|
16917
|
+
}, "handleSendTestPush");
|
|
16918
|
+
if (!open) return null;
|
|
16919
|
+
return /* @__PURE__ */ React.createElement("div", {
|
|
16920
|
+
className: "fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4 backdrop-blur-sm animate-in fade-in duration-150"
|
|
16921
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
16922
|
+
className: "w-full max-w-2xl max-h-[90vh] overflow-y-auto rounded-xl bg-white p-6 shadow-2xl dark:bg-gray-900 border border-gray-200 dark:border-gray-800 space-y-6"
|
|
16923
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
16924
|
+
className: "flex items-center justify-between border-b border-gray-200 pb-4 dark:border-gray-800"
|
|
16925
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
16926
|
+
className: "flex items-center gap-2"
|
|
16927
|
+
}, /* @__PURE__ */ React.createElement(Smartphone, {
|
|
16928
|
+
className: "h-5 w-5 text-gray-800 dark:text-gray-200"
|
|
16929
|
+
}), /* @__PURE__ */ React.createElement("h2", {
|
|
16930
|
+
className: "text-lg font-semibold text-gray-900 dark:text-gray-100"
|
|
16931
|
+
}, "Firebase Service Account JSON Configuration")), /* @__PURE__ */ React.createElement("button", {
|
|
16932
|
+
type: "button",
|
|
16933
|
+
onClick: /* @__PURE__ */ __name(() => onOpenChange(false), "onClick"),
|
|
16934
|
+
className: "text-gray-400 hover:text-gray-600 dark:hover:text-gray-300"
|
|
16935
|
+
}, "\u2715")), loading ? /* @__PURE__ */ React.createElement("div", {
|
|
16936
|
+
className: "flex items-center justify-center py-12"
|
|
16937
|
+
}, /* @__PURE__ */ React.createElement(Loader2, {
|
|
16938
|
+
className: "h-6 w-6 animate-spin text-gray-500"
|
|
16939
|
+
})) : /* @__PURE__ */ React.createElement("div", {
|
|
16940
|
+
className: "space-y-6"
|
|
16941
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
16942
|
+
className: "space-y-2"
|
|
16943
|
+
}, /* @__PURE__ */ React.createElement(Label3, {
|
|
16944
|
+
htmlFor: "service-account-json",
|
|
16945
|
+
className: "text-xs font-semibold text-gray-800 dark:text-gray-200 flex items-center justify-between"
|
|
16946
|
+
}, /* @__PURE__ */ React.createElement("span", {
|
|
16947
|
+
className: "flex items-center gap-1.5"
|
|
16948
|
+
}, /* @__PURE__ */ React.createElement(KeyRound, {
|
|
16949
|
+
className: "h-4 w-4 text-blue-500"
|
|
16950
|
+
}), "Firebase Service Account JSON File"), isValidJson && /* @__PURE__ */ React.createElement("span", {
|
|
16951
|
+
className: "text-xs font-normal text-green-600 flex items-center gap-1"
|
|
16952
|
+
}, /* @__PURE__ */ React.createElement(CheckCircle2, {
|
|
16953
|
+
className: "h-3.5 w-3.5"
|
|
16954
|
+
}), " Valid JSON")), /* @__PURE__ */ React.createElement(Textarea, {
|
|
16955
|
+
id: "service-account-json",
|
|
16956
|
+
value: serviceAccountJson,
|
|
16957
|
+
onChange: /* @__PURE__ */ __name((e) => handleJsonChange(e.target.value), "onChange"),
|
|
16958
|
+
placeholder: `Paste your entire service-account.json content here...
|
|
16959
|
+
{
|
|
16960
|
+
"type": "service_account",
|
|
16961
|
+
"project_id": "...",
|
|
16962
|
+
"private_key": "...",
|
|
16963
|
+
"client_email": "..."
|
|
16964
|
+
}`,
|
|
16965
|
+
className: "h-44 font-mono text-xs border-gray-300 dark:border-gray-700"
|
|
16966
|
+
})), isValidJson && /* @__PURE__ */ React.createElement("div", {
|
|
16967
|
+
className: "rounded-lg border border-gray-200 bg-gray-50/50 p-4 dark:border-gray-800 dark:bg-gray-800/40 space-y-3"
|
|
16968
|
+
}, /* @__PURE__ */ React.createElement(Label3, {
|
|
16969
|
+
className: "text-xs font-semibold text-gray-700 dark:text-gray-300"
|
|
16970
|
+
}, "Extracted Firebase Credentials Preview"), /* @__PURE__ */ React.createElement("div", {
|
|
16971
|
+
className: "grid grid-cols-1 sm:grid-cols-2 gap-3 text-xs"
|
|
16972
|
+
}, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("span", {
|
|
16973
|
+
className: "font-medium text-gray-500"
|
|
16974
|
+
}, "Project ID:"), /* @__PURE__ */ React.createElement("p", {
|
|
16975
|
+
className: "font-mono text-gray-900 dark:text-gray-100 truncate"
|
|
16976
|
+
}, projectId || "\u2014")), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("span", {
|
|
16977
|
+
className: "font-medium text-gray-500"
|
|
16978
|
+
}, "Client Email:"), /* @__PURE__ */ React.createElement("p", {
|
|
16979
|
+
className: "font-mono text-gray-900 dark:text-gray-100 truncate"
|
|
16980
|
+
}, clientEmail || "\u2014")))), /* @__PURE__ */ React.createElement("div", {
|
|
16981
|
+
className: "rounded-lg border border-gray-200 bg-gray-50/50 p-4 dark:border-gray-800 dark:bg-gray-800/40 space-y-3"
|
|
16982
|
+
}, /* @__PURE__ */ React.createElement(Label3, {
|
|
16983
|
+
className: "text-xs font-semibold text-gray-800 dark:text-gray-200 flex items-center gap-1.5"
|
|
16984
|
+
}, /* @__PURE__ */ React.createElement(Send, {
|
|
16985
|
+
className: "h-3.5 w-3.5 text-green-500"
|
|
16986
|
+
}), "Test Push Notification (Target Device Token)"), /* @__PURE__ */ React.createElement("div", {
|
|
16987
|
+
className: "grid grid-cols-1 sm:grid-cols-2 gap-2"
|
|
16988
|
+
}, /* @__PURE__ */ React.createElement(Input, {
|
|
16989
|
+
value: testTitle,
|
|
16990
|
+
onChange: /* @__PURE__ */ __name((e) => setTestTitle(e.target.value), "onChange"),
|
|
16991
|
+
placeholder: "Test Notification Title",
|
|
16992
|
+
className: "text-xs"
|
|
16993
|
+
}), /* @__PURE__ */ React.createElement(Input, {
|
|
16994
|
+
value: testBody,
|
|
16995
|
+
onChange: /* @__PURE__ */ __name((e) => setTestBody(e.target.value), "onChange"),
|
|
16996
|
+
placeholder: "Test Notification Body",
|
|
16997
|
+
className: "text-xs"
|
|
16998
|
+
})), /* @__PURE__ */ React.createElement("div", {
|
|
16999
|
+
className: "flex gap-2"
|
|
17000
|
+
}, /* @__PURE__ */ React.createElement(Input, {
|
|
17001
|
+
value: testToken,
|
|
17002
|
+
onChange: /* @__PURE__ */ __name((e) => setTestToken(e.target.value), "onChange"),
|
|
17003
|
+
placeholder: "Target FCM Device Token",
|
|
17004
|
+
className: "text-xs font-mono"
|
|
17005
|
+
}), /* @__PURE__ */ React.createElement(Button, {
|
|
17006
|
+
type: "button",
|
|
17007
|
+
variant: "secondary",
|
|
17008
|
+
size: "sm",
|
|
17009
|
+
disabled: testing,
|
|
17010
|
+
onClick: handleSendTestPush,
|
|
17011
|
+
className: "shrink-0 gap-1.5"
|
|
17012
|
+
}, testing ? /* @__PURE__ */ React.createElement(Loader2, {
|
|
17013
|
+
className: "h-3.5 w-3.5 animate-spin"
|
|
17014
|
+
}) : /* @__PURE__ */ React.createElement(Send, {
|
|
17015
|
+
className: "h-3.5 w-3.5"
|
|
17016
|
+
}), "Send Test"))), /* @__PURE__ */ React.createElement("div", {
|
|
17017
|
+
className: "flex justify-end gap-2 border-t border-gray-200 pt-4 dark:border-gray-800"
|
|
17018
|
+
}, /* @__PURE__ */ React.createElement(Button, {
|
|
17019
|
+
type: "button",
|
|
17020
|
+
variant: "outline",
|
|
17021
|
+
onClick: /* @__PURE__ */ __name(() => onOpenChange(false), "onClick")
|
|
17022
|
+
}, "Cancel"), /* @__PURE__ */ React.createElement(Button, {
|
|
17023
|
+
type: "button",
|
|
17024
|
+
disabled: saving,
|
|
17025
|
+
onClick: handleSaveConfig,
|
|
17026
|
+
className: "gap-1.5"
|
|
17027
|
+
}, saving && /* @__PURE__ */ React.createElement(Loader2, {
|
|
17028
|
+
className: "h-4 w-4 animate-spin"
|
|
17029
|
+
}), "Save Service Account JSON")))));
|
|
17030
|
+
}
|
|
17031
|
+
var init_PushConfigModal = __esm({
|
|
17032
|
+
"src/admin/components/PushConfigModal.tsx"() {
|
|
17033
|
+
"use client";
|
|
17034
|
+
init_button();
|
|
17035
|
+
init_input();
|
|
17036
|
+
init_textarea();
|
|
17037
|
+
init_label();
|
|
17038
|
+
__name(PushConfigModal, "PushConfigModal");
|
|
17039
|
+
}
|
|
17040
|
+
});
|
|
16272
17041
|
function EventNotificationsPluginSettings({ settingsGroup, enabled, onEnabledChange, onSaveSettings, saving }) {
|
|
16273
17042
|
const [mainTab, setMainTab] = useState("email");
|
|
16274
17043
|
const [audienceTab, setAudienceTab] = useState("customer");
|
|
@@ -16276,6 +17045,10 @@ function EventNotificationsPluginSettings({ settingsGroup, enabled, onEnabledCha
|
|
|
16276
17045
|
const [emailVendorEnabled, setEmailVendorEnabled] = useState(true);
|
|
16277
17046
|
const [emailAdminEnabled, setEmailAdminEnabled] = useState(true);
|
|
16278
17047
|
const [whatsappEnabled, setWhatsappEnabled] = useState(true);
|
|
17048
|
+
const [pushCustomerEnabled, setPushCustomerEnabled] = useState(true);
|
|
17049
|
+
const [pushVendorEnabled, setPushVendorEnabled] = useState(true);
|
|
17050
|
+
const [pushAdminEnabled, setPushAdminEnabled] = useState(true);
|
|
17051
|
+
const [showPushConfigModal, setShowPushConfigModal] = useState(false);
|
|
16279
17052
|
const [multiVendorOn, setMultiVendorOn] = useState(true);
|
|
16280
17053
|
const [loading, setLoading] = useState(true);
|
|
16281
17054
|
const [savingChannel, setSavingChannel] = useState(false);
|
|
@@ -16306,6 +17079,9 @@ function EventNotificationsPluginSettings({ settingsGroup, enabled, onEnabledCha
|
|
|
16306
17079
|
setEmailVendorEnabled(data.email_vendor_enabled !== "false" && data.email_vendor_enabled !== "0");
|
|
16307
17080
|
setEmailAdminEnabled(data.email_admin_enabled !== "false" && data.email_admin_enabled !== "0");
|
|
16308
17081
|
setWhatsappEnabled(data.whatsapp_enabled !== "false" && data.whatsapp_enabled !== "0");
|
|
17082
|
+
setPushCustomerEnabled(data.push_customer_enabled !== "false" && data.push_customer_enabled !== "0");
|
|
17083
|
+
setPushVendorEnabled(data.push_vendor_enabled !== "false" && data.push_vendor_enabled !== "0");
|
|
17084
|
+
setPushAdminEnabled(data.push_admin_enabled !== "false" && data.push_admin_enabled !== "0");
|
|
16309
17085
|
}
|
|
16310
17086
|
}
|
|
16311
17087
|
} catch {
|
|
@@ -16323,7 +17099,8 @@ function EventNotificationsPluginSettings({ settingsGroup, enabled, onEnabledCha
|
|
|
16323
17099
|
setSavingChannel(true);
|
|
16324
17100
|
try {
|
|
16325
17101
|
const isAnyEmailEnabled = emailCustomerEnabled || emailVendorEnabled || emailAdminEnabled;
|
|
16326
|
-
const
|
|
17102
|
+
const isAnyPushEnabled = pushCustomerEnabled || pushVendorEnabled || pushAdminEnabled;
|
|
17103
|
+
const isAnyChannelEnabled = isAnyEmailEnabled || whatsappEnabled || isAnyPushEnabled;
|
|
16327
17104
|
const res = await fetch(`/api/settings/${settingsGroup}`, {
|
|
16328
17105
|
method: "PUT",
|
|
16329
17106
|
headers: {
|
|
@@ -16350,6 +17127,22 @@ function EventNotificationsPluginSettings({ settingsGroup, enabled, onEnabledCha
|
|
|
16350
17127
|
value: whatsappEnabled ? "true" : "false",
|
|
16351
17128
|
type: "public"
|
|
16352
17129
|
},
|
|
17130
|
+
push_enabled: {
|
|
17131
|
+
value: isAnyPushEnabled ? "true" : "false",
|
|
17132
|
+
type: "public"
|
|
17133
|
+
},
|
|
17134
|
+
push_customer_enabled: {
|
|
17135
|
+
value: pushCustomerEnabled ? "true" : "false",
|
|
17136
|
+
type: "public"
|
|
17137
|
+
},
|
|
17138
|
+
push_vendor_enabled: {
|
|
17139
|
+
value: pushVendorEnabled ? "true" : "false",
|
|
17140
|
+
type: "public"
|
|
17141
|
+
},
|
|
17142
|
+
push_admin_enabled: {
|
|
17143
|
+
value: pushAdminEnabled ? "true" : "false",
|
|
17144
|
+
type: "public"
|
|
17145
|
+
},
|
|
16353
17146
|
enabled: {
|
|
16354
17147
|
value: isAnyChannelEnabled ? "true" : "false",
|
|
16355
17148
|
type: "public"
|
|
@@ -16371,7 +17164,10 @@ function EventNotificationsPluginSettings({ settingsGroup, enabled, onEnabledCha
|
|
|
16371
17164
|
}, "handleSaveChannels");
|
|
16372
17165
|
return /* @__PURE__ */ React.createElement("div", {
|
|
16373
17166
|
className: "space-y-5"
|
|
16374
|
-
}, /* @__PURE__ */ React.createElement(
|
|
17167
|
+
}, /* @__PURE__ */ React.createElement(PushConfigModal, {
|
|
17168
|
+
open: showPushConfigModal,
|
|
17169
|
+
onOpenChange: setShowPushConfigModal
|
|
17170
|
+
}), /* @__PURE__ */ React.createElement("div", {
|
|
16375
17171
|
className: "border-b border-gray-200 dark:border-gray-700"
|
|
16376
17172
|
}, /* @__PURE__ */ React.createElement("div", {
|
|
16377
17173
|
className: "flex gap-1"
|
|
@@ -16387,7 +17183,13 @@ function EventNotificationsPluginSettings({ settingsGroup, enabled, onEnabledCha
|
|
|
16387
17183
|
className: `inline-flex items-center gap-2 px-4 py-2.5 text-sm font-medium border-b-2 ${mainTab === "whatsapp" ? "border-gray-800 text-gray-800 dark:border-gray-200 dark:text-gray-100" : "border-transparent text-gray-500 hover:text-gray-700"}`
|
|
16388
17184
|
}, /* @__PURE__ */ React.createElement(MessageCircle, {
|
|
16389
17185
|
className: "h-4 w-4"
|
|
16390
|
-
}), "WhatsApp template")
|
|
17186
|
+
}), "WhatsApp template"), /* @__PURE__ */ React.createElement("button", {
|
|
17187
|
+
type: "button",
|
|
17188
|
+
onClick: /* @__PURE__ */ __name(() => setMainTab("push"), "onClick"),
|
|
17189
|
+
className: `inline-flex items-center gap-2 px-4 py-2.5 text-sm font-medium border-b-2 ${mainTab === "push" ? "border-gray-800 text-gray-800 dark:border-gray-200 dark:text-gray-100" : "border-transparent text-gray-500 hover:text-gray-700"}`
|
|
17190
|
+
}, /* @__PURE__ */ React.createElement(Smartphone, {
|
|
17191
|
+
className: "h-4 w-4"
|
|
17192
|
+
}), "Mobile notification template"))), mainTab === "email" && /* @__PURE__ */ React.createElement("div", {
|
|
16391
17193
|
className: "space-y-5"
|
|
16392
17194
|
}, /* @__PURE__ */ React.createElement("div", {
|
|
16393
17195
|
className: "flex rounded-md bg-gray-100 p-1 dark:bg-gray-800/60 w-fit"
|
|
@@ -16421,7 +17223,7 @@ function EventNotificationsPluginSettings({ settingsGroup, enabled, onEnabledCha
|
|
|
16421
17223
|
className: "h-4 w-4 text-blue-600 dark:text-blue-400"
|
|
16422
17224
|
}), "Enable Customer Email Notifications"), /* @__PURE__ */ React.createElement("p", {
|
|
16423
17225
|
className: "text-xs text-gray-500 dark:text-gray-400"
|
|
16424
|
-
}, "When enabled, order
|
|
17226
|
+
}, "When enabled, order updates, invoices, and ticket details are emailed to customers.")), /* @__PURE__ */ React.createElement(Switch, {
|
|
16425
17227
|
id: "email-customer-notifications-enabled",
|
|
16426
17228
|
checked: emailCustomerEnabled,
|
|
16427
17229
|
onCheckedChange: setEmailCustomerEnabled,
|
|
@@ -16437,10 +17239,10 @@ function EventNotificationsPluginSettings({ settingsGroup, enabled, onEnabledCha
|
|
|
16437
17239
|
}, /* @__PURE__ */ React.createElement("div", {
|
|
16438
17240
|
className: "text-sm font-medium text-gray-900 dark:text-gray-100 flex items-center gap-2"
|
|
16439
17241
|
}, /* @__PURE__ */ React.createElement(Store, {
|
|
16440
|
-
className: "h-4 w-4 text-purple-600 dark:
|
|
17242
|
+
className: "h-4 w-4 text-purple-600 dark:purple-400"
|
|
16441
17243
|
}), "Enable Vendor Email Notifications"), /* @__PURE__ */ React.createElement("p", {
|
|
16442
17244
|
className: "text-xs text-gray-500 dark:text-gray-400"
|
|
16443
|
-
}, "When enabled, vendors
|
|
17245
|
+
}, "When enabled, vendors receive email notifications for new orders assigned to them.")), /* @__PURE__ */ React.createElement(Switch, {
|
|
16444
17246
|
id: "email-vendor-notifications-enabled",
|
|
16445
17247
|
checked: emailVendorEnabled,
|
|
16446
17248
|
onCheckedChange: setEmailVendorEnabled,
|
|
@@ -16483,7 +17285,104 @@ function EventNotificationsPluginSettings({ settingsGroup, enabled, onEnabledCha
|
|
|
16483
17285
|
checked: whatsappEnabled,
|
|
16484
17286
|
onCheckedChange: setWhatsappEnabled,
|
|
16485
17287
|
disabled: loading
|
|
16486
|
-
})), /* @__PURE__ */ React.createElement(WhatsAppTriggerBindings, null)), /* @__PURE__ */ React.createElement(
|
|
17288
|
+
})), /* @__PURE__ */ React.createElement(WhatsAppTriggerBindings, null)), mainTab === "push" && /* @__PURE__ */ React.createElement("div", {
|
|
17289
|
+
className: "space-y-5"
|
|
17290
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
17291
|
+
className: "flex items-center justify-between gap-4 rounded-lg border border-blue-100 bg-blue-50/50 p-4 dark:border-blue-900/40 dark:bg-blue-950/20"
|
|
17292
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
17293
|
+
className: "space-y-0.5"
|
|
17294
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
17295
|
+
className: "text-sm font-semibold text-gray-900 dark:text-gray-100 flex items-center gap-2"
|
|
17296
|
+
}, /* @__PURE__ */ React.createElement(Smartphone, {
|
|
17297
|
+
className: "h-4 w-4 text-blue-600 dark:text-blue-400"
|
|
17298
|
+
}), "Firebase Cloud Messaging (FCM) Setup"), /* @__PURE__ */ React.createElement("p", {
|
|
17299
|
+
className: "text-xs text-gray-500 dark:text-gray-400"
|
|
17300
|
+
}, "Set up your Firebase project credentials to send mobile push notifications to iOS and Android apps.")), /* @__PURE__ */ React.createElement(Button, {
|
|
17301
|
+
type: "button",
|
|
17302
|
+
variant: "outline",
|
|
17303
|
+
size: "sm",
|
|
17304
|
+
onClick: /* @__PURE__ */ __name(() => setShowPushConfigModal(true), "onClick"),
|
|
17305
|
+
className: "gap-1.5 bg-white dark:bg-gray-900 shrink-0"
|
|
17306
|
+
}, /* @__PURE__ */ React.createElement(Settings, {
|
|
17307
|
+
className: "h-4 w-4 text-gray-600"
|
|
17308
|
+
}), "Set Configuration")), /* @__PURE__ */ React.createElement("div", {
|
|
17309
|
+
className: "flex rounded-md bg-gray-100 p-1 dark:bg-gray-800/60 w-fit"
|
|
17310
|
+
}, /* @__PURE__ */ React.createElement("button", {
|
|
17311
|
+
type: "button",
|
|
17312
|
+
onClick: /* @__PURE__ */ __name(() => setAudienceTab("customer"), "onClick"),
|
|
17313
|
+
className: `inline-flex items-center gap-1.5 rounded px-3 py-1.5 text-xs font-medium transition-all ${audienceTab === "customer" ? "bg-white text-gray-900 shadow-sm dark:bg-gray-900 dark:text-white" : "text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-white"}`
|
|
17314
|
+
}, /* @__PURE__ */ React.createElement(User, {
|
|
17315
|
+
className: "h-3.5 w-3.5 text-blue-500"
|
|
17316
|
+
}), "Customers"), multiVendorOn && /* @__PURE__ */ React.createElement("button", {
|
|
17317
|
+
type: "button",
|
|
17318
|
+
onClick: /* @__PURE__ */ __name(() => setAudienceTab("vendor"), "onClick"),
|
|
17319
|
+
className: `inline-flex items-center gap-1.5 rounded px-3 py-1.5 text-xs font-medium transition-all ${audienceTab === "vendor" ? "bg-white text-gray-900 shadow-sm dark:bg-gray-900 dark:text-white" : "text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-white"}`
|
|
17320
|
+
}, /* @__PURE__ */ React.createElement(Store, {
|
|
17321
|
+
className: "h-3.5 w-3.5 text-purple-500"
|
|
17322
|
+
}), "Vendors"), /* @__PURE__ */ React.createElement("button", {
|
|
17323
|
+
type: "button",
|
|
17324
|
+
onClick: /* @__PURE__ */ __name(() => setAudienceTab("admin"), "onClick"),
|
|
17325
|
+
className: `inline-flex items-center gap-1.5 rounded px-3 py-1.5 text-xs font-medium transition-all ${audienceTab === "admin" ? "bg-white text-gray-900 shadow-sm dark:bg-gray-900 dark:text-white" : "text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-white"}`
|
|
17326
|
+
}, /* @__PURE__ */ React.createElement(ShieldCheck, {
|
|
17327
|
+
className: "h-3.5 w-3.5 text-amber-500"
|
|
17328
|
+
}), "Admin")), audienceTab === "customer" && /* @__PURE__ */ React.createElement("div", {
|
|
17329
|
+
className: "space-y-4"
|
|
17330
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
17331
|
+
className: "flex items-center justify-between gap-4 rounded-lg border border-gray-200 bg-gray-50/50 p-4 dark:border-gray-800 dark:bg-gray-900/50"
|
|
17332
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
17333
|
+
className: "space-y-0.5"
|
|
17334
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
17335
|
+
className: "text-sm font-medium text-gray-900 dark:text-gray-100 flex items-center gap-2"
|
|
17336
|
+
}, /* @__PURE__ */ React.createElement(User, {
|
|
17337
|
+
className: "h-4 w-4 text-blue-600 dark:text-blue-400"
|
|
17338
|
+
}), "Enable Customer Mobile Push Notifications"), /* @__PURE__ */ React.createElement("p", {
|
|
17339
|
+
className: "text-xs text-gray-500 dark:text-gray-400"
|
|
17340
|
+
}, "When enabled, order confirmation alerts and updates are pushed directly to customer mobile apps.")), /* @__PURE__ */ React.createElement(Switch, {
|
|
17341
|
+
id: "push-customer-notifications-enabled",
|
|
17342
|
+
checked: pushCustomerEnabled,
|
|
17343
|
+
onCheckedChange: setPushCustomerEnabled,
|
|
17344
|
+
disabled: loading
|
|
17345
|
+
})), /* @__PURE__ */ React.createElement(PushTriggerBindings, {
|
|
17346
|
+
audience: "customer"
|
|
17347
|
+
})), audienceTab === "vendor" && multiVendorOn && /* @__PURE__ */ React.createElement("div", {
|
|
17348
|
+
className: "space-y-4"
|
|
17349
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
17350
|
+
className: "flex items-center justify-between gap-4 rounded-lg border border-gray-200 bg-gray-50/50 p-4 dark:border-gray-800 dark:bg-gray-900/50"
|
|
17351
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
17352
|
+
className: "space-y-0.5"
|
|
17353
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
17354
|
+
className: "text-sm font-medium text-gray-900 dark:text-gray-100 flex items-center gap-2"
|
|
17355
|
+
}, /* @__PURE__ */ React.createElement(Store, {
|
|
17356
|
+
className: "h-4 w-4 text-purple-600 dark:text-purple-400"
|
|
17357
|
+
}), "Enable Vendor Mobile Push Notifications"), /* @__PURE__ */ React.createElement("p", {
|
|
17358
|
+
className: "text-xs text-gray-500 dark:text-gray-400"
|
|
17359
|
+
}, "When enabled, vendor mobile app receives instant push alerts for assigned orders.")), /* @__PURE__ */ React.createElement(Switch, {
|
|
17360
|
+
id: "push-vendor-notifications-enabled",
|
|
17361
|
+
checked: pushVendorEnabled,
|
|
17362
|
+
onCheckedChange: setPushVendorEnabled,
|
|
17363
|
+
disabled: loading
|
|
17364
|
+
})), /* @__PURE__ */ React.createElement(PushTriggerBindings, {
|
|
17365
|
+
audience: "vendor"
|
|
17366
|
+
})), audienceTab === "admin" && /* @__PURE__ */ React.createElement("div", {
|
|
17367
|
+
className: "space-y-4"
|
|
17368
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
17369
|
+
className: "flex items-center justify-between gap-4 rounded-lg border border-gray-200 bg-gray-50/50 p-4 dark:border-gray-800 dark:bg-gray-900/50"
|
|
17370
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
17371
|
+
className: "space-y-0.5"
|
|
17372
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
17373
|
+
className: "text-sm font-medium text-gray-900 dark:text-gray-100 flex items-center gap-2"
|
|
17374
|
+
}, /* @__PURE__ */ React.createElement(ShieldCheck, {
|
|
17375
|
+
className: "h-4 w-4 text-amber-600 dark:text-amber-400"
|
|
17376
|
+
}), "Enable Admin Mobile Push Notifications"), /* @__PURE__ */ React.createElement("p", {
|
|
17377
|
+
className: "text-xs text-gray-500 dark:text-gray-400"
|
|
17378
|
+
}, "When enabled, store administrators receive mobile push alerts for all orders placed/cancelled.")), /* @__PURE__ */ React.createElement(Switch, {
|
|
17379
|
+
id: "push-admin-notifications-enabled",
|
|
17380
|
+
checked: pushAdminEnabled,
|
|
17381
|
+
onCheckedChange: setPushAdminEnabled,
|
|
17382
|
+
disabled: loading
|
|
17383
|
+
})), /* @__PURE__ */ React.createElement(PushTriggerBindings, {
|
|
17384
|
+
audience: "admin"
|
|
17385
|
+
}))), /* @__PURE__ */ React.createElement(Button, {
|
|
16487
17386
|
size: "sm",
|
|
16488
17387
|
onClick: /* @__PURE__ */ __name(() => void handleSaveChannels(), "onClick"),
|
|
16489
17388
|
disabled: saving || savingChannel || loading,
|
|
@@ -16499,9 +17398,207 @@ var init_EventNotificationsPluginSettings = __esm({
|
|
|
16499
17398
|
init_switch();
|
|
16500
17399
|
init_whatsappTriggerBindingsPage();
|
|
16501
17400
|
init_emailTriggersBindingsPage();
|
|
17401
|
+
init_pushTriggersBindingsPage();
|
|
17402
|
+
init_PushConfigModal();
|
|
16502
17403
|
__name(EventNotificationsPluginSettings, "EventNotificationsPluginSettings");
|
|
16503
17404
|
}
|
|
16504
17405
|
});
|
|
17406
|
+
function googleRedirectUri() {
|
|
17407
|
+
if (typeof window === "undefined") {
|
|
17408
|
+
const path2 = typeof process !== "undefined" && process.env.NEXT_PUBLIC_GOOGLE_OAUTH_CALLBACK_PATH?.trim() || "/api/auth/callback/google";
|
|
17409
|
+
return path2.startsWith("http") ? path2 : path2;
|
|
17410
|
+
}
|
|
17411
|
+
const configured = process.env.NEXT_PUBLIC_GOOGLE_OAUTH_CALLBACK_PATH?.trim();
|
|
17412
|
+
if (configured?.startsWith("http")) return configured;
|
|
17413
|
+
const path = configured || "/api/auth/callback/google";
|
|
17414
|
+
return `${window.location.origin}${path.startsWith("/") ? path : `/${path}`}`;
|
|
17415
|
+
}
|
|
17416
|
+
function AuthProvidersPluginSettings({ settingsGroup, onEnabledChange }) {
|
|
17417
|
+
const [loading, setLoading] = useState(true);
|
|
17418
|
+
const [saving, setSaving] = useState(false);
|
|
17419
|
+
const [googleEnabled, setGoogleEnabled] = useState(false);
|
|
17420
|
+
const [googleClientId, setGoogleClientId] = useState("");
|
|
17421
|
+
const [googleClientSecret, setGoogleClientSecret] = useState("");
|
|
17422
|
+
const [hasSavedSecret, setHasSavedSecret] = useState(false);
|
|
17423
|
+
const [copied, setCopied] = useState(false);
|
|
17424
|
+
const onEnabledChangeRef = useRef(onEnabledChange);
|
|
17425
|
+
onEnabledChangeRef.current = onEnabledChange;
|
|
17426
|
+
const redirectUri = useMemo(() => googleRedirectUri(), []);
|
|
17427
|
+
useEffect(() => {
|
|
17428
|
+
let cancelled = false;
|
|
17429
|
+
(async () => {
|
|
17430
|
+
setLoading(true);
|
|
17431
|
+
try {
|
|
17432
|
+
const res = await fetch(`/api/settings/${settingsGroup}`, {
|
|
17433
|
+
cache: "no-store"
|
|
17434
|
+
});
|
|
17435
|
+
const data = res.ok ? await res.json() : {};
|
|
17436
|
+
if (cancelled) return;
|
|
17437
|
+
const enabled = data.googleEnabled === "true" || data.googleEnabled === "1" || data.enabled === "true" && data.googleEnabled !== "false";
|
|
17438
|
+
setGoogleEnabled(enabled);
|
|
17439
|
+
setGoogleClientId(String(data.googleClientId ?? "").trim());
|
|
17440
|
+
const secret = String(data.googleClientSecret ?? "").trim();
|
|
17441
|
+
setGoogleClientSecret("");
|
|
17442
|
+
setHasSavedSecret(Boolean(secret));
|
|
17443
|
+
} catch {
|
|
17444
|
+
} finally {
|
|
17445
|
+
if (!cancelled) setLoading(false);
|
|
17446
|
+
}
|
|
17447
|
+
})();
|
|
17448
|
+
return () => {
|
|
17449
|
+
cancelled = true;
|
|
17450
|
+
};
|
|
17451
|
+
}, [
|
|
17452
|
+
settingsGroup
|
|
17453
|
+
]);
|
|
17454
|
+
const handleCopyRedirect = /* @__PURE__ */ __name(async () => {
|
|
17455
|
+
try {
|
|
17456
|
+
await navigator.clipboard.writeText(redirectUri);
|
|
17457
|
+
setCopied(true);
|
|
17458
|
+
toast.success("Redirect URI copied");
|
|
17459
|
+
setTimeout(() => setCopied(false), 2e3);
|
|
17460
|
+
} catch {
|
|
17461
|
+
toast.error("Could not copy redirect URI");
|
|
17462
|
+
}
|
|
17463
|
+
}, "handleCopyRedirect");
|
|
17464
|
+
const handleSave = /* @__PURE__ */ __name(async () => {
|
|
17465
|
+
setSaving(true);
|
|
17466
|
+
try {
|
|
17467
|
+
const payload = {
|
|
17468
|
+
enabled: {
|
|
17469
|
+
value: googleEnabled ? "true" : "false",
|
|
17470
|
+
type: "public"
|
|
17471
|
+
},
|
|
17472
|
+
googleEnabled: {
|
|
17473
|
+
value: googleEnabled ? "true" : "false",
|
|
17474
|
+
type: "public"
|
|
17475
|
+
},
|
|
17476
|
+
googleClientId: {
|
|
17477
|
+
value: googleClientId.trim(),
|
|
17478
|
+
type: "private"
|
|
17479
|
+
}
|
|
17480
|
+
};
|
|
17481
|
+
if (googleClientSecret.trim()) {
|
|
17482
|
+
payload.googleClientSecret = {
|
|
17483
|
+
value: googleClientSecret.trim(),
|
|
17484
|
+
type: "private",
|
|
17485
|
+
encrypted: true
|
|
17486
|
+
};
|
|
17487
|
+
}
|
|
17488
|
+
const res = await fetch(`/api/settings/${settingsGroup}`, {
|
|
17489
|
+
method: "PUT",
|
|
17490
|
+
headers: {
|
|
17491
|
+
"Content-Type": "application/json"
|
|
17492
|
+
},
|
|
17493
|
+
body: JSON.stringify(payload)
|
|
17494
|
+
});
|
|
17495
|
+
if (!res.ok) {
|
|
17496
|
+
toast.error("Failed to save Google auth settings");
|
|
17497
|
+
return;
|
|
17498
|
+
}
|
|
17499
|
+
if (googleClientSecret.trim()) {
|
|
17500
|
+
setHasSavedSecret(true);
|
|
17501
|
+
setGoogleClientSecret("");
|
|
17502
|
+
}
|
|
17503
|
+
onEnabledChangeRef.current?.(googleEnabled);
|
|
17504
|
+
toast.success("Authentication provider settings saved");
|
|
17505
|
+
} catch {
|
|
17506
|
+
toast.error("Failed to save Google auth settings");
|
|
17507
|
+
} finally {
|
|
17508
|
+
setSaving(false);
|
|
17509
|
+
}
|
|
17510
|
+
}, "handleSave");
|
|
17511
|
+
if (loading) {
|
|
17512
|
+
return /* @__PURE__ */ React.createElement("p", {
|
|
17513
|
+
className: "text-sm text-gray-500 dark:text-gray-400"
|
|
17514
|
+
}, "Loading\u2026");
|
|
17515
|
+
}
|
|
17516
|
+
return /* @__PURE__ */ React.createElement("div", {
|
|
17517
|
+
className: "space-y-4"
|
|
17518
|
+
}, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("h3", {
|
|
17519
|
+
className: "text-sm font-semibold text-gray-900 dark:text-white"
|
|
17520
|
+
}, "Google (Web)"), /* @__PURE__ */ React.createElement("p", {
|
|
17521
|
+
className: "mt-1 text-xs text-gray-500 dark:text-gray-400"
|
|
17522
|
+
}, "Create a Web OAuth client in Google Cloud Console, add the redirect URI below, then paste Client ID and Client Secret here. Only existing admin/vendor users (matching Google email) can sign in.")), /* @__PURE__ */ React.createElement("div", {
|
|
17523
|
+
className: "flex items-center justify-between gap-2"
|
|
17524
|
+
}, /* @__PURE__ */ React.createElement(Label3, {
|
|
17525
|
+
htmlFor: `${settingsGroup}-googleEnabled`,
|
|
17526
|
+
className: "text-sm"
|
|
17527
|
+
}, "Enable Google sign-in"), /* @__PURE__ */ React.createElement(Switch, {
|
|
17528
|
+
id: `${settingsGroup}-googleEnabled`,
|
|
17529
|
+
checked: googleEnabled,
|
|
17530
|
+
onCheckedChange: setGoogleEnabled
|
|
17531
|
+
})), /* @__PURE__ */ React.createElement("div", {
|
|
17532
|
+
className: "space-y-1"
|
|
17533
|
+
}, /* @__PURE__ */ React.createElement(Label3, {
|
|
17534
|
+
htmlFor: `${settingsGroup}-redirectUri`,
|
|
17535
|
+
className: "text-sm"
|
|
17536
|
+
}, "Redirect URI (add in Google Console)"), /* @__PURE__ */ React.createElement("div", {
|
|
17537
|
+
className: "flex gap-2"
|
|
17538
|
+
}, /* @__PURE__ */ React.createElement(Input, {
|
|
17539
|
+
id: `${settingsGroup}-redirectUri`,
|
|
17540
|
+
value: redirectUri,
|
|
17541
|
+
readOnly: true,
|
|
17542
|
+
className: "h-9 flex-1 font-mono text-xs"
|
|
17543
|
+
}), /* @__PURE__ */ React.createElement(Button, {
|
|
17544
|
+
type: "button",
|
|
17545
|
+
size: "sm",
|
|
17546
|
+
variant: "outline",
|
|
17547
|
+
onClick: handleCopyRedirect,
|
|
17548
|
+
className: "shrink-0 gap-1"
|
|
17549
|
+
}, copied ? /* @__PURE__ */ React.createElement(Check, {
|
|
17550
|
+
className: "h-3.5 w-3.5"
|
|
17551
|
+
}) : /* @__PURE__ */ React.createElement(Copy, {
|
|
17552
|
+
className: "h-3.5 w-3.5"
|
|
17553
|
+
}), copied ? "Copied" : "Copy")), /* @__PURE__ */ React.createElement("p", {
|
|
17554
|
+
className: "text-xs text-gray-500 dark:text-gray-400"
|
|
17555
|
+
}, "Must match ", /* @__PURE__ */ React.createElement("code", {
|
|
17556
|
+
className: "text-[11px]"
|
|
17557
|
+
}, "NEXTAUTH_URL"), " for this environment.")), /* @__PURE__ */ React.createElement("div", {
|
|
17558
|
+
className: "space-y-1"
|
|
17559
|
+
}, /* @__PURE__ */ React.createElement(Label3, {
|
|
17560
|
+
htmlFor: `${settingsGroup}-googleClientId`,
|
|
17561
|
+
className: "text-sm"
|
|
17562
|
+
}, "Client ID"), /* @__PURE__ */ React.createElement(Input, {
|
|
17563
|
+
id: `${settingsGroup}-googleClientId`,
|
|
17564
|
+
value: googleClientId,
|
|
17565
|
+
onChange: /* @__PURE__ */ __name((e) => setGoogleClientId(e.target.value), "onChange"),
|
|
17566
|
+
placeholder: "xxxxx.apps.googleusercontent.com",
|
|
17567
|
+
className: "h-9 text-sm",
|
|
17568
|
+
autoComplete: "off"
|
|
17569
|
+
})), /* @__PURE__ */ React.createElement("div", {
|
|
17570
|
+
className: "space-y-1"
|
|
17571
|
+
}, /* @__PURE__ */ React.createElement(Label3, {
|
|
17572
|
+
htmlFor: `${settingsGroup}-googleClientSecret`,
|
|
17573
|
+
className: "text-sm"
|
|
17574
|
+
}, "Client Secret ", hasSavedSecret && !googleClientSecret.trim() ? "(saved)" : ""), /* @__PURE__ */ React.createElement(Input, {
|
|
17575
|
+
id: `${settingsGroup}-googleClientSecret`,
|
|
17576
|
+
type: "password",
|
|
17577
|
+
value: googleClientSecret,
|
|
17578
|
+
onChange: /* @__PURE__ */ __name((e) => setGoogleClientSecret(e.target.value), "onChange"),
|
|
17579
|
+
placeholder: hasSavedSecret ? "Leave blank to keep saved secret" : "Paste client secret",
|
|
17580
|
+
className: "h-9 text-sm",
|
|
17581
|
+
autoComplete: "new-password"
|
|
17582
|
+
})), /* @__PURE__ */ React.createElement(Button, {
|
|
17583
|
+
size: "sm",
|
|
17584
|
+
onClick: handleSave,
|
|
17585
|
+
disabled: saving,
|
|
17586
|
+
className: "gap-1"
|
|
17587
|
+
}, /* @__PURE__ */ React.createElement(Save, {
|
|
17588
|
+
className: "h-3.5 w-3.5"
|
|
17589
|
+
}), saving ? "Saving\u2026" : "Save"));
|
|
17590
|
+
}
|
|
17591
|
+
var init_AuthProvidersPluginSettings = __esm({
|
|
17592
|
+
"src/admin/components/AuthProvidersPluginSettings.tsx"() {
|
|
17593
|
+
"use client";
|
|
17594
|
+
init_button();
|
|
17595
|
+
init_input();
|
|
17596
|
+
init_label();
|
|
17597
|
+
init_switch();
|
|
17598
|
+
__name(googleRedirectUri, "googleRedirectUri");
|
|
17599
|
+
__name(AuthProvidersPluginSettings, "AuthProvidersPluginSettings");
|
|
17600
|
+
}
|
|
17601
|
+
});
|
|
16505
17602
|
|
|
16506
17603
|
// src/plugins/llm/chat-email-intent.ts
|
|
16507
17604
|
function normalizeIntentKey(raw) {
|
|
@@ -16879,6 +17976,7 @@ function PluginSettingsPanel({ descriptor, onSaved }) {
|
|
|
16879
17976
|
const isEventNotifications = settingsGroup === "event_notifications";
|
|
16880
17977
|
const isSocialMedia = settingsGroup === "social_media";
|
|
16881
17978
|
const isMultiVendor = settingsGroup === "multi_vendor";
|
|
17979
|
+
const isAuthProviders = settingsGroup === "auth_providers";
|
|
16882
17980
|
const [enabled, setEnabled] = useState(true);
|
|
16883
17981
|
const [botName, setBotName] = useState("");
|
|
16884
17982
|
const [icon, setIcon] = useState("");
|
|
@@ -17228,6 +18326,10 @@ function PluginSettingsPanel({ descriptor, onSaved }) {
|
|
|
17228
18326
|
setWhatsappPhoneNumberId(String(data.phoneNumberId ?? data.WHATSAPP_PHONE_NUMBER_ID ?? "").trim());
|
|
17229
18327
|
setWhatsappWabaId(String(data.wabaId ?? data.WHATSAPP_WABA_ID ?? "").trim());
|
|
17230
18328
|
}
|
|
18329
|
+
if (isAuthProviders) {
|
|
18330
|
+
const googleOn = data.googleEnabled === "true" || data.googleEnabled === "1" || data.enabled === "true" && data.googleEnabled !== "false";
|
|
18331
|
+
setEnabled(googleOn);
|
|
18332
|
+
}
|
|
17231
18333
|
if (isSocialMedia) {
|
|
17232
18334
|
const savedLiToken = String(data.linkedin_access_token ?? "").trim();
|
|
17233
18335
|
setLinkedinAccessToken(savedLiToken);
|
|
@@ -17265,7 +18367,8 @@ function PluginSettingsPanel({ descriptor, onSaved }) {
|
|
|
17265
18367
|
isWhatsapp,
|
|
17266
18368
|
isEventNotifications,
|
|
17267
18369
|
isSocialMedia,
|
|
17268
|
-
isMultiVendor
|
|
18370
|
+
isMultiVendor,
|
|
18371
|
+
isAuthProviders
|
|
17269
18372
|
]);
|
|
17270
18373
|
useEffect(() => {
|
|
17271
18374
|
if (!isSocialMedia || loading || linkedInOrgsPrefetchedRef.current) return;
|
|
@@ -17711,6 +18814,18 @@ function PluginSettingsPanel({ descriptor, onSaved }) {
|
|
|
17711
18814
|
}
|
|
17712
18815
|
};
|
|
17713
18816
|
}
|
|
18817
|
+
if (isAuthProviders) {
|
|
18818
|
+
return {
|
|
18819
|
+
enabled: {
|
|
18820
|
+
value: enabled ? "true" : "false",
|
|
18821
|
+
type: "public"
|
|
18822
|
+
},
|
|
18823
|
+
googleEnabled: {
|
|
18824
|
+
value: enabled ? "true" : "false",
|
|
18825
|
+
type: "public"
|
|
18826
|
+
}
|
|
18827
|
+
};
|
|
18828
|
+
}
|
|
17714
18829
|
if (isSocialMedia) {
|
|
17715
18830
|
const payload2 = {
|
|
17716
18831
|
enabled: {
|
|
@@ -18196,6 +19311,15 @@ function PluginSettingsPanel({ descriptor, onSaved }) {
|
|
|
18196
19311
|
toast.success("Removed from agent");
|
|
18197
19312
|
await fetchAttachedKnowledge(slug);
|
|
18198
19313
|
}, "handleUnlinkKbDoc");
|
|
19314
|
+
if (isAuthProviders) {
|
|
19315
|
+
return /* @__PURE__ */ React.createElement(AuthProvidersPluginSettings, {
|
|
19316
|
+
settingsGroup,
|
|
19317
|
+
onEnabledChange: /* @__PURE__ */ __name((value) => {
|
|
19318
|
+
setEnabled(value);
|
|
19319
|
+
onSaved?.();
|
|
19320
|
+
}, "onEnabledChange")
|
|
19321
|
+
});
|
|
19322
|
+
}
|
|
18199
19323
|
if (loading) return /* @__PURE__ */ React.createElement("div", {
|
|
18200
19324
|
className: "text-sm text-gray-500 dark:text-gray-400"
|
|
18201
19325
|
}, "Loading...");
|
|
@@ -19532,6 +20656,10 @@ function PluginsPage() {
|
|
|
19532
20656
|
const en = pluginDescriptors.find((p) => p.name === "event_notifications");
|
|
19533
20657
|
if (en) setSelectedName(en.name);
|
|
19534
20658
|
}
|
|
20659
|
+
if (q === "auth_providers" || q === "auth-providers" || q === "authentication") {
|
|
20660
|
+
const ap = pluginDescriptors.find((p) => p.name === "auth_providers");
|
|
20661
|
+
if (ap) setSelectedName(ap.name);
|
|
20662
|
+
}
|
|
19535
20663
|
}, [
|
|
19536
20664
|
searchParams,
|
|
19537
20665
|
pluginDescriptors
|
|
@@ -19539,10 +20667,13 @@ function PluginsPage() {
|
|
|
19539
20667
|
useEffect(() => {
|
|
19540
20668
|
pluginDescriptors.forEach((p) => {
|
|
19541
20669
|
if (!p.settingsGroup) return;
|
|
19542
|
-
fetch(`/api/settings/${p.settingsGroup}`).then((r) => r.ok ? r.json() : {}).then((data) =>
|
|
19543
|
-
|
|
19544
|
-
|
|
19545
|
-
|
|
20670
|
+
fetch(`/api/settings/${p.settingsGroup}`).then((r) => r.ok ? r.json() : {}).then((data) => {
|
|
20671
|
+
const on = p.settingsGroup === "auth_providers" ? data.googleEnabled === "true" || data.googleEnabled === "1" || data.enabled !== "false" && data.googleEnabled !== "false" && data.enabled === "true" : data.enabled !== "false";
|
|
20672
|
+
setEnabledMap((prev) => ({
|
|
20673
|
+
...prev,
|
|
20674
|
+
[p.name]: on
|
|
20675
|
+
}));
|
|
20676
|
+
}).catch(() => {
|
|
19546
20677
|
});
|
|
19547
20678
|
});
|
|
19548
20679
|
}, [
|
|
@@ -19552,10 +20683,13 @@ function PluginsPage() {
|
|
|
19552
20683
|
const refreshEnabled = /* @__PURE__ */ __name((name) => {
|
|
19553
20684
|
const d = pluginDescriptors.find((p) => p.name === name);
|
|
19554
20685
|
if (!d?.settingsGroup) return;
|
|
19555
|
-
fetch(`/api/settings/${d.settingsGroup}`).then((r) => r.ok ? r.json() : {}).then((data) =>
|
|
19556
|
-
|
|
19557
|
-
|
|
19558
|
-
|
|
20686
|
+
fetch(`/api/settings/${d.settingsGroup}`).then((r) => r.ok ? r.json() : {}).then((data) => {
|
|
20687
|
+
const on = d.settingsGroup === "auth_providers" ? data.googleEnabled === "true" || data.googleEnabled === "1" || data.enabled === "true" && data.googleEnabled !== "false" : data.enabled !== "false";
|
|
20688
|
+
setEnabledMap((prev) => ({
|
|
20689
|
+
...prev,
|
|
20690
|
+
[name]: on
|
|
20691
|
+
}));
|
|
20692
|
+
}).catch(() => {
|
|
19559
20693
|
});
|
|
19560
20694
|
}, "refreshEnabled");
|
|
19561
20695
|
return /* @__PURE__ */ React.createElement("div", {
|
|
@@ -19637,6 +20771,7 @@ var init_PluginsPage = __esm({
|
|
|
19637
20771
|
init_checkbox();
|
|
19638
20772
|
init_select();
|
|
19639
20773
|
init_EventNotificationsPluginSettings();
|
|
20774
|
+
init_AuthProvidersPluginSettings();
|
|
19640
20775
|
init_ImageOrUrlField();
|
|
19641
20776
|
init_chat_email_intent();
|
|
19642
20777
|
init_llm_agent_scope();
|
|
@@ -19655,7 +20790,8 @@ var init_PluginsPage = __esm({
|
|
|
19655
20790
|
pg_boss: CalendarClock,
|
|
19656
20791
|
share: Share2,
|
|
19657
20792
|
whatsapp: MessageCircle,
|
|
19658
|
-
event_notifications: Bell
|
|
20793
|
+
event_notifications: Bell,
|
|
20794
|
+
auth_providers: KeyRound
|
|
19659
20795
|
};
|
|
19660
20796
|
__name(normalizeSmsProviderChoice, "normalizeSmsProviderChoice");
|
|
19661
20797
|
__name(normalizeMsg91ApiMode, "normalizeMsg91ApiMode");
|
|
@@ -20128,9 +21264,7 @@ function VendorRolesPage() {
|
|
|
20128
21264
|
className: "text-base font-semibold text-white"
|
|
20129
21265
|
}, "Vendor Store Roles & Permissions"), /* @__PURE__ */ React25__default.createElement("p", {
|
|
20130
21266
|
className: "mt-0.5 text-xs text-gray-300"
|
|
20131
|
-
}, "Set CRUD permissions for any role (Viewer, Manager, Fulfillment, Catalog Staff, or custom roles).
|
|
20132
|
-
className: "font-mono bg-gray-700 px-1 py-0.5 rounded text-gray-200"
|
|
20133
|
-
}, "vendor_role_permissions"), " table and apply directly to team members assigned to that role.")), /* @__PURE__ */ React25__default.createElement("div", {
|
|
21267
|
+
}, "Set CRUD permissions for any role (Viewer, Manager, Fulfillment, Catalog Staff, or custom roles).")), /* @__PURE__ */ React25__default.createElement("div", {
|
|
20134
21268
|
className: "min-w-0 p-6"
|
|
20135
21269
|
}, error ? /* @__PURE__ */ React25__default.createElement("p", {
|
|
20136
21270
|
className: "mb-4 text-sm text-red-600 dark:text-red-400"
|
|
@@ -20629,7 +21763,7 @@ function PlatformRolesPage() {
|
|
|
20629
21763
|
className: "p-2"
|
|
20630
21764
|
}, /* @__PURE__ */ React25__default.createElement("div", {
|
|
20631
21765
|
className: "flex items-center justify-center gap-1"
|
|
20632
|
-
}, /* @__PURE__ */ React25__default.createElement("span", null, "
|
|
21766
|
+
}, /* @__PURE__ */ React25__default.createElement("span", null, "Create"), /* @__PURE__ */ React25__default.createElement("input", {
|
|
20633
21767
|
type: "checkbox",
|
|
20634
21768
|
checked: isColumnAllChecked("canCreate"),
|
|
20635
21769
|
onChange: /* @__PURE__ */ __name(() => toggleColumn("canCreate"), "onChange")
|
|
@@ -20637,7 +21771,7 @@ function PlatformRolesPage() {
|
|
|
20637
21771
|
className: "p-2"
|
|
20638
21772
|
}, /* @__PURE__ */ React25__default.createElement("div", {
|
|
20639
21773
|
className: "flex items-center justify-center gap-1"
|
|
20640
|
-
}, /* @__PURE__ */ React25__default.createElement("span", null, "
|
|
21774
|
+
}, /* @__PURE__ */ React25__default.createElement("span", null, "Read"), /* @__PURE__ */ React25__default.createElement("input", {
|
|
20641
21775
|
type: "checkbox",
|
|
20642
21776
|
checked: isColumnAllChecked("canRead"),
|
|
20643
21777
|
onChange: /* @__PURE__ */ __name(() => toggleColumn("canRead"), "onChange")
|
|
@@ -20645,7 +21779,7 @@ function PlatformRolesPage() {
|
|
|
20645
21779
|
className: "p-2"
|
|
20646
21780
|
}, /* @__PURE__ */ React25__default.createElement("div", {
|
|
20647
21781
|
className: "flex items-center justify-center gap-1"
|
|
20648
|
-
}, /* @__PURE__ */ React25__default.createElement("span", null, "
|
|
21782
|
+
}, /* @__PURE__ */ React25__default.createElement("span", null, "Update"), /* @__PURE__ */ React25__default.createElement("input", {
|
|
20649
21783
|
type: "checkbox",
|
|
20650
21784
|
checked: isColumnAllChecked("canUpdate"),
|
|
20651
21785
|
onChange: /* @__PURE__ */ __name(() => toggleColumn("canUpdate"), "onChange")
|
|
@@ -20653,7 +21787,7 @@ function PlatformRolesPage() {
|
|
|
20653
21787
|
className: "p-2"
|
|
20654
21788
|
}, /* @__PURE__ */ React25__default.createElement("div", {
|
|
20655
21789
|
className: "flex items-center justify-center gap-1"
|
|
20656
|
-
}, /* @__PURE__ */ React25__default.createElement("span", null, "
|
|
21790
|
+
}, /* @__PURE__ */ React25__default.createElement("span", null, "Delete"), /* @__PURE__ */ React25__default.createElement("input", {
|
|
20657
21791
|
type: "checkbox",
|
|
20658
21792
|
checked: isColumnAllChecked("canDelete"),
|
|
20659
21793
|
onChange: /* @__PURE__ */ __name(() => toggleColumn("canDelete"), "onChange")
|
|
@@ -34165,7 +35299,7 @@ function VendorEditPage({ vendorId }) {
|
|
|
34165
35299
|
}), /* @__PURE__ */ React25__default.createElement(Label3, {
|
|
34166
35300
|
htmlFor: "termsAccepted",
|
|
34167
35301
|
className: "font-normal cursor-pointer text-sm leading-snug"
|
|
34168
|
-
}, "I confirm
|
|
35302
|
+
}, "I confirm I have read and accepted the terms and conditions for selling on this platform."))))),
|
|
34169
35303
|
sidebar: /* @__PURE__ */ React25__default.createElement(React25__default.Fragment, null, !create && /* @__PURE__ */ React25__default.createElement("section", null, /* @__PURE__ */ React25__default.createElement("h2", {
|
|
34170
35304
|
className: "text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2"
|
|
34171
35305
|
}, "Status"), /* @__PURE__ */ React25__default.createElement("div", {
|