@infuro/cms-core 1.0.31 → 1.0.33
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 +3 -2
- package/dist/admin.cjs +929 -345
- package/dist/admin.cjs.map +1 -1
- package/dist/admin.js +947 -362
- package/dist/admin.js.map +1 -1
- package/dist/api.cjs +839 -59
- package/dist/api.cjs.map +1 -1
- package/dist/api.d.cts +1 -1
- package/dist/api.d.ts +1 -1
- package/dist/api.js +833 -53
- package/dist/api.js.map +1 -1
- package/dist/auth.cjs +159 -14
- package/dist/auth.cjs.map +1 -1
- package/dist/auth.d.cts +37 -22
- package/dist/auth.d.ts +37 -22
- package/dist/auth.js +153 -14
- package/dist/auth.js.map +1 -1
- package/dist/cli.cjs +3 -2
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +3 -2
- package/dist/cli.js.map +1 -1
- package/dist/{index-Bda8D1Rm.d.ts → index-DWd5Gjc4.d.ts} +2 -2
- package/dist/{index-BcMRGNjS.d.cts → index-rZTnpK7y.d.cts} +2 -2
- package/dist/index.cjs +1141 -254
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +41 -30
- package/dist/index.d.ts +41 -30
- package/dist/index.js +1135 -254
- package/dist/index.js.map +1 -1
- package/dist/migrations/1778660000003-AddQrTokenToOrders.ts +32 -0
- package/dist/migrations/1779100000000-ChatConversationLeadEmailSent.ts +16 -0
- package/dist/migrations/1779200000000-LlmAgentScope.ts +72 -0
- package/package.json +2 -1
package/dist/admin.js
CHANGED
|
@@ -775,7 +775,7 @@ __export(ContactDetailPage_exports, {
|
|
|
775
775
|
import { useEffect as useEffect46, useState as useState49 } from "react";
|
|
776
776
|
import Link15 from "next/link";
|
|
777
777
|
import { useRouter as useRouter20, useSearchParams as useSearchParams19 } from "next/navigation";
|
|
778
|
-
import { Plus as Plus15, Trash2 as
|
|
778
|
+
import { Plus as Plus15, Trash2 as Trash215, X as X22 } from "lucide-react";
|
|
779
779
|
import { toast as toast11 } from "sonner";
|
|
780
780
|
import { Country as Country3, State as State3 } from "country-state-city";
|
|
781
781
|
import { Fragment as Fragment23, jsx as jsx82, jsxs as jsxs69 } from "react/jsx-runtime";
|
|
@@ -1023,7 +1023,7 @@ function ContactDetailPage({ contactId }) {
|
|
|
1023
1023
|
title: "Delete address",
|
|
1024
1024
|
"aria-label": `Delete address ${a.id}`,
|
|
1025
1025
|
onClick: () => setAddressPendingDelete(a),
|
|
1026
|
-
children: /* @__PURE__ */ jsx82(
|
|
1026
|
+
children: /* @__PURE__ */ jsx82(Trash215, { className: "h-4 w-4" })
|
|
1027
1027
|
}
|
|
1028
1028
|
) })
|
|
1029
1029
|
] }, a.id)) })
|
|
@@ -1542,7 +1542,7 @@ var defaultValue = {
|
|
|
1542
1542
|
var AdminConfigContext = createContext(defaultValue);
|
|
1543
1543
|
|
|
1544
1544
|
// src/lib/cms-version.ts
|
|
1545
|
-
var CMS_VERSION = true ? "1.0.
|
|
1545
|
+
var CMS_VERSION = true ? "1.0.33" : "0.0.0";
|
|
1546
1546
|
|
|
1547
1547
|
// src/components/Admin/Sidebar.tsx
|
|
1548
1548
|
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
@@ -2036,6 +2036,34 @@ var BUILTIN_PLUGIN_DESCRIPTORS = [
|
|
|
2036
2036
|
}
|
|
2037
2037
|
];
|
|
2038
2038
|
|
|
2039
|
+
// src/auth/auth-debug.ts
|
|
2040
|
+
var LOG_PREFIX = "[cms-auth]";
|
|
2041
|
+
function isAuthDebugClientEnabled() {
|
|
2042
|
+
if (typeof window === "undefined") return false;
|
|
2043
|
+
const v = process.env.NEXT_PUBLIC_CMS_AUTH_DEBUG?.trim().toLowerCase();
|
|
2044
|
+
if (v === "1" || v === "true" || v === "yes") return true;
|
|
2045
|
+
if (v === "0" || v === "false" || v === "no") return false;
|
|
2046
|
+
return process.env.NODE_ENV === "development";
|
|
2047
|
+
}
|
|
2048
|
+
function logAuthClient(message, data) {
|
|
2049
|
+
if (!isAuthDebugClientEnabled()) return;
|
|
2050
|
+
if (data) console.info(LOG_PREFIX, message, data);
|
|
2051
|
+
else console.info(LOG_PREFIX, message);
|
|
2052
|
+
}
|
|
2053
|
+
function summarizeSessionUserForLog(user) {
|
|
2054
|
+
if (!user || typeof user !== "object") return { present: false };
|
|
2055
|
+
const u = user;
|
|
2056
|
+
return {
|
|
2057
|
+
present: true,
|
|
2058
|
+
email: u.email ?? null,
|
|
2059
|
+
id: u.id ?? null,
|
|
2060
|
+
adminAccess: u.adminAccess ?? null,
|
|
2061
|
+
isRBACAdmin: u.isRBACAdmin ?? null,
|
|
2062
|
+
isVendorPortal: u.isVendorPortal ?? null,
|
|
2063
|
+
groupName: u.groupName ?? null
|
|
2064
|
+
};
|
|
2065
|
+
}
|
|
2066
|
+
|
|
2039
2067
|
// src/admin/pages/AdminLayout.tsx
|
|
2040
2068
|
import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
2041
2069
|
var PUBLIC_ADMIN_PATHS = [
|
|
@@ -2069,6 +2097,14 @@ function AdminLayoutInner({ children }) {
|
|
|
2069
2097
|
useEffect2(() => {
|
|
2070
2098
|
if (isMobile) setMoreSheetOpen(false);
|
|
2071
2099
|
}, [isMobile, pathname]);
|
|
2100
|
+
useEffect2(() => {
|
|
2101
|
+
logAuthClient("AdminLayout session state", {
|
|
2102
|
+
pathname,
|
|
2103
|
+
isPublicPath,
|
|
2104
|
+
status,
|
|
2105
|
+
sessionUser: summarizeSessionUserForLog(session?.user)
|
|
2106
|
+
});
|
|
2107
|
+
}, [pathname, isPublicPath, status, session?.user]);
|
|
2072
2108
|
useEffect2(() => {
|
|
2073
2109
|
if (isPublicPath) return;
|
|
2074
2110
|
if (status === "loading") {
|
|
@@ -2076,6 +2112,7 @@ function AdminLayoutInner({ children }) {
|
|
|
2076
2112
|
return () => clearTimeout(timeout);
|
|
2077
2113
|
}
|
|
2078
2114
|
if (status === "unauthenticated") {
|
|
2115
|
+
logAuthClient("AdminLayout redirect \u2192 /admin/signin (unauthenticated)", { pathname });
|
|
2079
2116
|
router.replace("/admin/signin");
|
|
2080
2117
|
} else {
|
|
2081
2118
|
setLoadingTimeout(false);
|
|
@@ -9043,7 +9080,9 @@ var SigninPage = () => {
|
|
|
9043
9080
|
const router = useRouter5();
|
|
9044
9081
|
const { status } = useSession5();
|
|
9045
9082
|
useEffect18(() => {
|
|
9083
|
+
logAuthClient("SignInPage session status", { status });
|
|
9046
9084
|
if (status === "authenticated") {
|
|
9085
|
+
logAuthClient("SignInPage redirect \u2192 /admin/dashboard (already authenticated)");
|
|
9047
9086
|
router.replace("/admin/dashboard");
|
|
9048
9087
|
}
|
|
9049
9088
|
}, [status, router]);
|
|
@@ -9052,14 +9091,22 @@ var SigninPage = () => {
|
|
|
9052
9091
|
setLoading(true);
|
|
9053
9092
|
setError("");
|
|
9054
9093
|
try {
|
|
9094
|
+
logAuthClient("SignInPage signIn start", { email });
|
|
9055
9095
|
const result = await signIn("credentials", {
|
|
9056
9096
|
email,
|
|
9057
9097
|
password,
|
|
9058
9098
|
redirect: false
|
|
9059
9099
|
});
|
|
9100
|
+
logAuthClient("SignInPage signIn result", {
|
|
9101
|
+
ok: result?.ok ?? null,
|
|
9102
|
+
error: result?.error ?? null,
|
|
9103
|
+
status: result?.status ?? null,
|
|
9104
|
+
url: result?.url ?? null
|
|
9105
|
+
});
|
|
9060
9106
|
if (result?.error) {
|
|
9061
9107
|
setError("Invalid email or password");
|
|
9062
9108
|
} else {
|
|
9109
|
+
logAuthClient("SignInPage navigate \u2192 /admin/dashboard");
|
|
9063
9110
|
window.location.assign("/admin/dashboard");
|
|
9064
9111
|
}
|
|
9065
9112
|
} catch (error2) {
|
|
@@ -10178,6 +10225,7 @@ import { useEffect as useEffect23, useState as useState26 } from "react";
|
|
|
10178
10225
|
import Link10 from "next/link";
|
|
10179
10226
|
import { useRouter as useRouter8, useSearchParams as useSearchParams5 } from "next/navigation";
|
|
10180
10227
|
import { X as X15, RefreshCw as RefreshCw2, Pencil } from "lucide-react";
|
|
10228
|
+
import { QRCode } from "react-qr-code";
|
|
10181
10229
|
import { Fragment as Fragment10, jsx as jsx52, jsxs as jsxs42 } from "react/jsx-runtime";
|
|
10182
10230
|
function formatMoney(amount, currency = "INR") {
|
|
10183
10231
|
return new Intl.NumberFormat("en-IN", {
|
|
@@ -10535,6 +10583,19 @@ function OrderDetailPage({ orderId }) {
|
|
|
10535
10583
|
},
|
|
10536
10584
|
p.id
|
|
10537
10585
|
)) })
|
|
10586
|
+
] }),
|
|
10587
|
+
order.qrToken && /* @__PURE__ */ jsxs42("section", { children: [
|
|
10588
|
+
/* @__PURE__ */ jsx52("h2", { className: "text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2", children: "Order QR Code" }),
|
|
10589
|
+
/* @__PURE__ */ jsxs42("div", { className: "min-w-0 border border-gray-200 rounded-lg p-4 bg-gray-50/50 flex flex-col items-center gap-2", children: [
|
|
10590
|
+
/* @__PURE__ */ jsx52(
|
|
10591
|
+
QRCode,
|
|
10592
|
+
{
|
|
10593
|
+
value: `${window.location.origin}/track/${order.qrToken}`,
|
|
10594
|
+
size: 180
|
|
10595
|
+
}
|
|
10596
|
+
),
|
|
10597
|
+
/* @__PURE__ */ jsx52("p", { className: "text-xs text-gray-400 break-all text-center", children: order.qrToken })
|
|
10598
|
+
] })
|
|
10538
10599
|
] })
|
|
10539
10600
|
] })
|
|
10540
10601
|
}
|
|
@@ -15183,6 +15244,7 @@ import {
|
|
|
15183
15244
|
Save as Save6,
|
|
15184
15245
|
X as X20,
|
|
15185
15246
|
Plus as Plus10,
|
|
15247
|
+
Trash2 as Trash29,
|
|
15186
15248
|
Smartphone,
|
|
15187
15249
|
Bot,
|
|
15188
15250
|
FileUp,
|
|
@@ -16131,6 +16193,155 @@ function serializeEmailRecipients(emails) {
|
|
|
16131
16193
|
init_button();
|
|
16132
16194
|
init_input();
|
|
16133
16195
|
import { toast as toast10 } from "sonner";
|
|
16196
|
+
|
|
16197
|
+
// src/plugins/llm/chat-email-intent.ts
|
|
16198
|
+
function normalizeIntentKey(raw) {
|
|
16199
|
+
return raw.trim().toUpperCase().replace(/[^A-Z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
16200
|
+
}
|
|
16201
|
+
function parseIntentsJson(raw) {
|
|
16202
|
+
if (!raw?.trim()) return null;
|
|
16203
|
+
try {
|
|
16204
|
+
const parsed = JSON.parse(raw);
|
|
16205
|
+
if (!Array.isArray(parsed)) return null;
|
|
16206
|
+
const out = [];
|
|
16207
|
+
for (const row of parsed) {
|
|
16208
|
+
if (!row || typeof row !== "object") continue;
|
|
16209
|
+
const o = row;
|
|
16210
|
+
const intent = normalizeIntentKey(String(o.intent ?? o.id ?? ""));
|
|
16211
|
+
const description = String(o.description ?? "").trim();
|
|
16212
|
+
const emailTo = String(o.emailTo ?? o.email ?? "").trim();
|
|
16213
|
+
if (!intent || !description || !emailTo) continue;
|
|
16214
|
+
out.push({ intent, description, emailTo });
|
|
16215
|
+
}
|
|
16216
|
+
return out.length > 0 ? out : null;
|
|
16217
|
+
} catch {
|
|
16218
|
+
return null;
|
|
16219
|
+
}
|
|
16220
|
+
}
|
|
16221
|
+
function dedupeIntents(intents) {
|
|
16222
|
+
const seen = /* @__PURE__ */ new Set();
|
|
16223
|
+
const out = [];
|
|
16224
|
+
for (const row of intents) {
|
|
16225
|
+
const key = normalizeIntentKey(row.intent);
|
|
16226
|
+
if (!key || seen.has(key)) continue;
|
|
16227
|
+
seen.add(key);
|
|
16228
|
+
out.push({
|
|
16229
|
+
intent: key,
|
|
16230
|
+
description: row.description.trim(),
|
|
16231
|
+
emailTo: row.emailTo.trim()
|
|
16232
|
+
});
|
|
16233
|
+
}
|
|
16234
|
+
return out;
|
|
16235
|
+
}
|
|
16236
|
+
function parseEmailIntentsFromSettings(raw) {
|
|
16237
|
+
return dedupeIntents(parseIntentsJson(raw) ?? []);
|
|
16238
|
+
}
|
|
16239
|
+
function serializeChatLeadIntents(intents) {
|
|
16240
|
+
return JSON.stringify(
|
|
16241
|
+
dedupeIntents(intents).map((r) => ({
|
|
16242
|
+
intent: r.intent,
|
|
16243
|
+
description: r.description,
|
|
16244
|
+
emailTo: r.emailTo
|
|
16245
|
+
}))
|
|
16246
|
+
);
|
|
16247
|
+
}
|
|
16248
|
+
var EMAIL_TOOL_VALIDATION_KEY = "emailTool";
|
|
16249
|
+
function parseEmailToolObject(raw) {
|
|
16250
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return null;
|
|
16251
|
+
const o = raw;
|
|
16252
|
+
const intentsRaw = o.intents;
|
|
16253
|
+
let intents;
|
|
16254
|
+
if (Array.isArray(intentsRaw)) {
|
|
16255
|
+
const parsed = parseIntentsJson(JSON.stringify(intentsRaw));
|
|
16256
|
+
if (parsed?.length) intents = parsed;
|
|
16257
|
+
}
|
|
16258
|
+
return {
|
|
16259
|
+
enabled: o.enabled === true,
|
|
16260
|
+
classifierInstructions: typeof o.classifierInstructions === "string" ? o.classifierInstructions.trim() : void 0,
|
|
16261
|
+
toolPrompt: typeof o.toolPrompt === "string" ? o.toolPrompt.trim() : void 0,
|
|
16262
|
+
intents
|
|
16263
|
+
};
|
|
16264
|
+
}
|
|
16265
|
+
function splitValidationRulesForAdmin(validationRulesText) {
|
|
16266
|
+
const raw = validationRulesText?.trim() ?? "";
|
|
16267
|
+
if (!raw) return { guardrailsJson: "", emailTool: null };
|
|
16268
|
+
try {
|
|
16269
|
+
const parsed = JSON.parse(raw);
|
|
16270
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
16271
|
+
return { guardrailsJson: raw, emailTool: null };
|
|
16272
|
+
}
|
|
16273
|
+
const emailTool = parseEmailToolObject(parsed[EMAIL_TOOL_VALIDATION_KEY]);
|
|
16274
|
+
const rest = { ...parsed };
|
|
16275
|
+
delete rest[EMAIL_TOOL_VALIDATION_KEY];
|
|
16276
|
+
const guardrailsJson = Object.keys(rest).length > 0 ? JSON.stringify(rest, null, 2) : "";
|
|
16277
|
+
return { guardrailsJson, emailTool };
|
|
16278
|
+
} catch {
|
|
16279
|
+
return { guardrailsJson: raw, emailTool: null };
|
|
16280
|
+
}
|
|
16281
|
+
}
|
|
16282
|
+
function mergeEmailToolIntoValidationRules(guardrailsJson, emailTool) {
|
|
16283
|
+
const intents = dedupeIntents(emailTool.intents);
|
|
16284
|
+
const hasEmail = intents.length > 0 || emailTool.classifierInstructions.trim() !== "" || emailTool.toolPrompt.trim() !== "";
|
|
16285
|
+
let base = {};
|
|
16286
|
+
const raw = guardrailsJson?.trim();
|
|
16287
|
+
if (raw) {
|
|
16288
|
+
try {
|
|
16289
|
+
const parsed = JSON.parse(raw);
|
|
16290
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
16291
|
+
base = { ...parsed };
|
|
16292
|
+
delete base[EMAIL_TOOL_VALIDATION_KEY];
|
|
16293
|
+
} else {
|
|
16294
|
+
return raw;
|
|
16295
|
+
}
|
|
16296
|
+
} catch {
|
|
16297
|
+
return raw;
|
|
16298
|
+
}
|
|
16299
|
+
}
|
|
16300
|
+
if (!hasEmail) {
|
|
16301
|
+
return Object.keys(base).length > 0 ? JSON.stringify(base, null, 2) : null;
|
|
16302
|
+
}
|
|
16303
|
+
base[EMAIL_TOOL_VALIDATION_KEY] = {
|
|
16304
|
+
enabled: true,
|
|
16305
|
+
classifierInstructions: emailTool.classifierInstructions.trim(),
|
|
16306
|
+
toolPrompt: emailTool.toolPrompt.trim(),
|
|
16307
|
+
intents: intents.map((r) => ({
|
|
16308
|
+
intent: r.intent,
|
|
16309
|
+
description: r.description,
|
|
16310
|
+
emailTo: r.emailTo
|
|
16311
|
+
}))
|
|
16312
|
+
};
|
|
16313
|
+
return JSON.stringify(base, null, 2);
|
|
16314
|
+
}
|
|
16315
|
+
|
|
16316
|
+
// src/plugins/llm/llm-agent-scope.ts
|
|
16317
|
+
var LLM_AGENT_SCOPE_CHATBOT = "chatbot";
|
|
16318
|
+
var LLM_AGENT_SCOPE_BLOG_CREATION = "blog_creation";
|
|
16319
|
+
var LLM_AGENT_SCOPE_SOCIAL_MEDIA_POST = "social_media_post";
|
|
16320
|
+
var LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT = "email_intent_chatbot";
|
|
16321
|
+
var LLM_AGENT_SCOPE_BLOG_METADATA = "blog_metadata";
|
|
16322
|
+
var LLM_AGENT_DEFAULT_SLUG_BY_SCOPE = {
|
|
16323
|
+
[LLM_AGENT_SCOPE_CHATBOT]: "site-chat-assistant",
|
|
16324
|
+
[LLM_AGENT_SCOPE_BLOG_CREATION]: "blog-generator",
|
|
16325
|
+
[LLM_AGENT_SCOPE_SOCIAL_MEDIA_POST]: "blog-generator-social",
|
|
16326
|
+
[LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT]: "email-intent-chatbot",
|
|
16327
|
+
[LLM_AGENT_SCOPE_BLOG_METADATA]: "blog-generator-metadata"
|
|
16328
|
+
};
|
|
16329
|
+
var LLM_AGENT_DEFAULT_NAME_BY_SCOPE = {
|
|
16330
|
+
[LLM_AGENT_SCOPE_CHATBOT]: "Site Chat Assistant",
|
|
16331
|
+
[LLM_AGENT_SCOPE_BLOG_CREATION]: "Blog Generator",
|
|
16332
|
+
[LLM_AGENT_SCOPE_SOCIAL_MEDIA_POST]: "Blog Generator (Social)",
|
|
16333
|
+
[LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT]: "Chat Lead Intent Classifier",
|
|
16334
|
+
[LLM_AGENT_SCOPE_BLOG_METADATA]: "Blog Generator (Metadata)"
|
|
16335
|
+
};
|
|
16336
|
+
var SITE_CHAT_ASSISTANT_SLUG = LLM_AGENT_DEFAULT_SLUG_BY_SCOPE[LLM_AGENT_SCOPE_CHATBOT];
|
|
16337
|
+
var SITE_CHAT_ASSISTANT_NAME = LLM_AGENT_DEFAULT_NAME_BY_SCOPE[LLM_AGENT_SCOPE_CHATBOT];
|
|
16338
|
+
var BLOG_LLM_AGENT_SLUGS = [
|
|
16339
|
+
LLM_AGENT_DEFAULT_SLUG_BY_SCOPE[LLM_AGENT_SCOPE_BLOG_CREATION],
|
|
16340
|
+
LLM_AGENT_DEFAULT_SLUG_BY_SCOPE[LLM_AGENT_SCOPE_BLOG_METADATA],
|
|
16341
|
+
LLM_AGENT_DEFAULT_SLUG_BY_SCOPE[LLM_AGENT_SCOPE_SOCIAL_MEDIA_POST]
|
|
16342
|
+
];
|
|
16343
|
+
|
|
16344
|
+
// src/admin/pages/PluginsPage.tsx
|
|
16134
16345
|
import { Fragment as Fragment16, jsx as jsx66, jsxs as jsxs55 } from "react/jsx-runtime";
|
|
16135
16346
|
function normalizeLinkedInOrganizations(payload) {
|
|
16136
16347
|
if (!payload || typeof payload !== "object") return [];
|
|
@@ -16170,10 +16381,6 @@ function normalizeFacebookGraphPages(graph) {
|
|
|
16170
16381
|
}
|
|
16171
16382
|
return out;
|
|
16172
16383
|
}
|
|
16173
|
-
function slugifyAgentKey(name) {
|
|
16174
|
-
const s = name.toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64);
|
|
16175
|
-
return s || "agent";
|
|
16176
|
-
}
|
|
16177
16384
|
function normalizeChatMode(raw) {
|
|
16178
16385
|
if (raw === "external" || raw === "llm") return raw;
|
|
16179
16386
|
return "whatsapp";
|
|
@@ -16312,6 +16519,8 @@ function PluginSettingsPanel({
|
|
|
16312
16519
|
descriptor,
|
|
16313
16520
|
onSaved
|
|
16314
16521
|
}) {
|
|
16522
|
+
const { pluginDescriptors = [] } = useContext7(AdminConfigContext);
|
|
16523
|
+
const emailPluginAvailable = pluginDescriptors.some((p) => p.name === "email" && p.enabled !== false);
|
|
16315
16524
|
const settingsGroup = descriptor.settingsGroup;
|
|
16316
16525
|
const isLlm = settingsGroup === "llm";
|
|
16317
16526
|
const isEmail = settingsGroup === "email";
|
|
@@ -16347,9 +16556,19 @@ function PluginSettingsPanel({
|
|
|
16347
16556
|
const [agentTemp, setAgentTemp] = useState37("");
|
|
16348
16557
|
const [agentMaxTokens, setAgentMaxTokens] = useState37("");
|
|
16349
16558
|
const [agentValidationJson, setAgentValidationJson] = useState37("");
|
|
16559
|
+
const [emailToolEnabled, setEmailToolEnabled] = useState37(false);
|
|
16560
|
+
const [emailIntents, setEmailIntents] = useState37([]);
|
|
16561
|
+
const [emailToolPrompt, setEmailToolPrompt] = useState37("");
|
|
16350
16562
|
const [agentLoading, setAgentLoading] = useState37(false);
|
|
16351
16563
|
const [agentSaving, setAgentSaving] = useState37(false);
|
|
16352
16564
|
const [agentProvisionError, setAgentProvisionError] = useState37(null);
|
|
16565
|
+
const [llmConfigTab, setLlmConfigTab] = useState37("chat");
|
|
16566
|
+
const [notifyEmailAgentId, setNotifyEmailAgentId] = useState37(null);
|
|
16567
|
+
const [notifyEmailName, setNotifyEmailName] = useState37("");
|
|
16568
|
+
const [notifyEmailSystem, setNotifyEmailSystem] = useState37("");
|
|
16569
|
+
const [notifyEmailLoading, setNotifyEmailLoading] = useState37(false);
|
|
16570
|
+
const [notifyEmailSaving, setNotifyEmailSaving] = useState37(false);
|
|
16571
|
+
const [notifyEmailProvisionError, setNotifyEmailProvisionError] = useState37(null);
|
|
16353
16572
|
const [kbCatalog, setKbCatalog] = useState37([]);
|
|
16354
16573
|
const [attachedAgentKnowledge, setAttachedAgentKnowledge] = useState37([]);
|
|
16355
16574
|
const [attachedKbLoading, setAttachedKbLoading] = useState37(false);
|
|
@@ -16571,7 +16790,12 @@ function PluginSettingsPanel({
|
|
|
16571
16790
|
setIconImageUrl(data.iconImageUrl ?? "");
|
|
16572
16791
|
setIconBackgroundColor(data.iconBackgroundColor ?? "#6366f1");
|
|
16573
16792
|
setHeaderColor(data.headerColor ?? "#6366f1");
|
|
16574
|
-
setAttachedAgentSlug(data.attachedAgentSlug ?? "");
|
|
16793
|
+
setAttachedAgentSlug((data.attachedAgentSlug ?? "").trim());
|
|
16794
|
+
setEmailToolEnabled(data.emailToolEnabled === "true");
|
|
16795
|
+
setEmailIntents(parseEmailIntentsFromSettings(data.emailIntents));
|
|
16796
|
+
const legacyClassifier = data.emailClassifierInstructions ?? [data.emailIntentPrompt, data.emailNegativeIntentPrompt].filter(Boolean).join("\n\n") ?? "";
|
|
16797
|
+
if (legacyClassifier) setNotifyEmailSystem(legacyClassifier);
|
|
16798
|
+
setEmailToolPrompt(data.emailToolPrompt ?? "");
|
|
16575
16799
|
}
|
|
16576
16800
|
if (isErp) {
|
|
16577
16801
|
setErpPipelineName(data.pipelineName ?? data.pipelineId ?? "");
|
|
@@ -16657,33 +16881,116 @@ function PluginSettingsPanel({
|
|
|
16657
16881
|
}).catch(() => setErpFormsCatalog([]));
|
|
16658
16882
|
}, [isErp, loading]);
|
|
16659
16883
|
const fetchLlmAgents = useCallback12(async () => {
|
|
16660
|
-
const res = await fetch(
|
|
16884
|
+
const res = await fetch(
|
|
16885
|
+
`/api/llm_agents?scope=${LLM_AGENT_SCOPE_CHATBOT}&limit=5&sortField=name&sortOrder=asc`
|
|
16886
|
+
);
|
|
16661
16887
|
if (!res.ok) {
|
|
16662
16888
|
setLlmAgents([]);
|
|
16889
|
+
setAgentId(null);
|
|
16663
16890
|
return;
|
|
16664
16891
|
}
|
|
16665
16892
|
const j = await res.json();
|
|
16666
|
-
const
|
|
16893
|
+
const chatRows = (j.data ?? []).filter(
|
|
16894
|
+
(r) => String(r.scope ?? "").trim() === LLM_AGENT_SCOPE_CHATBOT || String(r.slug ?? "").trim() === LLM_AGENT_DEFAULT_SLUG_BY_SCOPE[LLM_AGENT_SCOPE_CHATBOT]
|
|
16895
|
+
);
|
|
16896
|
+
const list = chatRows.map((r) => ({
|
|
16667
16897
|
id: r.id,
|
|
16668
16898
|
name: String(r.name ?? ""),
|
|
16669
16899
|
slug: String(r.slug ?? ""),
|
|
16900
|
+
scope: LLM_AGENT_SCOPE_CHATBOT,
|
|
16670
16901
|
enabled: r.enabled !== false
|
|
16671
16902
|
}));
|
|
16672
16903
|
setLlmAgents(list);
|
|
16673
16904
|
const pick = list.find((a) => a.enabled) ?? list[0];
|
|
16674
|
-
const fullRow =
|
|
16905
|
+
const fullRow = pick ? chatRows.find((r) => r.id === pick.id) : void 0;
|
|
16675
16906
|
if (pick && fullRow) {
|
|
16676
16907
|
setAgentId(pick.id);
|
|
16677
16908
|
setAgentName(pick.name);
|
|
16678
16909
|
setAgentSlug(pick.slug);
|
|
16910
|
+
setAttachedAgentSlug(pick.slug);
|
|
16679
16911
|
setAgentSystem(String(fullRow.systemInstruction ?? ""));
|
|
16680
16912
|
setAgentModel(String(fullRow.model ?? ""));
|
|
16681
16913
|
setAgentTemp(fullRow.temperature != null ? String(fullRow.temperature) : "");
|
|
16682
16914
|
setAgentMaxTokens(fullRow.maxTokens != null ? String(fullRow.maxTokens) : "");
|
|
16683
|
-
|
|
16684
|
-
|
|
16915
|
+
const { guardrailsJson } = splitValidationRulesForAdmin(fullRow.validationRules ?? null);
|
|
16916
|
+
setAgentValidationJson(guardrailsJson);
|
|
16917
|
+
} else {
|
|
16918
|
+
setAgentId(null);
|
|
16919
|
+
setAgentName(botName.trim() || LLM_AGENT_DEFAULT_NAME_BY_SCOPE[LLM_AGENT_SCOPE_CHATBOT]);
|
|
16920
|
+
setAgentSlug(LLM_AGENT_DEFAULT_SLUG_BY_SCOPE[LLM_AGENT_SCOPE_CHATBOT]);
|
|
16921
|
+
setAgentSystem("");
|
|
16922
|
+
setAgentModel("");
|
|
16923
|
+
setAgentTemp("");
|
|
16924
|
+
setAgentMaxTokens("");
|
|
16925
|
+
setAgentValidationJson("");
|
|
16926
|
+
}
|
|
16927
|
+
}, [botName]);
|
|
16928
|
+
const fetchNotifyEmailAgent = useCallback12(async () => {
|
|
16929
|
+
const res = await fetch(
|
|
16930
|
+
`/api/llm_agents?scope=${LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT}&limit=1&sortField=name&sortOrder=asc`
|
|
16931
|
+
);
|
|
16932
|
+
if (!res.ok) {
|
|
16933
|
+
setNotifyEmailAgentId(null);
|
|
16934
|
+
return;
|
|
16935
|
+
}
|
|
16936
|
+
const j = await res.json();
|
|
16937
|
+
const row = j.data?.find((r) => String(r.scope ?? "").trim() === LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT) ?? j.data?.find(
|
|
16938
|
+
(r) => String(r.slug ?? "").trim() === LLM_AGENT_DEFAULT_SLUG_BY_SCOPE[LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT]
|
|
16939
|
+
) ?? j.data?.[0];
|
|
16940
|
+
if (!row || String(row.scope ?? "").trim() !== LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT) {
|
|
16941
|
+
setNotifyEmailAgentId(null);
|
|
16942
|
+
setNotifyEmailName(LLM_AGENT_DEFAULT_NAME_BY_SCOPE[LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT]);
|
|
16943
|
+
setNotifyEmailSystem("");
|
|
16944
|
+
return;
|
|
16945
|
+
}
|
|
16946
|
+
setNotifyEmailAgentId(row.id);
|
|
16947
|
+
setNotifyEmailName(String(row.name ?? ""));
|
|
16948
|
+
setNotifyEmailSystem(String(row.systemInstruction ?? ""));
|
|
16949
|
+
const { emailTool } = splitValidationRulesForAdmin(row.validationRules ?? null);
|
|
16950
|
+
if (emailTool?.intents?.length) setEmailIntents(emailTool.intents);
|
|
16951
|
+
if (emailTool?.toolPrompt) setEmailToolPrompt(emailTool.toolPrompt);
|
|
16952
|
+
if (!row.systemInstruction?.trim() && emailTool?.classifierInstructions) {
|
|
16953
|
+
setNotifyEmailSystem(emailTool.classifierInstructions);
|
|
16685
16954
|
}
|
|
16686
16955
|
}, []);
|
|
16956
|
+
const bootstrapNotifyEmailAgent = useCallback12(async () => {
|
|
16957
|
+
setNotifyEmailProvisionError(null);
|
|
16958
|
+
const listRes = await fetch(
|
|
16959
|
+
`/api/llm_agents?scope=${LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT}&limit=1`
|
|
16960
|
+
);
|
|
16961
|
+
if (!listRes.ok) {
|
|
16962
|
+
const message = `Could not load notify email agent (HTTP ${listRes.status}).`;
|
|
16963
|
+
setNotifyEmailProvisionError(message);
|
|
16964
|
+
await fetchNotifyEmailAgent();
|
|
16965
|
+
return { ok: false, message };
|
|
16966
|
+
}
|
|
16967
|
+
const listJ = await listRes.json();
|
|
16968
|
+
const notifyRow = listJ.data?.find((a) => a.scope === LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT);
|
|
16969
|
+
if (notifyRow) {
|
|
16970
|
+
await fetchNotifyEmailAgent();
|
|
16971
|
+
return { ok: true };
|
|
16972
|
+
}
|
|
16973
|
+
const createRes = await fetch("/api/llm_agents", {
|
|
16974
|
+
method: "POST",
|
|
16975
|
+
headers: { "Content-Type": "application/json" },
|
|
16976
|
+
body: JSON.stringify({
|
|
16977
|
+
name: LLM_AGENT_DEFAULT_NAME_BY_SCOPE[LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT],
|
|
16978
|
+
slug: LLM_AGENT_DEFAULT_SLUG_BY_SCOPE[LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT],
|
|
16979
|
+
scope: LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT,
|
|
16980
|
+
systemInstruction: "",
|
|
16981
|
+
enabled: true
|
|
16982
|
+
})
|
|
16983
|
+
});
|
|
16984
|
+
if (!createRes.ok) {
|
|
16985
|
+
const errBody = await createRes.json().catch(() => ({}));
|
|
16986
|
+
const message = errBody.error ?? `Could not create notify email agent (HTTP ${createRes.status}).`;
|
|
16987
|
+
setNotifyEmailProvisionError(message);
|
|
16988
|
+
await fetchNotifyEmailAgent();
|
|
16989
|
+
return { ok: false, message };
|
|
16990
|
+
}
|
|
16991
|
+
await fetchNotifyEmailAgent();
|
|
16992
|
+
return { ok: true };
|
|
16993
|
+
}, [fetchNotifyEmailAgent]);
|
|
16687
16994
|
const fetchKbCatalog = useCallback12(async () => {
|
|
16688
16995
|
try {
|
|
16689
16996
|
const res = await fetch("/api/knowledge_base_documents?limit=300&sortField=name&sortOrder=asc");
|
|
@@ -16729,7 +17036,9 @@ function PluginSettingsPanel({
|
|
|
16729
17036
|
}, []);
|
|
16730
17037
|
const bootstrapLlmAgentForPlugins = useCallback12(async () => {
|
|
16731
17038
|
setAgentProvisionError(null);
|
|
16732
|
-
const listRes = await fetch(
|
|
17039
|
+
const listRes = await fetch(
|
|
17040
|
+
`/api/llm_agents?scope=${LLM_AGENT_SCOPE_CHATBOT}&limit=5&sortField=name&sortOrder=asc`
|
|
17041
|
+
);
|
|
16733
17042
|
if (!listRes.ok) {
|
|
16734
17043
|
const errBody = await listRes.json().catch(() => ({}));
|
|
16735
17044
|
const message = errBody.error ?? `Could not load agents (HTTP ${listRes.status}). Ensure your app uses the latest @infuro/cms-core and your admin user can read entity "llm_agents".`;
|
|
@@ -16738,16 +17047,25 @@ function PluginSettingsPanel({
|
|
|
16738
17047
|
return { ok: false, message };
|
|
16739
17048
|
}
|
|
16740
17049
|
const listJ = await listRes.json();
|
|
16741
|
-
|
|
17050
|
+
const chatRow = listJ.data?.find(
|
|
17051
|
+
(a) => String(a.scope ?? "").trim() === LLM_AGENT_SCOPE_CHATBOT || String(a.slug ?? "").trim() === LLM_AGENT_DEFAULT_SLUG_BY_SCOPE[LLM_AGENT_SCOPE_CHATBOT]
|
|
17052
|
+
);
|
|
17053
|
+
if (chatRow) {
|
|
16742
17054
|
await fetchLlmAgents();
|
|
16743
17055
|
return { ok: true };
|
|
16744
17056
|
}
|
|
16745
|
-
const defaultName = botName.trim() ||
|
|
16746
|
-
const defaultSlug =
|
|
17057
|
+
const defaultName = botName.trim() || LLM_AGENT_DEFAULT_NAME_BY_SCOPE[LLM_AGENT_SCOPE_CHATBOT];
|
|
17058
|
+
const defaultSlug = LLM_AGENT_DEFAULT_SLUG_BY_SCOPE[LLM_AGENT_SCOPE_CHATBOT];
|
|
16747
17059
|
const createRes = await fetch("/api/llm_agents", {
|
|
16748
17060
|
method: "POST",
|
|
16749
17061
|
headers: { "Content-Type": "application/json" },
|
|
16750
|
-
body: JSON.stringify({
|
|
17062
|
+
body: JSON.stringify({
|
|
17063
|
+
name: defaultName,
|
|
17064
|
+
slug: defaultSlug,
|
|
17065
|
+
scope: LLM_AGENT_SCOPE_CHATBOT,
|
|
17066
|
+
systemInstruction: "",
|
|
17067
|
+
enabled: true
|
|
17068
|
+
})
|
|
16751
17069
|
});
|
|
16752
17070
|
if (!createRes.ok) {
|
|
16753
17071
|
const errBody = await createRes.json().catch(() => ({}));
|
|
@@ -16773,11 +17091,7 @@ function PluginSettingsPanel({
|
|
|
16773
17091
|
}
|
|
16774
17092
|
};
|
|
16775
17093
|
const handleCreateAssistantFromForm = async () => {
|
|
16776
|
-
const name = agentName.trim() || botName.trim();
|
|
16777
|
-
if (!name) {
|
|
16778
|
-
toast10.error("Enter an assistant name");
|
|
16779
|
-
return;
|
|
16780
|
-
}
|
|
17094
|
+
const name = agentName.trim() || botName.trim() || LLM_AGENT_DEFAULT_NAME_BY_SCOPE[LLM_AGENT_SCOPE_CHATBOT];
|
|
16781
17095
|
const tempRaw = agentTemp.trim();
|
|
16782
17096
|
const maxRaw = agentMaxTokens.trim();
|
|
16783
17097
|
const temperature = tempRaw === "" ? null : Number(tempRaw);
|
|
@@ -16790,7 +17104,7 @@ function PluginSettingsPanel({
|
|
|
16790
17104
|
toast10.error("Max tokens must be a positive integer");
|
|
16791
17105
|
return;
|
|
16792
17106
|
}
|
|
16793
|
-
const slug =
|
|
17107
|
+
const slug = LLM_AGENT_DEFAULT_SLUG_BY_SCOPE[LLM_AGENT_SCOPE_CHATBOT];
|
|
16794
17108
|
setAgentSaving(true);
|
|
16795
17109
|
try {
|
|
16796
17110
|
const res = await fetch("/api/llm_agents", {
|
|
@@ -16799,6 +17113,7 @@ function PluginSettingsPanel({
|
|
|
16799
17113
|
body: JSON.stringify({
|
|
16800
17114
|
name,
|
|
16801
17115
|
slug,
|
|
17116
|
+
scope: LLM_AGENT_SCOPE_CHATBOT,
|
|
16802
17117
|
systemInstruction: agentSystem.trim(),
|
|
16803
17118
|
model: agentModel.trim() || null,
|
|
16804
17119
|
temperature,
|
|
@@ -16825,18 +17140,19 @@ function PluginSettingsPanel({
|
|
|
16825
17140
|
useEffect34(() => {
|
|
16826
17141
|
if (!isLlm || loading || chatMode !== "llm") return;
|
|
16827
17142
|
setAgentLoading(true);
|
|
17143
|
+
setNotifyEmailLoading(true);
|
|
16828
17144
|
void (async () => {
|
|
16829
17145
|
try {
|
|
16830
17146
|
await bootstrapLlmAgentForPlugins();
|
|
17147
|
+
await bootstrapNotifyEmailAgent();
|
|
17148
|
+
await fetchNotifyEmailAgent();
|
|
17149
|
+
await fetchKbCatalog();
|
|
16831
17150
|
} finally {
|
|
16832
17151
|
setAgentLoading(false);
|
|
17152
|
+
setNotifyEmailLoading(false);
|
|
16833
17153
|
}
|
|
16834
17154
|
})();
|
|
16835
|
-
}, [isLlm, loading, chatMode, bootstrapLlmAgentForPlugins]);
|
|
16836
|
-
useEffect34(() => {
|
|
16837
|
-
if (!isLlm || loading || chatMode !== "llm") return;
|
|
16838
|
-
void fetchKbCatalog();
|
|
16839
|
-
}, [isLlm, loading, chatMode, fetchKbCatalog]);
|
|
17155
|
+
}, [isLlm, loading, chatMode, bootstrapLlmAgentForPlugins, bootstrapNotifyEmailAgent, fetchNotifyEmailAgent, fetchKbCatalog]);
|
|
16840
17156
|
useEffect34(() => {
|
|
16841
17157
|
if (!isLlm || loading || chatMode !== "llm" || !attachedAgentSlug.trim()) {
|
|
16842
17158
|
setAttachedAgentKnowledge([]);
|
|
@@ -16927,7 +17243,13 @@ function PluginSettingsPanel({
|
|
|
16927
17243
|
payload.iconImageUrl = { value: iconImageUrl, type: "public" };
|
|
16928
17244
|
payload.iconBackgroundColor = { value: iconBackgroundColor, type: "public" };
|
|
16929
17245
|
payload.headerColor = { value: headerColor, type: "public" };
|
|
16930
|
-
payload.attachedAgentSlug = {
|
|
17246
|
+
payload.attachedAgentSlug = {
|
|
17247
|
+
value: agentSlug.trim() || attachedAgentSlug.trim() || LLM_AGENT_DEFAULT_SLUG_BY_SCOPE[LLM_AGENT_SCOPE_CHATBOT],
|
|
17248
|
+
type: "public"
|
|
17249
|
+
};
|
|
17250
|
+
payload.emailToolEnabled = { value: emailToolEnabled ? "true" : "false", type: "public" };
|
|
17251
|
+
payload.emailIntents = { value: serializeChatLeadIntents(emailIntents), type: "public" };
|
|
17252
|
+
payload.emailToolPrompt = { value: emailToolPrompt, type: "public" };
|
|
16931
17253
|
}
|
|
16932
17254
|
if (isEmail) {
|
|
16933
17255
|
payload.salesTeamEmails = { value: serializeEmailRecipients(salesTeamEmails), type: "public" };
|
|
@@ -16943,65 +17265,169 @@ function PluginSettingsPanel({
|
|
|
16943
17265
|
}
|
|
16944
17266
|
return payload;
|
|
16945
17267
|
};
|
|
16946
|
-
const
|
|
16947
|
-
|
|
16948
|
-
|
|
16949
|
-
|
|
16950
|
-
|
|
16951
|
-
|
|
16952
|
-
|
|
16953
|
-
|
|
16954
|
-
|
|
16955
|
-
}
|
|
17268
|
+
const savePluginSettings = async () => {
|
|
17269
|
+
const res = await fetch(`/api/settings/${settingsGroup}`, {
|
|
17270
|
+
method: "PUT",
|
|
17271
|
+
headers: { "Content-Type": "application/json" },
|
|
17272
|
+
body: JSON.stringify(buildPayload())
|
|
17273
|
+
});
|
|
17274
|
+
return res.ok;
|
|
17275
|
+
};
|
|
17276
|
+
const validateChatAgentNumbers = () => {
|
|
16956
17277
|
const tempRaw = agentTemp.trim();
|
|
16957
17278
|
const maxRaw = agentMaxTokens.trim();
|
|
16958
17279
|
const temperature = tempRaw === "" ? null : Number(tempRaw);
|
|
16959
17280
|
const maxTokens = maxRaw === "" ? null : parseInt(maxRaw, 10);
|
|
16960
17281
|
if (tempRaw !== "" && !Number.isFinite(temperature)) {
|
|
16961
17282
|
toast10.error("Temperature must be a number");
|
|
16962
|
-
return;
|
|
17283
|
+
return null;
|
|
16963
17284
|
}
|
|
16964
17285
|
if (maxRaw !== "" && (!Number.isFinite(maxTokens) || maxTokens < 1)) {
|
|
16965
17286
|
toast10.error("Max tokens must be a positive integer");
|
|
17287
|
+
return null;
|
|
17288
|
+
}
|
|
17289
|
+
return { temperature, maxTokens };
|
|
17290
|
+
};
|
|
17291
|
+
const persistChatAgent = async () => {
|
|
17292
|
+
if (!agentId) return false;
|
|
17293
|
+
const nums = validateChatAgentNumbers();
|
|
17294
|
+
if (!nums) return false;
|
|
17295
|
+
const name = agentName.trim() || botName.trim() || LLM_AGENT_DEFAULT_NAME_BY_SCOPE[LLM_AGENT_SCOPE_CHATBOT];
|
|
17296
|
+
const res = await fetch(`/api/llm_agents/${agentId}`, {
|
|
17297
|
+
method: "PUT",
|
|
17298
|
+
headers: { "Content-Type": "application/json" },
|
|
17299
|
+
body: JSON.stringify({
|
|
17300
|
+
name,
|
|
17301
|
+
systemInstruction: agentSystem.trim(),
|
|
17302
|
+
model: agentModel.trim() || null,
|
|
17303
|
+
temperature: nums.temperature,
|
|
17304
|
+
maxTokens: nums.maxTokens,
|
|
17305
|
+
validationRules: agentValidationJson.trim() || null,
|
|
17306
|
+
enabled: true
|
|
17307
|
+
})
|
|
17308
|
+
});
|
|
17309
|
+
if (!res.ok) return false;
|
|
17310
|
+
setAttachedAgentSlug(agentSlug);
|
|
17311
|
+
return true;
|
|
17312
|
+
};
|
|
17313
|
+
const persistNotifyEmailAgent = async (agentIdOverride) => {
|
|
17314
|
+
const id = agentIdOverride ?? notifyEmailAgentId;
|
|
17315
|
+
if (!id) return false;
|
|
17316
|
+
const validationRules = mergeEmailToolIntoValidationRules(null, {
|
|
17317
|
+
classifierInstructions: "",
|
|
17318
|
+
toolPrompt: emailToolPrompt,
|
|
17319
|
+
intents: emailIntents
|
|
17320
|
+
});
|
|
17321
|
+
const res = await fetch(`/api/llm_agents/${id}`, {
|
|
17322
|
+
method: "PUT",
|
|
17323
|
+
headers: { "Content-Type": "application/json" },
|
|
17324
|
+
body: JSON.stringify({
|
|
17325
|
+
name: notifyEmailName.trim() || LLM_AGENT_DEFAULT_NAME_BY_SCOPE[LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT],
|
|
17326
|
+
systemInstruction: notifyEmailSystem.trim(),
|
|
17327
|
+
validationRules,
|
|
17328
|
+
enabled: true
|
|
17329
|
+
})
|
|
17330
|
+
});
|
|
17331
|
+
return res.ok;
|
|
17332
|
+
};
|
|
17333
|
+
const saveLlmPluginSettingsOnly = async () => {
|
|
17334
|
+
const res = await fetch(`/api/settings/${settingsGroup}`, {
|
|
17335
|
+
method: "PUT",
|
|
17336
|
+
headers: { "Content-Type": "application/json" },
|
|
17337
|
+
body: JSON.stringify(buildPayload())
|
|
17338
|
+
});
|
|
17339
|
+
return res.ok;
|
|
17340
|
+
};
|
|
17341
|
+
const handleSaveLlmChatTab = async () => {
|
|
17342
|
+
if (!agentId) {
|
|
17343
|
+
toast10.error("Wait for the assistant to load, or click Create assistant");
|
|
16966
17344
|
return;
|
|
16967
17345
|
}
|
|
16968
|
-
|
|
17346
|
+
if (!validateChatAgentNumbers()) return;
|
|
17347
|
+
setSaving(true);
|
|
16969
17348
|
try {
|
|
16970
|
-
const
|
|
16971
|
-
|
|
16972
|
-
|
|
16973
|
-
|
|
16974
|
-
|
|
16975
|
-
|
|
16976
|
-
|
|
16977
|
-
|
|
16978
|
-
maxTokens,
|
|
16979
|
-
validationRules: agentValidationJson.trim() || null,
|
|
16980
|
-
enabled: true
|
|
16981
|
-
})
|
|
16982
|
-
});
|
|
16983
|
-
if (!res.ok) {
|
|
16984
|
-
const err = await res.json().catch(() => ({}));
|
|
16985
|
-
toast10.error(err.error || "Failed to update agent");
|
|
17349
|
+
const chatOk = await persistChatAgent();
|
|
17350
|
+
if (!chatOk) {
|
|
17351
|
+
toast10.error("Failed to save assistant");
|
|
17352
|
+
return;
|
|
17353
|
+
}
|
|
17354
|
+
const settingsOk = await saveLlmPluginSettingsOnly();
|
|
17355
|
+
if (!settingsOk) {
|
|
17356
|
+
toast10.error("Failed to save widget settings");
|
|
16986
17357
|
return;
|
|
16987
17358
|
}
|
|
16988
|
-
|
|
16989
|
-
toast10.success("Agent saved");
|
|
17359
|
+
toast10.success("Chat settings saved");
|
|
16990
17360
|
} catch {
|
|
16991
|
-
toast10.error("Failed to
|
|
17361
|
+
toast10.error("Failed to save");
|
|
16992
17362
|
} finally {
|
|
16993
|
-
|
|
17363
|
+
setSaving(false);
|
|
17364
|
+
}
|
|
17365
|
+
};
|
|
17366
|
+
const handleSaveLlmNotifyTab = async () => {
|
|
17367
|
+
if (!emailPluginAvailable) {
|
|
17368
|
+
toast10.error("Enable the Email plugin (SMTP) first");
|
|
17369
|
+
return;
|
|
17370
|
+
}
|
|
17371
|
+
const filledIntents = emailIntents.filter(
|
|
17372
|
+
(r) => r.intent.trim() && r.description.trim() && r.emailTo.trim()
|
|
17373
|
+
);
|
|
17374
|
+
if (filledIntents.length === 0) {
|
|
17375
|
+
toast10.error("Add at least one intent with Intent, Description, and Email To");
|
|
17376
|
+
return;
|
|
17377
|
+
}
|
|
17378
|
+
setEmailIntents(filledIntents);
|
|
17379
|
+
setNotifyEmailSaving(true);
|
|
17380
|
+
try {
|
|
17381
|
+
let notifyId = notifyEmailAgentId;
|
|
17382
|
+
if (!notifyId) {
|
|
17383
|
+
await bootstrapNotifyEmailAgent();
|
|
17384
|
+
const nr = await fetch(
|
|
17385
|
+
`/api/llm_agents?scope=${LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT}&limit=1`
|
|
17386
|
+
);
|
|
17387
|
+
if (nr.ok) {
|
|
17388
|
+
const nj = await nr.json();
|
|
17389
|
+
const row = nj.data?.find(
|
|
17390
|
+
(r) => String(r.scope ?? "").trim() === LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT
|
|
17391
|
+
);
|
|
17392
|
+
if (row) {
|
|
17393
|
+
notifyId = row.id;
|
|
17394
|
+
setNotifyEmailAgentId(row.id);
|
|
17395
|
+
}
|
|
17396
|
+
}
|
|
17397
|
+
}
|
|
17398
|
+
if (!notifyId) {
|
|
17399
|
+
toast10.error("Could not set up lead email \u2014 try again");
|
|
17400
|
+
return;
|
|
17401
|
+
}
|
|
17402
|
+
setEmailToolEnabled(true);
|
|
17403
|
+
const notifyOk = await persistNotifyEmailAgent(notifyId);
|
|
17404
|
+
if (!notifyOk) {
|
|
17405
|
+
toast10.error("Failed to save lead email settings");
|
|
17406
|
+
return;
|
|
17407
|
+
}
|
|
17408
|
+
const settingsOk = await saveLlmPluginSettingsOnly();
|
|
17409
|
+
if (!settingsOk) {
|
|
17410
|
+
toast10.warning("Routing saved, but enable flag failed to save in settings");
|
|
17411
|
+
return;
|
|
17412
|
+
}
|
|
17413
|
+
toast10.success("Lead email routing saved");
|
|
17414
|
+
await fetchNotifyEmailAgent();
|
|
17415
|
+
} catch {
|
|
17416
|
+
toast10.error("Failed to save");
|
|
17417
|
+
} finally {
|
|
17418
|
+
setNotifyEmailSaving(false);
|
|
16994
17419
|
}
|
|
16995
17420
|
};
|
|
16996
17421
|
const handleSave = async () => {
|
|
17422
|
+
if (isLlm && chatMode === "llm") {
|
|
17423
|
+
if (llmConfigTab === "notify") await handleSaveLlmNotifyTab();
|
|
17424
|
+
else await handleSaveLlmChatTab();
|
|
17425
|
+
return;
|
|
17426
|
+
}
|
|
16997
17427
|
setSaving(true);
|
|
16998
17428
|
try {
|
|
16999
|
-
const
|
|
17000
|
-
|
|
17001
|
-
headers: { "Content-Type": "application/json" },
|
|
17002
|
-
body: JSON.stringify(buildPayload())
|
|
17003
|
-
});
|
|
17004
|
-
if (!res.ok) throw new Error();
|
|
17429
|
+
const ok = await savePluginSettings();
|
|
17430
|
+
if (!ok) throw new Error();
|
|
17005
17431
|
if (isSocialMedia && (linkedinAccessToken.trim() || linkedinHasSavedToken)) {
|
|
17006
17432
|
if (linkedinAccessToken.trim()) {
|
|
17007
17433
|
setLinkedinHasSavedToken(true);
|
|
@@ -17923,328 +18349,458 @@ function PluginSettingsPanel({
|
|
|
17923
18349
|
/* @__PURE__ */ jsx66("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: "Only paste code from sources you trust." })
|
|
17924
18350
|
] }),
|
|
17925
18351
|
chatMode === "llm" && /* @__PURE__ */ jsxs55(Fragment16, { children: [
|
|
17926
|
-
/* @__PURE__ */ jsxs55("div", { className: "rounded-lg border border-gray-200 dark:border-gray-600
|
|
17927
|
-
/* @__PURE__ */ jsxs55(
|
|
17928
|
-
|
|
17929
|
-
|
|
17930
|
-
|
|
17931
|
-
|
|
17932
|
-
|
|
17933
|
-
|
|
17934
|
-
|
|
17935
|
-
|
|
17936
|
-
|
|
17937
|
-
|
|
17938
|
-
|
|
18352
|
+
/* @__PURE__ */ jsxs55("div", { className: "inline-flex rounded-lg border border-gray-200 bg-gray-50 p-0.5 dark:border-gray-600 dark:bg-gray-800/80", children: [
|
|
18353
|
+
/* @__PURE__ */ jsxs55(
|
|
18354
|
+
"button",
|
|
18355
|
+
{
|
|
18356
|
+
type: "button",
|
|
18357
|
+
className: `flex items-center gap-1.5 rounded-md px-3 py-1.5 text-xs font-medium transition-colors ${llmConfigTab === "chat" ? "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"}`,
|
|
18358
|
+
onClick: () => setLlmConfigTab("chat"),
|
|
18359
|
+
children: [
|
|
18360
|
+
/* @__PURE__ */ jsx66(MessageCircle, { className: "h-3.5 w-3.5 shrink-0" }),
|
|
18361
|
+
"Chat"
|
|
18362
|
+
]
|
|
18363
|
+
}
|
|
18364
|
+
),
|
|
18365
|
+
/* @__PURE__ */ jsxs55(
|
|
18366
|
+
"button",
|
|
18367
|
+
{
|
|
18368
|
+
type: "button",
|
|
18369
|
+
className: `flex items-center gap-1.5 rounded-md px-3 py-1.5 text-xs font-medium transition-colors ${llmConfigTab === "notify" ? "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"}`,
|
|
18370
|
+
onClick: () => setLlmConfigTab("notify"),
|
|
18371
|
+
children: [
|
|
18372
|
+
/* @__PURE__ */ jsx66(Mail2, { className: "h-3.5 w-3.5 shrink-0" }),
|
|
18373
|
+
"Notify"
|
|
18374
|
+
]
|
|
18375
|
+
}
|
|
18376
|
+
)
|
|
18377
|
+
] }),
|
|
18378
|
+
llmConfigTab === "chat" ? /* @__PURE__ */ jsxs55(Fragment16, { children: [
|
|
18379
|
+
/* @__PURE__ */ jsxs55("div", { className: "rounded-lg border border-gray-200 dark:border-gray-600 bg-white dark:bg-gray-900/40 p-3 space-y-3", children: [
|
|
18380
|
+
/* @__PURE__ */ jsx66("p", { className: "text-sm font-medium text-gray-900 dark:text-white", children: "Widget on your site" }),
|
|
18381
|
+
/* @__PURE__ */ jsx66("p", { className: "text-[11px] text-gray-500 dark:text-gray-400", children: "Title, icon, and colors visitors see on the chat bubble." }),
|
|
17939
18382
|
/* @__PURE__ */ jsxs55("div", { className: "space-y-1", children: [
|
|
17940
|
-
/* @__PURE__ */ jsx66(Label3, { htmlFor:
|
|
18383
|
+
/* @__PURE__ */ jsx66(Label3, { htmlFor: `${settingsGroup}-botName`, className: "text-sm", children: "Widget title" }),
|
|
17941
18384
|
/* @__PURE__ */ jsx66(
|
|
17942
18385
|
Input,
|
|
17943
18386
|
{
|
|
17944
|
-
id:
|
|
17945
|
-
value:
|
|
17946
|
-
onChange: (e) =>
|
|
18387
|
+
id: `${settingsGroup}-botName`,
|
|
18388
|
+
value: botName,
|
|
18389
|
+
onChange: (e) => setBotName(e.target.value),
|
|
17947
18390
|
placeholder: "e.g. JM Buddy",
|
|
17948
18391
|
className: "h-8 text-sm"
|
|
17949
18392
|
}
|
|
17950
18393
|
)
|
|
17951
18394
|
] }),
|
|
17952
18395
|
/* @__PURE__ */ jsxs55("div", { className: "space-y-1", children: [
|
|
17953
|
-
/* @__PURE__ */ jsx66(Label3, { htmlFor:
|
|
18396
|
+
/* @__PURE__ */ jsx66(Label3, { htmlFor: `${settingsGroup}-iconImageUrl`, className: "text-sm", children: "Icon image URL" }),
|
|
17954
18397
|
/* @__PURE__ */ jsx66(
|
|
17955
18398
|
Input,
|
|
17956
18399
|
{
|
|
17957
|
-
id:
|
|
17958
|
-
value:
|
|
17959
|
-
|
|
17960
|
-
|
|
18400
|
+
id: `${settingsGroup}-iconImageUrl`,
|
|
18401
|
+
value: iconImageUrl,
|
|
18402
|
+
onChange: (e) => setIconImageUrl(e.target.value),
|
|
18403
|
+
placeholder: "https://\u2026 or /images/chat-icon.png",
|
|
18404
|
+
className: "h-8 text-sm"
|
|
17961
18405
|
}
|
|
17962
18406
|
),
|
|
17963
|
-
/* @__PURE__ */ jsx66("p", { className: "text-
|
|
18407
|
+
/* @__PURE__ */ jsx66("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: "PNG or image URL. Leave empty to use emoji below." })
|
|
17964
18408
|
] }),
|
|
17965
18409
|
/* @__PURE__ */ jsxs55("div", { className: "space-y-1", children: [
|
|
17966
|
-
/* @__PURE__ */ jsx66(Label3, { htmlFor:
|
|
18410
|
+
/* @__PURE__ */ jsx66(Label3, { htmlFor: `${settingsGroup}-icon`, className: "text-sm", children: "Icon fallback (emoji)" }),
|
|
17967
18411
|
/* @__PURE__ */ jsx66(
|
|
17968
|
-
|
|
18412
|
+
Input,
|
|
17969
18413
|
{
|
|
17970
|
-
id:
|
|
17971
|
-
value:
|
|
17972
|
-
onChange: (e) =>
|
|
17973
|
-
|
|
17974
|
-
|
|
17975
|
-
className: "text-sm"
|
|
18414
|
+
id: `${settingsGroup}-icon`,
|
|
18415
|
+
value: icon,
|
|
18416
|
+
onChange: (e) => setIcon(e.target.value),
|
|
18417
|
+
placeholder: "e.g. \u{1F4AC}",
|
|
18418
|
+
className: "h-8 text-sm w-20"
|
|
17976
18419
|
}
|
|
17977
18420
|
)
|
|
17978
18421
|
] }),
|
|
17979
|
-
/* @__PURE__ */ jsxs55("div", { className: "
|
|
18422
|
+
/* @__PURE__ */ jsxs55("div", { className: "flex gap-4", children: [
|
|
18423
|
+
/* @__PURE__ */ jsxs55("div", { className: "space-y-1", children: [
|
|
18424
|
+
/* @__PURE__ */ jsx66(Label3, { htmlFor: `${settingsGroup}-iconBg`, className: "text-sm", children: "Icon background" }),
|
|
18425
|
+
/* @__PURE__ */ jsxs55("div", { className: "flex items-center gap-2", children: [
|
|
18426
|
+
/* @__PURE__ */ jsx66(
|
|
18427
|
+
"input",
|
|
18428
|
+
{
|
|
18429
|
+
type: "color",
|
|
18430
|
+
id: `${settingsGroup}-iconBg`,
|
|
18431
|
+
value: iconBackgroundColor,
|
|
18432
|
+
onChange: (e) => setIconBackgroundColor(e.target.value),
|
|
18433
|
+
className: "h-8 w-10 cursor-pointer rounded border border-gray-300 dark:border-gray-600"
|
|
18434
|
+
}
|
|
18435
|
+
),
|
|
18436
|
+
/* @__PURE__ */ jsx66(
|
|
18437
|
+
Input,
|
|
18438
|
+
{
|
|
18439
|
+
value: iconBackgroundColor,
|
|
18440
|
+
onChange: (e) => setIconBackgroundColor(e.target.value),
|
|
18441
|
+
className: "h-8 w-24 text-sm font-mono"
|
|
18442
|
+
}
|
|
18443
|
+
)
|
|
18444
|
+
] })
|
|
18445
|
+
] }),
|
|
18446
|
+
/* @__PURE__ */ jsxs55("div", { className: "space-y-1", children: [
|
|
18447
|
+
/* @__PURE__ */ jsx66(Label3, { htmlFor: `${settingsGroup}-headerColor`, className: "text-sm", children: "Header color" }),
|
|
18448
|
+
/* @__PURE__ */ jsxs55("div", { className: "flex items-center gap-2", children: [
|
|
18449
|
+
/* @__PURE__ */ jsx66(
|
|
18450
|
+
"input",
|
|
18451
|
+
{
|
|
18452
|
+
type: "color",
|
|
18453
|
+
id: `${settingsGroup}-headerColor`,
|
|
18454
|
+
value: headerColor,
|
|
18455
|
+
onChange: (e) => setHeaderColor(e.target.value),
|
|
18456
|
+
className: "h-8 w-10 cursor-pointer rounded border border-gray-300 dark:border-gray-600"
|
|
18457
|
+
}
|
|
18458
|
+
),
|
|
18459
|
+
/* @__PURE__ */ jsx66(
|
|
18460
|
+
Input,
|
|
18461
|
+
{
|
|
18462
|
+
value: headerColor,
|
|
18463
|
+
onChange: (e) => setHeaderColor(e.target.value),
|
|
18464
|
+
className: "h-8 w-24 text-sm font-mono"
|
|
18465
|
+
}
|
|
18466
|
+
)
|
|
18467
|
+
] })
|
|
18468
|
+
] })
|
|
18469
|
+
] })
|
|
18470
|
+
] }),
|
|
18471
|
+
/* @__PURE__ */ jsxs55("div", { className: "rounded-lg border border-gray-200 dark:border-gray-600 bg-gray-50/80 dark:bg-gray-800/40 p-3 space-y-4", children: [
|
|
18472
|
+
/* @__PURE__ */ jsxs55("div", { className: "space-y-1", children: [
|
|
18473
|
+
/* @__PURE__ */ jsxs55("div", { className: "flex items-center gap-2 text-sm font-medium text-gray-900 dark:text-white", children: [
|
|
18474
|
+
/* @__PURE__ */ jsx66(Bot, { className: "h-4 w-4" }),
|
|
18475
|
+
"Assistant"
|
|
18476
|
+
] }),
|
|
18477
|
+
/* @__PURE__ */ jsx66("p", { className: "text-[11px] text-gray-500 dark:text-gray-400", children: "Storefront assistant \u2014 model, instructions, and guardrails." })
|
|
18478
|
+
] }),
|
|
18479
|
+
agentLoading ? /* @__PURE__ */ jsxs55("div", { className: "flex items-center gap-2 text-sm text-gray-500", children: [
|
|
18480
|
+
/* @__PURE__ */ jsx66(Loader25, { className: "h-4 w-4 animate-spin" }),
|
|
18481
|
+
"Loading\u2026"
|
|
18482
|
+
] }) : /* @__PURE__ */ jsxs55(Fragment16, { children: [
|
|
18483
|
+
agentProvisionError ? /* @__PURE__ */ jsx66("p", { className: "rounded border border-amber-200 bg-amber-50 p-2 text-xs text-amber-900 dark:border-amber-800 dark:bg-amber-950/40 dark:text-amber-100", children: agentProvisionError }) : null,
|
|
17980
18484
|
/* @__PURE__ */ jsxs55("div", { className: "space-y-1", children: [
|
|
17981
|
-
/* @__PURE__ */ jsx66(Label3, { htmlFor: "agent-
|
|
18485
|
+
/* @__PURE__ */ jsx66(Label3, { htmlFor: "agent-system", className: "text-sm", children: "System instruction" }),
|
|
17982
18486
|
/* @__PURE__ */ jsx66(
|
|
17983
|
-
|
|
18487
|
+
Textarea,
|
|
17984
18488
|
{
|
|
17985
|
-
id: "agent-
|
|
17986
|
-
value:
|
|
17987
|
-
onChange: (e) =>
|
|
17988
|
-
|
|
17989
|
-
|
|
18489
|
+
id: "agent-system",
|
|
18490
|
+
value: agentSystem,
|
|
18491
|
+
onChange: (e) => setAgentSystem(e.target.value),
|
|
18492
|
+
rows: 5,
|
|
18493
|
+
placeholder: "How the model should behave\u2026",
|
|
18494
|
+
className: "text-sm"
|
|
17990
18495
|
}
|
|
17991
18496
|
)
|
|
17992
18497
|
] }),
|
|
18498
|
+
/* @__PURE__ */ jsxs55("div", { className: "grid grid-cols-2 gap-2", children: [
|
|
18499
|
+
/* @__PURE__ */ jsxs55("div", { className: "space-y-1", children: [
|
|
18500
|
+
/* @__PURE__ */ jsx66(Label3, { htmlFor: "agent-model", className: "text-sm", children: "Model (optional)" }),
|
|
18501
|
+
/* @__PURE__ */ jsx66(
|
|
18502
|
+
Input,
|
|
18503
|
+
{
|
|
18504
|
+
id: "agent-model",
|
|
18505
|
+
value: agentModel,
|
|
18506
|
+
onChange: (e) => setAgentModel(e.target.value),
|
|
18507
|
+
placeholder: "Gateway model id",
|
|
18508
|
+
className: "h-8 text-sm font-mono"
|
|
18509
|
+
}
|
|
18510
|
+
)
|
|
18511
|
+
] }),
|
|
18512
|
+
/* @__PURE__ */ jsxs55("div", { className: "space-y-1", children: [
|
|
18513
|
+
/* @__PURE__ */ jsx66(Label3, { htmlFor: "agent-temp", className: "text-sm", children: "Temperature" }),
|
|
18514
|
+
/* @__PURE__ */ jsx66(
|
|
18515
|
+
Input,
|
|
18516
|
+
{
|
|
18517
|
+
id: "agent-temp",
|
|
18518
|
+
value: agentTemp,
|
|
18519
|
+
onChange: (e) => setAgentTemp(e.target.value),
|
|
18520
|
+
placeholder: "e.g. 0.7",
|
|
18521
|
+
className: "h-8 text-sm"
|
|
18522
|
+
}
|
|
18523
|
+
)
|
|
18524
|
+
] })
|
|
18525
|
+
] }),
|
|
17993
18526
|
/* @__PURE__ */ jsxs55("div", { className: "space-y-1", children: [
|
|
17994
|
-
/* @__PURE__ */ jsx66(Label3, { htmlFor: "agent-
|
|
18527
|
+
/* @__PURE__ */ jsx66(Label3, { htmlFor: "agent-max", className: "text-sm", children: "Max tokens" }),
|
|
17995
18528
|
/* @__PURE__ */ jsx66(
|
|
17996
18529
|
Input,
|
|
17997
18530
|
{
|
|
17998
|
-
id: "agent-
|
|
17999
|
-
value:
|
|
18000
|
-
onChange: (e) =>
|
|
18001
|
-
placeholder: "e.g.
|
|
18531
|
+
id: "agent-max",
|
|
18532
|
+
value: agentMaxTokens,
|
|
18533
|
+
onChange: (e) => setAgentMaxTokens(e.target.value.replace(/\D/g, "")),
|
|
18534
|
+
placeholder: "e.g. 1024",
|
|
18002
18535
|
className: "h-8 text-sm"
|
|
18003
18536
|
}
|
|
18004
18537
|
)
|
|
18005
|
-
] })
|
|
18006
|
-
|
|
18007
|
-
|
|
18008
|
-
|
|
18009
|
-
|
|
18010
|
-
|
|
18011
|
-
|
|
18012
|
-
|
|
18013
|
-
|
|
18014
|
-
|
|
18015
|
-
|
|
18016
|
-
|
|
18017
|
-
|
|
18018
|
-
|
|
18538
|
+
] }),
|
|
18539
|
+
/* @__PURE__ */ jsxs55("div", { className: "space-y-1", children: [
|
|
18540
|
+
/* @__PURE__ */ jsx66(Label3, { htmlFor: "agent-validation", className: "text-sm", children: "Validation & output guardrails" }),
|
|
18541
|
+
/* @__PURE__ */ jsx66(
|
|
18542
|
+
Textarea,
|
|
18543
|
+
{
|
|
18544
|
+
id: "agent-validation",
|
|
18545
|
+
value: agentValidationJson,
|
|
18546
|
+
onChange: (e) => setAgentValidationJson(e.target.value),
|
|
18547
|
+
rows: 4,
|
|
18548
|
+
placeholder: 'Plain text or JSON: {"guardrails":"Never promise refunds.","maxUserChars":2000}',
|
|
18549
|
+
className: "text-xs font-mono"
|
|
18550
|
+
}
|
|
18551
|
+
)
|
|
18552
|
+
] }),
|
|
18553
|
+
!agentId ? /* @__PURE__ */ jsxs55("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
18554
|
+
/* @__PURE__ */ jsx66(
|
|
18555
|
+
Button,
|
|
18556
|
+
{
|
|
18557
|
+
type: "button",
|
|
18558
|
+
size: "sm",
|
|
18559
|
+
className: "gap-1",
|
|
18560
|
+
disabled: agentSaving,
|
|
18561
|
+
onClick: () => void handleCreateAssistantFromForm(),
|
|
18562
|
+
children: agentSaving ? /* @__PURE__ */ jsxs55("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
18563
|
+
/* @__PURE__ */ jsx66(Loader25, { className: "h-3.5 w-3.5 animate-spin" }),
|
|
18564
|
+
"Creating\u2026"
|
|
18565
|
+
] }) : /* @__PURE__ */ jsxs55(Fragment16, { children: [
|
|
18566
|
+
/* @__PURE__ */ jsx66(Bot, { className: "h-3.5 w-3.5" }),
|
|
18567
|
+
"Create assistant"
|
|
18568
|
+
] })
|
|
18569
|
+
}
|
|
18570
|
+
),
|
|
18571
|
+
/* @__PURE__ */ jsx66(
|
|
18572
|
+
Button,
|
|
18573
|
+
{
|
|
18574
|
+
type: "button",
|
|
18575
|
+
size: "sm",
|
|
18576
|
+
variant: "secondary",
|
|
18577
|
+
className: "gap-1",
|
|
18578
|
+
disabled: agentSaving || agentLoading,
|
|
18579
|
+
onClick: () => void handleRetryBootstrapAgent(),
|
|
18580
|
+
children: "Retry auto-setup"
|
|
18581
|
+
}
|
|
18582
|
+
)
|
|
18583
|
+
] }) : null
|
|
18019
18584
|
] }),
|
|
18585
|
+
agentId && agentSlug.trim() ? /* @__PURE__ */ jsxs55("div", { className: "rounded-md border border-dashed border-gray-300 dark:border-gray-600 bg-white/60 dark:bg-gray-900/30 p-3 space-y-3", children: [
|
|
18586
|
+
/* @__PURE__ */ jsxs55("div", { className: "flex items-center gap-2 text-xs font-medium text-gray-800 dark:text-gray-200", children: [
|
|
18587
|
+
/* @__PURE__ */ jsx66(FileUp, { className: "h-3.5 w-3.5 shrink-0" }),
|
|
18588
|
+
"Knowledge for this agent"
|
|
18589
|
+
] }),
|
|
18590
|
+
/* @__PURE__ */ jsx66("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: "Upload text (.txt, .md, .json) or PDF (.pdf), or link documents already in the knowledge base." }),
|
|
18591
|
+
attachedKbLoading ? /* @__PURE__ */ jsx66("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: "Loading linked documents\u2026" }) : attachedAgentKnowledge.length === 0 ? /* @__PURE__ */ jsx66("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: "No documents linked yet." }) : /* @__PURE__ */ jsx66("ul", { className: "max-h-32 space-y-1.5 overflow-y-auto", children: attachedAgentKnowledge.map((d) => /* @__PURE__ */ jsxs55("li", { className: "flex items-center justify-between gap-2 text-sm", children: [
|
|
18592
|
+
/* @__PURE__ */ jsx66("span", { className: "min-w-0 truncate", title: d.name, children: d.name }),
|
|
18593
|
+
/* @__PURE__ */ jsx66(
|
|
18594
|
+
Button,
|
|
18595
|
+
{
|
|
18596
|
+
type: "button",
|
|
18597
|
+
variant: "ghost",
|
|
18598
|
+
size: "sm",
|
|
18599
|
+
className: "h-7 shrink-0 text-xs text-red-600 hover:text-red-700 dark:text-red-400",
|
|
18600
|
+
onClick: () => void handleUnlinkKbDoc(d.id),
|
|
18601
|
+
children: "Remove"
|
|
18602
|
+
}
|
|
18603
|
+
)
|
|
18604
|
+
] }, d.id)) }),
|
|
18605
|
+
/* @__PURE__ */ jsxs55("div", { className: "min-w-[180px] space-y-1", children: [
|
|
18606
|
+
/* @__PURE__ */ jsx66(Label3, { className: "text-xs", children: "Upload file" }),
|
|
18607
|
+
/* @__PURE__ */ jsxs55("div", { className: "relative", children: [
|
|
18608
|
+
/* @__PURE__ */ jsx66(
|
|
18609
|
+
Input,
|
|
18610
|
+
{
|
|
18611
|
+
type: "file",
|
|
18612
|
+
accept: ".txt,.md,.json,.pdf,text/plain,text/markdown,application/json,application/pdf",
|
|
18613
|
+
disabled: uploadingAttachedKbFile || uploadingAttachedKbLink,
|
|
18614
|
+
className: "h-8 cursor-pointer text-xs disabled:opacity-60",
|
|
18615
|
+
onChange: onAttachedKbFileChange
|
|
18616
|
+
},
|
|
18617
|
+
attachedKbInputKey
|
|
18618
|
+
),
|
|
18619
|
+
uploadingAttachedKbFile ? /* @__PURE__ */ jsxs55(
|
|
18620
|
+
"div",
|
|
18621
|
+
{
|
|
18622
|
+
className: "pointer-events-none absolute inset-0 flex items-center justify-center gap-2 rounded-md bg-background/85 text-xs font-medium text-gray-700 dark:text-gray-200",
|
|
18623
|
+
"aria-live": "polite",
|
|
18624
|
+
children: [
|
|
18625
|
+
/* @__PURE__ */ jsx66(Loader25, { className: "h-4 w-4 shrink-0 animate-spin" }),
|
|
18626
|
+
"Saving & linking\u2026"
|
|
18627
|
+
]
|
|
18628
|
+
}
|
|
18629
|
+
) : null
|
|
18630
|
+
] }),
|
|
18631
|
+
/* @__PURE__ */ jsx66("p", { className: "text-[11px] text-gray-500 dark:text-gray-400", children: "Pick a file to upload immediately (chunking, embeddings if configured, then link to this agent)." })
|
|
18632
|
+
] }),
|
|
18633
|
+
/* @__PURE__ */ jsxs55("div", { className: "flex flex-wrap items-end gap-2", children: [
|
|
18634
|
+
/* @__PURE__ */ jsxs55("div", { className: "min-w-[200px] flex-1 space-y-1", children: [
|
|
18635
|
+
/* @__PURE__ */ jsx66(Label3, { className: "text-xs", children: "Attach existing document" }),
|
|
18636
|
+
/* @__PURE__ */ jsxs55(Select, { value: attachExistingDocId, onValueChange: setAttachExistingDocId, children: [
|
|
18637
|
+
/* @__PURE__ */ jsx66(SelectTrigger, { className: "h-8 text-xs", children: /* @__PURE__ */ jsx66(SelectValue, { placeholder: "Choose a document" }) }),
|
|
18638
|
+
/* @__PURE__ */ jsxs55(SelectContent, { children: [
|
|
18639
|
+
/* @__PURE__ */ jsx66(SelectItem, { value: "__none__", children: "\u2014 Select \u2014" }),
|
|
18640
|
+
kbCatalog.filter((d) => !attachedAgentKnowledge.some((a) => a.id === d.id)).map((d) => /* @__PURE__ */ jsx66(SelectItem, { value: String(d.id), children: d.name }, d.id))
|
|
18641
|
+
] })
|
|
18642
|
+
] })
|
|
18643
|
+
] }),
|
|
18644
|
+
/* @__PURE__ */ jsx66(
|
|
18645
|
+
Button,
|
|
18646
|
+
{
|
|
18647
|
+
type: "button",
|
|
18648
|
+
size: "sm",
|
|
18649
|
+
className: "h-8",
|
|
18650
|
+
disabled: uploadingAttachedKbFile || uploadingAttachedKbLink || attachExistingDocId === "__none__",
|
|
18651
|
+
onClick: () => void handleAttachExistingToAttached(),
|
|
18652
|
+
children: uploadingAttachedKbLink ? /* @__PURE__ */ jsxs55("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
18653
|
+
/* @__PURE__ */ jsx66(Loader25, { className: "h-3.5 w-3.5 animate-spin" }),
|
|
18654
|
+
"Linking\u2026"
|
|
18655
|
+
] }) : "Attach"
|
|
18656
|
+
}
|
|
18657
|
+
)
|
|
18658
|
+
] })
|
|
18659
|
+
] }) : null
|
|
18660
|
+
] }),
|
|
18661
|
+
/* @__PURE__ */ jsxs55(
|
|
18662
|
+
Button,
|
|
18663
|
+
{
|
|
18664
|
+
type: "button",
|
|
18665
|
+
size: "sm",
|
|
18666
|
+
onClick: () => void handleSaveLlmChatTab(),
|
|
18667
|
+
disabled: saving,
|
|
18668
|
+
className: "gap-1",
|
|
18669
|
+
children: [
|
|
18670
|
+
saving ? /* @__PURE__ */ jsx66(Loader25, { className: "h-3.5 w-3.5 animate-spin" }) : /* @__PURE__ */ jsx66(Save6, { className: "h-3.5 w-3.5" }),
|
|
18671
|
+
"Save"
|
|
18672
|
+
]
|
|
18673
|
+
}
|
|
18674
|
+
)
|
|
18675
|
+
] }) : /* @__PURE__ */ jsxs55("div", { className: "rounded-lg border border-gray-200 dark:border-gray-600 bg-gray-50/80 dark:bg-gray-800/40 p-3 space-y-4", children: [
|
|
18676
|
+
/* @__PURE__ */ jsxs55("div", { children: [
|
|
18677
|
+
/* @__PURE__ */ jsx66("p", { className: "text-sm font-medium text-gray-900 dark:text-white", children: "Lead email routing" }),
|
|
18678
|
+
/* @__PURE__ */ jsx66("p", { className: "mt-0.5 text-[11px] text-gray-500 dark:text-gray-400", children: "Routing instructions and intents. When a message matches, your team gets one email per conversation." })
|
|
18679
|
+
] }),
|
|
18680
|
+
!emailPluginAvailable ? /* @__PURE__ */ jsx66("p", { className: "rounded border border-amber-200 bg-amber-50/80 p-2 text-[11px] text-amber-700 dark:border-amber-800 dark:bg-amber-950/40 dark:text-amber-300", children: "Enable the Email plugin (SMTP) to send lead alert emails." }) : notifyEmailLoading ? /* @__PURE__ */ jsxs55("div", { className: "flex items-center gap-2 text-sm text-gray-500", children: [
|
|
18681
|
+
/* @__PURE__ */ jsx66(Loader25, { className: "h-4 w-4 animate-spin" }),
|
|
18682
|
+
"Loading\u2026"
|
|
18683
|
+
] }) : /* @__PURE__ */ jsxs55(Fragment16, { children: [
|
|
18684
|
+
notifyEmailProvisionError ? /* @__PURE__ */ jsx66("p", { className: "rounded border border-amber-200 bg-amber-50 p-2 text-xs text-amber-900 dark:border-amber-800 dark:bg-amber-950/40 dark:text-amber-100", children: notifyEmailProvisionError }) : null,
|
|
18020
18685
|
/* @__PURE__ */ jsxs55("div", { className: "space-y-1", children: [
|
|
18021
|
-
/* @__PURE__ */ jsx66(Label3, { htmlFor: "
|
|
18686
|
+
/* @__PURE__ */ jsx66(Label3, { htmlFor: "notify-email-system", className: "text-sm", children: "Routing instructions" }),
|
|
18022
18687
|
/* @__PURE__ */ jsx66(
|
|
18023
18688
|
Textarea,
|
|
18024
18689
|
{
|
|
18025
|
-
id: "
|
|
18026
|
-
value:
|
|
18027
|
-
onChange: (e) =>
|
|
18690
|
+
id: "notify-email-system",
|
|
18691
|
+
value: notifyEmailSystem,
|
|
18692
|
+
onChange: (e) => setNotifyEmailSystem(e.target.value),
|
|
18028
18693
|
rows: 4,
|
|
18029
|
-
placeholder:
|
|
18030
|
-
className: "text-
|
|
18031
|
-
}
|
|
18032
|
-
)
|
|
18033
|
-
] }),
|
|
18034
|
-
!agentId ? /* @__PURE__ */ jsxs55("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
18035
|
-
/* @__PURE__ */ jsx66(
|
|
18036
|
-
Button,
|
|
18037
|
-
{
|
|
18038
|
-
type: "button",
|
|
18039
|
-
size: "sm",
|
|
18040
|
-
className: "gap-1",
|
|
18041
|
-
disabled: agentSaving,
|
|
18042
|
-
onClick: () => void handleCreateAssistantFromForm(),
|
|
18043
|
-
children: agentSaving ? /* @__PURE__ */ jsxs55("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
18044
|
-
/* @__PURE__ */ jsx66(Loader25, { className: "h-3.5 w-3.5 animate-spin" }),
|
|
18045
|
-
"Creating\u2026"
|
|
18046
|
-
] }) : /* @__PURE__ */ jsxs55(Fragment16, { children: [
|
|
18047
|
-
/* @__PURE__ */ jsx66(Bot, { className: "h-3.5 w-3.5" }),
|
|
18048
|
-
"Create assistant"
|
|
18049
|
-
] })
|
|
18050
|
-
}
|
|
18051
|
-
),
|
|
18052
|
-
/* @__PURE__ */ jsx66(
|
|
18053
|
-
Button,
|
|
18054
|
-
{
|
|
18055
|
-
type: "button",
|
|
18056
|
-
size: "sm",
|
|
18057
|
-
variant: "secondary",
|
|
18058
|
-
className: "gap-1",
|
|
18059
|
-
disabled: agentSaving || agentLoading,
|
|
18060
|
-
onClick: () => void handleRetryBootstrapAgent(),
|
|
18061
|
-
children: "Retry auto-setup"
|
|
18694
|
+
placeholder: "When to treat a message as a lead, priority, when not to email\u2026",
|
|
18695
|
+
className: "text-sm"
|
|
18062
18696
|
}
|
|
18063
18697
|
)
|
|
18064
|
-
] }) : /* @__PURE__ */ jsx66(
|
|
18065
|
-
Button,
|
|
18066
|
-
{
|
|
18067
|
-
type: "button",
|
|
18068
|
-
size: "sm",
|
|
18069
|
-
className: "gap-1",
|
|
18070
|
-
disabled: agentSaving,
|
|
18071
|
-
onClick: () => void handleSaveAgent(),
|
|
18072
|
-
children: agentSaving ? /* @__PURE__ */ jsxs55("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
18073
|
-
/* @__PURE__ */ jsx66(Loader25, { className: "h-3.5 w-3.5 animate-spin" }),
|
|
18074
|
-
"Saving\u2026"
|
|
18075
|
-
] }) : /* @__PURE__ */ jsxs55(Fragment16, { children: [
|
|
18076
|
-
/* @__PURE__ */ jsx66(Save6, { className: "h-3.5 w-3.5" }),
|
|
18077
|
-
"Save assistant"
|
|
18078
|
-
] })
|
|
18079
|
-
}
|
|
18080
|
-
)
|
|
18081
|
-
] }),
|
|
18082
|
-
agentId && agentSlug.trim() ? /* @__PURE__ */ jsxs55("div", { className: "rounded-md border border-dashed border-gray-300 dark:border-gray-600 bg-white/60 dark:bg-gray-900/30 p-3 space-y-3", children: [
|
|
18083
|
-
/* @__PURE__ */ jsxs55("div", { className: "flex items-center gap-2 text-xs font-medium text-gray-800 dark:text-gray-200", children: [
|
|
18084
|
-
/* @__PURE__ */ jsx66(FileUp, { className: "h-3.5 w-3.5 shrink-0" }),
|
|
18085
|
-
"Knowledge for this agent"
|
|
18086
18698
|
] }),
|
|
18087
|
-
/* @__PURE__ */
|
|
18088
|
-
|
|
18089
|
-
|
|
18090
|
-
|
|
18091
|
-
|
|
18092
|
-
{
|
|
18093
|
-
type: "button",
|
|
18094
|
-
variant: "ghost",
|
|
18095
|
-
size: "sm",
|
|
18096
|
-
className: "h-7 shrink-0 text-xs text-red-600 hover:text-red-700 dark:text-red-400",
|
|
18097
|
-
onClick: () => void handleUnlinkKbDoc(d.id),
|
|
18098
|
-
children: "Remove"
|
|
18099
|
-
}
|
|
18100
|
-
)
|
|
18101
|
-
] }, d.id)) }),
|
|
18102
|
-
/* @__PURE__ */ jsxs55("div", { className: "min-w-[180px] space-y-1", children: [
|
|
18103
|
-
/* @__PURE__ */ jsx66(Label3, { className: "text-xs", children: "Upload file" }),
|
|
18104
|
-
/* @__PURE__ */ jsxs55("div", { className: "relative", children: [
|
|
18105
|
-
/* @__PURE__ */ jsx66(
|
|
18106
|
-
Input,
|
|
18107
|
-
{
|
|
18108
|
-
type: "file",
|
|
18109
|
-
accept: ".txt,.md,.json,.pdf,text/plain,text/markdown,application/json,application/pdf",
|
|
18110
|
-
disabled: uploadingAttachedKbFile || uploadingAttachedKbLink,
|
|
18111
|
-
className: "h-8 cursor-pointer text-xs disabled:opacity-60",
|
|
18112
|
-
onChange: onAttachedKbFileChange
|
|
18113
|
-
},
|
|
18114
|
-
attachedKbInputKey
|
|
18115
|
-
),
|
|
18116
|
-
uploadingAttachedKbFile ? /* @__PURE__ */ jsxs55(
|
|
18117
|
-
"div",
|
|
18699
|
+
/* @__PURE__ */ jsxs55("div", { className: "space-y-2", children: [
|
|
18700
|
+
/* @__PURE__ */ jsxs55("div", { className: "flex items-center justify-between gap-2", children: [
|
|
18701
|
+
/* @__PURE__ */ jsx66(Label3, { className: "text-sm", children: "Intents" }),
|
|
18702
|
+
/* @__PURE__ */ jsxs55(
|
|
18703
|
+
Button,
|
|
18118
18704
|
{
|
|
18119
|
-
|
|
18120
|
-
|
|
18705
|
+
type: "button",
|
|
18706
|
+
size: "sm",
|
|
18707
|
+
variant: "outline",
|
|
18708
|
+
className: "h-7 gap-1 text-xs",
|
|
18709
|
+
onClick: () => setEmailIntents((rows) => [
|
|
18710
|
+
...rows,
|
|
18711
|
+
{ intent: "", description: "", emailTo: "" }
|
|
18712
|
+
]),
|
|
18121
18713
|
children: [
|
|
18122
|
-
/* @__PURE__ */ jsx66(
|
|
18123
|
-
"
|
|
18714
|
+
/* @__PURE__ */ jsx66(Plus10, { className: "h-3 w-3" }),
|
|
18715
|
+
"Add intent"
|
|
18124
18716
|
]
|
|
18125
18717
|
}
|
|
18126
|
-
)
|
|
18718
|
+
)
|
|
18127
18719
|
] }),
|
|
18128
|
-
/* @__PURE__ */ jsx66("
|
|
18129
|
-
|
|
18130
|
-
|
|
18131
|
-
|
|
18132
|
-
|
|
18133
|
-
|
|
18134
|
-
|
|
18135
|
-
|
|
18136
|
-
|
|
18137
|
-
|
|
18138
|
-
|
|
18720
|
+
/* @__PURE__ */ jsx66("div", { className: "overflow-x-auto rounded border border-gray-200 dark:border-gray-600", children: /* @__PURE__ */ jsxs55("table", { className: "w-full text-xs", children: [
|
|
18721
|
+
/* @__PURE__ */ jsx66("thead", { children: /* @__PURE__ */ jsxs55("tr", { className: "bg-gray-100/80 text-left dark:bg-gray-900/60", children: [
|
|
18722
|
+
/* @__PURE__ */ jsx66("th", { className: "w-[28%] p-2 font-medium", children: "Intent" }),
|
|
18723
|
+
/* @__PURE__ */ jsx66("th", { className: "w-[42%] p-2 font-medium", children: "Description" }),
|
|
18724
|
+
/* @__PURE__ */ jsx66("th", { className: "w-[26%] p-2 font-medium", children: "Email To" }),
|
|
18725
|
+
/* @__PURE__ */ jsx66("th", { className: "w-8 p-2" })
|
|
18726
|
+
] }) }),
|
|
18727
|
+
/* @__PURE__ */ jsxs55("tbody", { children: [
|
|
18728
|
+
emailIntents.length === 0 ? /* @__PURE__ */ jsx66("tr", { children: /* @__PURE__ */ jsx66("td", { colSpan: 4, className: "p-4 text-center text-gray-500 dark:text-gray-400", children: "Add at least one intent, then Save." }) }) : null,
|
|
18729
|
+
emailIntents.map((row, idx) => /* @__PURE__ */ jsxs55("tr", { className: "border-t border-gray-200 dark:border-gray-700", children: [
|
|
18730
|
+
/* @__PURE__ */ jsx66("td", { className: "p-1.5 align-top", children: /* @__PURE__ */ jsx66(
|
|
18731
|
+
Input,
|
|
18732
|
+
{
|
|
18733
|
+
value: row.intent,
|
|
18734
|
+
onChange: (e) => {
|
|
18735
|
+
const v = e.target.value.toUpperCase().replace(/[^A-Z0-9_]/g, "");
|
|
18736
|
+
setEmailIntents(
|
|
18737
|
+
(rows) => rows.map((r, i) => i === idx ? { ...r, intent: v } : r)
|
|
18738
|
+
);
|
|
18739
|
+
},
|
|
18740
|
+
placeholder: "SALES_LEAD",
|
|
18741
|
+
className: "h-8 font-mono text-xs"
|
|
18742
|
+
}
|
|
18743
|
+
) }),
|
|
18744
|
+
/* @__PURE__ */ jsx66("td", { className: "p-1.5 align-top", children: /* @__PURE__ */ jsx66(
|
|
18745
|
+
Input,
|
|
18746
|
+
{
|
|
18747
|
+
value: row.description,
|
|
18748
|
+
onChange: (e) => setEmailIntents(
|
|
18749
|
+
(rows) => rows.map(
|
|
18750
|
+
(r, i) => i === idx ? { ...r, description: e.target.value } : r
|
|
18751
|
+
)
|
|
18752
|
+
),
|
|
18753
|
+
placeholder: "What this intent means",
|
|
18754
|
+
className: "h-8 text-xs"
|
|
18755
|
+
}
|
|
18756
|
+
) }),
|
|
18757
|
+
/* @__PURE__ */ jsx66("td", { className: "p-1.5 align-top", children: /* @__PURE__ */ jsx66(
|
|
18758
|
+
Input,
|
|
18759
|
+
{
|
|
18760
|
+
value: row.emailTo,
|
|
18761
|
+
onChange: (e) => setEmailIntents(
|
|
18762
|
+
(rows) => rows.map(
|
|
18763
|
+
(r, i) => i === idx ? { ...r, emailTo: e.target.value } : r
|
|
18764
|
+
)
|
|
18765
|
+
),
|
|
18766
|
+
placeholder: "team@company.com",
|
|
18767
|
+
className: "h-8 text-xs"
|
|
18768
|
+
}
|
|
18769
|
+
) }),
|
|
18770
|
+
/* @__PURE__ */ jsx66("td", { className: "p-1.5 align-top", children: /* @__PURE__ */ jsx66(
|
|
18771
|
+
Button,
|
|
18772
|
+
{
|
|
18773
|
+
type: "button",
|
|
18774
|
+
size: "icon",
|
|
18775
|
+
variant: "ghost",
|
|
18776
|
+
className: "h-8 w-8 text-red-600",
|
|
18777
|
+
onClick: () => setEmailIntents((rows) => rows.filter((_, i) => i !== idx)),
|
|
18778
|
+
"aria-label": "Remove intent",
|
|
18779
|
+
children: /* @__PURE__ */ jsx66(Trash29, { className: "h-3.5 w-3.5" })
|
|
18780
|
+
}
|
|
18781
|
+
) })
|
|
18782
|
+
] }, idx))
|
|
18139
18783
|
] })
|
|
18140
|
-
] })
|
|
18141
|
-
/* @__PURE__ */ jsx66(
|
|
18142
|
-
Button,
|
|
18143
|
-
{
|
|
18144
|
-
type: "button",
|
|
18145
|
-
size: "sm",
|
|
18146
|
-
className: "h-8",
|
|
18147
|
-
disabled: uploadingAttachedKbFile || uploadingAttachedKbLink || attachExistingDocId === "__none__",
|
|
18148
|
-
onClick: () => void handleAttachExistingToAttached(),
|
|
18149
|
-
children: uploadingAttachedKbLink ? /* @__PURE__ */ jsxs55("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
18150
|
-
/* @__PURE__ */ jsx66(Loader25, { className: "h-3.5 w-3.5 animate-spin" }),
|
|
18151
|
-
"Linking\u2026"
|
|
18152
|
-
] }) : "Attach"
|
|
18153
|
-
}
|
|
18154
|
-
)
|
|
18784
|
+
] }) })
|
|
18155
18785
|
] })
|
|
18156
|
-
] })
|
|
18157
|
-
|
|
18158
|
-
|
|
18159
|
-
/* @__PURE__ */ jsx66(Label3, { htmlFor: `${settingsGroup}-botName`, className: "text-sm", children: "Widget title" }),
|
|
18160
|
-
/* @__PURE__ */ jsx66(
|
|
18161
|
-
Input,
|
|
18162
|
-
{
|
|
18163
|
-
id: `${settingsGroup}-botName`,
|
|
18164
|
-
value: botName,
|
|
18165
|
-
onChange: (e) => setBotName(e.target.value),
|
|
18166
|
-
placeholder: "e.g. Support Bot",
|
|
18167
|
-
className: "h-8 text-sm"
|
|
18168
|
-
}
|
|
18169
|
-
)
|
|
18170
|
-
] }),
|
|
18171
|
-
/* @__PURE__ */ jsxs55("div", { className: "space-y-1", children: [
|
|
18172
|
-
/* @__PURE__ */ jsx66(Label3, { htmlFor: `${settingsGroup}-iconImageUrl`, className: "text-sm", children: "Icon image URL" }),
|
|
18173
|
-
/* @__PURE__ */ jsx66(
|
|
18174
|
-
Input,
|
|
18175
|
-
{
|
|
18176
|
-
id: `${settingsGroup}-iconImageUrl`,
|
|
18177
|
-
value: iconImageUrl,
|
|
18178
|
-
onChange: (e) => setIconImageUrl(e.target.value),
|
|
18179
|
-
placeholder: "https://\u2026 or /images/chat-icon.png",
|
|
18180
|
-
className: "h-8 text-sm"
|
|
18181
|
-
}
|
|
18182
|
-
),
|
|
18183
|
-
/* @__PURE__ */ jsx66("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: "PNG or image URL. Leave empty to use emoji below." })
|
|
18184
|
-
] }),
|
|
18185
|
-
/* @__PURE__ */ jsxs55("div", { className: "space-y-1", children: [
|
|
18186
|
-
/* @__PURE__ */ jsx66(Label3, { htmlFor: `${settingsGroup}-icon`, className: "text-sm", children: "Icon fallback (emoji)" }),
|
|
18187
|
-
/* @__PURE__ */ jsx66(
|
|
18188
|
-
Input,
|
|
18786
|
+
] }),
|
|
18787
|
+
/* @__PURE__ */ jsxs55(
|
|
18788
|
+
Button,
|
|
18189
18789
|
{
|
|
18190
|
-
|
|
18191
|
-
|
|
18192
|
-
|
|
18193
|
-
|
|
18194
|
-
className: "
|
|
18790
|
+
type: "button",
|
|
18791
|
+
size: "sm",
|
|
18792
|
+
onClick: () => void handleSaveLlmNotifyTab(),
|
|
18793
|
+
disabled: notifyEmailSaving || !emailPluginAvailable,
|
|
18794
|
+
className: "gap-1",
|
|
18795
|
+
children: [
|
|
18796
|
+
notifyEmailSaving ? /* @__PURE__ */ jsx66(Loader25, { className: "h-3.5 w-3.5 animate-spin" }) : /* @__PURE__ */ jsx66(Save6, { className: "h-3.5 w-3.5" }),
|
|
18797
|
+
"Save"
|
|
18798
|
+
]
|
|
18195
18799
|
}
|
|
18196
18800
|
)
|
|
18197
|
-
] }),
|
|
18198
|
-
/* @__PURE__ */ jsxs55("div", { className: "flex gap-4", children: [
|
|
18199
|
-
/* @__PURE__ */ jsxs55("div", { className: "space-y-1", children: [
|
|
18200
|
-
/* @__PURE__ */ jsx66(Label3, { htmlFor: `${settingsGroup}-iconBg`, className: "text-sm", children: "Icon background" }),
|
|
18201
|
-
/* @__PURE__ */ jsxs55("div", { className: "flex items-center gap-2", children: [
|
|
18202
|
-
/* @__PURE__ */ jsx66(
|
|
18203
|
-
"input",
|
|
18204
|
-
{
|
|
18205
|
-
type: "color",
|
|
18206
|
-
id: `${settingsGroup}-iconBg`,
|
|
18207
|
-
value: iconBackgroundColor,
|
|
18208
|
-
onChange: (e) => setIconBackgroundColor(e.target.value),
|
|
18209
|
-
className: "h-8 w-10 cursor-pointer rounded border border-gray-300 dark:border-gray-600"
|
|
18210
|
-
}
|
|
18211
|
-
),
|
|
18212
|
-
/* @__PURE__ */ jsx66(
|
|
18213
|
-
Input,
|
|
18214
|
-
{
|
|
18215
|
-
value: iconBackgroundColor,
|
|
18216
|
-
onChange: (e) => setIconBackgroundColor(e.target.value),
|
|
18217
|
-
className: "h-8 w-24 text-sm font-mono"
|
|
18218
|
-
}
|
|
18219
|
-
)
|
|
18220
|
-
] })
|
|
18221
|
-
] }),
|
|
18222
|
-
/* @__PURE__ */ jsxs55("div", { className: "space-y-1", children: [
|
|
18223
|
-
/* @__PURE__ */ jsx66(Label3, { htmlFor: `${settingsGroup}-headerColor`, className: "text-sm", children: "Header color" }),
|
|
18224
|
-
/* @__PURE__ */ jsxs55("div", { className: "flex items-center gap-2", children: [
|
|
18225
|
-
/* @__PURE__ */ jsx66(
|
|
18226
|
-
"input",
|
|
18227
|
-
{
|
|
18228
|
-
type: "color",
|
|
18229
|
-
id: `${settingsGroup}-headerColor`,
|
|
18230
|
-
value: headerColor,
|
|
18231
|
-
onChange: (e) => setHeaderColor(e.target.value),
|
|
18232
|
-
className: "h-8 w-10 cursor-pointer rounded border border-gray-300 dark:border-gray-600"
|
|
18233
|
-
}
|
|
18234
|
-
),
|
|
18235
|
-
/* @__PURE__ */ jsx66(
|
|
18236
|
-
Input,
|
|
18237
|
-
{
|
|
18238
|
-
value: headerColor,
|
|
18239
|
-
onChange: (e) => setHeaderColor(e.target.value),
|
|
18240
|
-
className: "h-8 w-24 text-sm font-mono"
|
|
18241
|
-
}
|
|
18242
|
-
)
|
|
18243
|
-
] })
|
|
18244
|
-
] })
|
|
18245
18801
|
] })
|
|
18246
18802
|
] }),
|
|
18247
|
-
/* @__PURE__ */ jsxs55(Button, { size: "sm", onClick: handleSave, disabled: saving, className: "gap-1", children: [
|
|
18803
|
+
chatMode !== "llm" && /* @__PURE__ */ jsxs55(Button, { size: "sm", onClick: handleSave, disabled: saving, className: "gap-1", children: [
|
|
18248
18804
|
/* @__PURE__ */ jsx66(Save6, { className: "h-3.5 w-3.5" }),
|
|
18249
18805
|
"Save"
|
|
18250
18806
|
] })
|
|
@@ -18747,7 +19303,7 @@ function BrandEditPage({ brandId }) {
|
|
|
18747
19303
|
init_admin_list_return_url();
|
|
18748
19304
|
import { useState as useState40, useEffect as useEffect37, useMemo as useMemo8, useContext as useContext8 } from "react";
|
|
18749
19305
|
import { useRouter as useRouter15, useSearchParams as useSearchParams15 } from "next/navigation";
|
|
18750
|
-
import { AlertCircle as AlertCircle7, Plus as Plus11, Trash2 as
|
|
19306
|
+
import { AlertCircle as AlertCircle7, Plus as Plus11, Trash2 as Trash210, Star, Save as Save8 } from "lucide-react";
|
|
18751
19307
|
init_DetailPageLayout();
|
|
18752
19308
|
init_DetailPageHeader();
|
|
18753
19309
|
|
|
@@ -19211,12 +19767,10 @@ function ProductEditPage({ productId }) {
|
|
|
19211
19767
|
setSaving(true);
|
|
19212
19768
|
try {
|
|
19213
19769
|
const activeCurrency = String(currency || "INR");
|
|
19214
|
-
console.log("DEBUG save:", { activeCurrency, price, compareAtPrice });
|
|
19215
19770
|
let saveRate = 1;
|
|
19216
19771
|
if (activeCurrency !== "INR") {
|
|
19217
19772
|
const displayRate = await fetchDisplayRate(activeCurrency);
|
|
19218
19773
|
saveRate = displayRate !== 0 && displayRate !== 1 ? 1 / displayRate : 1;
|
|
19219
|
-
console.log("DEBUG rate:", { displayRate, saveRate, priceInBase: Math.round(Number(price) * saveRate * 100) / 100 });
|
|
19220
19774
|
}
|
|
19221
19775
|
const priceInBase = Math.round(Number(price) * saveRate * 100) / 100;
|
|
19222
19776
|
const compareAtPriceInBase = compareAtPrice ? Math.round(Number(compareAtPrice) * saveRate * 100) / 100 : null;
|
|
@@ -19623,7 +20177,7 @@ function ProductEditPage({ productId }) {
|
|
|
19623
20177
|
type: "button",
|
|
19624
20178
|
onClick: () => removeTaxRow(i),
|
|
19625
20179
|
className: "p-2 text-gray-400 hover:text-red-600 rounded shrink-0 mb-0.5",
|
|
19626
|
-
children: /* @__PURE__ */ jsx70(
|
|
20180
|
+
children: /* @__PURE__ */ jsx70(Trash210, { className: "h-4 w-4" })
|
|
19627
20181
|
}
|
|
19628
20182
|
)
|
|
19629
20183
|
] }, i);
|
|
@@ -19665,7 +20219,7 @@ function ProductEditPage({ productId }) {
|
|
|
19665
20219
|
className: `${inputCls} flex-1 min-w-[120px]`
|
|
19666
20220
|
}
|
|
19667
20221
|
),
|
|
19668
|
-
/* @__PURE__ */ jsx70("button", { type: "button", onClick: () => removeFacet(i), className: "p-2 text-gray-400 hover:text-red-600 rounded shrink-0 mt-0.5", children: /* @__PURE__ */ jsx70(
|
|
20222
|
+
/* @__PURE__ */ jsx70("button", { type: "button", onClick: () => removeFacet(i), className: "p-2 text-gray-400 hover:text-red-600 rounded shrink-0 mt-0.5", children: /* @__PURE__ */ jsx70(Trash210, { className: "h-4 w-4" }) })
|
|
19669
20223
|
] }, i)),
|
|
19670
20224
|
/* @__PURE__ */ jsxs59("button", { type: "button", onClick: addFacet, className: "inline-flex items-center gap-1 rounded border border-gray-300 bg-white px-2 py-1.5 text-xs font-medium text-gray-700 hover:bg-gray-50", children: [
|
|
19671
20225
|
/* @__PURE__ */ jsx70(Plus11, { className: "h-3.5 w-3.5" }),
|
|
@@ -19712,7 +20266,7 @@ function ProductEditPage({ productId }) {
|
|
|
19712
20266
|
children: /* @__PURE__ */ jsx70(Star, { className: `h-4 w-4 ${row.isDefault ? "fill-amber-400 text-amber-500" : "text-gray-400"}` })
|
|
19713
20267
|
}
|
|
19714
20268
|
),
|
|
19715
|
-
/* @__PURE__ */ jsx70("button", { type: "button", onClick: () => removeImage(i), className: "mt-6 p-2 text-gray-400 hover:text-red-600 rounded", children: /* @__PURE__ */ jsx70(
|
|
20269
|
+
/* @__PURE__ */ jsx70("button", { type: "button", onClick: () => removeImage(i), className: "mt-6 p-2 text-gray-400 hover:text-red-600 rounded", children: /* @__PURE__ */ jsx70(Trash210, { className: "h-4 w-4" }) })
|
|
19716
20270
|
] }, i)),
|
|
19717
20271
|
/* @__PURE__ */ jsxs59("button", { type: "button", onClick: addImage, className: "inline-flex items-center gap-1 rounded border border-gray-300 bg-white px-2 py-1.5 text-xs font-medium text-gray-700 hover:bg-gray-50", children: [
|
|
19718
20272
|
/* @__PURE__ */ jsx70(Plus11, { className: "h-3.5 w-3.5" }),
|
|
@@ -19757,7 +20311,7 @@ function ProductEditPage({ productId }) {
|
|
|
19757
20311
|
className: `${inputCls} flex-1`
|
|
19758
20312
|
}
|
|
19759
20313
|
),
|
|
19760
|
-
/* @__PURE__ */ jsx70("button", { type: "button", onClick: () => removeSpec(i), className: "p-2 text-gray-400 hover:text-red-600 rounded shrink-0", children: /* @__PURE__ */ jsx70(
|
|
20314
|
+
/* @__PURE__ */ jsx70("button", { type: "button", onClick: () => removeSpec(i), className: "p-2 text-gray-400 hover:text-red-600 rounded shrink-0", children: /* @__PURE__ */ jsx70(Trash210, { className: "h-4 w-4" }) })
|
|
19761
20315
|
] }, i)),
|
|
19762
20316
|
/* @__PURE__ */ jsxs59("button", { type: "button", onClick: addSpec, className: "inline-flex items-center gap-1 rounded border border-gray-300 bg-white px-2 py-1.5 text-xs font-medium text-gray-700 hover:bg-gray-50", children: [
|
|
19763
20317
|
/* @__PURE__ */ jsx70(Plus11, { className: "h-3.5 w-3.5" }),
|
|
@@ -19779,7 +20333,7 @@ function ProductEditPage({ productId }) {
|
|
|
19779
20333
|
init_admin_list_return_url();
|
|
19780
20334
|
import { useState as useState41, useEffect as useEffect38 } from "react";
|
|
19781
20335
|
import { useRouter as useRouter16, useSearchParams as useSearchParams16 } from "next/navigation";
|
|
19782
|
-
import { AlertCircle as AlertCircle8, Plus as Plus12, Trash2 as
|
|
20336
|
+
import { AlertCircle as AlertCircle8, Plus as Plus12, Trash2 as Trash211, ChevronDown as ChevronDown6, ChevronUp as ChevronUp2, Save as Save9, Power as Power2 } from "lucide-react";
|
|
19783
20337
|
init_DetailPageLayout();
|
|
19784
20338
|
init_DetailPageHeader();
|
|
19785
20339
|
import { Fragment as Fragment19, jsx as jsx71, jsxs as jsxs60 } from "react/jsx-runtime";
|
|
@@ -20106,7 +20660,7 @@ function CollectionEditPage({ collectionId }) {
|
|
|
20106
20660
|
/* @__PURE__ */ jsx71("option", { value: "video", children: "Video" })
|
|
20107
20661
|
] }),
|
|
20108
20662
|
/* @__PURE__ */ jsx71("input", { type: "text", value: slide.caption, onChange: (e) => updateHeroSlide(i, "caption", e.target.value), placeholder: "Caption", className: `${inputCls2} flex-1 min-w-[120px]` }),
|
|
20109
|
-
/* @__PURE__ */ jsx71("button", { type: "button", onClick: () => removeHeroSlide(i), className: "p-2 text-gray-400 hover:text-red-600 rounded shrink-0", children: /* @__PURE__ */ jsx71(
|
|
20663
|
+
/* @__PURE__ */ jsx71("button", { type: "button", onClick: () => removeHeroSlide(i), className: "p-2 text-gray-400 hover:text-red-600 rounded shrink-0", children: /* @__PURE__ */ jsx71(Trash211, { className: "h-4 w-4" }) })
|
|
20110
20664
|
] }, i)),
|
|
20111
20665
|
/* @__PURE__ */ jsxs60("button", { type: "button", onClick: addHeroSlide, className: "inline-flex items-center gap-1 rounded border border-gray-300 bg-white px-2 py-1.5 text-xs font-medium text-gray-700 hover:bg-gray-50", children: [
|
|
20112
20666
|
/* @__PURE__ */ jsx71(Plus12, { className: "h-3.5 w-3.5" }),
|
|
@@ -20119,12 +20673,12 @@ function CollectionEditPage({ collectionId }) {
|
|
|
20119
20673
|
/* @__PURE__ */ jsxs60("div", { className: "flex gap-2", children: [
|
|
20120
20674
|
/* @__PURE__ */ jsx71("input", { type: "text", value: v.name, onChange: (e) => updateVariant(i, "name", e.target.value), placeholder: "Name", className: `${inputCls2} w-40` }),
|
|
20121
20675
|
/* @__PURE__ */ jsx71("input", { type: "number", value: v.price, onChange: (e) => updateVariant(i, "price", e.target.value), placeholder: "Price", className: `${inputCls2} w-28` }),
|
|
20122
|
-
/* @__PURE__ */ jsx71("button", { type: "button", onClick: () => removeVariant(i), className: "p-2 text-gray-400 hover:text-red-600 rounded shrink-0", children: /* @__PURE__ */ jsx71(
|
|
20676
|
+
/* @__PURE__ */ jsx71("button", { type: "button", onClick: () => removeVariant(i), className: "p-2 text-gray-400 hover:text-red-600 rounded shrink-0", children: /* @__PURE__ */ jsx71(Trash211, { className: "h-4 w-4" }) })
|
|
20123
20677
|
] }),
|
|
20124
20678
|
v.extraSpecs.map((s, si) => /* @__PURE__ */ jsxs60("div", { className: "flex gap-2", children: [
|
|
20125
20679
|
/* @__PURE__ */ jsx71("input", { type: "text", value: s.key, onChange: (e) => updateVariantExtraSpec(i, si, "key", e.target.value), placeholder: "Key", className: `${inputCls2} flex-1` }),
|
|
20126
20680
|
/* @__PURE__ */ jsx71("input", { type: "text", value: s.value, onChange: (e) => updateVariantExtraSpec(i, si, "value", e.target.value), placeholder: "Value", className: `${inputCls2} flex-1` }),
|
|
20127
|
-
/* @__PURE__ */ jsx71("button", { type: "button", onClick: () => removeVariantExtraSpec(i, si), className: "p-2 text-gray-400 hover:text-red-600 rounded shrink-0", children: /* @__PURE__ */ jsx71(
|
|
20681
|
+
/* @__PURE__ */ jsx71("button", { type: "button", onClick: () => removeVariantExtraSpec(i, si), className: "p-2 text-gray-400 hover:text-red-600 rounded shrink-0", children: /* @__PURE__ */ jsx71(Trash211, { className: "h-4 w-4" }) })
|
|
20128
20682
|
] }, si)),
|
|
20129
20683
|
/* @__PURE__ */ jsxs60("button", { type: "button", onClick: () => addVariantExtraSpec(i), className: "inline-flex items-center gap-1 rounded border border-gray-300 bg-white px-2 py-1 text-xs text-gray-700 hover:bg-gray-50", children: [
|
|
20130
20684
|
/* @__PURE__ */ jsx71(Plus12, { className: "h-3 w-3" }),
|
|
@@ -20170,7 +20724,7 @@ init_permission_entities();
|
|
|
20170
20724
|
init_vendor_scope();
|
|
20171
20725
|
import { useCallback as useCallback13, useEffect as useEffect39, useState as useState42 } from "react";
|
|
20172
20726
|
import { useSession as useSession8 } from "next-auth/react";
|
|
20173
|
-
import { Shield as Shield2, Save as Save10, Trash2 as
|
|
20727
|
+
import { Shield as Shield2, Save as Save10, Trash2 as Trash212 } from "lucide-react";
|
|
20174
20728
|
|
|
20175
20729
|
// src/auth/helpers.ts
|
|
20176
20730
|
init_rbac_debug();
|
|
@@ -20422,7 +20976,7 @@ function RolesPage() {
|
|
|
20422
20976
|
saving ? "Saving\u2026" : "Save"
|
|
20423
20977
|
] }),
|
|
20424
20978
|
!vendorScoped && selected && !isSuperAdminGroupName(selected.name) && /* @__PURE__ */ jsxs61(Button, { size: "sm", variant: "outline", className: "gap-1 text-red-600", onClick: () => setDeleteRoleOpen(true), children: [
|
|
20425
|
-
/* @__PURE__ */ jsx72(
|
|
20979
|
+
/* @__PURE__ */ jsx72(Trash212, { className: "h-3.5 w-3.5" }),
|
|
20426
20980
|
"Delete role"
|
|
20427
20981
|
] })
|
|
20428
20982
|
] }),
|
|
@@ -21375,7 +21929,7 @@ function RuleTreeNode({ node, depth = 0 }) {
|
|
|
21375
21929
|
node.type && /* @__PURE__ */ jsx78("span", { className: "rounded bg-white border border-gray-200 px-2 py-0.5 text-xs text-gray-700", children: RULE_TYPE_LABEL[node.type] ?? node.type }),
|
|
21376
21930
|
node.subType && /* @__PURE__ */ jsx78("span", { className: "text-gray-400 text-xs", children: node.subType }),
|
|
21377
21931
|
node.comparisonOperator && /* @__PURE__ */ jsx78("span", { className: "font-mono text-xs font-semibold text-gray-700", children: node.comparisonOperator }),
|
|
21378
|
-
node.value && Object.keys(node.value).length > 0 && /* @__PURE__ */ jsx78("span", { className: "font-mono text-xs bg-white border border-gray-200 rounded px-2 py-0.5 text-gray-800 break-all", children: Object.keys(node.value).length === 1 && "v" in node.value ? String(node.value.v) : JSON.stringify(node.value) })
|
|
21932
|
+
node.value && Object.keys(node.value).length > 0 && /* @__PURE__ */ jsx78("span", { className: "font-mono text-xs bg-white border border-gray-200 rounded px-2 py-0.5 text-gray-800 break-all", children: node.type === "quantity" && node.subType === "productId" && "v" in node.value ? `product #${node.value.productId} >= ${node.value.v}` : Object.keys(node.value).length === 1 && "v" in node.value ? String(node.value.v) : JSON.stringify(node.value) })
|
|
21379
21933
|
] }) }),
|
|
21380
21934
|
isGroup && open && (node.children ?? []).length > 0 && /* @__PURE__ */ jsx78("div", { className: "mt-2 pl-4 space-y-2", children: (node.children ?? []).map((child) => /* @__PURE__ */ jsx78(RuleTreeNode, { node: child, depth: depth + 1 }, child.id)) })
|
|
21381
21935
|
] });
|
|
@@ -21619,7 +22173,7 @@ import { AlertCircle as AlertCircle9, Save as Save11, Zap as Zap3 } from "lucide
|
|
|
21619
22173
|
// src/admin/pages/DiscountsConditionsBuilder.tsx
|
|
21620
22174
|
init_button();
|
|
21621
22175
|
import { useState as useState46, useEffect as useEffect43 } from "react";
|
|
21622
|
-
import { Plus as Plus13, Trash2 as
|
|
22176
|
+
import { Plus as Plus13, Trash2 as Trash213, Search as Search5, Package as Package2, ShoppingCart as ShoppingCart5, User as User3, Hash, DollarSign, Gift } from "lucide-react";
|
|
21623
22177
|
import { jsx as jsx79, jsxs as jsxs66 } from "react/jsx-runtime";
|
|
21624
22178
|
function uid() {
|
|
21625
22179
|
return Math.random().toString(36).slice(2, 10);
|
|
@@ -21635,10 +22189,10 @@ function conditionToRule(c) {
|
|
|
21635
22189
|
return { ...base, type: "minAmount", comparisonOperator: "gte", value: { v: c.amount ?? "0" } };
|
|
21636
22190
|
case "minQuantity":
|
|
21637
22191
|
return { ...base, type: "quantity", comparisonOperator: "gte", value: { v: c.quantity ?? "1" } };
|
|
21638
|
-
case "
|
|
21639
|
-
return { ...base, type: "
|
|
22192
|
+
case "productMinQuantity":
|
|
22193
|
+
return { ...base, type: "quantity", subType: "productId", comparisonOperator: "gte", value: { v: c.quantity ?? "1", productId: String(c.productId ?? "") } };
|
|
21640
22194
|
case "nthOrder":
|
|
21641
|
-
return { ...base, type: "order", subType: "nthOrder", comparisonOperator: "
|
|
22195
|
+
return { ...base, type: "order", subType: "nthOrder", comparisonOperator: "eq", value: { v: c.nthOrder ?? "1" } };
|
|
21642
22196
|
case "userType":
|
|
21643
22197
|
return { ...base, type: "user", subType: "userType", comparisonOperator: "eq", value: { v: c.userType ?? "" } };
|
|
21644
22198
|
case "paymentMethod":
|
|
@@ -21704,9 +22258,16 @@ function ruleTreeToFriendly(rules) {
|
|
|
21704
22258
|
case "minAmount":
|
|
21705
22259
|
return { id: rule._clientId ?? uid(), kind: "minAmount", amount: v };
|
|
21706
22260
|
case "quantity":
|
|
22261
|
+
if (rule.subType === "productId") {
|
|
22262
|
+
return {
|
|
22263
|
+
id: rule._clientId ?? uid(),
|
|
22264
|
+
kind: "productMinQuantity",
|
|
22265
|
+
quantity: v,
|
|
22266
|
+
productId: Number(rule.value?.productId) || null,
|
|
22267
|
+
productName: void 0
|
|
22268
|
+
};
|
|
22269
|
+
}
|
|
21707
22270
|
return { id: rule._clientId ?? uid(), kind: "minQuantity", quantity: v };
|
|
21708
|
-
case "product":
|
|
21709
|
-
return { id: rule._clientId ?? uid(), kind: "Product", productId: Number(v) || null, productName: void 0 };
|
|
21710
22271
|
case "order":
|
|
21711
22272
|
return { id: rule._clientId ?? uid(), kind: "nthOrder", nthOrder: v };
|
|
21712
22273
|
case "user":
|
|
@@ -22030,7 +22591,7 @@ function ConditionCard({
|
|
|
22030
22591
|
const iconMap = {
|
|
22031
22592
|
minAmount: /* @__PURE__ */ jsx79(DollarSign, { className: "h-3.5 w-3.5 text-blue-500" }),
|
|
22032
22593
|
minQuantity: /* @__PURE__ */ jsx79(Hash, { className: "h-3.5 w-3.5 text-purple-500" }),
|
|
22033
|
-
|
|
22594
|
+
productMinQuantity: /* @__PURE__ */ jsx79(Hash, { className: "h-3.5 w-3.5 text-green-600" }),
|
|
22034
22595
|
nthOrder: /* @__PURE__ */ jsx79(ShoppingCart5, { className: "h-3.5 w-3.5 text-orange-500" }),
|
|
22035
22596
|
userType: /* @__PURE__ */ jsx79(User3, { className: "h-3.5 w-3.5 text-pink-500" }),
|
|
22036
22597
|
paymentMethod: /* @__PURE__ */ jsx79(DollarSign, { className: "h-3.5 w-3.5 text-indigo-500" }),
|
|
@@ -22052,7 +22613,7 @@ function ConditionCard({
|
|
|
22052
22613
|
/* @__PURE__ */ jsxs66(SelectContent, { children: [
|
|
22053
22614
|
/* @__PURE__ */ jsx79(SelectItem, { value: "minAmount", children: "Minimum order amount" }),
|
|
22054
22615
|
/* @__PURE__ */ jsx79(SelectItem, { value: "minQuantity", children: "Minimum quantity" }),
|
|
22055
|
-
/* @__PURE__ */ jsx79(SelectItem, { value: "
|
|
22616
|
+
/* @__PURE__ */ jsx79(SelectItem, { value: "productMinQuantity", children: "Product" }),
|
|
22056
22617
|
/* @__PURE__ */ jsx79(SelectItem, { value: "nthOrder", children: "Customer's Nth order" }),
|
|
22057
22618
|
/* @__PURE__ */ jsx79(SelectItem, { value: "userType", children: "User type" }),
|
|
22058
22619
|
/* @__PURE__ */ jsx79(SelectItem, { value: "paymentMethod", children: "Payment method" }),
|
|
@@ -22072,9 +22633,33 @@ function ConditionCard({
|
|
|
22072
22633
|
/* @__PURE__ */ jsx79("span", { className: "text-xs text-gray-500 shrink-0", children: "Qty \u2265" }),
|
|
22073
22634
|
/* @__PURE__ */ jsx79("input", { type: "number", min: 1, step: "1", value: condition.quantity ?? "", onChange: (e) => onChange({ ...condition, quantity: e.target.value }), className: inputCls3, placeholder: "2" })
|
|
22074
22635
|
] }),
|
|
22075
|
-
condition.kind === "
|
|
22636
|
+
condition.kind === "productMinQuantity" && /* @__PURE__ */ jsxs66("div", { className: "space-y-2", children: [
|
|
22637
|
+
/* @__PURE__ */ jsx79(
|
|
22638
|
+
ProductPicker,
|
|
22639
|
+
{
|
|
22640
|
+
value: condition.productId,
|
|
22641
|
+
label: condition.productName,
|
|
22642
|
+
onChange: (id, name) => onChange({ ...condition, productId: id, productName: name })
|
|
22643
|
+
}
|
|
22644
|
+
),
|
|
22645
|
+
/* @__PURE__ */ jsxs66("div", { className: "flex items-center gap-2", children: [
|
|
22646
|
+
/* @__PURE__ */ jsx79("span", { className: "text-xs text-gray-500 shrink-0", children: "Minimum quantity of this product" }),
|
|
22647
|
+
/* @__PURE__ */ jsx79(
|
|
22648
|
+
"input",
|
|
22649
|
+
{
|
|
22650
|
+
type: "number",
|
|
22651
|
+
min: 1,
|
|
22652
|
+
step: "1",
|
|
22653
|
+
value: condition.quantity ?? "",
|
|
22654
|
+
onChange: (e) => onChange({ ...condition, quantity: e.target.value }),
|
|
22655
|
+
className: inputCls3,
|
|
22656
|
+
placeholder: "2"
|
|
22657
|
+
}
|
|
22658
|
+
)
|
|
22659
|
+
] })
|
|
22660
|
+
] }),
|
|
22076
22661
|
condition.kind === "nthOrder" && /* @__PURE__ */ jsxs66("div", { className: "flex items-center gap-2", children: [
|
|
22077
|
-
/* @__PURE__ */ jsx79("span", { className: "text-xs text-gray-500 shrink-0", children: "Order number
|
|
22662
|
+
/* @__PURE__ */ jsx79("span", { className: "text-xs text-gray-500 shrink-0", children: "Order number =" }),
|
|
22078
22663
|
/* @__PURE__ */ jsx79("input", { type: "number", min: 1, step: "1", value: condition.nthOrder ?? "", onChange: (e) => onChange({ ...condition, nthOrder: e.target.value }), className: inputCls3, placeholder: "2" }),
|
|
22079
22664
|
/* @__PURE__ */ jsx79("span", { className: "text-xs text-gray-400 shrink-0", children: "(e.g. 2 = 2nd+ order)" })
|
|
22080
22665
|
] }),
|
|
@@ -22102,7 +22687,7 @@ function ConditionCard({
|
|
|
22102
22687
|
condition.kind === "shipping" && /* @__PURE__ */ jsx79("p", { className: "text-xs text-gray-400 italic", children: "Applied when any shipping method is selected." }),
|
|
22103
22688
|
condition.kind === "referral" && /* @__PURE__ */ jsx79("p", { className: "text-xs text-gray-400 italic", children: "Applied when order comes from a referral." })
|
|
22104
22689
|
] }),
|
|
22105
|
-
/* @__PURE__ */ jsx79("button", { type: "button", onClick: onRemove, className: "shrink-0 text-gray-300 hover:text-red-500 transition-colors mt-0.5", children: /* @__PURE__ */ jsx79(
|
|
22690
|
+
/* @__PURE__ */ jsx79("button", { type: "button", onClick: onRemove, className: "shrink-0 text-gray-300 hover:text-red-500 transition-colors mt-0.5", children: /* @__PURE__ */ jsx79(Trash213, { className: "h-4 w-4" }) })
|
|
22106
22691
|
] });
|
|
22107
22692
|
}
|
|
22108
22693
|
function RewardCard({
|
|
@@ -22127,7 +22712,7 @@ function RewardCard({
|
|
|
22127
22712
|
] }),
|
|
22128
22713
|
/* @__PURE__ */ jsx79("p", { className: "text-[11px] text-purple-600", children: "This product will be automatically added to cart when the discount is applied." })
|
|
22129
22714
|
] }),
|
|
22130
|
-
/* @__PURE__ */ jsx79("button", { type: "button", onClick: onRemove, className: "shrink-0 text-gray-300 hover:text-red-500 transition-colors mt-0.5", children: /* @__PURE__ */ jsx79(
|
|
22715
|
+
/* @__PURE__ */ jsx79("button", { type: "button", onClick: onRemove, className: "shrink-0 text-gray-300 hover:text-red-500 transition-colors mt-0.5", children: /* @__PURE__ */ jsx79(Trash213, { className: "h-4 w-4" }) })
|
|
22131
22716
|
] });
|
|
22132
22717
|
}
|
|
22133
22718
|
function DiscountConditionsBuilder({
|
|
@@ -22144,7 +22729,7 @@ function DiscountConditionsBuilder({
|
|
|
22144
22729
|
const missingNameIds = [];
|
|
22145
22730
|
for (const g of groups) {
|
|
22146
22731
|
for (const c of g.conditions) {
|
|
22147
|
-
if (c.kind === "
|
|
22732
|
+
if (c.kind === "productMinQuantity" && c.productId && !c.productName)
|
|
22148
22733
|
missingNameIds.push({ type: "product", id: c.id, entityId: c.productId, groupId: g.id });
|
|
22149
22734
|
if (c.kind === "category" && c.categoryId && !c.categoryName)
|
|
22150
22735
|
missingNameIds.push({ type: "category", id: c.id, entityId: c.categoryId, groupId: g.id });
|
|
@@ -22284,7 +22869,7 @@ function DiscountConditionsBuilder({
|
|
|
22284
22869
|
type: "button",
|
|
22285
22870
|
onClick: () => removeGroup(group.id),
|
|
22286
22871
|
className: "text-gray-300 hover:text-red-500 transition-colors",
|
|
22287
|
-
children: /* @__PURE__ */ jsx79(
|
|
22872
|
+
children: /* @__PURE__ */ jsx79(Trash213, { className: "h-3.5 w-3.5" })
|
|
22288
22873
|
}
|
|
22289
22874
|
)
|
|
22290
22875
|
] }),
|