@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.cjs
CHANGED
|
@@ -489,7 +489,7 @@ var init_admin_config_context = __esm({
|
|
|
489
489
|
var CMS_VERSION;
|
|
490
490
|
var init_cms_version = __esm({
|
|
491
491
|
"src/lib/cms-version.ts"() {
|
|
492
|
-
CMS_VERSION = "1.0.
|
|
492
|
+
CMS_VERSION = "1.0.50" ;
|
|
493
493
|
}
|
|
494
494
|
});
|
|
495
495
|
function useCatalogCategories(enabled = true) {
|
|
@@ -1180,6 +1180,15 @@ var init_builtin_plugin_descriptors = __esm({
|
|
|
1180
1180
|
enabled: true,
|
|
1181
1181
|
icon: "event_notifications",
|
|
1182
1182
|
settingsGroup: "event_notifications"
|
|
1183
|
+
},
|
|
1184
|
+
{
|
|
1185
|
+
name: "auth_providers",
|
|
1186
|
+
label: "Authentication Provider",
|
|
1187
|
+
version: "1.0.0",
|
|
1188
|
+
description: "Enable Google sign-in for admin and vendor users (existing accounts only).",
|
|
1189
|
+
enabled: true,
|
|
1190
|
+
icon: "auth_providers",
|
|
1191
|
+
settingsGroup: "auth_providers"
|
|
1183
1192
|
}
|
|
1184
1193
|
];
|
|
1185
1194
|
}
|
|
@@ -9174,28 +9183,75 @@ var init_AuthPageLayout = __esm({
|
|
|
9174
9183
|
}
|
|
9175
9184
|
});
|
|
9176
9185
|
|
|
9186
|
+
// src/auth/auth-providers-settings.ts
|
|
9187
|
+
function parseEnabled(raw) {
|
|
9188
|
+
if (typeof raw === "boolean") return raw;
|
|
9189
|
+
if (typeof raw === "number") return raw !== 0;
|
|
9190
|
+
if (typeof raw === "string") {
|
|
9191
|
+
const n = raw.trim().toLowerCase();
|
|
9192
|
+
return n === "true" || n === "1" || n === "yes" || n === "on";
|
|
9193
|
+
}
|
|
9194
|
+
return false;
|
|
9195
|
+
}
|
|
9196
|
+
function isGoogleAuthPubliclyEnabled(settings) {
|
|
9197
|
+
if (!settings) return false;
|
|
9198
|
+
if (settings.googleEnabled !== void 0 && settings.googleEnabled !== "") {
|
|
9199
|
+
return parseEnabled(settings.googleEnabled);
|
|
9200
|
+
}
|
|
9201
|
+
return parseEnabled(settings.enabled);
|
|
9202
|
+
}
|
|
9203
|
+
var init_auth_providers_settings = __esm({
|
|
9204
|
+
"src/auth/auth-providers-settings.ts"() {
|
|
9205
|
+
init_auth_debug();
|
|
9206
|
+
__name(parseEnabled, "parseEnabled");
|
|
9207
|
+
__name(isGoogleAuthPubliclyEnabled, "isGoogleAuthPubliclyEnabled");
|
|
9208
|
+
}
|
|
9209
|
+
});
|
|
9210
|
+
|
|
9177
9211
|
// src/admin/pages/SignInPage.tsx
|
|
9178
9212
|
var SignInPage_exports = {};
|
|
9179
9213
|
__export(SignInPage_exports, {
|
|
9180
9214
|
default: () => exports.AdminSignInPage
|
|
9181
9215
|
});
|
|
9216
|
+
function oauthErrorMessage(code) {
|
|
9217
|
+
if (!code) return "";
|
|
9218
|
+
const c = code.toLowerCase();
|
|
9219
|
+
if (c === "accessdenied" || c === "access_denied") {
|
|
9220
|
+
return "No account for this Google email. Ask an admin to invite you first.";
|
|
9221
|
+
}
|
|
9222
|
+
if (c === "oauthaccountnotlinked") {
|
|
9223
|
+
return "This Google account is not linked to an existing user. Sign in with email/password or ask an admin to invite you.";
|
|
9224
|
+
}
|
|
9225
|
+
if (c === "oauthcallback" || c === "oauthsignin" || c === "oauthcreateaccount") {
|
|
9226
|
+
return "Google sign-in failed. Check Authentication Provider settings and the redirect URI in Google Cloud Console.";
|
|
9227
|
+
}
|
|
9228
|
+
if (c === "configuration") {
|
|
9229
|
+
return "Google sign-in is not configured correctly.";
|
|
9230
|
+
}
|
|
9231
|
+
return "Invalid email or password";
|
|
9232
|
+
}
|
|
9182
9233
|
var SigninPage; exports.AdminSignInPage = void 0;
|
|
9183
9234
|
var init_SignInPage = __esm({
|
|
9184
9235
|
"src/admin/pages/SignInPage.tsx"() {
|
|
9185
9236
|
"use client";
|
|
9186
9237
|
init_AuthPageLayout();
|
|
9187
9238
|
init_auth_debug();
|
|
9239
|
+
init_auth_providers_settings();
|
|
9240
|
+
__name(oauthErrorMessage, "oauthErrorMessage");
|
|
9188
9241
|
SigninPage = /* @__PURE__ */ __name(() => {
|
|
9189
9242
|
const [email, setEmail] = React25.useState("");
|
|
9190
9243
|
const [password, setPassword] = React25.useState("");
|
|
9191
9244
|
const [error, setError] = React25.useState("");
|
|
9192
9245
|
const [success, setSuccess] = React25.useState("");
|
|
9193
9246
|
const [loading, setLoading] = React25.useState(false);
|
|
9247
|
+
const [googleLoading, setGoogleLoading] = React25.useState(false);
|
|
9248
|
+
const [googleEnabled, setGoogleEnabled] = React25.useState(false);
|
|
9194
9249
|
const { status } = react.useSession();
|
|
9195
9250
|
const searchParams = navigation.useSearchParams();
|
|
9196
9251
|
React25.useEffect(() => {
|
|
9197
|
-
|
|
9198
|
-
|
|
9252
|
+
const err = searchParams.get("error");
|
|
9253
|
+
if (err) {
|
|
9254
|
+
setError(oauthErrorMessage(err));
|
|
9199
9255
|
}
|
|
9200
9256
|
if (searchParams.get("activated") === "1") {
|
|
9201
9257
|
setSuccess("Account activated. Sign in with your new password.");
|
|
@@ -9206,6 +9262,23 @@ var init_SignInPage = __esm({
|
|
|
9206
9262
|
}, [
|
|
9207
9263
|
searchParams
|
|
9208
9264
|
]);
|
|
9265
|
+
React25.useEffect(() => {
|
|
9266
|
+
let cancelled = false;
|
|
9267
|
+
(async () => {
|
|
9268
|
+
try {
|
|
9269
|
+
const res = await fetch("/api/settings/auth_providers", {
|
|
9270
|
+
cache: "no-store"
|
|
9271
|
+
});
|
|
9272
|
+
if (!res.ok) return;
|
|
9273
|
+
const data = await res.json();
|
|
9274
|
+
if (!cancelled) setGoogleEnabled(isGoogleAuthPubliclyEnabled(data));
|
|
9275
|
+
} catch {
|
|
9276
|
+
}
|
|
9277
|
+
})();
|
|
9278
|
+
return () => {
|
|
9279
|
+
cancelled = true;
|
|
9280
|
+
};
|
|
9281
|
+
}, []);
|
|
9209
9282
|
React25.useEffect(() => {
|
|
9210
9283
|
logAuthClient("SignInPage session status", {
|
|
9211
9284
|
status
|
|
@@ -9263,6 +9336,19 @@ var init_SignInPage = __esm({
|
|
|
9263
9336
|
setLoading(false);
|
|
9264
9337
|
}
|
|
9265
9338
|
}, "handleSubmit");
|
|
9339
|
+
const handleGoogle = /* @__PURE__ */ __name(async () => {
|
|
9340
|
+
setGoogleLoading(true);
|
|
9341
|
+
setError("");
|
|
9342
|
+
try {
|
|
9343
|
+
logAuthClient("SignInPage Google signIn start");
|
|
9344
|
+
await react.signIn("google", {
|
|
9345
|
+
callbackUrl: "/admin/dashboard"
|
|
9346
|
+
});
|
|
9347
|
+
} catch {
|
|
9348
|
+
setError("Google sign-in failed. Please try again.");
|
|
9349
|
+
setGoogleLoading(false);
|
|
9350
|
+
}
|
|
9351
|
+
}, "handleGoogle");
|
|
9266
9352
|
return /* @__PURE__ */ React.createElement(AuthPageLayout, null, /* @__PURE__ */ React.createElement("div", {
|
|
9267
9353
|
className: "w-full shadow-md rounded-lg bg-white px-4 py-6 sm:px-6 sm:py-8"
|
|
9268
9354
|
}, /* @__PURE__ */ React.createElement("h3", {
|
|
@@ -9315,9 +9401,42 @@ var init_SignInPage = __esm({
|
|
|
9315
9401
|
className: "text-xs font-medium text-gray-600 hover:underline"
|
|
9316
9402
|
}, "Forgot password?")), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("button", {
|
|
9317
9403
|
type: "submit",
|
|
9318
|
-
disabled: loading,
|
|
9404
|
+
disabled: loading || googleLoading,
|
|
9319
9405
|
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"
|
|
9320
|
-
}, loading ? "Signing in..." : "Sign in")))
|
|
9406
|
+
}, loading ? "Signing in..." : "Sign in"))), googleEnabled && /* @__PURE__ */ React.createElement("div", {
|
|
9407
|
+
className: "mt-6"
|
|
9408
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
9409
|
+
className: "relative mb-4"
|
|
9410
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
9411
|
+
className: "absolute inset-0 flex items-center"
|
|
9412
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
9413
|
+
className: "w-full border-t border-gray-200"
|
|
9414
|
+
})), /* @__PURE__ */ React.createElement("div", {
|
|
9415
|
+
className: "relative flex justify-center text-xs"
|
|
9416
|
+
}, /* @__PURE__ */ React.createElement("span", {
|
|
9417
|
+
className: "bg-white px-2 text-gray-500"
|
|
9418
|
+
}, "or"))), /* @__PURE__ */ React.createElement("button", {
|
|
9419
|
+
type: "button",
|
|
9420
|
+
onClick: handleGoogle,
|
|
9421
|
+
disabled: loading || googleLoading,
|
|
9422
|
+
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"
|
|
9423
|
+
}, /* @__PURE__ */ React.createElement("svg", {
|
|
9424
|
+
className: "h-4 w-4",
|
|
9425
|
+
viewBox: "0 0 24 24",
|
|
9426
|
+
"aria-hidden": "true"
|
|
9427
|
+
}, /* @__PURE__ */ React.createElement("path", {
|
|
9428
|
+
fill: "#4285F4",
|
|
9429
|
+
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"
|
|
9430
|
+
}), /* @__PURE__ */ React.createElement("path", {
|
|
9431
|
+
fill: "#34A853",
|
|
9432
|
+
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"
|
|
9433
|
+
}), /* @__PURE__ */ React.createElement("path", {
|
|
9434
|
+
fill: "#FBBC05",
|
|
9435
|
+
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"
|
|
9436
|
+
}), /* @__PURE__ */ React.createElement("path", {
|
|
9437
|
+
fill: "#EA4335",
|
|
9438
|
+
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"
|
|
9439
|
+
})), googleLoading ? "Redirecting\u2026" : "Continue with Google"))));
|
|
9321
9440
|
}, "SigninPage");
|
|
9322
9441
|
exports.AdminSignInPage = SigninPage;
|
|
9323
9442
|
}
|
|
@@ -15441,6 +15560,30 @@ function getEmailTriggerDefaults(triggerKey, audience = "customer") {
|
|
|
15441
15560
|
bodyPlaceholder: "Hi {{customerName}},\n\nYour order {{orderNumber}} has been updated."
|
|
15442
15561
|
};
|
|
15443
15562
|
}
|
|
15563
|
+
function getPushTriggerDefaults(triggerKey, audience = "customer") {
|
|
15564
|
+
if (audience === "vendor") {
|
|
15565
|
+
return VENDOR_PUSH_TRIGGER_DEFAULTS[triggerKey] ?? {
|
|
15566
|
+
subject: "Vendor Push Update",
|
|
15567
|
+
body: "Hi {{vendorName}}, order {{orderNumber}} update.",
|
|
15568
|
+
subjectPlaceholder: "e.g. Vendor Push Update",
|
|
15569
|
+
bodyPlaceholder: "Hi {{vendorName}}, order {{orderNumber}} update."
|
|
15570
|
+
};
|
|
15571
|
+
}
|
|
15572
|
+
if (audience === "admin") {
|
|
15573
|
+
return ADMIN_PUSH_TRIGGER_DEFAULTS[triggerKey] ?? {
|
|
15574
|
+
subject: "Admin Push Alert",
|
|
15575
|
+
body: "Admin Alert: Order {{orderNumber}} update.",
|
|
15576
|
+
subjectPlaceholder: "e.g. Admin Push Alert",
|
|
15577
|
+
bodyPlaceholder: "Admin Alert: Order {{orderNumber}} update."
|
|
15578
|
+
};
|
|
15579
|
+
}
|
|
15580
|
+
return PUSH_TRIGGER_DEFAULTS[triggerKey] ?? {
|
|
15581
|
+
subject: "Order Update",
|
|
15582
|
+
body: "Hi {{customerName}}, order {{orderNumber}} update.",
|
|
15583
|
+
subjectPlaceholder: "e.g. Order Update",
|
|
15584
|
+
bodyPlaceholder: "Hi {{customerName}}, order {{orderNumber}} update."
|
|
15585
|
+
};
|
|
15586
|
+
}
|
|
15444
15587
|
async function jsonFetch(url, init) {
|
|
15445
15588
|
const res = await fetch(url, {
|
|
15446
15589
|
credentials: "include",
|
|
@@ -15532,7 +15675,7 @@ function useOrderNotificationTriggerBindings(channel, audienceType = "customers"
|
|
|
15532
15675
|
rebind
|
|
15533
15676
|
};
|
|
15534
15677
|
}
|
|
15535
|
-
var KNOWN_VARS, EMAIL_TRIGGER_DEFAULTS, VENDOR_EMAIL_TRIGGER_DEFAULTS, ADMIN_EMAIL_TRIGGER_DEFAULTS;
|
|
15678
|
+
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;
|
|
15536
15679
|
var init_order_notification_bindings_shared = __esm({
|
|
15537
15680
|
"src/admin/components/order-notification-bindings-shared.ts"() {
|
|
15538
15681
|
"use client";
|
|
@@ -15548,9 +15691,7 @@ var init_order_notification_bindings_shared = __esm({
|
|
|
15548
15691
|
"vendorId",
|
|
15549
15692
|
"refundAmount",
|
|
15550
15693
|
"invoiceNumber",
|
|
15551
|
-
"invoiceUrl"
|
|
15552
|
-
"ticketQr",
|
|
15553
|
-
"qrImageUrl"
|
|
15694
|
+
"invoiceUrl"
|
|
15554
15695
|
];
|
|
15555
15696
|
EMAIL_TRIGGER_DEFAULTS = {
|
|
15556
15697
|
order_placed: {
|
|
@@ -15629,7 +15770,7 @@ Order Summary:
|
|
|
15629
15770
|
Customer Name: {{customerName}}
|
|
15630
15771
|
Customer Email: {{customerEmail}}
|
|
15631
15772
|
Customer Phone: {{customerPhone}}`,
|
|
15632
|
-
bodyPlaceholder: "
|
|
15773
|
+
bodyPlaceholder: "New order {{orderNumber}} placed by {{customerName}}."
|
|
15633
15774
|
},
|
|
15634
15775
|
order_cancelled: {
|
|
15635
15776
|
subject: "Order {{orderNumber}} cancelled",
|
|
@@ -15645,6 +15786,66 @@ Refund Due: {{refundAmount}} {{currency}}`,
|
|
|
15645
15786
|
}
|
|
15646
15787
|
};
|
|
15647
15788
|
__name(getEmailTriggerDefaults, "getEmailTriggerDefaults");
|
|
15789
|
+
PUSH_TRIGGER_DEFAULTS = {
|
|
15790
|
+
order_placed: {
|
|
15791
|
+
subject: "Order {{orderNumber}} Confirmed!",
|
|
15792
|
+
subjectPlaceholder: "e.g. Order {{orderNumber}} Confirmed!",
|
|
15793
|
+
body: `Hi {{customerName}}, your order {{orderNumber}} for {{total}} {{currency}} is confirmed.`,
|
|
15794
|
+
bodyPlaceholder: "Hi {{customerName}}, your order {{orderNumber}} is confirmed."
|
|
15795
|
+
},
|
|
15796
|
+
order_cancelled: {
|
|
15797
|
+
subject: "Order {{orderNumber}} Cancelled",
|
|
15798
|
+
subjectPlaceholder: "e.g. Order {{orderNumber}} Cancelled",
|
|
15799
|
+
body: `Hi {{customerName}}, your order {{orderNumber}} for {{total}} {{currency}} has been cancelled.`,
|
|
15800
|
+
bodyPlaceholder: "Hi {{customerName}}, your order {{orderNumber}} has been cancelled."
|
|
15801
|
+
}
|
|
15802
|
+
};
|
|
15803
|
+
VENDOR_PUSH_TRIGGER_DEFAULTS = {
|
|
15804
|
+
order_placed: {
|
|
15805
|
+
subject: "New Order Received: {{orderNumber}}",
|
|
15806
|
+
subjectPlaceholder: "e.g. New Order Received: {{orderNumber}}",
|
|
15807
|
+
body: `Hi {{vendorName}}, you received a new order {{orderNumber}} for {{total}} {{currency}} from {{customerName}}.`,
|
|
15808
|
+
bodyPlaceholder: "Hi {{vendorName}}, you received a new order {{orderNumber}}."
|
|
15809
|
+
},
|
|
15810
|
+
order_cancelled: {
|
|
15811
|
+
subject: "Order {{orderNumber}} Cancelled",
|
|
15812
|
+
subjectPlaceholder: "e.g. Order {{orderNumber}} Cancelled",
|
|
15813
|
+
body: `Hi {{vendorName}}, order {{orderNumber}} from {{customerName}} has been cancelled.`,
|
|
15814
|
+
bodyPlaceholder: "Hi {{vendorName}}, order {{orderNumber}} was cancelled."
|
|
15815
|
+
}
|
|
15816
|
+
};
|
|
15817
|
+
ADMIN_PUSH_TRIGGER_DEFAULTS = {
|
|
15818
|
+
order_placed: {
|
|
15819
|
+
subject: "New Order {{orderNumber}} ({{total}} {{currency}})",
|
|
15820
|
+
subjectPlaceholder: "e.g. New Order {{orderNumber}} placed",
|
|
15821
|
+
body: `Hi Admin,
|
|
15822
|
+
|
|
15823
|
+
A new order {{orderNumber}} of {{total}} {{currency}} was placed.
|
|
15824
|
+
|
|
15825
|
+
Vendor: {{vendorName}}
|
|
15826
|
+
|
|
15827
|
+
Order Summary:
|
|
15828
|
+
{{orderDetails}}
|
|
15829
|
+
|
|
15830
|
+
Customer Name: {{customerName}}
|
|
15831
|
+
Customer Email: {{customerEmail}}
|
|
15832
|
+
Customer Phone: {{customerPhone}}`,
|
|
15833
|
+
bodyPlaceholder: "New order {{orderNumber}} placed by {{customerName}}."
|
|
15834
|
+
},
|
|
15835
|
+
order_cancelled: {
|
|
15836
|
+
subject: "Order {{orderNumber}} Cancelled",
|
|
15837
|
+
subjectPlaceholder: "e.g. Order {{orderNumber}} cancelled",
|
|
15838
|
+
body: `Hi Admin,
|
|
15839
|
+
|
|
15840
|
+
Order {{orderNumber}} has been cancelled.
|
|
15841
|
+
|
|
15842
|
+
Customer: {{customerName}}
|
|
15843
|
+
Vendor: {{vendorName}}
|
|
15844
|
+
Refund Due: {{refundAmount}} {{currency}}`,
|
|
15845
|
+
bodyPlaceholder: "Hi Admin,\n\nOrder {{orderNumber}} cancelled."
|
|
15846
|
+
}
|
|
15847
|
+
};
|
|
15848
|
+
__name(getPushTriggerDefaults, "getPushTriggerDefaults");
|
|
15648
15849
|
__name(jsonFetch, "jsonFetch");
|
|
15649
15850
|
__name(useOrderNotificationTriggerBindings, "useOrderNotificationTriggerBindings");
|
|
15650
15851
|
}
|
|
@@ -16295,14 +16496,582 @@ var init_emailTriggersBindingsPage = __esm({
|
|
|
16295
16496
|
vendorId: "Vendor / store ID",
|
|
16296
16497
|
refundAmount: "Refund amount (refund triggers)",
|
|
16297
16498
|
invoiceNumber: "Generated invoice number",
|
|
16298
|
-
invoiceUrl: "Link to download invoice PDF"
|
|
16299
|
-
ticketQr: "Embedded ticket QR code image",
|
|
16300
|
-
qrImageUrl: "Direct QR code image URL"
|
|
16499
|
+
invoiceUrl: "Link to download invoice PDF"
|
|
16301
16500
|
};
|
|
16302
16501
|
__name(EmailTriggerBindings, "EmailTriggerBindings");
|
|
16303
16502
|
__name(TriggerEmailEditor, "TriggerEmailEditor");
|
|
16304
16503
|
}
|
|
16305
16504
|
});
|
|
16505
|
+
function PushTriggerBindings({ audience = "customer" }) {
|
|
16506
|
+
const audienceType = audience === "vendor" ? "vendors" : audience === "admin" ? "admin" : "customers";
|
|
16507
|
+
const { triggers, bindings, loading, reload, rebind } = useOrderNotificationTriggerBindings("mobile", audienceType);
|
|
16508
|
+
const [selectedKey, setSelectedKey] = React25.useState("");
|
|
16509
|
+
const [templates, setTemplates] = React25.useState([]);
|
|
16510
|
+
const [loadingTpl, setLoadingTpl] = React25.useState(true);
|
|
16511
|
+
const [title, setTitle] = React25.useState("");
|
|
16512
|
+
const [body, setBody] = React25.useState("");
|
|
16513
|
+
const [saving, setSaving] = React25.useState(false);
|
|
16514
|
+
const bodyRef = React25.useRef(null);
|
|
16515
|
+
const subjectRef = React25.useRef(null);
|
|
16516
|
+
const lastFocused = React25.useRef("body");
|
|
16517
|
+
React25.useEffect(() => {
|
|
16518
|
+
let cancelled = false;
|
|
16519
|
+
(async () => {
|
|
16520
|
+
try {
|
|
16521
|
+
setLoadingTpl(true);
|
|
16522
|
+
const res = await fetch("/api/message-templates/email", {
|
|
16523
|
+
cache: "no-store"
|
|
16524
|
+
});
|
|
16525
|
+
if (!res.ok) throw new Error("Failed to load message templates");
|
|
16526
|
+
const data = await res.json();
|
|
16527
|
+
if (!cancelled) setTemplates(Array.isArray(data.items) ? data.items : []);
|
|
16528
|
+
} catch {
|
|
16529
|
+
if (!cancelled) sonner.toast.error("Could not load message templates");
|
|
16530
|
+
} finally {
|
|
16531
|
+
if (!cancelled) setLoadingTpl(false);
|
|
16532
|
+
}
|
|
16533
|
+
})();
|
|
16534
|
+
return () => {
|
|
16535
|
+
cancelled = true;
|
|
16536
|
+
};
|
|
16537
|
+
}, []);
|
|
16538
|
+
React25.useEffect(() => {
|
|
16539
|
+
if (triggers.length > 0 && !selectedKey) {
|
|
16540
|
+
setSelectedKey(triggers[0].triggerKey);
|
|
16541
|
+
}
|
|
16542
|
+
}, [
|
|
16543
|
+
triggers,
|
|
16544
|
+
selectedKey
|
|
16545
|
+
]);
|
|
16546
|
+
const activeTrigger = React25.useMemo(() => triggers.find((t) => t.triggerKey === selectedKey), [
|
|
16547
|
+
triggers,
|
|
16548
|
+
selectedKey
|
|
16549
|
+
]);
|
|
16550
|
+
const bindingMap = React25.useMemo(() => {
|
|
16551
|
+
const m = /* @__PURE__ */ new Map();
|
|
16552
|
+
for (const b of bindings) {
|
|
16553
|
+
if (b.messageTemplateId != null) m.set(b.triggerKey, b.messageTemplateId);
|
|
16554
|
+
}
|
|
16555
|
+
return m;
|
|
16556
|
+
}, [
|
|
16557
|
+
bindings
|
|
16558
|
+
]);
|
|
16559
|
+
const activeBindingTplId = selectedKey ? bindingMap.get(selectedKey) ?? null : null;
|
|
16560
|
+
const activeTemplate = React25.useMemo(() => {
|
|
16561
|
+
if (!activeBindingTplId) return null;
|
|
16562
|
+
return templates.find((t) => t.id === activeBindingTplId) ?? null;
|
|
16563
|
+
}, [
|
|
16564
|
+
activeBindingTplId,
|
|
16565
|
+
templates
|
|
16566
|
+
]);
|
|
16567
|
+
const defaults = React25.useMemo(() => {
|
|
16568
|
+
if (!selectedKey) return {
|
|
16569
|
+
subject: "",
|
|
16570
|
+
body: "",
|
|
16571
|
+
subjectPlaceholder: "",
|
|
16572
|
+
bodyPlaceholder: ""
|
|
16573
|
+
};
|
|
16574
|
+
return getPushTriggerDefaults(selectedKey, audience);
|
|
16575
|
+
}, [
|
|
16576
|
+
selectedKey,
|
|
16577
|
+
audience
|
|
16578
|
+
]);
|
|
16579
|
+
React25.useEffect(() => {
|
|
16580
|
+
if (activeTemplate) {
|
|
16581
|
+
setTitle(activeTemplate.subject ?? "");
|
|
16582
|
+
setBody(activeTemplate.body ?? "");
|
|
16583
|
+
} else {
|
|
16584
|
+
setTitle(defaults.subject);
|
|
16585
|
+
setBody(defaults.body);
|
|
16586
|
+
}
|
|
16587
|
+
}, [
|
|
16588
|
+
activeTemplate,
|
|
16589
|
+
defaults,
|
|
16590
|
+
selectedKey
|
|
16591
|
+
]);
|
|
16592
|
+
const insertVariable = /* @__PURE__ */ __name((varName) => {
|
|
16593
|
+
const token = `{{${varName}}}`;
|
|
16594
|
+
if (lastFocused.current === "subject" && subjectRef.current) {
|
|
16595
|
+
const el = subjectRef.current;
|
|
16596
|
+
const start = el.selectionStart ?? title.length;
|
|
16597
|
+
const end = el.selectionEnd ?? title.length;
|
|
16598
|
+
const next = title.slice(0, start) + token + title.slice(end);
|
|
16599
|
+
setTitle(next);
|
|
16600
|
+
setTimeout(() => {
|
|
16601
|
+
el.focus();
|
|
16602
|
+
el.setSelectionRange(start + token.length, start + token.length);
|
|
16603
|
+
}, 0);
|
|
16604
|
+
return;
|
|
16605
|
+
}
|
|
16606
|
+
if (bodyRef.current) {
|
|
16607
|
+
const el = bodyRef.current;
|
|
16608
|
+
const start = el.selectionStart ?? body.length;
|
|
16609
|
+
const end = el.selectionEnd ?? body.length;
|
|
16610
|
+
const next = body.slice(0, start) + token + body.slice(end);
|
|
16611
|
+
setBody(next);
|
|
16612
|
+
setTimeout(() => {
|
|
16613
|
+
el.focus();
|
|
16614
|
+
el.setSelectionRange(start + token.length, start + token.length);
|
|
16615
|
+
}, 0);
|
|
16616
|
+
} else {
|
|
16617
|
+
setBody((prev) => prev + token);
|
|
16618
|
+
}
|
|
16619
|
+
}, "insertVariable");
|
|
16620
|
+
const handleSave = /* @__PURE__ */ __name(async () => {
|
|
16621
|
+
if (!selectedKey) return;
|
|
16622
|
+
setSaving(true);
|
|
16623
|
+
try {
|
|
16624
|
+
let tplId = activeBindingTplId;
|
|
16625
|
+
if (tplId) {
|
|
16626
|
+
const res = await jsonFetch(`/api/message-templates/email/${tplId}`, {
|
|
16627
|
+
method: "PATCH",
|
|
16628
|
+
headers: {
|
|
16629
|
+
"Content-Type": "application/json"
|
|
16630
|
+
},
|
|
16631
|
+
body: JSON.stringify({
|
|
16632
|
+
name: `${audienceType}_push_${selectedKey}`,
|
|
16633
|
+
subject: title,
|
|
16634
|
+
body
|
|
16635
|
+
})
|
|
16636
|
+
});
|
|
16637
|
+
if (res.item) {
|
|
16638
|
+
setTemplates((prev) => prev.map((t) => t.id === res.item.id ? res.item : t));
|
|
16639
|
+
}
|
|
16640
|
+
} else {
|
|
16641
|
+
const res = await jsonFetch("/api/message-templates/email", {
|
|
16642
|
+
method: "POST",
|
|
16643
|
+
headers: {
|
|
16644
|
+
"Content-Type": "application/json"
|
|
16645
|
+
},
|
|
16646
|
+
body: JSON.stringify({
|
|
16647
|
+
name: `${audienceType}_push_${selectedKey}`,
|
|
16648
|
+
subject: title,
|
|
16649
|
+
body
|
|
16650
|
+
})
|
|
16651
|
+
});
|
|
16652
|
+
const createdItem = res.item || res;
|
|
16653
|
+
tplId = createdItem.id;
|
|
16654
|
+
if (createdItem) {
|
|
16655
|
+
setTemplates((prev) => [
|
|
16656
|
+
createdItem,
|
|
16657
|
+
...prev
|
|
16658
|
+
]);
|
|
16659
|
+
}
|
|
16660
|
+
}
|
|
16661
|
+
await rebind(selectedKey, tplId, `${audienceType}_push_${selectedKey}`);
|
|
16662
|
+
sonner.toast.success("Push notification template saved");
|
|
16663
|
+
await reload();
|
|
16664
|
+
} catch (e) {
|
|
16665
|
+
const msg = e instanceof Error ? e.message : "Save failed";
|
|
16666
|
+
sonner.toast.error(msg);
|
|
16667
|
+
} finally {
|
|
16668
|
+
setSaving(false);
|
|
16669
|
+
}
|
|
16670
|
+
}, "handleSave");
|
|
16671
|
+
if (loading || loadingTpl) {
|
|
16672
|
+
return /* @__PURE__ */ React.createElement("div", {
|
|
16673
|
+
className: "flex items-center gap-2 p-6 text-sm text-gray-500"
|
|
16674
|
+
}, /* @__PURE__ */ React.createElement(LucideIcons.Loader2, {
|
|
16675
|
+
className: "h-4 w-4 animate-spin"
|
|
16676
|
+
}), " Loading push notification triggers\u2026");
|
|
16677
|
+
}
|
|
16678
|
+
return /* @__PURE__ */ React.createElement("div", {
|
|
16679
|
+
className: "space-y-6"
|
|
16680
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
16681
|
+
className: "flex flex-col sm:flex-row sm:items-center justify-between gap-4"
|
|
16682
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
16683
|
+
className: "space-y-1"
|
|
16684
|
+
}, /* @__PURE__ */ React.createElement("h3", {
|
|
16685
|
+
className: "text-base font-semibold text-gray-900 dark:text-gray-100 flex items-center gap-2"
|
|
16686
|
+
}, /* @__PURE__ */ React.createElement(LucideIcons.Smartphone, {
|
|
16687
|
+
className: "h-5 w-5 text-gray-700 dark:text-gray-300"
|
|
16688
|
+
}), "Mobile Push Notification Templates"), /* @__PURE__ */ React.createElement("p", {
|
|
16689
|
+
className: "text-xs text-gray-500"
|
|
16690
|
+
}, "Configure push notification title and message body per trigger for", " ", /* @__PURE__ */ React.createElement("span", {
|
|
16691
|
+
className: "font-semibold capitalize text-gray-700 dark:text-gray-300"
|
|
16692
|
+
}, audience, "s"), ".")), /* @__PURE__ */ React.createElement(Button, {
|
|
16693
|
+
type: "button",
|
|
16694
|
+
onClick: handleSave,
|
|
16695
|
+
disabled: saving || !selectedKey,
|
|
16696
|
+
className: "gap-2 shrink-0"
|
|
16697
|
+
}, saving ? /* @__PURE__ */ React.createElement(LucideIcons.Loader2, {
|
|
16698
|
+
className: "h-4 w-4 animate-spin"
|
|
16699
|
+
}) : /* @__PURE__ */ React.createElement(LucideIcons.Save, {
|
|
16700
|
+
className: "h-4 w-4"
|
|
16701
|
+
}), "Save Template")), /* @__PURE__ */ React.createElement("div", {
|
|
16702
|
+
className: "grid grid-cols-1 md:grid-cols-4 gap-6"
|
|
16703
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
16704
|
+
className: "md:col-span-1 space-y-2"
|
|
16705
|
+
}, /* @__PURE__ */ React.createElement(Label3, {
|
|
16706
|
+
className: "text-xs font-semibold text-gray-500 uppercase tracking-wider"
|
|
16707
|
+
}, "Triggers"), /* @__PURE__ */ React.createElement("div", {
|
|
16708
|
+
className: "flex flex-col gap-1"
|
|
16709
|
+
}, triggers.map((t) => {
|
|
16710
|
+
const isBound = bindingMap.has(t.triggerKey);
|
|
16711
|
+
const isSelected = t.triggerKey === selectedKey;
|
|
16712
|
+
return /* @__PURE__ */ React.createElement("button", {
|
|
16713
|
+
key: t.triggerKey,
|
|
16714
|
+
type: "button",
|
|
16715
|
+
onClick: /* @__PURE__ */ __name(() => setSelectedKey(t.triggerKey), "onClick"),
|
|
16716
|
+
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"}`
|
|
16717
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
16718
|
+
className: "flex items-center justify-between w-full"
|
|
16719
|
+
}, /* @__PURE__ */ React.createElement("span", {
|
|
16720
|
+
className: "font-medium text-sm"
|
|
16721
|
+
}, t.label), isBound && /* @__PURE__ */ React.createElement("span", {
|
|
16722
|
+
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"}`
|
|
16723
|
+
}, "Configured")), /* @__PURE__ */ React.createElement("span", {
|
|
16724
|
+
className: `text-xs mt-1 ${isSelected ? "text-gray-300 dark:text-gray-600" : "text-gray-500 dark:text-gray-400"}`
|
|
16725
|
+
}, t.triggerKey));
|
|
16726
|
+
}))), /* @__PURE__ */ React.createElement("div", {
|
|
16727
|
+
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"
|
|
16728
|
+
}, activeTrigger ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("h4", {
|
|
16729
|
+
className: "text-sm font-semibold text-gray-900 dark:text-gray-100"
|
|
16730
|
+
}, activeTrigger.label, " (", activeTrigger.triggerKey, ")"), activeTrigger.description && /* @__PURE__ */ React.createElement("p", {
|
|
16731
|
+
className: "text-xs text-gray-500 mt-0.5"
|
|
16732
|
+
}, activeTrigger.description)), /* @__PURE__ */ React.createElement("div", {
|
|
16733
|
+
className: "space-y-1.5"
|
|
16734
|
+
}, /* @__PURE__ */ React.createElement(Label3, {
|
|
16735
|
+
className: "text-xs font-medium text-gray-700 dark:text-gray-300"
|
|
16736
|
+
}, "Insert Variables"), /* @__PURE__ */ React.createElement("div", {
|
|
16737
|
+
className: "flex flex-wrap gap-1.5"
|
|
16738
|
+
}, KNOWN_VARS.map((v) => /* @__PURE__ */ React.createElement("button", {
|
|
16739
|
+
key: v,
|
|
16740
|
+
type: "button",
|
|
16741
|
+
onClick: /* @__PURE__ */ __name(() => insertVariable(v), "onClick"),
|
|
16742
|
+
title: VAR_HINTS2[v],
|
|
16743
|
+
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"
|
|
16744
|
+
}, `{{${v}}}`)))), /* @__PURE__ */ React.createElement("div", {
|
|
16745
|
+
className: "space-y-1.5"
|
|
16746
|
+
}, /* @__PURE__ */ React.createElement(Label3, {
|
|
16747
|
+
htmlFor: "push-title",
|
|
16748
|
+
className: "text-xs font-medium"
|
|
16749
|
+
}, "Notification Title"), /* @__PURE__ */ React.createElement(Input, {
|
|
16750
|
+
id: "push-title",
|
|
16751
|
+
ref: subjectRef,
|
|
16752
|
+
value: title,
|
|
16753
|
+
onFocus: /* @__PURE__ */ __name(() => {
|
|
16754
|
+
lastFocused.current = "subject";
|
|
16755
|
+
}, "onFocus"),
|
|
16756
|
+
onChange: /* @__PURE__ */ __name((e) => setTitle(e.target.value), "onChange"),
|
|
16757
|
+
placeholder: defaults.subjectPlaceholder
|
|
16758
|
+
})), /* @__PURE__ */ React.createElement("div", {
|
|
16759
|
+
className: "space-y-1.5"
|
|
16760
|
+
}, /* @__PURE__ */ React.createElement(Label3, {
|
|
16761
|
+
htmlFor: "push-body",
|
|
16762
|
+
className: "text-xs font-medium"
|
|
16763
|
+
}, "Notification Body"), /* @__PURE__ */ React.createElement(Textarea, {
|
|
16764
|
+
id: "push-body",
|
|
16765
|
+
ref: bodyRef,
|
|
16766
|
+
value: body,
|
|
16767
|
+
onFocus: /* @__PURE__ */ __name(() => {
|
|
16768
|
+
lastFocused.current = "body";
|
|
16769
|
+
}, "onFocus"),
|
|
16770
|
+
onChange: /* @__PURE__ */ __name((e) => setBody(e.target.value), "onChange"),
|
|
16771
|
+
placeholder: defaults.bodyPlaceholder,
|
|
16772
|
+
className: "h-36 font-mono text-xs"
|
|
16773
|
+
}))) : /* @__PURE__ */ React.createElement("div", {
|
|
16774
|
+
className: "p-12 text-center text-sm text-gray-500"
|
|
16775
|
+
}, "Select a trigger from the left to configure push notification template."))));
|
|
16776
|
+
}
|
|
16777
|
+
var VAR_HINTS2;
|
|
16778
|
+
var init_pushTriggersBindingsPage = __esm({
|
|
16779
|
+
"src/admin/pages/pushTriggersBindingsPage.tsx"() {
|
|
16780
|
+
"use client";
|
|
16781
|
+
init_button();
|
|
16782
|
+
init_input();
|
|
16783
|
+
init_textarea();
|
|
16784
|
+
init_label();
|
|
16785
|
+
init_order_notification_bindings_shared();
|
|
16786
|
+
VAR_HINTS2 = {
|
|
16787
|
+
orderId: "Internal order ID",
|
|
16788
|
+
orderNumber: "Display order number",
|
|
16789
|
+
customerName: "Customer full name",
|
|
16790
|
+
customerPhone: "Customer phone",
|
|
16791
|
+
eventName: "Event title / product name",
|
|
16792
|
+
vendorName: "Vendor / store name",
|
|
16793
|
+
total: "Order total amount",
|
|
16794
|
+
currency: "Currency code (e.g. INR)",
|
|
16795
|
+
vendorId: "Vendor / store ID",
|
|
16796
|
+
refundAmount: "Refund amount (refund triggers)",
|
|
16797
|
+
invoiceNumber: "Generated invoice number",
|
|
16798
|
+
invoiceUrl: "Link to download invoice PDF"
|
|
16799
|
+
};
|
|
16800
|
+
__name(PushTriggerBindings, "PushTriggerBindings");
|
|
16801
|
+
}
|
|
16802
|
+
});
|
|
16803
|
+
function PushConfigModal({ open, onOpenChange }) {
|
|
16804
|
+
const [loading, setLoading] = React25.useState(false);
|
|
16805
|
+
const [saving, setSaving] = React25.useState(false);
|
|
16806
|
+
const [testing, setTesting] = React25.useState(false);
|
|
16807
|
+
const [serviceAccountJson, setServiceAccountJson] = React25.useState("");
|
|
16808
|
+
const [projectId, setProjectId] = React25.useState("");
|
|
16809
|
+
const [clientEmail, setClientEmail] = React25.useState("");
|
|
16810
|
+
const [privateKey, setPrivateKey] = React25.useState("");
|
|
16811
|
+
const [isValidJson, setIsValidJson] = React25.useState(false);
|
|
16812
|
+
const [testToken, setTestToken] = React25.useState("");
|
|
16813
|
+
const [testTitle, setTestTitle] = React25.useState("Test Push Notification");
|
|
16814
|
+
const [testBody, setTestBody] = React25.useState("Firebase Push Notification setup is working!");
|
|
16815
|
+
React25.useEffect(() => {
|
|
16816
|
+
if (!open) return;
|
|
16817
|
+
let cancelled = false;
|
|
16818
|
+
(async () => {
|
|
16819
|
+
try {
|
|
16820
|
+
setLoading(true);
|
|
16821
|
+
const res = await fetch("/api/settings/push", {
|
|
16822
|
+
cache: "no-store"
|
|
16823
|
+
});
|
|
16824
|
+
if (res.ok) {
|
|
16825
|
+
const data = await res.json();
|
|
16826
|
+
if (!cancelled && data) {
|
|
16827
|
+
const rawJson = data.firebase_service_account_json || "";
|
|
16828
|
+
setServiceAccountJson(rawJson);
|
|
16829
|
+
if (rawJson.trim()) {
|
|
16830
|
+
parseAndExtract(rawJson, false);
|
|
16831
|
+
} else {
|
|
16832
|
+
setProjectId(data.firebase_project_id || "");
|
|
16833
|
+
setClientEmail(data.firebase_client_email || "");
|
|
16834
|
+
setPrivateKey(data.firebase_private_key || "");
|
|
16835
|
+
}
|
|
16836
|
+
}
|
|
16837
|
+
}
|
|
16838
|
+
} catch {
|
|
16839
|
+
sonner.toast.error("Failed to load push configuration");
|
|
16840
|
+
} finally {
|
|
16841
|
+
if (!cancelled) setLoading(false);
|
|
16842
|
+
}
|
|
16843
|
+
})();
|
|
16844
|
+
return () => {
|
|
16845
|
+
cancelled = true;
|
|
16846
|
+
};
|
|
16847
|
+
}, [
|
|
16848
|
+
open
|
|
16849
|
+
]);
|
|
16850
|
+
const parseAndExtract = /* @__PURE__ */ __name((input, showToast = true) => {
|
|
16851
|
+
if (!input.trim()) {
|
|
16852
|
+
setIsValidJson(false);
|
|
16853
|
+
return;
|
|
16854
|
+
}
|
|
16855
|
+
try {
|
|
16856
|
+
const parsed = JSON.parse(input);
|
|
16857
|
+
if (parsed.project_id) setProjectId(parsed.project_id);
|
|
16858
|
+
if (parsed.client_email) setClientEmail(parsed.client_email);
|
|
16859
|
+
if (parsed.private_key) setPrivateKey(parsed.private_key);
|
|
16860
|
+
setIsValidJson(true);
|
|
16861
|
+
if (showToast) {
|
|
16862
|
+
sonner.toast.success("Valid Service Account JSON loaded");
|
|
16863
|
+
}
|
|
16864
|
+
} catch {
|
|
16865
|
+
setIsValidJson(false);
|
|
16866
|
+
if (showToast) {
|
|
16867
|
+
sonner.toast.error("Invalid Service Account JSON format");
|
|
16868
|
+
}
|
|
16869
|
+
}
|
|
16870
|
+
}, "parseAndExtract");
|
|
16871
|
+
const handleJsonChange = /* @__PURE__ */ __name((val) => {
|
|
16872
|
+
setServiceAccountJson(val);
|
|
16873
|
+
if (val.trim()) {
|
|
16874
|
+
parseAndExtract(val, false);
|
|
16875
|
+
} else {
|
|
16876
|
+
setIsValidJson(false);
|
|
16877
|
+
}
|
|
16878
|
+
}, "handleJsonChange");
|
|
16879
|
+
const handleSaveConfig = /* @__PURE__ */ __name(async () => {
|
|
16880
|
+
if (serviceAccountJson.trim() && !isValidJson) {
|
|
16881
|
+
sonner.toast.error("Please enter a valid Firebase Service Account JSON file");
|
|
16882
|
+
return;
|
|
16883
|
+
}
|
|
16884
|
+
setSaving(true);
|
|
16885
|
+
try {
|
|
16886
|
+
const res = await fetch("/api/settings/push", {
|
|
16887
|
+
method: "PUT",
|
|
16888
|
+
headers: {
|
|
16889
|
+
"Content-Type": "application/json"
|
|
16890
|
+
},
|
|
16891
|
+
body: JSON.stringify({
|
|
16892
|
+
firebase_service_account_json: {
|
|
16893
|
+
value: serviceAccountJson.trim(),
|
|
16894
|
+
type: "secret"
|
|
16895
|
+
},
|
|
16896
|
+
firebase_project_id: {
|
|
16897
|
+
value: projectId.trim(),
|
|
16898
|
+
type: "secret"
|
|
16899
|
+
},
|
|
16900
|
+
firebase_client_email: {
|
|
16901
|
+
value: clientEmail.trim(),
|
|
16902
|
+
type: "secret"
|
|
16903
|
+
},
|
|
16904
|
+
firebase_private_key: {
|
|
16905
|
+
value: privateKey.trim(),
|
|
16906
|
+
type: "secret"
|
|
16907
|
+
}
|
|
16908
|
+
})
|
|
16909
|
+
});
|
|
16910
|
+
if (!res.ok) {
|
|
16911
|
+
sonner.toast.error("Failed to save push configuration");
|
|
16912
|
+
return;
|
|
16913
|
+
}
|
|
16914
|
+
sonner.toast.success("Firebase Service Account JSON saved successfully");
|
|
16915
|
+
onOpenChange(false);
|
|
16916
|
+
} catch {
|
|
16917
|
+
sonner.toast.error("Failed to save push configuration");
|
|
16918
|
+
} finally {
|
|
16919
|
+
setSaving(false);
|
|
16920
|
+
}
|
|
16921
|
+
}, "handleSaveConfig");
|
|
16922
|
+
const handleSendTestPush = /* @__PURE__ */ __name(async () => {
|
|
16923
|
+
if (!testToken.trim()) {
|
|
16924
|
+
sonner.toast.error("Please enter a target FCM device token to test");
|
|
16925
|
+
return;
|
|
16926
|
+
}
|
|
16927
|
+
setTesting(true);
|
|
16928
|
+
try {
|
|
16929
|
+
const res = await fetch("/api/settings/push/test", {
|
|
16930
|
+
method: "POST",
|
|
16931
|
+
headers: {
|
|
16932
|
+
"Content-Type": "application/json"
|
|
16933
|
+
},
|
|
16934
|
+
body: JSON.stringify({
|
|
16935
|
+
token: testToken.trim(),
|
|
16936
|
+
title: testTitle.trim(),
|
|
16937
|
+
body: testBody.trim()
|
|
16938
|
+
})
|
|
16939
|
+
});
|
|
16940
|
+
const data = await res.json();
|
|
16941
|
+
if (!res.ok || !data.success) {
|
|
16942
|
+
sonner.toast.error(data.error || "Failed to send test push notification");
|
|
16943
|
+
return;
|
|
16944
|
+
}
|
|
16945
|
+
sonner.toast.success("Test push notification sent successfully!");
|
|
16946
|
+
} catch {
|
|
16947
|
+
sonner.toast.error("Failed to send test push notification");
|
|
16948
|
+
} finally {
|
|
16949
|
+
setTesting(false);
|
|
16950
|
+
}
|
|
16951
|
+
}, "handleSendTestPush");
|
|
16952
|
+
if (!open) return null;
|
|
16953
|
+
return /* @__PURE__ */ React.createElement("div", {
|
|
16954
|
+
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"
|
|
16955
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
16956
|
+
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"
|
|
16957
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
16958
|
+
className: "flex items-center justify-between border-b border-gray-200 pb-4 dark:border-gray-800"
|
|
16959
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
16960
|
+
className: "flex items-center gap-2"
|
|
16961
|
+
}, /* @__PURE__ */ React.createElement(LucideIcons.Smartphone, {
|
|
16962
|
+
className: "h-5 w-5 text-gray-800 dark:text-gray-200"
|
|
16963
|
+
}), /* @__PURE__ */ React.createElement("h2", {
|
|
16964
|
+
className: "text-lg font-semibold text-gray-900 dark:text-gray-100"
|
|
16965
|
+
}, "Firebase Service Account JSON Configuration")), /* @__PURE__ */ React.createElement("button", {
|
|
16966
|
+
type: "button",
|
|
16967
|
+
onClick: /* @__PURE__ */ __name(() => onOpenChange(false), "onClick"),
|
|
16968
|
+
className: "text-gray-400 hover:text-gray-600 dark:hover:text-gray-300"
|
|
16969
|
+
}, "\u2715")), loading ? /* @__PURE__ */ React.createElement("div", {
|
|
16970
|
+
className: "flex items-center justify-center py-12"
|
|
16971
|
+
}, /* @__PURE__ */ React.createElement(LucideIcons.Loader2, {
|
|
16972
|
+
className: "h-6 w-6 animate-spin text-gray-500"
|
|
16973
|
+
})) : /* @__PURE__ */ React.createElement("div", {
|
|
16974
|
+
className: "space-y-6"
|
|
16975
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
16976
|
+
className: "space-y-2"
|
|
16977
|
+
}, /* @__PURE__ */ React.createElement(Label3, {
|
|
16978
|
+
htmlFor: "service-account-json",
|
|
16979
|
+
className: "text-xs font-semibold text-gray-800 dark:text-gray-200 flex items-center justify-between"
|
|
16980
|
+
}, /* @__PURE__ */ React.createElement("span", {
|
|
16981
|
+
className: "flex items-center gap-1.5"
|
|
16982
|
+
}, /* @__PURE__ */ React.createElement(LucideIcons.KeyRound, {
|
|
16983
|
+
className: "h-4 w-4 text-blue-500"
|
|
16984
|
+
}), "Firebase Service Account JSON File"), isValidJson && /* @__PURE__ */ React.createElement("span", {
|
|
16985
|
+
className: "text-xs font-normal text-green-600 flex items-center gap-1"
|
|
16986
|
+
}, /* @__PURE__ */ React.createElement(LucideIcons.CheckCircle2, {
|
|
16987
|
+
className: "h-3.5 w-3.5"
|
|
16988
|
+
}), " Valid JSON")), /* @__PURE__ */ React.createElement(Textarea, {
|
|
16989
|
+
id: "service-account-json",
|
|
16990
|
+
value: serviceAccountJson,
|
|
16991
|
+
onChange: /* @__PURE__ */ __name((e) => handleJsonChange(e.target.value), "onChange"),
|
|
16992
|
+
placeholder: `Paste your entire service-account.json content here...
|
|
16993
|
+
{
|
|
16994
|
+
"type": "service_account",
|
|
16995
|
+
"project_id": "...",
|
|
16996
|
+
"private_key": "...",
|
|
16997
|
+
"client_email": "..."
|
|
16998
|
+
}`,
|
|
16999
|
+
className: "h-44 font-mono text-xs border-gray-300 dark:border-gray-700"
|
|
17000
|
+
})), isValidJson && /* @__PURE__ */ React.createElement("div", {
|
|
17001
|
+
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"
|
|
17002
|
+
}, /* @__PURE__ */ React.createElement(Label3, {
|
|
17003
|
+
className: "text-xs font-semibold text-gray-700 dark:text-gray-300"
|
|
17004
|
+
}, "Extracted Firebase Credentials Preview"), /* @__PURE__ */ React.createElement("div", {
|
|
17005
|
+
className: "grid grid-cols-1 sm:grid-cols-2 gap-3 text-xs"
|
|
17006
|
+
}, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("span", {
|
|
17007
|
+
className: "font-medium text-gray-500"
|
|
17008
|
+
}, "Project ID:"), /* @__PURE__ */ React.createElement("p", {
|
|
17009
|
+
className: "font-mono text-gray-900 dark:text-gray-100 truncate"
|
|
17010
|
+
}, projectId || "\u2014")), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("span", {
|
|
17011
|
+
className: "font-medium text-gray-500"
|
|
17012
|
+
}, "Client Email:"), /* @__PURE__ */ React.createElement("p", {
|
|
17013
|
+
className: "font-mono text-gray-900 dark:text-gray-100 truncate"
|
|
17014
|
+
}, clientEmail || "\u2014")))), /* @__PURE__ */ React.createElement("div", {
|
|
17015
|
+
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"
|
|
17016
|
+
}, /* @__PURE__ */ React.createElement(Label3, {
|
|
17017
|
+
className: "text-xs font-semibold text-gray-800 dark:text-gray-200 flex items-center gap-1.5"
|
|
17018
|
+
}, /* @__PURE__ */ React.createElement(LucideIcons.Send, {
|
|
17019
|
+
className: "h-3.5 w-3.5 text-green-500"
|
|
17020
|
+
}), "Test Push Notification (Target Device Token)"), /* @__PURE__ */ React.createElement("div", {
|
|
17021
|
+
className: "grid grid-cols-1 sm:grid-cols-2 gap-2"
|
|
17022
|
+
}, /* @__PURE__ */ React.createElement(Input, {
|
|
17023
|
+
value: testTitle,
|
|
17024
|
+
onChange: /* @__PURE__ */ __name((e) => setTestTitle(e.target.value), "onChange"),
|
|
17025
|
+
placeholder: "Test Notification Title",
|
|
17026
|
+
className: "text-xs"
|
|
17027
|
+
}), /* @__PURE__ */ React.createElement(Input, {
|
|
17028
|
+
value: testBody,
|
|
17029
|
+
onChange: /* @__PURE__ */ __name((e) => setTestBody(e.target.value), "onChange"),
|
|
17030
|
+
placeholder: "Test Notification Body",
|
|
17031
|
+
className: "text-xs"
|
|
17032
|
+
})), /* @__PURE__ */ React.createElement("div", {
|
|
17033
|
+
className: "flex gap-2"
|
|
17034
|
+
}, /* @__PURE__ */ React.createElement(Input, {
|
|
17035
|
+
value: testToken,
|
|
17036
|
+
onChange: /* @__PURE__ */ __name((e) => setTestToken(e.target.value), "onChange"),
|
|
17037
|
+
placeholder: "Target FCM Device Token",
|
|
17038
|
+
className: "text-xs font-mono"
|
|
17039
|
+
}), /* @__PURE__ */ React.createElement(Button, {
|
|
17040
|
+
type: "button",
|
|
17041
|
+
variant: "secondary",
|
|
17042
|
+
size: "sm",
|
|
17043
|
+
disabled: testing,
|
|
17044
|
+
onClick: handleSendTestPush,
|
|
17045
|
+
className: "shrink-0 gap-1.5"
|
|
17046
|
+
}, testing ? /* @__PURE__ */ React.createElement(LucideIcons.Loader2, {
|
|
17047
|
+
className: "h-3.5 w-3.5 animate-spin"
|
|
17048
|
+
}) : /* @__PURE__ */ React.createElement(LucideIcons.Send, {
|
|
17049
|
+
className: "h-3.5 w-3.5"
|
|
17050
|
+
}), "Send Test"))), /* @__PURE__ */ React.createElement("div", {
|
|
17051
|
+
className: "flex justify-end gap-2 border-t border-gray-200 pt-4 dark:border-gray-800"
|
|
17052
|
+
}, /* @__PURE__ */ React.createElement(Button, {
|
|
17053
|
+
type: "button",
|
|
17054
|
+
variant: "outline",
|
|
17055
|
+
onClick: /* @__PURE__ */ __name(() => onOpenChange(false), "onClick")
|
|
17056
|
+
}, "Cancel"), /* @__PURE__ */ React.createElement(Button, {
|
|
17057
|
+
type: "button",
|
|
17058
|
+
disabled: saving,
|
|
17059
|
+
onClick: handleSaveConfig,
|
|
17060
|
+
className: "gap-1.5"
|
|
17061
|
+
}, saving && /* @__PURE__ */ React.createElement(LucideIcons.Loader2, {
|
|
17062
|
+
className: "h-4 w-4 animate-spin"
|
|
17063
|
+
}), "Save Service Account JSON")))));
|
|
17064
|
+
}
|
|
17065
|
+
var init_PushConfigModal = __esm({
|
|
17066
|
+
"src/admin/components/PushConfigModal.tsx"() {
|
|
17067
|
+
"use client";
|
|
17068
|
+
init_button();
|
|
17069
|
+
init_input();
|
|
17070
|
+
init_textarea();
|
|
17071
|
+
init_label();
|
|
17072
|
+
__name(PushConfigModal, "PushConfigModal");
|
|
17073
|
+
}
|
|
17074
|
+
});
|
|
16306
17075
|
function EventNotificationsPluginSettings({ settingsGroup, enabled, onEnabledChange, onSaveSettings, saving }) {
|
|
16307
17076
|
const [mainTab, setMainTab] = React25.useState("email");
|
|
16308
17077
|
const [audienceTab, setAudienceTab] = React25.useState("customer");
|
|
@@ -16310,6 +17079,10 @@ function EventNotificationsPluginSettings({ settingsGroup, enabled, onEnabledCha
|
|
|
16310
17079
|
const [emailVendorEnabled, setEmailVendorEnabled] = React25.useState(true);
|
|
16311
17080
|
const [emailAdminEnabled, setEmailAdminEnabled] = React25.useState(true);
|
|
16312
17081
|
const [whatsappEnabled, setWhatsappEnabled] = React25.useState(true);
|
|
17082
|
+
const [pushCustomerEnabled, setPushCustomerEnabled] = React25.useState(true);
|
|
17083
|
+
const [pushVendorEnabled, setPushVendorEnabled] = React25.useState(true);
|
|
17084
|
+
const [pushAdminEnabled, setPushAdminEnabled] = React25.useState(true);
|
|
17085
|
+
const [showPushConfigModal, setShowPushConfigModal] = React25.useState(false);
|
|
16313
17086
|
const [multiVendorOn, setMultiVendorOn] = React25.useState(true);
|
|
16314
17087
|
const [loading, setLoading] = React25.useState(true);
|
|
16315
17088
|
const [savingChannel, setSavingChannel] = React25.useState(false);
|
|
@@ -16340,6 +17113,9 @@ function EventNotificationsPluginSettings({ settingsGroup, enabled, onEnabledCha
|
|
|
16340
17113
|
setEmailVendorEnabled(data.email_vendor_enabled !== "false" && data.email_vendor_enabled !== "0");
|
|
16341
17114
|
setEmailAdminEnabled(data.email_admin_enabled !== "false" && data.email_admin_enabled !== "0");
|
|
16342
17115
|
setWhatsappEnabled(data.whatsapp_enabled !== "false" && data.whatsapp_enabled !== "0");
|
|
17116
|
+
setPushCustomerEnabled(data.push_customer_enabled !== "false" && data.push_customer_enabled !== "0");
|
|
17117
|
+
setPushVendorEnabled(data.push_vendor_enabled !== "false" && data.push_vendor_enabled !== "0");
|
|
17118
|
+
setPushAdminEnabled(data.push_admin_enabled !== "false" && data.push_admin_enabled !== "0");
|
|
16343
17119
|
}
|
|
16344
17120
|
}
|
|
16345
17121
|
} catch {
|
|
@@ -16357,7 +17133,8 @@ function EventNotificationsPluginSettings({ settingsGroup, enabled, onEnabledCha
|
|
|
16357
17133
|
setSavingChannel(true);
|
|
16358
17134
|
try {
|
|
16359
17135
|
const isAnyEmailEnabled = emailCustomerEnabled || emailVendorEnabled || emailAdminEnabled;
|
|
16360
|
-
const
|
|
17136
|
+
const isAnyPushEnabled = pushCustomerEnabled || pushVendorEnabled || pushAdminEnabled;
|
|
17137
|
+
const isAnyChannelEnabled = isAnyEmailEnabled || whatsappEnabled || isAnyPushEnabled;
|
|
16361
17138
|
const res = await fetch(`/api/settings/${settingsGroup}`, {
|
|
16362
17139
|
method: "PUT",
|
|
16363
17140
|
headers: {
|
|
@@ -16384,6 +17161,22 @@ function EventNotificationsPluginSettings({ settingsGroup, enabled, onEnabledCha
|
|
|
16384
17161
|
value: whatsappEnabled ? "true" : "false",
|
|
16385
17162
|
type: "public"
|
|
16386
17163
|
},
|
|
17164
|
+
push_enabled: {
|
|
17165
|
+
value: isAnyPushEnabled ? "true" : "false",
|
|
17166
|
+
type: "public"
|
|
17167
|
+
},
|
|
17168
|
+
push_customer_enabled: {
|
|
17169
|
+
value: pushCustomerEnabled ? "true" : "false",
|
|
17170
|
+
type: "public"
|
|
17171
|
+
},
|
|
17172
|
+
push_vendor_enabled: {
|
|
17173
|
+
value: pushVendorEnabled ? "true" : "false",
|
|
17174
|
+
type: "public"
|
|
17175
|
+
},
|
|
17176
|
+
push_admin_enabled: {
|
|
17177
|
+
value: pushAdminEnabled ? "true" : "false",
|
|
17178
|
+
type: "public"
|
|
17179
|
+
},
|
|
16387
17180
|
enabled: {
|
|
16388
17181
|
value: isAnyChannelEnabled ? "true" : "false",
|
|
16389
17182
|
type: "public"
|
|
@@ -16405,7 +17198,10 @@ function EventNotificationsPluginSettings({ settingsGroup, enabled, onEnabledCha
|
|
|
16405
17198
|
}, "handleSaveChannels");
|
|
16406
17199
|
return /* @__PURE__ */ React.createElement("div", {
|
|
16407
17200
|
className: "space-y-5"
|
|
16408
|
-
}, /* @__PURE__ */ React.createElement(
|
|
17201
|
+
}, /* @__PURE__ */ React.createElement(PushConfigModal, {
|
|
17202
|
+
open: showPushConfigModal,
|
|
17203
|
+
onOpenChange: setShowPushConfigModal
|
|
17204
|
+
}), /* @__PURE__ */ React.createElement("div", {
|
|
16409
17205
|
className: "border-b border-gray-200 dark:border-gray-700"
|
|
16410
17206
|
}, /* @__PURE__ */ React.createElement("div", {
|
|
16411
17207
|
className: "flex gap-1"
|
|
@@ -16421,7 +17217,13 @@ function EventNotificationsPluginSettings({ settingsGroup, enabled, onEnabledCha
|
|
|
16421
17217
|
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"}`
|
|
16422
17218
|
}, /* @__PURE__ */ React.createElement(LucideIcons.MessageCircle, {
|
|
16423
17219
|
className: "h-4 w-4"
|
|
16424
|
-
}), "WhatsApp template")
|
|
17220
|
+
}), "WhatsApp template"), /* @__PURE__ */ React.createElement("button", {
|
|
17221
|
+
type: "button",
|
|
17222
|
+
onClick: /* @__PURE__ */ __name(() => setMainTab("push"), "onClick"),
|
|
17223
|
+
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"}`
|
|
17224
|
+
}, /* @__PURE__ */ React.createElement(LucideIcons.Smartphone, {
|
|
17225
|
+
className: "h-4 w-4"
|
|
17226
|
+
}), "Mobile notification template"))), mainTab === "email" && /* @__PURE__ */ React.createElement("div", {
|
|
16425
17227
|
className: "space-y-5"
|
|
16426
17228
|
}, /* @__PURE__ */ React.createElement("div", {
|
|
16427
17229
|
className: "flex rounded-md bg-gray-100 p-1 dark:bg-gray-800/60 w-fit"
|
|
@@ -16455,7 +17257,7 @@ function EventNotificationsPluginSettings({ settingsGroup, enabled, onEnabledCha
|
|
|
16455
17257
|
className: "h-4 w-4 text-blue-600 dark:text-blue-400"
|
|
16456
17258
|
}), "Enable Customer Email Notifications"), /* @__PURE__ */ React.createElement("p", {
|
|
16457
17259
|
className: "text-xs text-gray-500 dark:text-gray-400"
|
|
16458
|
-
}, "When enabled, order
|
|
17260
|
+
}, "When enabled, order updates, invoices, and ticket details are emailed to customers.")), /* @__PURE__ */ React.createElement(Switch, {
|
|
16459
17261
|
id: "email-customer-notifications-enabled",
|
|
16460
17262
|
checked: emailCustomerEnabled,
|
|
16461
17263
|
onCheckedChange: setEmailCustomerEnabled,
|
|
@@ -16471,10 +17273,10 @@ function EventNotificationsPluginSettings({ settingsGroup, enabled, onEnabledCha
|
|
|
16471
17273
|
}, /* @__PURE__ */ React.createElement("div", {
|
|
16472
17274
|
className: "text-sm font-medium text-gray-900 dark:text-gray-100 flex items-center gap-2"
|
|
16473
17275
|
}, /* @__PURE__ */ React.createElement(LucideIcons.Store, {
|
|
16474
|
-
className: "h-4 w-4 text-purple-600 dark:
|
|
17276
|
+
className: "h-4 w-4 text-purple-600 dark:purple-400"
|
|
16475
17277
|
}), "Enable Vendor Email Notifications"), /* @__PURE__ */ React.createElement("p", {
|
|
16476
17278
|
className: "text-xs text-gray-500 dark:text-gray-400"
|
|
16477
|
-
}, "When enabled, vendors
|
|
17279
|
+
}, "When enabled, vendors receive email notifications for new orders assigned to them.")), /* @__PURE__ */ React.createElement(Switch, {
|
|
16478
17280
|
id: "email-vendor-notifications-enabled",
|
|
16479
17281
|
checked: emailVendorEnabled,
|
|
16480
17282
|
onCheckedChange: setEmailVendorEnabled,
|
|
@@ -16517,7 +17319,104 @@ function EventNotificationsPluginSettings({ settingsGroup, enabled, onEnabledCha
|
|
|
16517
17319
|
checked: whatsappEnabled,
|
|
16518
17320
|
onCheckedChange: setWhatsappEnabled,
|
|
16519
17321
|
disabled: loading
|
|
16520
|
-
})), /* @__PURE__ */ React.createElement(WhatsAppTriggerBindings, null)), /* @__PURE__ */ React.createElement(
|
|
17322
|
+
})), /* @__PURE__ */ React.createElement(WhatsAppTriggerBindings, null)), mainTab === "push" && /* @__PURE__ */ React.createElement("div", {
|
|
17323
|
+
className: "space-y-5"
|
|
17324
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
17325
|
+
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"
|
|
17326
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
17327
|
+
className: "space-y-0.5"
|
|
17328
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
17329
|
+
className: "text-sm font-semibold text-gray-900 dark:text-gray-100 flex items-center gap-2"
|
|
17330
|
+
}, /* @__PURE__ */ React.createElement(LucideIcons.Smartphone, {
|
|
17331
|
+
className: "h-4 w-4 text-blue-600 dark:text-blue-400"
|
|
17332
|
+
}), "Firebase Cloud Messaging (FCM) Setup"), /* @__PURE__ */ React.createElement("p", {
|
|
17333
|
+
className: "text-xs text-gray-500 dark:text-gray-400"
|
|
17334
|
+
}, "Set up your Firebase project credentials to send mobile push notifications to iOS and Android apps.")), /* @__PURE__ */ React.createElement(Button, {
|
|
17335
|
+
type: "button",
|
|
17336
|
+
variant: "outline",
|
|
17337
|
+
size: "sm",
|
|
17338
|
+
onClick: /* @__PURE__ */ __name(() => setShowPushConfigModal(true), "onClick"),
|
|
17339
|
+
className: "gap-1.5 bg-white dark:bg-gray-900 shrink-0"
|
|
17340
|
+
}, /* @__PURE__ */ React.createElement(LucideIcons.Settings, {
|
|
17341
|
+
className: "h-4 w-4 text-gray-600"
|
|
17342
|
+
}), "Set Configuration")), /* @__PURE__ */ React.createElement("div", {
|
|
17343
|
+
className: "flex rounded-md bg-gray-100 p-1 dark:bg-gray-800/60 w-fit"
|
|
17344
|
+
}, /* @__PURE__ */ React.createElement("button", {
|
|
17345
|
+
type: "button",
|
|
17346
|
+
onClick: /* @__PURE__ */ __name(() => setAudienceTab("customer"), "onClick"),
|
|
17347
|
+
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"}`
|
|
17348
|
+
}, /* @__PURE__ */ React.createElement(LucideIcons.User, {
|
|
17349
|
+
className: "h-3.5 w-3.5 text-blue-500"
|
|
17350
|
+
}), "Customers"), multiVendorOn && /* @__PURE__ */ React.createElement("button", {
|
|
17351
|
+
type: "button",
|
|
17352
|
+
onClick: /* @__PURE__ */ __name(() => setAudienceTab("vendor"), "onClick"),
|
|
17353
|
+
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"}`
|
|
17354
|
+
}, /* @__PURE__ */ React.createElement(LucideIcons.Store, {
|
|
17355
|
+
className: "h-3.5 w-3.5 text-purple-500"
|
|
17356
|
+
}), "Vendors"), /* @__PURE__ */ React.createElement("button", {
|
|
17357
|
+
type: "button",
|
|
17358
|
+
onClick: /* @__PURE__ */ __name(() => setAudienceTab("admin"), "onClick"),
|
|
17359
|
+
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"}`
|
|
17360
|
+
}, /* @__PURE__ */ React.createElement(LucideIcons.ShieldCheck, {
|
|
17361
|
+
className: "h-3.5 w-3.5 text-amber-500"
|
|
17362
|
+
}), "Admin")), audienceTab === "customer" && /* @__PURE__ */ React.createElement("div", {
|
|
17363
|
+
className: "space-y-4"
|
|
17364
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
17365
|
+
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"
|
|
17366
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
17367
|
+
className: "space-y-0.5"
|
|
17368
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
17369
|
+
className: "text-sm font-medium text-gray-900 dark:text-gray-100 flex items-center gap-2"
|
|
17370
|
+
}, /* @__PURE__ */ React.createElement(LucideIcons.User, {
|
|
17371
|
+
className: "h-4 w-4 text-blue-600 dark:text-blue-400"
|
|
17372
|
+
}), "Enable Customer Mobile Push Notifications"), /* @__PURE__ */ React.createElement("p", {
|
|
17373
|
+
className: "text-xs text-gray-500 dark:text-gray-400"
|
|
17374
|
+
}, "When enabled, order confirmation alerts and updates are pushed directly to customer mobile apps.")), /* @__PURE__ */ React.createElement(Switch, {
|
|
17375
|
+
id: "push-customer-notifications-enabled",
|
|
17376
|
+
checked: pushCustomerEnabled,
|
|
17377
|
+
onCheckedChange: setPushCustomerEnabled,
|
|
17378
|
+
disabled: loading
|
|
17379
|
+
})), /* @__PURE__ */ React.createElement(PushTriggerBindings, {
|
|
17380
|
+
audience: "customer"
|
|
17381
|
+
})), audienceTab === "vendor" && multiVendorOn && /* @__PURE__ */ React.createElement("div", {
|
|
17382
|
+
className: "space-y-4"
|
|
17383
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
17384
|
+
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"
|
|
17385
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
17386
|
+
className: "space-y-0.5"
|
|
17387
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
17388
|
+
className: "text-sm font-medium text-gray-900 dark:text-gray-100 flex items-center gap-2"
|
|
17389
|
+
}, /* @__PURE__ */ React.createElement(LucideIcons.Store, {
|
|
17390
|
+
className: "h-4 w-4 text-purple-600 dark:text-purple-400"
|
|
17391
|
+
}), "Enable Vendor Mobile Push Notifications"), /* @__PURE__ */ React.createElement("p", {
|
|
17392
|
+
className: "text-xs text-gray-500 dark:text-gray-400"
|
|
17393
|
+
}, "When enabled, vendor mobile app receives instant push alerts for assigned orders.")), /* @__PURE__ */ React.createElement(Switch, {
|
|
17394
|
+
id: "push-vendor-notifications-enabled",
|
|
17395
|
+
checked: pushVendorEnabled,
|
|
17396
|
+
onCheckedChange: setPushVendorEnabled,
|
|
17397
|
+
disabled: loading
|
|
17398
|
+
})), /* @__PURE__ */ React.createElement(PushTriggerBindings, {
|
|
17399
|
+
audience: "vendor"
|
|
17400
|
+
})), audienceTab === "admin" && /* @__PURE__ */ React.createElement("div", {
|
|
17401
|
+
className: "space-y-4"
|
|
17402
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
17403
|
+
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"
|
|
17404
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
17405
|
+
className: "space-y-0.5"
|
|
17406
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
17407
|
+
className: "text-sm font-medium text-gray-900 dark:text-gray-100 flex items-center gap-2"
|
|
17408
|
+
}, /* @__PURE__ */ React.createElement(LucideIcons.ShieldCheck, {
|
|
17409
|
+
className: "h-4 w-4 text-amber-600 dark:text-amber-400"
|
|
17410
|
+
}), "Enable Admin Mobile Push Notifications"), /* @__PURE__ */ React.createElement("p", {
|
|
17411
|
+
className: "text-xs text-gray-500 dark:text-gray-400"
|
|
17412
|
+
}, "When enabled, store administrators receive mobile push alerts for all orders placed/cancelled.")), /* @__PURE__ */ React.createElement(Switch, {
|
|
17413
|
+
id: "push-admin-notifications-enabled",
|
|
17414
|
+
checked: pushAdminEnabled,
|
|
17415
|
+
onCheckedChange: setPushAdminEnabled,
|
|
17416
|
+
disabled: loading
|
|
17417
|
+
})), /* @__PURE__ */ React.createElement(PushTriggerBindings, {
|
|
17418
|
+
audience: "admin"
|
|
17419
|
+
}))), /* @__PURE__ */ React.createElement(Button, {
|
|
16521
17420
|
size: "sm",
|
|
16522
17421
|
onClick: /* @__PURE__ */ __name(() => void handleSaveChannels(), "onClick"),
|
|
16523
17422
|
disabled: saving || savingChannel || loading,
|
|
@@ -16533,9 +17432,207 @@ var init_EventNotificationsPluginSettings = __esm({
|
|
|
16533
17432
|
init_switch();
|
|
16534
17433
|
init_whatsappTriggerBindingsPage();
|
|
16535
17434
|
init_emailTriggersBindingsPage();
|
|
17435
|
+
init_pushTriggersBindingsPage();
|
|
17436
|
+
init_PushConfigModal();
|
|
16536
17437
|
__name(EventNotificationsPluginSettings, "EventNotificationsPluginSettings");
|
|
16537
17438
|
}
|
|
16538
17439
|
});
|
|
17440
|
+
function googleRedirectUri() {
|
|
17441
|
+
if (typeof window === "undefined") {
|
|
17442
|
+
const path2 = typeof process !== "undefined" && process.env.NEXT_PUBLIC_GOOGLE_OAUTH_CALLBACK_PATH?.trim() || "/api/auth/callback/google";
|
|
17443
|
+
return path2.startsWith("http") ? path2 : path2;
|
|
17444
|
+
}
|
|
17445
|
+
const configured = process.env.NEXT_PUBLIC_GOOGLE_OAUTH_CALLBACK_PATH?.trim();
|
|
17446
|
+
if (configured?.startsWith("http")) return configured;
|
|
17447
|
+
const path = configured || "/api/auth/callback/google";
|
|
17448
|
+
return `${window.location.origin}${path.startsWith("/") ? path : `/${path}`}`;
|
|
17449
|
+
}
|
|
17450
|
+
function AuthProvidersPluginSettings({ settingsGroup, onEnabledChange }) {
|
|
17451
|
+
const [loading, setLoading] = React25.useState(true);
|
|
17452
|
+
const [saving, setSaving] = React25.useState(false);
|
|
17453
|
+
const [googleEnabled, setGoogleEnabled] = React25.useState(false);
|
|
17454
|
+
const [googleClientId, setGoogleClientId] = React25.useState("");
|
|
17455
|
+
const [googleClientSecret, setGoogleClientSecret] = React25.useState("");
|
|
17456
|
+
const [hasSavedSecret, setHasSavedSecret] = React25.useState(false);
|
|
17457
|
+
const [copied, setCopied] = React25.useState(false);
|
|
17458
|
+
const onEnabledChangeRef = React25.useRef(onEnabledChange);
|
|
17459
|
+
onEnabledChangeRef.current = onEnabledChange;
|
|
17460
|
+
const redirectUri = React25.useMemo(() => googleRedirectUri(), []);
|
|
17461
|
+
React25.useEffect(() => {
|
|
17462
|
+
let cancelled = false;
|
|
17463
|
+
(async () => {
|
|
17464
|
+
setLoading(true);
|
|
17465
|
+
try {
|
|
17466
|
+
const res = await fetch(`/api/settings/${settingsGroup}`, {
|
|
17467
|
+
cache: "no-store"
|
|
17468
|
+
});
|
|
17469
|
+
const data = res.ok ? await res.json() : {};
|
|
17470
|
+
if (cancelled) return;
|
|
17471
|
+
const enabled = data.googleEnabled === "true" || data.googleEnabled === "1" || data.enabled === "true" && data.googleEnabled !== "false";
|
|
17472
|
+
setGoogleEnabled(enabled);
|
|
17473
|
+
setGoogleClientId(String(data.googleClientId ?? "").trim());
|
|
17474
|
+
const secret = String(data.googleClientSecret ?? "").trim();
|
|
17475
|
+
setGoogleClientSecret("");
|
|
17476
|
+
setHasSavedSecret(Boolean(secret));
|
|
17477
|
+
} catch {
|
|
17478
|
+
} finally {
|
|
17479
|
+
if (!cancelled) setLoading(false);
|
|
17480
|
+
}
|
|
17481
|
+
})();
|
|
17482
|
+
return () => {
|
|
17483
|
+
cancelled = true;
|
|
17484
|
+
};
|
|
17485
|
+
}, [
|
|
17486
|
+
settingsGroup
|
|
17487
|
+
]);
|
|
17488
|
+
const handleCopyRedirect = /* @__PURE__ */ __name(async () => {
|
|
17489
|
+
try {
|
|
17490
|
+
await navigator.clipboard.writeText(redirectUri);
|
|
17491
|
+
setCopied(true);
|
|
17492
|
+
sonner.toast.success("Redirect URI copied");
|
|
17493
|
+
setTimeout(() => setCopied(false), 2e3);
|
|
17494
|
+
} catch {
|
|
17495
|
+
sonner.toast.error("Could not copy redirect URI");
|
|
17496
|
+
}
|
|
17497
|
+
}, "handleCopyRedirect");
|
|
17498
|
+
const handleSave = /* @__PURE__ */ __name(async () => {
|
|
17499
|
+
setSaving(true);
|
|
17500
|
+
try {
|
|
17501
|
+
const payload = {
|
|
17502
|
+
enabled: {
|
|
17503
|
+
value: googleEnabled ? "true" : "false",
|
|
17504
|
+
type: "public"
|
|
17505
|
+
},
|
|
17506
|
+
googleEnabled: {
|
|
17507
|
+
value: googleEnabled ? "true" : "false",
|
|
17508
|
+
type: "public"
|
|
17509
|
+
},
|
|
17510
|
+
googleClientId: {
|
|
17511
|
+
value: googleClientId.trim(),
|
|
17512
|
+
type: "private"
|
|
17513
|
+
}
|
|
17514
|
+
};
|
|
17515
|
+
if (googleClientSecret.trim()) {
|
|
17516
|
+
payload.googleClientSecret = {
|
|
17517
|
+
value: googleClientSecret.trim(),
|
|
17518
|
+
type: "private",
|
|
17519
|
+
encrypted: true
|
|
17520
|
+
};
|
|
17521
|
+
}
|
|
17522
|
+
const res = await fetch(`/api/settings/${settingsGroup}`, {
|
|
17523
|
+
method: "PUT",
|
|
17524
|
+
headers: {
|
|
17525
|
+
"Content-Type": "application/json"
|
|
17526
|
+
},
|
|
17527
|
+
body: JSON.stringify(payload)
|
|
17528
|
+
});
|
|
17529
|
+
if (!res.ok) {
|
|
17530
|
+
sonner.toast.error("Failed to save Google auth settings");
|
|
17531
|
+
return;
|
|
17532
|
+
}
|
|
17533
|
+
if (googleClientSecret.trim()) {
|
|
17534
|
+
setHasSavedSecret(true);
|
|
17535
|
+
setGoogleClientSecret("");
|
|
17536
|
+
}
|
|
17537
|
+
onEnabledChangeRef.current?.(googleEnabled);
|
|
17538
|
+
sonner.toast.success("Authentication provider settings saved");
|
|
17539
|
+
} catch {
|
|
17540
|
+
sonner.toast.error("Failed to save Google auth settings");
|
|
17541
|
+
} finally {
|
|
17542
|
+
setSaving(false);
|
|
17543
|
+
}
|
|
17544
|
+
}, "handleSave");
|
|
17545
|
+
if (loading) {
|
|
17546
|
+
return /* @__PURE__ */ React.createElement("p", {
|
|
17547
|
+
className: "text-sm text-gray-500 dark:text-gray-400"
|
|
17548
|
+
}, "Loading\u2026");
|
|
17549
|
+
}
|
|
17550
|
+
return /* @__PURE__ */ React.createElement("div", {
|
|
17551
|
+
className: "space-y-4"
|
|
17552
|
+
}, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("h3", {
|
|
17553
|
+
className: "text-sm font-semibold text-gray-900 dark:text-white"
|
|
17554
|
+
}, "Google (Web)"), /* @__PURE__ */ React.createElement("p", {
|
|
17555
|
+
className: "mt-1 text-xs text-gray-500 dark:text-gray-400"
|
|
17556
|
+
}, "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", {
|
|
17557
|
+
className: "flex items-center justify-between gap-2"
|
|
17558
|
+
}, /* @__PURE__ */ React.createElement(Label3, {
|
|
17559
|
+
htmlFor: `${settingsGroup}-googleEnabled`,
|
|
17560
|
+
className: "text-sm"
|
|
17561
|
+
}, "Enable Google sign-in"), /* @__PURE__ */ React.createElement(Switch, {
|
|
17562
|
+
id: `${settingsGroup}-googleEnabled`,
|
|
17563
|
+
checked: googleEnabled,
|
|
17564
|
+
onCheckedChange: setGoogleEnabled
|
|
17565
|
+
})), /* @__PURE__ */ React.createElement("div", {
|
|
17566
|
+
className: "space-y-1"
|
|
17567
|
+
}, /* @__PURE__ */ React.createElement(Label3, {
|
|
17568
|
+
htmlFor: `${settingsGroup}-redirectUri`,
|
|
17569
|
+
className: "text-sm"
|
|
17570
|
+
}, "Redirect URI (add in Google Console)"), /* @__PURE__ */ React.createElement("div", {
|
|
17571
|
+
className: "flex gap-2"
|
|
17572
|
+
}, /* @__PURE__ */ React.createElement(Input, {
|
|
17573
|
+
id: `${settingsGroup}-redirectUri`,
|
|
17574
|
+
value: redirectUri,
|
|
17575
|
+
readOnly: true,
|
|
17576
|
+
className: "h-9 flex-1 font-mono text-xs"
|
|
17577
|
+
}), /* @__PURE__ */ React.createElement(Button, {
|
|
17578
|
+
type: "button",
|
|
17579
|
+
size: "sm",
|
|
17580
|
+
variant: "outline",
|
|
17581
|
+
onClick: handleCopyRedirect,
|
|
17582
|
+
className: "shrink-0 gap-1"
|
|
17583
|
+
}, copied ? /* @__PURE__ */ React.createElement(LucideIcons.Check, {
|
|
17584
|
+
className: "h-3.5 w-3.5"
|
|
17585
|
+
}) : /* @__PURE__ */ React.createElement(LucideIcons.Copy, {
|
|
17586
|
+
className: "h-3.5 w-3.5"
|
|
17587
|
+
}), copied ? "Copied" : "Copy")), /* @__PURE__ */ React.createElement("p", {
|
|
17588
|
+
className: "text-xs text-gray-500 dark:text-gray-400"
|
|
17589
|
+
}, "Must match ", /* @__PURE__ */ React.createElement("code", {
|
|
17590
|
+
className: "text-[11px]"
|
|
17591
|
+
}, "NEXTAUTH_URL"), " for this environment.")), /* @__PURE__ */ React.createElement("div", {
|
|
17592
|
+
className: "space-y-1"
|
|
17593
|
+
}, /* @__PURE__ */ React.createElement(Label3, {
|
|
17594
|
+
htmlFor: `${settingsGroup}-googleClientId`,
|
|
17595
|
+
className: "text-sm"
|
|
17596
|
+
}, "Client ID"), /* @__PURE__ */ React.createElement(Input, {
|
|
17597
|
+
id: `${settingsGroup}-googleClientId`,
|
|
17598
|
+
value: googleClientId,
|
|
17599
|
+
onChange: /* @__PURE__ */ __name((e) => setGoogleClientId(e.target.value), "onChange"),
|
|
17600
|
+
placeholder: "xxxxx.apps.googleusercontent.com",
|
|
17601
|
+
className: "h-9 text-sm",
|
|
17602
|
+
autoComplete: "off"
|
|
17603
|
+
})), /* @__PURE__ */ React.createElement("div", {
|
|
17604
|
+
className: "space-y-1"
|
|
17605
|
+
}, /* @__PURE__ */ React.createElement(Label3, {
|
|
17606
|
+
htmlFor: `${settingsGroup}-googleClientSecret`,
|
|
17607
|
+
className: "text-sm"
|
|
17608
|
+
}, "Client Secret ", hasSavedSecret && !googleClientSecret.trim() ? "(saved)" : ""), /* @__PURE__ */ React.createElement(Input, {
|
|
17609
|
+
id: `${settingsGroup}-googleClientSecret`,
|
|
17610
|
+
type: "password",
|
|
17611
|
+
value: googleClientSecret,
|
|
17612
|
+
onChange: /* @__PURE__ */ __name((e) => setGoogleClientSecret(e.target.value), "onChange"),
|
|
17613
|
+
placeholder: hasSavedSecret ? "Leave blank to keep saved secret" : "Paste client secret",
|
|
17614
|
+
className: "h-9 text-sm",
|
|
17615
|
+
autoComplete: "new-password"
|
|
17616
|
+
})), /* @__PURE__ */ React.createElement(Button, {
|
|
17617
|
+
size: "sm",
|
|
17618
|
+
onClick: handleSave,
|
|
17619
|
+
disabled: saving,
|
|
17620
|
+
className: "gap-1"
|
|
17621
|
+
}, /* @__PURE__ */ React.createElement(LucideIcons.Save, {
|
|
17622
|
+
className: "h-3.5 w-3.5"
|
|
17623
|
+
}), saving ? "Saving\u2026" : "Save"));
|
|
17624
|
+
}
|
|
17625
|
+
var init_AuthProvidersPluginSettings = __esm({
|
|
17626
|
+
"src/admin/components/AuthProvidersPluginSettings.tsx"() {
|
|
17627
|
+
"use client";
|
|
17628
|
+
init_button();
|
|
17629
|
+
init_input();
|
|
17630
|
+
init_label();
|
|
17631
|
+
init_switch();
|
|
17632
|
+
__name(googleRedirectUri, "googleRedirectUri");
|
|
17633
|
+
__name(AuthProvidersPluginSettings, "AuthProvidersPluginSettings");
|
|
17634
|
+
}
|
|
17635
|
+
});
|
|
16539
17636
|
|
|
16540
17637
|
// src/plugins/llm/chat-email-intent.ts
|
|
16541
17638
|
function normalizeIntentKey(raw) {
|
|
@@ -16913,6 +18010,7 @@ function PluginSettingsPanel({ descriptor, onSaved }) {
|
|
|
16913
18010
|
const isEventNotifications = settingsGroup === "event_notifications";
|
|
16914
18011
|
const isSocialMedia = settingsGroup === "social_media";
|
|
16915
18012
|
const isMultiVendor = settingsGroup === "multi_vendor";
|
|
18013
|
+
const isAuthProviders = settingsGroup === "auth_providers";
|
|
16916
18014
|
const [enabled, setEnabled] = React25.useState(true);
|
|
16917
18015
|
const [botName, setBotName] = React25.useState("");
|
|
16918
18016
|
const [icon, setIcon] = React25.useState("");
|
|
@@ -17262,6 +18360,10 @@ function PluginSettingsPanel({ descriptor, onSaved }) {
|
|
|
17262
18360
|
setWhatsappPhoneNumberId(String(data.phoneNumberId ?? data.WHATSAPP_PHONE_NUMBER_ID ?? "").trim());
|
|
17263
18361
|
setWhatsappWabaId(String(data.wabaId ?? data.WHATSAPP_WABA_ID ?? "").trim());
|
|
17264
18362
|
}
|
|
18363
|
+
if (isAuthProviders) {
|
|
18364
|
+
const googleOn = data.googleEnabled === "true" || data.googleEnabled === "1" || data.enabled === "true" && data.googleEnabled !== "false";
|
|
18365
|
+
setEnabled(googleOn);
|
|
18366
|
+
}
|
|
17265
18367
|
if (isSocialMedia) {
|
|
17266
18368
|
const savedLiToken = String(data.linkedin_access_token ?? "").trim();
|
|
17267
18369
|
setLinkedinAccessToken(savedLiToken);
|
|
@@ -17299,7 +18401,8 @@ function PluginSettingsPanel({ descriptor, onSaved }) {
|
|
|
17299
18401
|
isWhatsapp,
|
|
17300
18402
|
isEventNotifications,
|
|
17301
18403
|
isSocialMedia,
|
|
17302
|
-
isMultiVendor
|
|
18404
|
+
isMultiVendor,
|
|
18405
|
+
isAuthProviders
|
|
17303
18406
|
]);
|
|
17304
18407
|
React25.useEffect(() => {
|
|
17305
18408
|
if (!isSocialMedia || loading || linkedInOrgsPrefetchedRef.current) return;
|
|
@@ -17745,6 +18848,18 @@ function PluginSettingsPanel({ descriptor, onSaved }) {
|
|
|
17745
18848
|
}
|
|
17746
18849
|
};
|
|
17747
18850
|
}
|
|
18851
|
+
if (isAuthProviders) {
|
|
18852
|
+
return {
|
|
18853
|
+
enabled: {
|
|
18854
|
+
value: enabled ? "true" : "false",
|
|
18855
|
+
type: "public"
|
|
18856
|
+
},
|
|
18857
|
+
googleEnabled: {
|
|
18858
|
+
value: enabled ? "true" : "false",
|
|
18859
|
+
type: "public"
|
|
18860
|
+
}
|
|
18861
|
+
};
|
|
18862
|
+
}
|
|
17748
18863
|
if (isSocialMedia) {
|
|
17749
18864
|
const payload2 = {
|
|
17750
18865
|
enabled: {
|
|
@@ -18230,6 +19345,15 @@ function PluginSettingsPanel({ descriptor, onSaved }) {
|
|
|
18230
19345
|
sonner.toast.success("Removed from agent");
|
|
18231
19346
|
await fetchAttachedKnowledge(slug);
|
|
18232
19347
|
}, "handleUnlinkKbDoc");
|
|
19348
|
+
if (isAuthProviders) {
|
|
19349
|
+
return /* @__PURE__ */ React.createElement(AuthProvidersPluginSettings, {
|
|
19350
|
+
settingsGroup,
|
|
19351
|
+
onEnabledChange: /* @__PURE__ */ __name((value) => {
|
|
19352
|
+
setEnabled(value);
|
|
19353
|
+
onSaved?.();
|
|
19354
|
+
}, "onEnabledChange")
|
|
19355
|
+
});
|
|
19356
|
+
}
|
|
18233
19357
|
if (loading) return /* @__PURE__ */ React.createElement("div", {
|
|
18234
19358
|
className: "text-sm text-gray-500 dark:text-gray-400"
|
|
18235
19359
|
}, "Loading...");
|
|
@@ -19566,6 +20690,10 @@ function PluginsPage() {
|
|
|
19566
20690
|
const en = pluginDescriptors.find((p) => p.name === "event_notifications");
|
|
19567
20691
|
if (en) setSelectedName(en.name);
|
|
19568
20692
|
}
|
|
20693
|
+
if (q === "auth_providers" || q === "auth-providers" || q === "authentication") {
|
|
20694
|
+
const ap = pluginDescriptors.find((p) => p.name === "auth_providers");
|
|
20695
|
+
if (ap) setSelectedName(ap.name);
|
|
20696
|
+
}
|
|
19569
20697
|
}, [
|
|
19570
20698
|
searchParams,
|
|
19571
20699
|
pluginDescriptors
|
|
@@ -19573,10 +20701,13 @@ function PluginsPage() {
|
|
|
19573
20701
|
React25.useEffect(() => {
|
|
19574
20702
|
pluginDescriptors.forEach((p) => {
|
|
19575
20703
|
if (!p.settingsGroup) return;
|
|
19576
|
-
fetch(`/api/settings/${p.settingsGroup}`).then((r) => r.ok ? r.json() : {}).then((data) =>
|
|
19577
|
-
|
|
19578
|
-
|
|
19579
|
-
|
|
20704
|
+
fetch(`/api/settings/${p.settingsGroup}`).then((r) => r.ok ? r.json() : {}).then((data) => {
|
|
20705
|
+
const on = p.settingsGroup === "auth_providers" ? data.googleEnabled === "true" || data.googleEnabled === "1" || data.enabled !== "false" && data.googleEnabled !== "false" && data.enabled === "true" : data.enabled !== "false";
|
|
20706
|
+
setEnabledMap((prev) => ({
|
|
20707
|
+
...prev,
|
|
20708
|
+
[p.name]: on
|
|
20709
|
+
}));
|
|
20710
|
+
}).catch(() => {
|
|
19580
20711
|
});
|
|
19581
20712
|
});
|
|
19582
20713
|
}, [
|
|
@@ -19586,10 +20717,13 @@ function PluginsPage() {
|
|
|
19586
20717
|
const refreshEnabled = /* @__PURE__ */ __name((name) => {
|
|
19587
20718
|
const d = pluginDescriptors.find((p) => p.name === name);
|
|
19588
20719
|
if (!d?.settingsGroup) return;
|
|
19589
|
-
fetch(`/api/settings/${d.settingsGroup}`).then((r) => r.ok ? r.json() : {}).then((data) =>
|
|
19590
|
-
|
|
19591
|
-
|
|
19592
|
-
|
|
20720
|
+
fetch(`/api/settings/${d.settingsGroup}`).then((r) => r.ok ? r.json() : {}).then((data) => {
|
|
20721
|
+
const on = d.settingsGroup === "auth_providers" ? data.googleEnabled === "true" || data.googleEnabled === "1" || data.enabled === "true" && data.googleEnabled !== "false" : data.enabled !== "false";
|
|
20722
|
+
setEnabledMap((prev) => ({
|
|
20723
|
+
...prev,
|
|
20724
|
+
[name]: on
|
|
20725
|
+
}));
|
|
20726
|
+
}).catch(() => {
|
|
19593
20727
|
});
|
|
19594
20728
|
}, "refreshEnabled");
|
|
19595
20729
|
return /* @__PURE__ */ React.createElement("div", {
|
|
@@ -19671,6 +20805,7 @@ var init_PluginsPage = __esm({
|
|
|
19671
20805
|
init_checkbox();
|
|
19672
20806
|
init_select();
|
|
19673
20807
|
init_EventNotificationsPluginSettings();
|
|
20808
|
+
init_AuthProvidersPluginSettings();
|
|
19674
20809
|
init_ImageOrUrlField();
|
|
19675
20810
|
init_chat_email_intent();
|
|
19676
20811
|
init_llm_agent_scope();
|
|
@@ -19689,7 +20824,8 @@ var init_PluginsPage = __esm({
|
|
|
19689
20824
|
pg_boss: LucideIcons.CalendarClock,
|
|
19690
20825
|
share: LucideIcons.Share2,
|
|
19691
20826
|
whatsapp: LucideIcons.MessageCircle,
|
|
19692
|
-
event_notifications: LucideIcons.Bell
|
|
20827
|
+
event_notifications: LucideIcons.Bell,
|
|
20828
|
+
auth_providers: LucideIcons.KeyRound
|
|
19693
20829
|
};
|
|
19694
20830
|
__name(normalizeSmsProviderChoice, "normalizeSmsProviderChoice");
|
|
19695
20831
|
__name(normalizeMsg91ApiMode, "normalizeMsg91ApiMode");
|
|
@@ -20162,9 +21298,7 @@ function VendorRolesPage() {
|
|
|
20162
21298
|
className: "text-base font-semibold text-white"
|
|
20163
21299
|
}, "Vendor Store Roles & Permissions"), /* @__PURE__ */ React25__namespace.default.createElement("p", {
|
|
20164
21300
|
className: "mt-0.5 text-xs text-gray-300"
|
|
20165
|
-
}, "Set CRUD permissions for any role (Viewer, Manager, Fulfillment, Catalog Staff, or custom roles).
|
|
20166
|
-
className: "font-mono bg-gray-700 px-1 py-0.5 rounded text-gray-200"
|
|
20167
|
-
}, "vendor_role_permissions"), " table and apply directly to team members assigned to that role.")), /* @__PURE__ */ React25__namespace.default.createElement("div", {
|
|
21301
|
+
}, "Set CRUD permissions for any role (Viewer, Manager, Fulfillment, Catalog Staff, or custom roles).")), /* @__PURE__ */ React25__namespace.default.createElement("div", {
|
|
20168
21302
|
className: "min-w-0 p-6"
|
|
20169
21303
|
}, error ? /* @__PURE__ */ React25__namespace.default.createElement("p", {
|
|
20170
21304
|
className: "mb-4 text-sm text-red-600 dark:text-red-400"
|
|
@@ -20663,7 +21797,7 @@ function PlatformRolesPage() {
|
|
|
20663
21797
|
className: "p-2"
|
|
20664
21798
|
}, /* @__PURE__ */ React25__namespace.default.createElement("div", {
|
|
20665
21799
|
className: "flex items-center justify-center gap-1"
|
|
20666
|
-
}, /* @__PURE__ */ React25__namespace.default.createElement("span", null, "
|
|
21800
|
+
}, /* @__PURE__ */ React25__namespace.default.createElement("span", null, "Create"), /* @__PURE__ */ React25__namespace.default.createElement("input", {
|
|
20667
21801
|
type: "checkbox",
|
|
20668
21802
|
checked: isColumnAllChecked("canCreate"),
|
|
20669
21803
|
onChange: /* @__PURE__ */ __name(() => toggleColumn("canCreate"), "onChange")
|
|
@@ -20671,7 +21805,7 @@ function PlatformRolesPage() {
|
|
|
20671
21805
|
className: "p-2"
|
|
20672
21806
|
}, /* @__PURE__ */ React25__namespace.default.createElement("div", {
|
|
20673
21807
|
className: "flex items-center justify-center gap-1"
|
|
20674
|
-
}, /* @__PURE__ */ React25__namespace.default.createElement("span", null, "
|
|
21808
|
+
}, /* @__PURE__ */ React25__namespace.default.createElement("span", null, "Read"), /* @__PURE__ */ React25__namespace.default.createElement("input", {
|
|
20675
21809
|
type: "checkbox",
|
|
20676
21810
|
checked: isColumnAllChecked("canRead"),
|
|
20677
21811
|
onChange: /* @__PURE__ */ __name(() => toggleColumn("canRead"), "onChange")
|
|
@@ -20679,7 +21813,7 @@ function PlatformRolesPage() {
|
|
|
20679
21813
|
className: "p-2"
|
|
20680
21814
|
}, /* @__PURE__ */ React25__namespace.default.createElement("div", {
|
|
20681
21815
|
className: "flex items-center justify-center gap-1"
|
|
20682
|
-
}, /* @__PURE__ */ React25__namespace.default.createElement("span", null, "
|
|
21816
|
+
}, /* @__PURE__ */ React25__namespace.default.createElement("span", null, "Update"), /* @__PURE__ */ React25__namespace.default.createElement("input", {
|
|
20683
21817
|
type: "checkbox",
|
|
20684
21818
|
checked: isColumnAllChecked("canUpdate"),
|
|
20685
21819
|
onChange: /* @__PURE__ */ __name(() => toggleColumn("canUpdate"), "onChange")
|
|
@@ -20687,7 +21821,7 @@ function PlatformRolesPage() {
|
|
|
20687
21821
|
className: "p-2"
|
|
20688
21822
|
}, /* @__PURE__ */ React25__namespace.default.createElement("div", {
|
|
20689
21823
|
className: "flex items-center justify-center gap-1"
|
|
20690
|
-
}, /* @__PURE__ */ React25__namespace.default.createElement("span", null, "
|
|
21824
|
+
}, /* @__PURE__ */ React25__namespace.default.createElement("span", null, "Delete"), /* @__PURE__ */ React25__namespace.default.createElement("input", {
|
|
20691
21825
|
type: "checkbox",
|
|
20692
21826
|
checked: isColumnAllChecked("canDelete"),
|
|
20693
21827
|
onChange: /* @__PURE__ */ __name(() => toggleColumn("canDelete"), "onChange")
|
|
@@ -34199,7 +35333,7 @@ function VendorEditPage({ vendorId }) {
|
|
|
34199
35333
|
}), /* @__PURE__ */ React25__namespace.default.createElement(Label3, {
|
|
34200
35334
|
htmlFor: "termsAccepted",
|
|
34201
35335
|
className: "font-normal cursor-pointer text-sm leading-snug"
|
|
34202
|
-
}, "I confirm
|
|
35336
|
+
}, "I confirm I have read and accepted the terms and conditions for selling on this platform."))))),
|
|
34203
35337
|
sidebar: /* @__PURE__ */ React25__namespace.default.createElement(React25__namespace.default.Fragment, null, !create && /* @__PURE__ */ React25__namespace.default.createElement("section", null, /* @__PURE__ */ React25__namespace.default.createElement("h2", {
|
|
34204
35338
|
className: "text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2"
|
|
34205
35339
|
}, "Status"), /* @__PURE__ */ React25__namespace.default.createElement("div", {
|