@infuro/cms-core 1.0.31 → 1.0.34
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 +12 -8
- package/dist/admin.cjs +1907 -1144
- package/dist/admin.cjs.map +1 -1
- package/dist/admin.d.cts +7 -2
- package/dist/admin.d.ts +7 -2
- package/dist/admin.js +1955 -1191
- package/dist/admin.js.map +1 -1
- package/dist/api.cjs +2704 -914
- 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 +2664 -875
- package/dist/api.js.map +1 -1
- package/dist/auth.cjs +251 -23
- package/dist/auth.cjs.map +1 -1
- package/dist/auth.d.cts +53 -22
- package/dist/auth.d.ts +53 -22
- package/dist/auth.js +240 -23
- package/dist/auth.js.map +1 -1
- package/dist/cli.cjs +42 -2
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +42 -2
- package/dist/cli.js.map +1 -1
- package/dist/{index-BcMRGNjS.d.cts → index-Bf5GO8fu.d.cts} +4 -3
- package/dist/{index-Bda8D1Rm.d.ts → index-DOiJuMQA.d.ts} +4 -3
- package/dist/index.cjs +3408 -1284
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +121 -35
- package/dist/index.d.ts +121 -35
- package/dist/index.js +3334 -1226
- package/dist/index.js.map +1 -1
- package/dist/migrations/1778660000003-AddQrTokenToOrders.ts +32 -0
- package/dist/migrations/1778660000004-CreateCustomerAndCustomerContacts.ts +99 -0
- package/dist/migrations/1778660000005-AddCustomerIdToVendorCustomers.ts +39 -0
- package/dist/migrations/1778660000006-UpdateVendorCustomersContactNullable.ts +36 -0
- package/dist/migrations/1778660000007-VendorOwnerCustomerContactsPermission.ts +39 -0
- package/dist/migrations/1779100000000-ChatConversationLeadEmailSent.ts +16 -0
- package/dist/migrations/1779200000000-LlmAgentScope.ts +72 -0
- package/dist/migrations/1779300000000-VendorOwnerContactsPermission.ts +39 -0
- package/dist/migrations/1779400000000-AddCustomerContactIdToOrders.ts +33 -0
- package/package.json +5 -3
package/dist/admin.js
CHANGED
|
@@ -99,6 +99,30 @@ var init_permission_entities = __esm({
|
|
|
99
99
|
}
|
|
100
100
|
});
|
|
101
101
|
|
|
102
|
+
// src/auth/role-helpers.ts
|
|
103
|
+
function isSuperAdmin(user) {
|
|
104
|
+
if (!user) return false;
|
|
105
|
+
if (user.groupId === SUPER_ADMIN_GROUP_ID) return true;
|
|
106
|
+
if (user.isRBACAdmin === true) return true;
|
|
107
|
+
return isSuperAdminGroupName(user.groupName);
|
|
108
|
+
}
|
|
109
|
+
function isVendorAdmin(user) {
|
|
110
|
+
if (!user?.email || isSuperAdmin(user)) return false;
|
|
111
|
+
if (user.groupId === VENDOR_ADMIN_GROUP_ID) return true;
|
|
112
|
+
if ((user.vendorIds?.length ?? 0) > 0) return true;
|
|
113
|
+
return isVendorGroupName(user.groupName);
|
|
114
|
+
}
|
|
115
|
+
var SUPER_ADMIN_GROUP_ID, VENDOR_ADMIN_GROUP_ID;
|
|
116
|
+
var init_role_helpers = __esm({
|
|
117
|
+
"src/auth/role-helpers.ts"() {
|
|
118
|
+
"use strict";
|
|
119
|
+
init_permission_entities();
|
|
120
|
+
init_vendor_scope();
|
|
121
|
+
SUPER_ADMIN_GROUP_ID = 1;
|
|
122
|
+
VENDOR_ADMIN_GROUP_ID = 5;
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
|
|
102
126
|
// src/auth/vendor-scope.ts
|
|
103
127
|
function isVendorGroupName(name) {
|
|
104
128
|
if (!name?.trim()) return false;
|
|
@@ -107,12 +131,12 @@ function isVendorGroupName(name) {
|
|
|
107
131
|
}
|
|
108
132
|
function isPlatformAdministrator(user) {
|
|
109
133
|
if (!user?.email) return false;
|
|
110
|
-
return
|
|
134
|
+
return isSuperAdmin(user);
|
|
111
135
|
}
|
|
112
136
|
function isVendorPortalUser(user) {
|
|
113
137
|
if (user?.isVendorPortal === true) return true;
|
|
114
138
|
if (!user?.email || isPlatformAdministrator(user)) return false;
|
|
115
|
-
if ((user
|
|
139
|
+
if (isVendorAdmin(user)) return true;
|
|
116
140
|
return isVendorGroupName(user.groupName);
|
|
117
141
|
}
|
|
118
142
|
function isVendorOwner(user) {
|
|
@@ -136,7 +160,7 @@ var VENDOR_SCOPED_STORE_ENTITIES, VENDOR_STORE_RBAC_ENTITIES, VENDOR_OWNER_GROUP
|
|
|
136
160
|
var init_vendor_scope = __esm({
|
|
137
161
|
"src/auth/vendor-scope.ts"() {
|
|
138
162
|
"use strict";
|
|
139
|
-
|
|
163
|
+
init_role_helpers();
|
|
140
164
|
VENDOR_SCOPED_STORE_ENTITIES = /* @__PURE__ */ new Set([
|
|
141
165
|
"products",
|
|
142
166
|
"collections",
|
|
@@ -401,7 +425,7 @@ var init_admin_list_return_url = __esm({
|
|
|
401
425
|
import Link8 from "next/link";
|
|
402
426
|
import { useRouter as useRouter7 } from "next/navigation";
|
|
403
427
|
import { ArrowLeft as ArrowLeft3, X as X14 } from "lucide-react";
|
|
404
|
-
import { Fragment as
|
|
428
|
+
import { Fragment as Fragment10, jsx as jsx49, jsxs as jsxs39 } from "react/jsx-runtime";
|
|
405
429
|
function DetailPageHeader({
|
|
406
430
|
title,
|
|
407
431
|
subtitle,
|
|
@@ -436,7 +460,7 @@ function DetailPageHeader({
|
|
|
436
460
|
] })
|
|
437
461
|
] }),
|
|
438
462
|
/* @__PURE__ */ jsxs39("div", { className: "flex items-center gap-2 shrink-0", children: [
|
|
439
|
-
menuItems.length > 0 && /* @__PURE__ */ jsxs39(
|
|
463
|
+
menuItems.length > 0 && /* @__PURE__ */ jsxs39(Fragment10, { children: [
|
|
440
464
|
/* @__PURE__ */ jsx49("div", { className: "flex items-center gap-2 md:hidden", children: menuItems.map((item, i) => {
|
|
441
465
|
const Icon2 = item.icon;
|
|
442
466
|
return /* @__PURE__ */ jsxs39(
|
|
@@ -774,11 +798,11 @@ __export(ContactDetailPage_exports, {
|
|
|
774
798
|
});
|
|
775
799
|
import { useEffect as useEffect46, useState as useState49 } from "react";
|
|
776
800
|
import Link15 from "next/link";
|
|
777
|
-
import { useRouter as
|
|
778
|
-
import { Plus as Plus15, Trash2 as
|
|
801
|
+
import { useRouter as useRouter21, useSearchParams as useSearchParams19 } from "next/navigation";
|
|
802
|
+
import { Plus as Plus15, Trash2 as Trash215, X as X22 } from "lucide-react";
|
|
779
803
|
import { toast as toast11 } from "sonner";
|
|
780
804
|
import { Country as Country3, State as State3 } from "country-state-city";
|
|
781
|
-
import { Fragment as
|
|
805
|
+
import { Fragment as Fragment24, jsx as jsx82, jsxs as jsxs69 } from "react/jsx-runtime";
|
|
782
806
|
function formatMoney5(amount, currency = "INR") {
|
|
783
807
|
return new Intl.NumberFormat("en-IN", {
|
|
784
808
|
style: "currency",
|
|
@@ -802,7 +826,7 @@ function RequiredMark() {
|
|
|
802
826
|
] });
|
|
803
827
|
}
|
|
804
828
|
function ContactDetailPage({ contactId }) {
|
|
805
|
-
const router =
|
|
829
|
+
const router = useRouter21();
|
|
806
830
|
const searchParams = useSearchParams19();
|
|
807
831
|
const listReturnUrl = safeAdminListReturnUrl(searchParams.get("from")) ?? "/admin/contacts";
|
|
808
832
|
const [contact, setContact] = useState49(null);
|
|
@@ -943,7 +967,7 @@ function ContactDetailPage({ contactId }) {
|
|
|
943
967
|
/* @__PURE__ */ jsx82(
|
|
944
968
|
DetailPageLayout,
|
|
945
969
|
{
|
|
946
|
-
main: /* @__PURE__ */ jsxs69(
|
|
970
|
+
main: /* @__PURE__ */ jsxs69(Fragment24, { children: [
|
|
947
971
|
/* @__PURE__ */ jsxs69("section", { children: [
|
|
948
972
|
/* @__PURE__ */ jsx82("h2", { className: "text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2", children: "Contact details" }),
|
|
949
973
|
/* @__PURE__ */ jsx82("div", { className: "min-w-0 overflow-hidden border border-gray-200 rounded-lg p-4 bg-gray-50/50", children: /* @__PURE__ */ jsxs69("dl", { className: "min-w-0 grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-3 text-sm", children: [
|
|
@@ -959,7 +983,7 @@ function ContactDetailPage({ contactId }) {
|
|
|
959
983
|
/* @__PURE__ */ jsx82("dt", { className: "text-gray-500", children: "Phone" }),
|
|
960
984
|
/* @__PURE__ */ jsx82("dd", { className: "font-medium text-gray-900 break-words", children: contact.phone ?? "\u2014" })
|
|
961
985
|
] }),
|
|
962
|
-
(contact.type ?? contact.company ?? contact.taxId) && /* @__PURE__ */ jsxs69(
|
|
986
|
+
(contact.type ?? contact.company ?? contact.taxId) && /* @__PURE__ */ jsxs69(Fragment24, { children: [
|
|
963
987
|
contact.type && /* @__PURE__ */ jsxs69("div", { className: "min-w-0", children: [
|
|
964
988
|
/* @__PURE__ */ jsx82("dt", { className: "text-gray-500", children: "Type" }),
|
|
965
989
|
/* @__PURE__ */ jsx82("dd", { className: "font-medium text-gray-900 break-words", children: formatContactType(contact.type) })
|
|
@@ -1023,14 +1047,14 @@ function ContactDetailPage({ contactId }) {
|
|
|
1023
1047
|
title: "Delete address",
|
|
1024
1048
|
"aria-label": `Delete address ${a.id}`,
|
|
1025
1049
|
onClick: () => setAddressPendingDelete(a),
|
|
1026
|
-
children: /* @__PURE__ */ jsx82(
|
|
1050
|
+
children: /* @__PURE__ */ jsx82(Trash215, { className: "h-4 w-4" })
|
|
1027
1051
|
}
|
|
1028
1052
|
) })
|
|
1029
1053
|
] }, a.id)) })
|
|
1030
1054
|
] }) })
|
|
1031
1055
|
] })
|
|
1032
1056
|
] }),
|
|
1033
|
-
sidebar: /* @__PURE__ */ jsxs69(
|
|
1057
|
+
sidebar: /* @__PURE__ */ jsxs69(Fragment24, { children: [
|
|
1034
1058
|
/* @__PURE__ */ jsxs69("section", { children: [
|
|
1035
1059
|
/* @__PURE__ */ jsx82("h2", { className: "text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2", children: "Summary" }),
|
|
1036
1060
|
/* @__PURE__ */ jsx82("div", { className: "min-w-0 overflow-hidden border border-gray-200 rounded-lg p-4 bg-gray-50/50", children: /* @__PURE__ */ jsxs69("dl", { className: "min-w-0 grid grid-cols-1 sm:grid-cols-3 gap-3 text-sm", children: [
|
|
@@ -1542,7 +1566,7 @@ var defaultValue = {
|
|
|
1542
1566
|
var AdminConfigContext = createContext(defaultValue);
|
|
1543
1567
|
|
|
1544
1568
|
// src/lib/cms-version.ts
|
|
1545
|
-
var CMS_VERSION = true ? "1.0.
|
|
1569
|
+
var CMS_VERSION = true ? "1.0.34" : "0.0.0";
|
|
1546
1570
|
|
|
1547
1571
|
// src/components/Admin/Sidebar.tsx
|
|
1548
1572
|
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
@@ -1750,7 +1774,7 @@ function AdminSidebar({ variant = "sidebar" }) {
|
|
|
1750
1774
|
className: `${linkCls} ${isActive("/admin/vendor-onboard") ? linkActive : linkInactive}`,
|
|
1751
1775
|
children: [
|
|
1752
1776
|
/* @__PURE__ */ jsx4(Store, { className: `h-4 w-4 mr-2 ${isActive("/admin/vendor-onboard") ? iconActive : iconInactive}` }),
|
|
1753
|
-
"
|
|
1777
|
+
"Vendors"
|
|
1754
1778
|
]
|
|
1755
1779
|
}
|
|
1756
1780
|
) }),
|
|
@@ -2036,6 +2060,34 @@ var BUILTIN_PLUGIN_DESCRIPTORS = [
|
|
|
2036
2060
|
}
|
|
2037
2061
|
];
|
|
2038
2062
|
|
|
2063
|
+
// src/auth/auth-debug.ts
|
|
2064
|
+
var LOG_PREFIX = "[cms-auth]";
|
|
2065
|
+
function isAuthDebugClientEnabled() {
|
|
2066
|
+
if (typeof window === "undefined") return false;
|
|
2067
|
+
const v = process.env.NEXT_PUBLIC_CMS_AUTH_DEBUG?.trim().toLowerCase();
|
|
2068
|
+
if (v === "1" || v === "true" || v === "yes") return true;
|
|
2069
|
+
if (v === "0" || v === "false" || v === "no") return false;
|
|
2070
|
+
return process.env.NODE_ENV === "development";
|
|
2071
|
+
}
|
|
2072
|
+
function logAuthClient(message, data) {
|
|
2073
|
+
if (!isAuthDebugClientEnabled()) return;
|
|
2074
|
+
if (data) console.info(LOG_PREFIX, message, data);
|
|
2075
|
+
else console.info(LOG_PREFIX, message);
|
|
2076
|
+
}
|
|
2077
|
+
function summarizeSessionUserForLog(user) {
|
|
2078
|
+
if (!user || typeof user !== "object") return { present: false };
|
|
2079
|
+
const u = user;
|
|
2080
|
+
return {
|
|
2081
|
+
present: true,
|
|
2082
|
+
email: u.email ?? null,
|
|
2083
|
+
id: u.id ?? null,
|
|
2084
|
+
adminAccess: u.adminAccess ?? null,
|
|
2085
|
+
isRBACAdmin: u.isRBACAdmin ?? null,
|
|
2086
|
+
isVendorPortal: u.isVendorPortal ?? null,
|
|
2087
|
+
groupName: u.groupName ?? null
|
|
2088
|
+
};
|
|
2089
|
+
}
|
|
2090
|
+
|
|
2039
2091
|
// src/admin/pages/AdminLayout.tsx
|
|
2040
2092
|
import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
2041
2093
|
var PUBLIC_ADMIN_PATHS = [
|
|
@@ -2069,6 +2121,14 @@ function AdminLayoutInner({ children }) {
|
|
|
2069
2121
|
useEffect2(() => {
|
|
2070
2122
|
if (isMobile) setMoreSheetOpen(false);
|
|
2071
2123
|
}, [isMobile, pathname]);
|
|
2124
|
+
useEffect2(() => {
|
|
2125
|
+
logAuthClient("AdminLayout session state", {
|
|
2126
|
+
pathname,
|
|
2127
|
+
isPublicPath,
|
|
2128
|
+
status,
|
|
2129
|
+
sessionUser: summarizeSessionUserForLog(session?.user)
|
|
2130
|
+
});
|
|
2131
|
+
}, [pathname, isPublicPath, status, session?.user]);
|
|
2072
2132
|
useEffect2(() => {
|
|
2073
2133
|
if (isPublicPath) return;
|
|
2074
2134
|
if (status === "loading") {
|
|
@@ -2076,6 +2136,7 @@ function AdminLayoutInner({ children }) {
|
|
|
2076
2136
|
return () => clearTimeout(timeout);
|
|
2077
2137
|
}
|
|
2078
2138
|
if (status === "unauthenticated") {
|
|
2139
|
+
logAuthClient("AdminLayout redirect \u2192 /admin/signin (unauthenticated)", { pathname });
|
|
2079
2140
|
router.replace("/admin/signin");
|
|
2080
2141
|
} else {
|
|
2081
2142
|
setLoadingTimeout(false);
|
|
@@ -2666,7 +2727,7 @@ function RelationAutocomplete({
|
|
|
2666
2727
|
|
|
2667
2728
|
// src/components/Admin/CreateEditForm.tsx
|
|
2668
2729
|
import { toast } from "sonner";
|
|
2669
|
-
import { jsx as jsx17, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
2730
|
+
import { Fragment as Fragment3, jsx as jsx17, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
2670
2731
|
function todayLocalDateString() {
|
|
2671
2732
|
const d = /* @__PURE__ */ new Date();
|
|
2672
2733
|
const y = d.getFullYear();
|
|
@@ -2708,7 +2769,8 @@ function CreateEditForm({
|
|
|
2708
2769
|
apiEndpoint,
|
|
2709
2770
|
columns,
|
|
2710
2771
|
existingData,
|
|
2711
|
-
duplicateSeed
|
|
2772
|
+
duplicateSeed,
|
|
2773
|
+
resource
|
|
2712
2774
|
}) {
|
|
2713
2775
|
const isMobile = useIsMobile();
|
|
2714
2776
|
const { currency } = useContext3(AdminConfigContext);
|
|
@@ -2716,6 +2778,9 @@ function CreateEditForm({
|
|
|
2716
2778
|
currency: currency || "INR"
|
|
2717
2779
|
});
|
|
2718
2780
|
const [errors, setErrors] = useState6({});
|
|
2781
|
+
const [password, setPassword] = useState6("");
|
|
2782
|
+
const [confirmPassword, setConfirmPassword] = useState6("");
|
|
2783
|
+
const isCustomerCreate = resource === "vendor_customers" && !existingData;
|
|
2719
2784
|
useEffect4(() => {
|
|
2720
2785
|
fetch("/api/settings/store").then((res) => res.json()).then((data) => {
|
|
2721
2786
|
setFormData((prev) => ({
|
|
@@ -2745,14 +2810,10 @@ function CreateEditForm({
|
|
|
2745
2810
|
};
|
|
2746
2811
|
}).filter(Boolean)
|
|
2747
2812
|
);
|
|
2748
|
-
}).catch(
|
|
2749
|
-
(err) => console.error("Failed to load customers", err)
|
|
2750
|
-
);
|
|
2813
|
+
}).catch((err) => console.error("Failed to load customers", err));
|
|
2751
2814
|
}, [columns]);
|
|
2752
2815
|
const handleCustomerSelect = (customerId) => {
|
|
2753
|
-
const customer = customers.find(
|
|
2754
|
-
(c) => String(c.id) === customerId
|
|
2755
|
-
);
|
|
2816
|
+
const customer = customers.find((c) => String(c.id) === customerId);
|
|
2756
2817
|
if (!customer) return;
|
|
2757
2818
|
setFormData((prev) => ({
|
|
2758
2819
|
...prev,
|
|
@@ -2766,23 +2827,14 @@ function CreateEditForm({
|
|
|
2766
2827
|
const [totalLoading, setTotalLoading] = useState6(false);
|
|
2767
2828
|
useEffect4(() => {
|
|
2768
2829
|
return () => {
|
|
2769
|
-
if (debounceRef.current)
|
|
2770
|
-
clearTimeout(debounceRef.current);
|
|
2771
|
-
}
|
|
2830
|
+
if (debounceRef.current) clearTimeout(debounceRef.current);
|
|
2772
2831
|
};
|
|
2773
2832
|
}, []);
|
|
2774
2833
|
const recalculateTotal = (itemsSummaryValue) => {
|
|
2775
|
-
if (debounceRef.current)
|
|
2776
|
-
clearTimeout(debounceRef.current);
|
|
2777
|
-
}
|
|
2834
|
+
if (debounceRef.current) clearTimeout(debounceRef.current);
|
|
2778
2835
|
const names = itemsSummaryValue.split(",").map((s) => s.trim()).filter(Boolean);
|
|
2779
2836
|
if (names.length === 0) {
|
|
2780
|
-
setFormData((prev) => ({
|
|
2781
|
-
...prev,
|
|
2782
|
-
subtotal: "",
|
|
2783
|
-
tax: "",
|
|
2784
|
-
total: ""
|
|
2785
|
-
}));
|
|
2837
|
+
setFormData((prev) => ({ ...prev, subtotal: "", tax: "", total: "" }));
|
|
2786
2838
|
return;
|
|
2787
2839
|
}
|
|
2788
2840
|
debounceRef.current = setTimeout(async () => {
|
|
@@ -2790,12 +2842,8 @@ function CreateEditForm({
|
|
|
2790
2842
|
try {
|
|
2791
2843
|
const res = await fetch("/api/orders/calculate", {
|
|
2792
2844
|
method: "POST",
|
|
2793
|
-
headers: {
|
|
2794
|
-
|
|
2795
|
-
},
|
|
2796
|
-
body: JSON.stringify({
|
|
2797
|
-
itemsSummary: itemsSummaryValue
|
|
2798
|
-
})
|
|
2845
|
+
headers: { "Content-Type": "application/json" },
|
|
2846
|
+
body: JSON.stringify({ itemsSummary: itemsSummaryValue })
|
|
2799
2847
|
});
|
|
2800
2848
|
if (!res.ok) return;
|
|
2801
2849
|
const data = await res.json();
|
|
@@ -2820,13 +2868,9 @@ function CreateEditForm({
|
|
|
2820
2868
|
const path = col.field || col.key;
|
|
2821
2869
|
if (!path) return;
|
|
2822
2870
|
const v = getNestedValue(ex, path);
|
|
2823
|
-
if (v !== void 0)
|
|
2824
|
-
merged[path] = v === null ? "" : v;
|
|
2825
|
-
}
|
|
2871
|
+
if (v !== void 0) merged[path] = v === null ? "" : v;
|
|
2826
2872
|
});
|
|
2827
|
-
columns.filter(
|
|
2828
|
-
(col) => !col.hideInForm && isDateFormColumn(col.type)
|
|
2829
|
-
).forEach((col) => {
|
|
2873
|
+
columns.filter((col) => !col.hideInForm && isDateFormColumn(col.type)).forEach((col) => {
|
|
2830
2874
|
const path = col.field || col.key;
|
|
2831
2875
|
if (!path) return;
|
|
2832
2876
|
const raw = merged[path];
|
|
@@ -2842,9 +2886,7 @@ function CreateEditForm({
|
|
|
2842
2886
|
).forEach((col) => {
|
|
2843
2887
|
const path = col.field || col.key;
|
|
2844
2888
|
if (!path) return;
|
|
2845
|
-
const allowed = new Set(
|
|
2846
|
-
col.options.map((o) => String(o.value))
|
|
2847
|
-
);
|
|
2889
|
+
const allowed = new Set(col.options.map((o) => String(o.value)));
|
|
2848
2890
|
const raw = merged[path];
|
|
2849
2891
|
if (raw != null && raw !== "" && !allowed.has(String(raw))) {
|
|
2850
2892
|
merged[path] = "";
|
|
@@ -2852,6 +2894,8 @@ function CreateEditForm({
|
|
|
2852
2894
|
});
|
|
2853
2895
|
setFormData(merged);
|
|
2854
2896
|
} else {
|
|
2897
|
+
setPassword("");
|
|
2898
|
+
setConfirmPassword("");
|
|
2855
2899
|
setFormData(
|
|
2856
2900
|
columns.filter((col) => !col.hideInForm).reduce((acc, col) => {
|
|
2857
2901
|
const path = col.field || col.key;
|
|
@@ -2860,29 +2904,18 @@ function CreateEditForm({
|
|
|
2860
2904
|
if (isDateFormColumn(col.type) && (initial === "" || initial == null)) {
|
|
2861
2905
|
initial = todayLocalDateString();
|
|
2862
2906
|
}
|
|
2863
|
-
return {
|
|
2864
|
-
...acc,
|
|
2865
|
-
[path]: initial
|
|
2866
|
-
};
|
|
2907
|
+
return { ...acc, [path]: initial };
|
|
2867
2908
|
}, {})
|
|
2868
2909
|
);
|
|
2869
2910
|
}
|
|
2870
2911
|
}, [existingData, duplicateSeed, columns]);
|
|
2871
2912
|
const handleChange = (e, field) => {
|
|
2872
2913
|
const value = e.target.value;
|
|
2873
|
-
setFormData((prev) => ({
|
|
2874
|
-
|
|
2875
|
-
[field]: value
|
|
2876
|
-
}));
|
|
2877
|
-
if (field === "itemsSummary") {
|
|
2878
|
-
recalculateTotal(value);
|
|
2879
|
-
}
|
|
2914
|
+
setFormData((prev) => ({ ...prev, [field]: value }));
|
|
2915
|
+
if (field === "itemsSummary") recalculateTotal(value);
|
|
2880
2916
|
};
|
|
2881
2917
|
const handleFileUpload = (field, url) => {
|
|
2882
|
-
setFormData({
|
|
2883
|
-
...formData,
|
|
2884
|
-
[field]: url
|
|
2885
|
-
});
|
|
2918
|
+
setFormData({ ...formData, [field]: url });
|
|
2886
2919
|
};
|
|
2887
2920
|
const isValidPhoneFieldValue = (value) => {
|
|
2888
2921
|
const v = String(value ?? "").trim();
|
|
@@ -2906,6 +2939,18 @@ function CreateEditForm({
|
|
|
2906
2939
|
}
|
|
2907
2940
|
}
|
|
2908
2941
|
});
|
|
2942
|
+
if (isCustomerCreate) {
|
|
2943
|
+
if (!password) {
|
|
2944
|
+
newErrors["_password"] = "Password is required";
|
|
2945
|
+
} else if (password.length < 6) {
|
|
2946
|
+
newErrors["_password"] = "Password must be at least 6 characters";
|
|
2947
|
+
}
|
|
2948
|
+
if (!confirmPassword) {
|
|
2949
|
+
newErrors["_confirmPassword"] = "Please confirm your password";
|
|
2950
|
+
} else if (password && confirmPassword !== password) {
|
|
2951
|
+
newErrors["_confirmPassword"] = "Passwords do not match";
|
|
2952
|
+
}
|
|
2953
|
+
}
|
|
2909
2954
|
setErrors(newErrors);
|
|
2910
2955
|
return Object.keys(newErrors).length === 0;
|
|
2911
2956
|
};
|
|
@@ -2923,16 +2968,19 @@ function CreateEditForm({
|
|
|
2923
2968
|
if (!existingData) {
|
|
2924
2969
|
delete payload.id;
|
|
2925
2970
|
}
|
|
2971
|
+
if (isCustomerCreate) {
|
|
2972
|
+
payload._password = password;
|
|
2973
|
+
}
|
|
2926
2974
|
try {
|
|
2927
2975
|
const res = await fetch(url, {
|
|
2928
2976
|
method,
|
|
2929
|
-
headers: {
|
|
2930
|
-
"Content-Type": "application/json"
|
|
2931
|
-
},
|
|
2977
|
+
headers: { "Content-Type": "application/json" },
|
|
2932
2978
|
body: JSON.stringify(payload)
|
|
2933
2979
|
});
|
|
2934
2980
|
if (!res.ok) {
|
|
2935
|
-
|
|
2981
|
+
const errData = await res.json().catch(() => ({}));
|
|
2982
|
+
toast.error(errData.error ?? "Failed to save data");
|
|
2983
|
+
return;
|
|
2936
2984
|
}
|
|
2937
2985
|
const result = await res.json();
|
|
2938
2986
|
if (result.inviteLink) {
|
|
@@ -2946,13 +2994,12 @@ Note: ${result.note}`
|
|
|
2946
2994
|
onClose();
|
|
2947
2995
|
} catch (error) {
|
|
2948
2996
|
console.error("Error saving data:", error);
|
|
2997
|
+
toast.error("An unexpected error occurred. Please try again.");
|
|
2949
2998
|
}
|
|
2950
2999
|
};
|
|
2951
3000
|
const visibleColumns = columns.filter((col) => {
|
|
2952
3001
|
if (col.hideInForm) return false;
|
|
2953
|
-
if (!existingData && col.hideInCreate)
|
|
2954
|
-
return false;
|
|
2955
|
-
}
|
|
3002
|
+
if (!existingData && col.hideInCreate) return false;
|
|
2956
3003
|
return true;
|
|
2957
3004
|
});
|
|
2958
3005
|
const isFieldDisabled = (path) => {
|
|
@@ -2982,228 +3029,193 @@ Note: ${result.note}`
|
|
|
2982
3029
|
}
|
|
2983
3030
|
)
|
|
2984
3031
|
] }),
|
|
2985
|
-
/* @__PURE__ */ jsxs11(
|
|
2986
|
-
"
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
) : null;
|
|
3000
|
-
const rawStr = formData[path] != null && formData[path] !== "" ? String(formData[path]) : "";
|
|
3001
|
-
const selectValue = optionSet ? rawStr !== "" && optionSet.has(rawStr) ? rawStr : col.defaultValue : void 0;
|
|
3002
|
-
return /* @__PURE__ */ jsxs11(React12.Fragment, { children: [
|
|
3003
|
-
/* @__PURE__ */ jsxs11("div", { children: [
|
|
3004
|
-
/* @__PURE__ */ jsxs11(Label3, { className: "block text-sm font-medium mb-1", children: [
|
|
3005
|
-
col.displayName,
|
|
3006
|
-
["subtotal", "tax", "total"].includes(path) && totalLoading && /* @__PURE__ */ jsx17("span", { className: "ml-2 text-xs text-gray-400 font-normal", children: "Calculating\u2026" })
|
|
3007
|
-
] }),
|
|
3008
|
-
col.type === "customerDropdown" ? /* @__PURE__ */ jsxs11(
|
|
3009
|
-
Select,
|
|
3010
|
-
{
|
|
3011
|
-
value: (() => {
|
|
3012
|
-
const match = customers.find(
|
|
3013
|
-
(c) => String(c.id) === String(
|
|
3014
|
-
formData["contactId"]
|
|
3015
|
-
) || c.name === formData["contact.name"]
|
|
3016
|
-
);
|
|
3017
|
-
return match ? String(match.id) : void 0;
|
|
3018
|
-
})(),
|
|
3019
|
-
onValueChange: handleCustomerSelect,
|
|
3020
|
-
children: [
|
|
3021
|
-
/* @__PURE__ */ jsx17(SelectTrigger, { children: /* @__PURE__ */ jsx17(SelectValue, { placeholder: "Select a customer" }) }),
|
|
3022
|
-
/* @__PURE__ */ jsx17(SelectContent, { children: customers.length === 0 ? /* @__PURE__ */ jsx17(
|
|
3023
|
-
SelectItem,
|
|
3024
|
-
{
|
|
3025
|
-
value: "__loading__",
|
|
3026
|
-
disabled: true,
|
|
3027
|
-
children: "Loading\u2026"
|
|
3028
|
-
}
|
|
3029
|
-
) : customers.map((c) => /* @__PURE__ */ jsx17(
|
|
3030
|
-
SelectItem,
|
|
3031
|
-
{
|
|
3032
|
-
value: String(
|
|
3033
|
-
c.id
|
|
3034
|
-
),
|
|
3035
|
-
children: c.name
|
|
3036
|
-
},
|
|
3037
|
-
c.id
|
|
3038
|
-
)) })
|
|
3039
|
-
]
|
|
3040
|
-
}
|
|
3041
|
-
) : col.relationApi ? /* @__PURE__ */ jsx17(
|
|
3042
|
-
RelationAutocomplete,
|
|
3043
|
-
{
|
|
3044
|
-
apiEndpoint: col.relationApi,
|
|
3045
|
-
value: formData[path] ?? "",
|
|
3046
|
-
onChange: (v) => setFormData({
|
|
3047
|
-
...formData,
|
|
3048
|
-
[path]: v
|
|
3049
|
-
}),
|
|
3050
|
-
labelField: col.relationLabelField ?? "name",
|
|
3051
|
-
valueField: col.relationValueField ?? "id",
|
|
3052
|
-
queryParams: col.relationQueryParams,
|
|
3053
|
-
placeholder: `Select ${col.displayName}`
|
|
3054
|
-
}
|
|
3055
|
-
) : col.type === "textarea" ? /* @__PURE__ */ jsx17(
|
|
3056
|
-
Textarea,
|
|
3057
|
-
{
|
|
3058
|
-
rows: typeof col.textareaRows === "number" ? col.textareaRows : 4,
|
|
3059
|
-
className: "min-h-[80px] font-mono text-sm",
|
|
3060
|
-
value: formData[path] ?? "",
|
|
3061
|
-
onChange: (e) => handleChange(e, path),
|
|
3062
|
-
placeholder: col.placeholder,
|
|
3063
|
-
disabled
|
|
3064
|
-
}
|
|
3065
|
-
) : col.type === "select" && Array.isArray(
|
|
3066
|
-
col.options
|
|
3067
|
-
) && col.options.length > 0 ? /* @__PURE__ */ jsxs11(
|
|
3068
|
-
Select,
|
|
3069
|
-
{
|
|
3070
|
-
value: selectValue,
|
|
3071
|
-
onValueChange: (value) => setFormData({
|
|
3072
|
-
...formData,
|
|
3073
|
-
[path]: value
|
|
3074
|
-
}),
|
|
3075
|
-
disabled,
|
|
3076
|
-
children: [
|
|
3077
|
-
/* @__PURE__ */ jsx17(SelectTrigger, { children: /* @__PURE__ */ jsx17(
|
|
3078
|
-
SelectValue,
|
|
3079
|
-
{
|
|
3080
|
-
placeholder: selectValue ? void 0 : "Select an option"
|
|
3081
|
-
}
|
|
3082
|
-
) }),
|
|
3083
|
-
/* @__PURE__ */ jsx17(SelectContent, { children: col.options.map(
|
|
3084
|
-
(option) => /* @__PURE__ */ jsx17(
|
|
3085
|
-
SelectItem,
|
|
3086
|
-
{
|
|
3087
|
-
value: option.value,
|
|
3088
|
-
children: option.label
|
|
3089
|
-
},
|
|
3090
|
-
option.value
|
|
3091
|
-
)
|
|
3092
|
-
) })
|
|
3093
|
-
]
|
|
3094
|
-
}
|
|
3095
|
-
) : col.type === "boolean" ? /* @__PURE__ */ jsx17(
|
|
3096
|
-
Switch,
|
|
3097
|
-
{
|
|
3098
|
-
checked: Boolean(
|
|
3099
|
-
formData[path]
|
|
3100
|
-
),
|
|
3101
|
-
onCheckedChange: (checked) => setFormData({
|
|
3102
|
-
...formData,
|
|
3103
|
-
[path]: checked
|
|
3104
|
-
}),
|
|
3105
|
-
disabled
|
|
3106
|
-
}
|
|
3107
|
-
) : isDateFormColumn(
|
|
3108
|
-
col.type
|
|
3109
|
-
) ? /* @__PURE__ */ jsx17(
|
|
3110
|
-
Input,
|
|
3111
|
-
{
|
|
3112
|
-
type: "date",
|
|
3113
|
-
value: formData[path] ?? "",
|
|
3114
|
-
onChange: (e) => handleChange(e, path),
|
|
3115
|
-
disabled
|
|
3116
|
-
}
|
|
3117
|
-
) : col.type === "password" ? /* @__PURE__ */ jsx17(
|
|
3118
|
-
Input,
|
|
3119
|
-
{
|
|
3120
|
-
type: "password",
|
|
3121
|
-
value: formData[path] || "",
|
|
3122
|
-
onChange: (e) => handleChange(e, path),
|
|
3123
|
-
disabled
|
|
3124
|
-
}
|
|
3125
|
-
) : col.type === "number" ? /* @__PURE__ */ jsx17(
|
|
3126
|
-
Input,
|
|
3127
|
-
{
|
|
3128
|
-
type: "number",
|
|
3129
|
-
placeholder: col.placeholder,
|
|
3130
|
-
value: formData[path] ?? "",
|
|
3131
|
-
onChange: (e) => handleChange(e, path),
|
|
3132
|
-
disabled
|
|
3133
|
-
}
|
|
3134
|
-
) : col.type === "phone" || col.type === "tel" ? /* @__PURE__ */ jsx17(
|
|
3135
|
-
Input,
|
|
3136
|
-
{
|
|
3137
|
-
type: "tel",
|
|
3138
|
-
inputMode: "tel",
|
|
3139
|
-
autoComplete: "tel",
|
|
3140
|
-
placeholder: col.placeholder ?? "e.g. +1 555 123 4567",
|
|
3141
|
-
value: formData[path] ?? "",
|
|
3142
|
-
onChange: (e) => handleChange(e, path),
|
|
3143
|
-
disabled
|
|
3144
|
-
}
|
|
3145
|
-
) : col.type === "file" ? /* @__PURE__ */ jsx17(
|
|
3146
|
-
FileUpload,
|
|
3147
|
-
{
|
|
3148
|
-
onUploadSuccess: (url) => handleFileUpload(
|
|
3149
|
-
path,
|
|
3150
|
-
url
|
|
3151
|
-
)
|
|
3152
|
-
}
|
|
3153
|
-
) : /* @__PURE__ */ jsx17(
|
|
3154
|
-
Input,
|
|
3155
|
-
{
|
|
3156
|
-
type: col.type || "text",
|
|
3157
|
-
placeholder: ["subtotal", "tax", "total"].includes(path) ? "Auto-calculated from items" : col.placeholder,
|
|
3158
|
-
value: formData[path] ?? "",
|
|
3159
|
-
onChange: (e) => handleChange(e, path),
|
|
3160
|
-
disabled
|
|
3161
|
-
}
|
|
3162
|
-
),
|
|
3163
|
-
errors[path] && /* @__PURE__ */ jsx17("p", { className: "text-red-500 text-sm mt-1", children: errors[path] })
|
|
3032
|
+
/* @__PURE__ */ jsxs11("form", { onSubmit: handleSubmit, className: "flex flex-col flex-1 min-h-0", children: [
|
|
3033
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex-1 min-h-0 overflow-y-auto p-6 space-y-4", children: [
|
|
3034
|
+
visibleColumns.map((col) => {
|
|
3035
|
+
const path = col.field || col.key;
|
|
3036
|
+
if (!path) return null;
|
|
3037
|
+
const disabled = isFieldDisabled(path);
|
|
3038
|
+
const optionSet = col.type === "select" && Array.isArray(col.options) ? new Set(col.options.map((o) => String(o.value))) : null;
|
|
3039
|
+
const rawStr = formData[path] != null && formData[path] !== "" ? String(formData[path]) : "";
|
|
3040
|
+
const selectValue = optionSet ? rawStr !== "" && optionSet.has(rawStr) ? rawStr : col.defaultValue : void 0;
|
|
3041
|
+
return /* @__PURE__ */ jsxs11(React12.Fragment, { children: [
|
|
3042
|
+
/* @__PURE__ */ jsxs11("div", { children: [
|
|
3043
|
+
/* @__PURE__ */ jsxs11(Label3, { className: "block text-sm font-medium mb-1", children: [
|
|
3044
|
+
col.displayName,
|
|
3045
|
+
["subtotal", "tax", "total"].includes(path) && totalLoading && /* @__PURE__ */ jsx17("span", { className: "ml-2 text-xs text-gray-400 font-normal", children: "Calculating\u2026" })
|
|
3164
3046
|
] }),
|
|
3165
|
-
col.type === "customerDropdown"
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3047
|
+
col.type === "customerDropdown" ? /* @__PURE__ */ jsxs11(
|
|
3048
|
+
Select,
|
|
3049
|
+
{
|
|
3050
|
+
value: (() => {
|
|
3051
|
+
const match = customers.find(
|
|
3052
|
+
(c) => String(c.id) === String(formData["contactId"]) || c.name === formData["contact.name"]
|
|
3053
|
+
);
|
|
3054
|
+
return match ? String(match.id) : void 0;
|
|
3055
|
+
})(),
|
|
3056
|
+
onValueChange: handleCustomerSelect,
|
|
3057
|
+
children: [
|
|
3058
|
+
/* @__PURE__ */ jsx17(SelectTrigger, { children: /* @__PURE__ */ jsx17(SelectValue, { placeholder: "Select a customer" }) }),
|
|
3059
|
+
/* @__PURE__ */ jsx17(SelectContent, { children: customers.length === 0 ? /* @__PURE__ */ jsx17(SelectItem, { value: "__loading__", disabled: true, children: "Loading\u2026" }) : customers.map((c) => /* @__PURE__ */ jsx17(SelectItem, { value: String(c.id), children: c.name }, c.id)) })
|
|
3060
|
+
]
|
|
3061
|
+
}
|
|
3062
|
+
) : col.relationApi ? /* @__PURE__ */ jsx17(
|
|
3063
|
+
RelationAutocomplete,
|
|
3064
|
+
{
|
|
3065
|
+
apiEndpoint: col.relationApi,
|
|
3066
|
+
value: formData[path] ?? "",
|
|
3067
|
+
onChange: (v) => setFormData({ ...formData, [path]: v }),
|
|
3068
|
+
labelField: col.relationLabelField ?? "name",
|
|
3069
|
+
valueField: col.relationValueField ?? "id",
|
|
3070
|
+
queryParams: col.relationQueryParams,
|
|
3071
|
+
placeholder: `Select ${col.displayName}`
|
|
3072
|
+
}
|
|
3073
|
+
) : col.type === "textarea" ? /* @__PURE__ */ jsx17(
|
|
3074
|
+
Textarea,
|
|
3075
|
+
{
|
|
3076
|
+
rows: typeof col.textareaRows === "number" ? col.textareaRows : 4,
|
|
3077
|
+
className: "min-h-[80px] font-mono text-sm",
|
|
3078
|
+
value: formData[path] ?? "",
|
|
3079
|
+
onChange: (e) => handleChange(e, path),
|
|
3080
|
+
placeholder: col.placeholder,
|
|
3081
|
+
disabled
|
|
3082
|
+
}
|
|
3083
|
+
) : col.type === "select" && Array.isArray(col.options) && col.options.length > 0 ? /* @__PURE__ */ jsxs11(
|
|
3084
|
+
Select,
|
|
3085
|
+
{
|
|
3086
|
+
value: selectValue,
|
|
3087
|
+
onValueChange: (value) => setFormData({ ...formData, [path]: value }),
|
|
3088
|
+
disabled,
|
|
3089
|
+
children: [
|
|
3090
|
+
/* @__PURE__ */ jsx17(SelectTrigger, { children: /* @__PURE__ */ jsx17(
|
|
3091
|
+
SelectValue,
|
|
3092
|
+
{
|
|
3093
|
+
placeholder: selectValue ? void 0 : "Select an option"
|
|
3094
|
+
}
|
|
3095
|
+
) }),
|
|
3096
|
+
/* @__PURE__ */ jsx17(SelectContent, { children: col.options.map((option) => /* @__PURE__ */ jsx17(SelectItem, { value: option.value, children: option.label }, option.value)) })
|
|
3097
|
+
]
|
|
3098
|
+
}
|
|
3099
|
+
) : col.type === "boolean" ? /* @__PURE__ */ jsx17(
|
|
3100
|
+
Switch,
|
|
3101
|
+
{
|
|
3102
|
+
checked: Boolean(formData[path]),
|
|
3103
|
+
onCheckedChange: (checked) => setFormData({ ...formData, [path]: checked }),
|
|
3104
|
+
disabled
|
|
3105
|
+
}
|
|
3106
|
+
) : isDateFormColumn(col.type) ? /* @__PURE__ */ jsx17(
|
|
3107
|
+
Input,
|
|
3108
|
+
{
|
|
3109
|
+
type: "date",
|
|
3110
|
+
value: formData[path] ?? "",
|
|
3111
|
+
onChange: (e) => handleChange(e, path),
|
|
3112
|
+
disabled
|
|
3113
|
+
}
|
|
3114
|
+
) : col.type === "password" ? /* @__PURE__ */ jsx17(
|
|
3115
|
+
Input,
|
|
3116
|
+
{
|
|
3117
|
+
type: "password",
|
|
3118
|
+
value: formData[path] || "",
|
|
3119
|
+
onChange: (e) => handleChange(e, path),
|
|
3120
|
+
disabled
|
|
3121
|
+
}
|
|
3122
|
+
) : col.type === "number" ? /* @__PURE__ */ jsx17(
|
|
3123
|
+
Input,
|
|
3124
|
+
{
|
|
3125
|
+
type: "number",
|
|
3126
|
+
placeholder: col.placeholder,
|
|
3127
|
+
value: formData[path] ?? "",
|
|
3128
|
+
onChange: (e) => handleChange(e, path),
|
|
3129
|
+
disabled
|
|
3130
|
+
}
|
|
3131
|
+
) : col.type === "phone" || col.type === "tel" ? /* @__PURE__ */ jsx17(
|
|
3132
|
+
Input,
|
|
3133
|
+
{
|
|
3134
|
+
type: "tel",
|
|
3135
|
+
inputMode: "tel",
|
|
3136
|
+
autoComplete: "tel",
|
|
3137
|
+
placeholder: col.placeholder ?? "e.g. +1 555 123 4567",
|
|
3138
|
+
value: formData[path] ?? "",
|
|
3139
|
+
onChange: (e) => handleChange(e, path),
|
|
3140
|
+
disabled
|
|
3141
|
+
}
|
|
3142
|
+
) : col.type === "file" ? /* @__PURE__ */ jsx17(
|
|
3143
|
+
FileUpload,
|
|
3144
|
+
{
|
|
3145
|
+
onUploadSuccess: (url) => handleFileUpload(path, url)
|
|
3146
|
+
}
|
|
3147
|
+
) : /* @__PURE__ */ jsx17(
|
|
3148
|
+
Input,
|
|
3149
|
+
{
|
|
3150
|
+
type: col.type || "text",
|
|
3151
|
+
placeholder: ["subtotal", "tax", "total"].includes(path) ? "Auto-calculated from items" : col.placeholder,
|
|
3152
|
+
value: formData[path] ?? "",
|
|
3153
|
+
onChange: (e) => handleChange(e, path),
|
|
3154
|
+
disabled
|
|
3155
|
+
}
|
|
3156
|
+
),
|
|
3157
|
+
errors[path] && /* @__PURE__ */ jsx17("p", { className: "text-red-500 text-sm mt-1", children: errors[path] })
|
|
3158
|
+
] }),
|
|
3159
|
+
col.type === "customerDropdown" && /* @__PURE__ */ jsxs11("div", { children: [
|
|
3160
|
+
/* @__PURE__ */ jsx17(Label3, { className: "block text-sm font-medium mb-1", children: "Name" }),
|
|
3161
|
+
/* @__PURE__ */ jsx17(
|
|
3162
|
+
Input,
|
|
3163
|
+
{
|
|
3164
|
+
type: "text",
|
|
3165
|
+
placeholder: "Customer name",
|
|
3166
|
+
value: formData["contact.name"] ?? "",
|
|
3167
|
+
onChange: (e) => setFormData((prev) => ({
|
|
3168
|
+
...prev,
|
|
3169
|
+
"contact.name": e.target.value
|
|
3170
|
+
}))
|
|
3171
|
+
}
|
|
3172
|
+
)
|
|
3173
|
+
] })
|
|
3174
|
+
] }, path);
|
|
3175
|
+
}),
|
|
3176
|
+
isCustomerCreate && /* @__PURE__ */ jsxs11(Fragment3, { children: [
|
|
3177
|
+
/* @__PURE__ */ jsxs11("div", { children: [
|
|
3178
|
+
/* @__PURE__ */ jsx17(Label3, { className: "block text-sm font-medium mb-1", children: "Password" }),
|
|
3185
3179
|
/* @__PURE__ */ jsx17(
|
|
3186
|
-
|
|
3180
|
+
Input,
|
|
3187
3181
|
{
|
|
3188
|
-
type: "
|
|
3189
|
-
|
|
3190
|
-
|
|
3182
|
+
type: "password",
|
|
3183
|
+
value: password,
|
|
3184
|
+
onChange: (e) => setPassword(e.target.value),
|
|
3185
|
+
placeholder: "Min. 6 characters"
|
|
3191
3186
|
}
|
|
3192
3187
|
),
|
|
3188
|
+
errors["_password"] && /* @__PURE__ */ jsx17("p", { className: "text-red-500 text-sm mt-1", children: errors["_password"] })
|
|
3189
|
+
] }),
|
|
3190
|
+
/* @__PURE__ */ jsxs11("div", { children: [
|
|
3191
|
+
/* @__PURE__ */ jsx17(Label3, { className: "block text-sm font-medium mb-1", children: "Confirm Password" }),
|
|
3193
3192
|
/* @__PURE__ */ jsx17(
|
|
3194
|
-
|
|
3193
|
+
Input,
|
|
3195
3194
|
{
|
|
3196
|
-
type: "
|
|
3197
|
-
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
children: "Cancel"
|
|
3195
|
+
type: "password",
|
|
3196
|
+
value: confirmPassword,
|
|
3197
|
+
onChange: (e) => setConfirmPassword(e.target.value),
|
|
3198
|
+
placeholder: "Re-enter password"
|
|
3201
3199
|
}
|
|
3202
|
-
)
|
|
3200
|
+
),
|
|
3201
|
+
errors["_confirmPassword"] && /* @__PURE__ */ jsx17("p", { className: "text-red-500 text-sm mt-1", children: errors["_confirmPassword"] })
|
|
3203
3202
|
] })
|
|
3204
|
-
]
|
|
3205
|
-
}
|
|
3206
|
-
|
|
3203
|
+
] })
|
|
3204
|
+
] }),
|
|
3205
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex gap-2 p-4 border-t border-gray-200 shrink-0 bg-white", children: [
|
|
3206
|
+
/* @__PURE__ */ jsx17(Button, { type: "submit", className: "flex-1", children: "Save" }),
|
|
3207
|
+
/* @__PURE__ */ jsx17(
|
|
3208
|
+
Button,
|
|
3209
|
+
{
|
|
3210
|
+
type: "button",
|
|
3211
|
+
variant: "outline",
|
|
3212
|
+
onClick: onClose,
|
|
3213
|
+
className: "flex-1",
|
|
3214
|
+
children: "Cancel"
|
|
3215
|
+
}
|
|
3216
|
+
)
|
|
3217
|
+
] })
|
|
3218
|
+
] })
|
|
3207
3219
|
]
|
|
3208
3220
|
}
|
|
3209
3221
|
) }) : null;
|
|
@@ -3746,7 +3758,7 @@ init_input();
|
|
|
3746
3758
|
import { useCallback as useCallback2, useEffect as useEffect6, useMemo as useMemo2, useRef as useRef4, useState as useState8 } from "react";
|
|
3747
3759
|
init_utils();
|
|
3748
3760
|
import { Filter, Search, X as X5 } from "lucide-react";
|
|
3749
|
-
import { Fragment as
|
|
3761
|
+
import { Fragment as Fragment4, jsx as jsx22, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
3750
3762
|
var FILTER_BY_NONE = "__filter_by_none__";
|
|
3751
3763
|
var SELECT_VALUE_ALL = "__select_all__";
|
|
3752
3764
|
function isPointerOnRadixOverlayTarget(target, shell) {
|
|
@@ -4030,7 +4042,7 @@ function CrudSearchFilterBar({
|
|
|
4030
4042
|
}
|
|
4031
4043
|
)
|
|
4032
4044
|
] }),
|
|
4033
|
-
activeDef ? /* @__PURE__ */ jsxs15(
|
|
4045
|
+
activeDef ? /* @__PURE__ */ jsxs15(Fragment4, { children: [
|
|
4034
4046
|
activeDef.type === "select" ? /* @__PURE__ */ jsxs15("div", { className: "w-full min-w-0 flex-1 sm:min-w-[200px] sm:max-w-md", children: [
|
|
4035
4047
|
/* @__PURE__ */ jsx22(Label3, { className: "mb-1.5 block text-xs font-medium text-gray-500", children: "Value" }),
|
|
4036
4048
|
activeDef.relationApi && (!relationLabelMaps[activeDef.relationApi] || Object.keys(relationLabelMaps[activeDef.relationApi] ?? {}).length === 0) ? /* @__PURE__ */ jsx22("p", { className: "text-sm text-muted-foreground", children: "Loading options\u2026" }) : /* @__PURE__ */ jsxs15(
|
|
@@ -4386,7 +4398,7 @@ function prepareRecordForDuplicate(resourceName, row) {
|
|
|
4386
4398
|
var CRUD_NO_DUPLICATE_RESOURCES = /* @__PURE__ */ new Set(["form-submissions", "payments"]);
|
|
4387
4399
|
|
|
4388
4400
|
// src/components/Admin/CRUD.tsx
|
|
4389
|
-
import { Fragment as
|
|
4401
|
+
import { Fragment as Fragment5, jsx as jsx23, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
4390
4402
|
function getNestedValue2(obj, path) {
|
|
4391
4403
|
return path.split(".").reduce((current, key) => {
|
|
4392
4404
|
return current && current[key] !== void 0 ? current[key] : null;
|
|
@@ -5047,7 +5059,7 @@ function AdminCRUD({
|
|
|
5047
5059
|
/* @__PURE__ */ jsx23(Button, { onClick: () => window.location.reload(), children: "Retry" })
|
|
5048
5060
|
] }) });
|
|
5049
5061
|
}
|
|
5050
|
-
return /* @__PURE__ */ jsx23(
|
|
5062
|
+
return /* @__PURE__ */ jsx23(Fragment5, { children: /* @__PURE__ */ jsxs16("div", { className: "rounded-lg bg-white shadow-md min-w-0", children: [
|
|
5051
5063
|
/* @__PURE__ */ jsx23("div", { className: "bg-gray-800 border-b border-gray-700 px-4 py-2.5 rounded-t-lg", children: isMobile ? /* @__PURE__ */ jsxs16("div", { className: "flex items-center gap-2 min-w-0", children: [
|
|
5052
5064
|
/* @__PURE__ */ jsxs16("div", { className: "min-w-0 flex-1", children: [
|
|
5053
5065
|
/* @__PURE__ */ jsx23("h1", { className: "text-base font-semibold text-white truncate", children: title }),
|
|
@@ -5449,7 +5461,8 @@ function AdminCRUD({
|
|
|
5449
5461
|
apiEndpoint,
|
|
5450
5462
|
columns,
|
|
5451
5463
|
existingData: editingItem,
|
|
5452
|
-
duplicateSeed
|
|
5464
|
+
duplicateSeed,
|
|
5465
|
+
resource: resourceName
|
|
5453
5466
|
}
|
|
5454
5467
|
),
|
|
5455
5468
|
/* @__PURE__ */ jsx23(
|
|
@@ -6524,7 +6537,7 @@ init_input();
|
|
|
6524
6537
|
init_button();
|
|
6525
6538
|
import { useState as useState13, useEffect as useEffect9, useRef as useRef7, useCallback as useCallback6 } from "react";
|
|
6526
6539
|
import { X as X10, Plus as Plus4, Search as Search2 } from "lucide-react";
|
|
6527
|
-
import { Fragment as
|
|
6540
|
+
import { Fragment as Fragment6, jsx as jsx29, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
6528
6541
|
function TagAutocomplete({
|
|
6529
6542
|
selectedTags,
|
|
6530
6543
|
onTagsChange,
|
|
@@ -6667,7 +6680,7 @@ function TagAutocomplete({
|
|
|
6667
6680
|
onClick: handleCreateTag,
|
|
6668
6681
|
disabled: isCreating || selectedTags.includes(inputValue.trim()),
|
|
6669
6682
|
className: "absolute right-1 top-1/2 -translate-y-1/2 h-7 px-2",
|
|
6670
|
-
children: isCreating ? "Creating..." : /* @__PURE__ */ jsxs20(
|
|
6683
|
+
children: isCreating ? "Creating..." : /* @__PURE__ */ jsxs20(Fragment6, { children: [
|
|
6671
6684
|
/* @__PURE__ */ jsx29(Plus4, { className: "h-3 w-3 mr-1" }),
|
|
6672
6685
|
"Create"
|
|
6673
6686
|
] })
|
|
@@ -6797,7 +6810,7 @@ init_input();
|
|
|
6797
6810
|
init_button();
|
|
6798
6811
|
import { useState as useState14, useEffect as useEffect10, useRef as useRef8 } from "react";
|
|
6799
6812
|
import { X as X11, Plus as Plus5, Search as Search3, Check as Check5 } from "lucide-react";
|
|
6800
|
-
import { Fragment as
|
|
6813
|
+
import { Fragment as Fragment7, jsx as jsx31, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
6801
6814
|
function CategoryAutocomplete({
|
|
6802
6815
|
selectedCategory,
|
|
6803
6816
|
onCategoryChange,
|
|
@@ -6935,7 +6948,7 @@ function CategoryAutocomplete({
|
|
|
6935
6948
|
onClick: handleCreateCategory,
|
|
6936
6949
|
disabled: isCreating,
|
|
6937
6950
|
className: "absolute right-1 top-1/2 -translate-y-1/2 h-7 px-2",
|
|
6938
|
-
children: isCreating ? "Creating..." : /* @__PURE__ */ jsxs21(
|
|
6951
|
+
children: isCreating ? "Creating..." : /* @__PURE__ */ jsxs21(Fragment7, { children: [
|
|
6939
6952
|
/* @__PURE__ */ jsx31(Plus5, { className: "h-3 w-3 mr-1" }),
|
|
6940
6953
|
"Create"
|
|
6941
6954
|
] })
|
|
@@ -8456,7 +8469,7 @@ var BLOG_GENERATOR_DEFAULT_VALIDATION_RULES = JSON.stringify(
|
|
|
8456
8469
|
);
|
|
8457
8470
|
|
|
8458
8471
|
// src/components/Admin/BlogGeneratorRssTool.tsx
|
|
8459
|
-
import { Fragment as
|
|
8472
|
+
import { Fragment as Fragment8, jsx as jsx41, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
8460
8473
|
function BlogGeneratorRssTool({
|
|
8461
8474
|
inputIdPrefix = "blog-gen-rss",
|
|
8462
8475
|
variant = "page"
|
|
@@ -8919,11 +8932,11 @@ function BlogGeneratorRssTool({
|
|
|
8919
8932
|
" row \u2014 model",
|
|
8920
8933
|
" ",
|
|
8921
8934
|
/* @__PURE__ */ jsx41("span", { className: "font-mono", children: llmAgentInfo.model ?? "(gateway default)" }),
|
|
8922
|
-
llmAgentInfo.temperature != null && /* @__PURE__ */ jsxs31(
|
|
8935
|
+
llmAgentInfo.temperature != null && /* @__PURE__ */ jsxs31(Fragment8, { children: [
|
|
8923
8936
|
", temperature ",
|
|
8924
8937
|
/* @__PURE__ */ jsx41("span", { className: "font-mono", children: String(llmAgentInfo.temperature) })
|
|
8925
8938
|
] }),
|
|
8926
|
-
llmAgentInfo.maxTokens != null && /* @__PURE__ */ jsxs31(
|
|
8939
|
+
llmAgentInfo.maxTokens != null && /* @__PURE__ */ jsxs31(Fragment8, { children: [
|
|
8927
8940
|
", max_tokens ",
|
|
8928
8941
|
/* @__PURE__ */ jsx41("span", { className: "font-mono", children: String(llmAgentInfo.maxTokens) })
|
|
8929
8942
|
] }),
|
|
@@ -8946,11 +8959,11 @@ function BlogGeneratorRssTool({
|
|
|
8946
8959
|
" \u2014 model",
|
|
8947
8960
|
" ",
|
|
8948
8961
|
/* @__PURE__ */ jsx41("span", { className: "font-mono", children: metadataLlmAgentInfo.model ?? "(gateway default)" }),
|
|
8949
|
-
metadataLlmAgentInfo.temperature != null && /* @__PURE__ */ jsxs31(
|
|
8962
|
+
metadataLlmAgentInfo.temperature != null && /* @__PURE__ */ jsxs31(Fragment8, { children: [
|
|
8950
8963
|
", temperature ",
|
|
8951
8964
|
/* @__PURE__ */ jsx41("span", { className: "font-mono", children: String(metadataLlmAgentInfo.temperature) })
|
|
8952
8965
|
] }),
|
|
8953
|
-
metadataLlmAgentInfo.maxTokens != null && /* @__PURE__ */ jsxs31(
|
|
8966
|
+
metadataLlmAgentInfo.maxTokens != null && /* @__PURE__ */ jsxs31(Fragment8, { children: [
|
|
8954
8967
|
", max_tokens ",
|
|
8955
8968
|
/* @__PURE__ */ jsx41("span", { className: "font-mono", children: String(metadataLlmAgentInfo.maxTokens) })
|
|
8956
8969
|
] }),
|
|
@@ -9043,7 +9056,9 @@ var SigninPage = () => {
|
|
|
9043
9056
|
const router = useRouter5();
|
|
9044
9057
|
const { status } = useSession5();
|
|
9045
9058
|
useEffect18(() => {
|
|
9059
|
+
logAuthClient("SignInPage session status", { status });
|
|
9046
9060
|
if (status === "authenticated") {
|
|
9061
|
+
logAuthClient("SignInPage redirect \u2192 /admin/dashboard (already authenticated)");
|
|
9047
9062
|
router.replace("/admin/dashboard");
|
|
9048
9063
|
}
|
|
9049
9064
|
}, [status, router]);
|
|
@@ -9052,14 +9067,22 @@ var SigninPage = () => {
|
|
|
9052
9067
|
setLoading(true);
|
|
9053
9068
|
setError("");
|
|
9054
9069
|
try {
|
|
9070
|
+
logAuthClient("SignInPage signIn start", { email });
|
|
9055
9071
|
const result = await signIn("credentials", {
|
|
9056
9072
|
email,
|
|
9057
9073
|
password,
|
|
9058
9074
|
redirect: false
|
|
9059
9075
|
});
|
|
9076
|
+
logAuthClient("SignInPage signIn result", {
|
|
9077
|
+
ok: result?.ok ?? null,
|
|
9078
|
+
error: result?.error ?? null,
|
|
9079
|
+
status: result?.status ?? null,
|
|
9080
|
+
url: result?.url ?? null
|
|
9081
|
+
});
|
|
9060
9082
|
if (result?.error) {
|
|
9061
9083
|
setError("Invalid email or password");
|
|
9062
9084
|
} else {
|
|
9085
|
+
logAuthClient("SignInPage navigate \u2192 /admin/dashboard");
|
|
9063
9086
|
window.location.assign("/admin/dashboard");
|
|
9064
9087
|
}
|
|
9065
9088
|
} catch (error2) {
|
|
@@ -9348,7 +9371,7 @@ import { useRouter as useRouter6 } from "next/navigation";
|
|
|
9348
9371
|
import { Chart as ChartJS2, ArcElement, Tooltip as Tooltip2, Legend as Legend2 } from "chart.js";
|
|
9349
9372
|
import { Doughnut } from "react-chartjs-2";
|
|
9350
9373
|
import { Users as Users4, Eye, MousePointer, Globe, FileText, ClipboardList as ClipboardList2, UserCheck, TrendingUp, BarChart3, Activity } from "lucide-react";
|
|
9351
|
-
import { Fragment as
|
|
9374
|
+
import { Fragment as Fragment9, jsx as jsx48, jsxs as jsxs38 } from "react/jsx-runtime";
|
|
9352
9375
|
ChartJS2.register(ArcElement, Tooltip2, Legend2);
|
|
9353
9376
|
function DashboardPage() {
|
|
9354
9377
|
const { data: session } = useSession6();
|
|
@@ -9692,7 +9715,7 @@ function DashboardPage() {
|
|
|
9692
9715
|
) })
|
|
9693
9716
|
] })
|
|
9694
9717
|
] }),
|
|
9695
|
-
activeTab === "overview" && analyticsEnabled && !isLoading && analyticsData && /* @__PURE__ */ jsxs38(
|
|
9718
|
+
activeTab === "overview" && analyticsEnabled && !isLoading && analyticsData && /* @__PURE__ */ jsxs38(Fragment9, { children: [
|
|
9696
9719
|
/* @__PURE__ */ jsxs38("div", { className: "mb-4", children: [
|
|
9697
9720
|
/* @__PURE__ */ jsxs38("div", { className: "flex items-center mb-2", children: [
|
|
9698
9721
|
/* @__PURE__ */ jsx48(Globe, { className: "w-4 h-4 text-gray-600 mr-2" }),
|
|
@@ -9778,7 +9801,7 @@ function DashboardPage() {
|
|
|
9778
9801
|
/* @__PURE__ */ jsx48("div", { className: "border-t-2 border-dotted border-gray-200 my-6" }),
|
|
9779
9802
|
/* @__PURE__ */ jsx48("div", { className: "mb-6", children: /* @__PURE__ */ jsx48(GeographicMap, { data: analyticsData.geographicData }) })
|
|
9780
9803
|
] }),
|
|
9781
|
-
activeTab === "crm" && !isLoading && /* @__PURE__ */ jsxs38(
|
|
9804
|
+
activeTab === "crm" && !isLoading && /* @__PURE__ */ jsxs38(Fragment9, { children: [
|
|
9782
9805
|
/* @__PURE__ */ jsxs38("div", { className: "mb-4", children: [
|
|
9783
9806
|
/* @__PURE__ */ jsxs38("div", { className: "flex items-center mb-2", children: [
|
|
9784
9807
|
/* @__PURE__ */ jsx48(Users4, { className: "w-4 h-4 text-gray-600 mr-2" }),
|
|
@@ -9896,7 +9919,7 @@ function DashboardPage() {
|
|
|
9896
9919
|
] })
|
|
9897
9920
|
] })
|
|
9898
9921
|
] }),
|
|
9899
|
-
activeTab === "sales" && !isLoading && storeEnabled && ecommerceData && /* @__PURE__ */ jsxs38(
|
|
9922
|
+
activeTab === "sales" && !isLoading && storeEnabled && ecommerceData && /* @__PURE__ */ jsxs38(Fragment9, { children: [
|
|
9900
9923
|
/* @__PURE__ */ jsx48("div", { className: "border-t-2 border-dotted border-gray-200 my-6" }),
|
|
9901
9924
|
/* @__PURE__ */ jsxs38("div", { className: "mb-4", children: [
|
|
9902
9925
|
/* @__PURE__ */ jsxs38("div", { className: "flex items-center mb-2", children: [
|
|
@@ -10042,7 +10065,7 @@ function DashboardPage() {
|
|
|
10042
10065
|
// src/admin/pages/AdminPageResolver.tsx
|
|
10043
10066
|
import { useState as useState50, useEffect as useEffect47, useContext as useContext9, useMemo as useMemo10, Suspense as Suspense3 } from "react";
|
|
10044
10067
|
import dynamic2 from "next/dynamic";
|
|
10045
|
-
import { useRouter as
|
|
10068
|
+
import { useRouter as useRouter22, useSearchParams as useSearchParams20 } from "next/navigation";
|
|
10046
10069
|
|
|
10047
10070
|
// src/admin/pages/SubmissionDetailPage.tsx
|
|
10048
10071
|
init_admin_list_return_url();
|
|
@@ -10178,7 +10201,8 @@ import { useEffect as useEffect23, useState as useState26 } from "react";
|
|
|
10178
10201
|
import Link10 from "next/link";
|
|
10179
10202
|
import { useRouter as useRouter8, useSearchParams as useSearchParams5 } from "next/navigation";
|
|
10180
10203
|
import { X as X15, RefreshCw as RefreshCw2, Pencil } from "lucide-react";
|
|
10181
|
-
import {
|
|
10204
|
+
import { QRCode } from "react-qr-code";
|
|
10205
|
+
import { Fragment as Fragment11, jsx as jsx52, jsxs as jsxs42 } from "react/jsx-runtime";
|
|
10182
10206
|
function formatMoney(amount, currency = "INR") {
|
|
10183
10207
|
return new Intl.NumberFormat("en-IN", {
|
|
10184
10208
|
style: "currency",
|
|
@@ -10309,7 +10333,7 @@ function OrderDetailPage({ orderId }) {
|
|
|
10309
10333
|
/* @__PURE__ */ jsx52(
|
|
10310
10334
|
DetailPageLayout,
|
|
10311
10335
|
{
|
|
10312
|
-
main: /* @__PURE__ */ jsxs42(
|
|
10336
|
+
main: /* @__PURE__ */ jsxs42(Fragment11, { children: [
|
|
10313
10337
|
/* @__PURE__ */ jsxs42("section", { children: [
|
|
10314
10338
|
/* @__PURE__ */ jsx52("h2", { className: "text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2", children: "Order details" }),
|
|
10315
10339
|
/* @__PURE__ */ jsx52("div", { className: "min-w-0 overflow-hidden border border-gray-200 rounded-lg p-4 bg-gray-50/50", children: /* @__PURE__ */ jsxs42("dl", { className: "min-w-0 grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-3 text-sm", children: [
|
|
@@ -10341,7 +10365,7 @@ function OrderDetailPage({ orderId }) {
|
|
|
10341
10365
|
/* @__PURE__ */ jsx52("dt", { className: "text-gray-500", children: "Total" }),
|
|
10342
10366
|
/* @__PURE__ */ jsx52("dd", { className: "font-medium text-gray-900", children: formatMoney(Number(order.total), currency) })
|
|
10343
10367
|
] }),
|
|
10344
|
-
(order.orderKind || order.parentOrderId != null) && /* @__PURE__ */ jsxs42(
|
|
10368
|
+
(order.orderKind || order.parentOrderId != null) && /* @__PURE__ */ jsxs42(Fragment11, { children: [
|
|
10345
10369
|
/* @__PURE__ */ jsxs42("div", { className: "min-w-0", children: [
|
|
10346
10370
|
/* @__PURE__ */ jsx52("dt", { className: "text-gray-500", children: "Kind" }),
|
|
10347
10371
|
/* @__PURE__ */ jsx52("dd", { className: "font-medium text-gray-900 capitalize", children: order.orderKind ?? "sale" })
|
|
@@ -10464,7 +10488,7 @@ function OrderDetailPage({ orderId }) {
|
|
|
10464
10488
|
] })
|
|
10465
10489
|
] }) })
|
|
10466
10490
|
] }),
|
|
10467
|
-
sidebar: /* @__PURE__ */ jsxs42(
|
|
10491
|
+
sidebar: /* @__PURE__ */ jsxs42(Fragment11, { children: [
|
|
10468
10492
|
contact && /* @__PURE__ */ jsxs42("section", { children: [
|
|
10469
10493
|
/* @__PURE__ */ jsx52("h2", { className: "text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2", children: "Customer" }),
|
|
10470
10494
|
/* @__PURE__ */ jsx52("div", { className: "min-w-0 overflow-hidden border border-gray-200 rounded-lg p-4 bg-gray-50/50", children: /* @__PURE__ */ jsxs42("dl", { className: "min-w-0 grid grid-cols-1 sm:grid-cols-3 gap-3 text-sm", children: [
|
|
@@ -10535,6 +10559,19 @@ function OrderDetailPage({ orderId }) {
|
|
|
10535
10559
|
},
|
|
10536
10560
|
p.id
|
|
10537
10561
|
)) })
|
|
10562
|
+
] }),
|
|
10563
|
+
order.qrToken && /* @__PURE__ */ jsxs42("section", { children: [
|
|
10564
|
+
/* @__PURE__ */ jsx52("h2", { className: "text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2", children: "Order QR Code" }),
|
|
10565
|
+
/* @__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: [
|
|
10566
|
+
/* @__PURE__ */ jsx52(
|
|
10567
|
+
QRCode,
|
|
10568
|
+
{
|
|
10569
|
+
value: `${window.location.origin}/track/${order.qrToken}`,
|
|
10570
|
+
size: 180
|
|
10571
|
+
}
|
|
10572
|
+
),
|
|
10573
|
+
/* @__PURE__ */ jsx52("p", { className: "text-xs text-gray-400 break-all text-center", children: order.qrToken })
|
|
10574
|
+
] })
|
|
10538
10575
|
] })
|
|
10539
10576
|
] })
|
|
10540
10577
|
}
|
|
@@ -10580,7 +10617,7 @@ Checkbox.displayName = CheckboxPrimitive.Root.displayName;
|
|
|
10580
10617
|
init_table();
|
|
10581
10618
|
init_DetailPageHeader();
|
|
10582
10619
|
import { toast as toast5 } from "sonner";
|
|
10583
|
-
import { Trash2 as Trash25, ShoppingCart as ShoppingCart4 } from "lucide-react";
|
|
10620
|
+
import { Trash2 as Trash25, ShoppingCart as ShoppingCart4, Users as Users6 } from "lucide-react";
|
|
10584
10621
|
|
|
10585
10622
|
// src/admin/pages/OrderDiscountPanel.tsx
|
|
10586
10623
|
init_input();
|
|
@@ -10992,6 +11029,7 @@ function formatMoney3(amount, currency) {
|
|
|
10992
11029
|
}).format(Number(amount));
|
|
10993
11030
|
}
|
|
10994
11031
|
var MANUAL_CUSTOMER = "__manual__";
|
|
11032
|
+
var MANUAL_CONTACT = "__manual__";
|
|
10995
11033
|
function OrderPlacementPage({ editOrderId }) {
|
|
10996
11034
|
const router = useRouter9();
|
|
10997
11035
|
const searchParams = useSearchParams6();
|
|
@@ -10999,25 +11037,23 @@ function OrderPlacementPage({ editOrderId }) {
|
|
|
10999
11037
|
const [customers, setCustomers] = useState28([]);
|
|
11000
11038
|
const [customersLoading, setCustomersLoading] = useState28(true);
|
|
11001
11039
|
const [contactId, setContactId] = useState28(null);
|
|
11040
|
+
const [selectedCustomerId, setSelectedCustomerId] = useState28(null);
|
|
11002
11041
|
const [contactName, setContactName] = useState28("");
|
|
11003
11042
|
const [contactEmail, setContactEmail] = useState28("");
|
|
11004
11043
|
const [contactPhone, setContactPhone] = useState28("");
|
|
11044
|
+
const [placeForSomeoneElse, setPlaceForSomeoneElse] = useState28(false);
|
|
11045
|
+
const [customerContacts, setCustomerContacts] = useState28([]);
|
|
11046
|
+
const [customerContactsLoading, setCustomerContactsLoading] = useState28(false);
|
|
11047
|
+
const [subContactId, setSubContactId] = useState28(null);
|
|
11048
|
+
const [subContactName, setSubContactName] = useState28("");
|
|
11049
|
+
const [subContactEmail, setSubContactEmail] = useState28("");
|
|
11050
|
+
const [subContactPhone, setSubContactPhone] = useState28("");
|
|
11005
11051
|
const [status, setStatus] = useState28("pending");
|
|
11006
11052
|
const [currency, setCurrency] = useState28("INR");
|
|
11007
11053
|
const [loadingOrder, setLoadingOrder] = useState28(Boolean(editOrderId));
|
|
11008
11054
|
const [orderLoadError, setOrderLoadError] = useState28(null);
|
|
11009
|
-
const [couponError, setCouponError] = useState28(null);
|
|
11010
|
-
const [couponLoading, setCouponLoading] = useState28(false);
|
|
11011
11055
|
const [coupons, setCoupons] = useState28([]);
|
|
11012
|
-
const
|
|
11013
|
-
const emptyAddress = {
|
|
11014
|
-
line1: "",
|
|
11015
|
-
line2: "",
|
|
11016
|
-
city: "",
|
|
11017
|
-
state: "",
|
|
11018
|
-
country: "",
|
|
11019
|
-
postalCode: ""
|
|
11020
|
-
};
|
|
11056
|
+
const emptyAddress = { line1: "", line2: "", city: "", state: "", country: "", postalCode: "" };
|
|
11021
11057
|
const [billingAddress, setBillingAddress] = useState28(emptyAddress);
|
|
11022
11058
|
const [shippingAddress, setShippingAddress] = useState28(emptyAddress);
|
|
11023
11059
|
const [sameAsBilling, setSameAsBilling] = useState28(true);
|
|
@@ -11080,9 +11116,7 @@ function OrderPlacementPage({ editOrderId }) {
|
|
|
11080
11116
|
setSameAsBilling(true);
|
|
11081
11117
|
}
|
|
11082
11118
|
const loadedCid = typeof cid === "number" && Number.isFinite(cid) ? cid : null;
|
|
11083
|
-
if (loadedCid && !o.billingAddress && !o.shippingAddress)
|
|
11084
|
-
void loadCustomerAddresses(loadedCid);
|
|
11085
|
-
}
|
|
11119
|
+
if (loadedCid && !o.billingAddress && !o.shippingAddress) void loadContactAddresses(loadedCid);
|
|
11086
11120
|
setStatus(String(o.status ?? "pending"));
|
|
11087
11121
|
const cur = String(o.currency ?? "INR").trim().toUpperCase().slice(0, 8);
|
|
11088
11122
|
if (cur) setCurrency(cur);
|
|
@@ -11092,13 +11126,7 @@ function OrderPlacementPage({ editOrderId }) {
|
|
|
11092
11126
|
const coll = p?.collection?.name;
|
|
11093
11127
|
const nm = p?.name;
|
|
11094
11128
|
const label = [coll, nm].filter(Boolean).join(" \u2014 ") || nm || `Product #${pid}`;
|
|
11095
|
-
return {
|
|
11096
|
-
key: `line-${it.id}`,
|
|
11097
|
-
productId: pid,
|
|
11098
|
-
label,
|
|
11099
|
-
sku: p?.sku ?? null,
|
|
11100
|
-
quantity: Math.max(1, Math.floor(Number(it.quantity) || 1))
|
|
11101
|
-
};
|
|
11129
|
+
return { key: `line-${it.id}`, productId: pid, label, sku: p?.sku ?? null, quantity: Math.max(1, Math.floor(Number(it.quantity) || 1)) };
|
|
11102
11130
|
});
|
|
11103
11131
|
setLines(draft);
|
|
11104
11132
|
try {
|
|
@@ -11111,18 +11139,7 @@ function OrderPlacementPage({ editOrderId }) {
|
|
|
11111
11139
|
if (dr.ok) {
|
|
11112
11140
|
const d = await dr.json();
|
|
11113
11141
|
if (d?.id) {
|
|
11114
|
-
setCoupons([{
|
|
11115
|
-
couponCode: d.couponCode ?? "",
|
|
11116
|
-
discountId: d.id,
|
|
11117
|
-
name: d.name,
|
|
11118
|
-
value: d.value,
|
|
11119
|
-
type: d.discountType,
|
|
11120
|
-
canCombine: !!d.canCombineWithOtherDiscounts,
|
|
11121
|
-
calculatedDiscount: 0,
|
|
11122
|
-
rewardProductIds: [],
|
|
11123
|
-
rewardLines: [],
|
|
11124
|
-
isAutomatic: d.isAutomatic ?? false
|
|
11125
|
-
}]);
|
|
11142
|
+
setCoupons([{ couponCode: d.couponCode ?? "", discountId: d.id, name: d.name, value: d.value, type: d.discountType, canCombine: !!d.canCombineWithOtherDiscounts, calculatedDiscount: 0, rewardProductIds: [], rewardLines: [], isAutomatic: d.isAutomatic ?? false }]);
|
|
11126
11143
|
}
|
|
11127
11144
|
}
|
|
11128
11145
|
}
|
|
@@ -11133,12 +11150,7 @@ function OrderPlacementPage({ editOrderId }) {
|
|
|
11133
11150
|
const pid = Number(it.productId);
|
|
11134
11151
|
const p = it.product;
|
|
11135
11152
|
const unit = Number(it.unitPrice ?? 0);
|
|
11136
|
-
productCache.current.set(pid, {
|
|
11137
|
-
id: pid,
|
|
11138
|
-
name: p?.name ?? null,
|
|
11139
|
-
sku: p?.sku ?? null,
|
|
11140
|
-
price: Number.isFinite(unit) ? unit : 0
|
|
11141
|
-
});
|
|
11153
|
+
productCache.current.set(pid, { id: pid, name: p?.name ?? null, sku: p?.sku ?? null, price: Number.isFinite(unit) ? unit : 0 });
|
|
11142
11154
|
}
|
|
11143
11155
|
} catch {
|
|
11144
11156
|
if (!cancelled) setOrderLoadError("Failed to load order");
|
|
@@ -11155,23 +11167,17 @@ function OrderPlacementPage({ editOrderId }) {
|
|
|
11155
11167
|
(async () => {
|
|
11156
11168
|
setCustomersLoading(true);
|
|
11157
11169
|
try {
|
|
11158
|
-
const res = await fetch(
|
|
11159
|
-
"/api/vendor_customers?limit=500&sortField=createdAt&sortOrder=asc"
|
|
11160
|
-
);
|
|
11170
|
+
const res = await fetch("/api/vendor_customers?limit=500&sortField=createdAt&sortOrder=asc");
|
|
11161
11171
|
if (!res.ok) {
|
|
11162
11172
|
if (!cancelled) setCustomers([]);
|
|
11163
11173
|
return;
|
|
11164
11174
|
}
|
|
11165
11175
|
const data = await res.json();
|
|
11166
11176
|
const rows = (Array.isArray(data?.data) ? data.data : []).map((row) => {
|
|
11167
|
-
const id = Number(row.
|
|
11177
|
+
const id = Number(row.id);
|
|
11168
11178
|
if (!Number.isFinite(id)) return null;
|
|
11169
|
-
|
|
11170
|
-
|
|
11171
|
-
name: row.name ?? row.contact?.name ?? null,
|
|
11172
|
-
email: row.email ?? row.contact?.email ?? null,
|
|
11173
|
-
phone: row.phone ?? row.contact?.phone ?? null
|
|
11174
|
-
};
|
|
11179
|
+
const rawCustomerId = Number(row.customerId);
|
|
11180
|
+
return { id, customerId: Number.isFinite(rawCustomerId) && rawCustomerId > 0 ? rawCustomerId : null, name: row.name ?? null, email: row.email ?? null, phone: row.phone ?? null };
|
|
11175
11181
|
}).filter((r) => r != null);
|
|
11176
11182
|
if (!cancelled) setCustomers(rows);
|
|
11177
11183
|
} catch {
|
|
@@ -11184,6 +11190,140 @@ function OrderPlacementPage({ editOrderId }) {
|
|
|
11184
11190
|
cancelled = true;
|
|
11185
11191
|
};
|
|
11186
11192
|
}, []);
|
|
11193
|
+
async function loadCustomerContacts(customerId) {
|
|
11194
|
+
setCustomerContactsLoading(true);
|
|
11195
|
+
setCustomerContacts([]);
|
|
11196
|
+
setSubContactId(null);
|
|
11197
|
+
setSubContactName("");
|
|
11198
|
+
setSubContactEmail("");
|
|
11199
|
+
setSubContactPhone("");
|
|
11200
|
+
try {
|
|
11201
|
+
const res = await fetch(`/api/customer_contacts?customerId=${customerId}&limit=200&sortField=id&sortOrder=asc`);
|
|
11202
|
+
if (!res.ok) return;
|
|
11203
|
+
const data = await res.json();
|
|
11204
|
+
const rows = (Array.isArray(data?.data) ? data.data : Array.isArray(data) ? data : []).filter((r) => r.contact && Number.isFinite(Number(r.contactId)));
|
|
11205
|
+
setCustomerContacts(rows);
|
|
11206
|
+
} catch {
|
|
11207
|
+
setCustomerContacts([]);
|
|
11208
|
+
} finally {
|
|
11209
|
+
setCustomerContactsLoading(false);
|
|
11210
|
+
}
|
|
11211
|
+
}
|
|
11212
|
+
async function loadContactAddressesByEmail(email) {
|
|
11213
|
+
try {
|
|
11214
|
+
const res = await fetch(`/api/contacts?search=${encodeURIComponent(email)}&limit=5`);
|
|
11215
|
+
if (!res.ok) {
|
|
11216
|
+
setBillingAddress({ ...emptyAddress });
|
|
11217
|
+
setShippingAddress({ ...emptyAddress });
|
|
11218
|
+
return;
|
|
11219
|
+
}
|
|
11220
|
+
const data = await res.json();
|
|
11221
|
+
const match = data.data?.find((c) => c.email?.toLowerCase() === email.toLowerCase());
|
|
11222
|
+
if (!match) {
|
|
11223
|
+
setBillingAddress({ ...emptyAddress });
|
|
11224
|
+
setShippingAddress({ ...emptyAddress });
|
|
11225
|
+
return;
|
|
11226
|
+
}
|
|
11227
|
+
await loadContactAddresses(match.id);
|
|
11228
|
+
} catch {
|
|
11229
|
+
setBillingAddress({ ...emptyAddress });
|
|
11230
|
+
setShippingAddress({ ...emptyAddress });
|
|
11231
|
+
}
|
|
11232
|
+
}
|
|
11233
|
+
async function loadContactAddresses(cid) {
|
|
11234
|
+
try {
|
|
11235
|
+
const res = await fetch(`/api/order_addresses?contactId=${cid}&limit=100&sortField=createdAt&sortOrder=desc`);
|
|
11236
|
+
if (!res.ok) return;
|
|
11237
|
+
const body = await res.json();
|
|
11238
|
+
const rows = Array.isArray(body) ? body : Array.isArray(body?.data) ? body.data : [];
|
|
11239
|
+
const billing = rows.find((a) => a.addressType === "billing_address");
|
|
11240
|
+
const shipping = rows.find((a) => a.addressType === "shipping_address");
|
|
11241
|
+
if (billing) setBillingAddress(mapAddressToForm(billing));
|
|
11242
|
+
else setBillingAddress({ ...emptyAddress });
|
|
11243
|
+
if (sameAsBilling) setShippingAddress(billing ? mapAddressToForm(billing) : { ...emptyAddress });
|
|
11244
|
+
else setShippingAddress(shipping ? mapAddressToForm(shipping) : { ...emptyAddress });
|
|
11245
|
+
} catch {
|
|
11246
|
+
setBillingAddress(emptyAddress);
|
|
11247
|
+
setShippingAddress(emptyAddress);
|
|
11248
|
+
}
|
|
11249
|
+
}
|
|
11250
|
+
function handleCustomerSelect(value) {
|
|
11251
|
+
if (value === MANUAL_CUSTOMER) {
|
|
11252
|
+
setContactId(null);
|
|
11253
|
+
setSelectedCustomerId(null);
|
|
11254
|
+
setCustomerContacts([]);
|
|
11255
|
+
setSubContactId(null);
|
|
11256
|
+
setSubContactName("");
|
|
11257
|
+
setSubContactEmail("");
|
|
11258
|
+
setSubContactPhone("");
|
|
11259
|
+
setBillingAddress({ ...emptyAddress });
|
|
11260
|
+
setShippingAddress({ ...emptyAddress });
|
|
11261
|
+
return;
|
|
11262
|
+
}
|
|
11263
|
+
const id = Number(value);
|
|
11264
|
+
if (!Number.isFinite(id)) return;
|
|
11265
|
+
const customer = customers.find((c) => c.id === id);
|
|
11266
|
+
if (!customer) return;
|
|
11267
|
+
setContactId(id);
|
|
11268
|
+
setSelectedCustomerId(customer.customerId ?? null);
|
|
11269
|
+
setContactName(customer.name ?? "");
|
|
11270
|
+
setContactEmail(customer.email ?? "");
|
|
11271
|
+
setContactPhone(customer.phone ?? "");
|
|
11272
|
+
setSubContactId(null);
|
|
11273
|
+
setSubContactName("");
|
|
11274
|
+
setSubContactEmail("");
|
|
11275
|
+
setSubContactPhone("");
|
|
11276
|
+
setPlaceForSomeoneElse(false);
|
|
11277
|
+
if (customer.customerId != null) loadCustomerContacts(customer.customerId);
|
|
11278
|
+
if (customer.email) {
|
|
11279
|
+
loadContactAddressesByEmail(customer.email);
|
|
11280
|
+
} else {
|
|
11281
|
+
setBillingAddress({ ...emptyAddress });
|
|
11282
|
+
setShippingAddress({ ...emptyAddress });
|
|
11283
|
+
}
|
|
11284
|
+
}
|
|
11285
|
+
function handleSubContactSelect(value) {
|
|
11286
|
+
if (value === MANUAL_CONTACT) {
|
|
11287
|
+
setSubContactId(null);
|
|
11288
|
+
setSubContactName("");
|
|
11289
|
+
setSubContactEmail("");
|
|
11290
|
+
setSubContactPhone("");
|
|
11291
|
+
setBillingAddress({ ...emptyAddress });
|
|
11292
|
+
setShippingAddress({ ...emptyAddress });
|
|
11293
|
+
return;
|
|
11294
|
+
}
|
|
11295
|
+
const cid = Number(value);
|
|
11296
|
+
if (!Number.isFinite(cid)) return;
|
|
11297
|
+
const row = customerContacts.find((r) => r.contactId === cid);
|
|
11298
|
+
if (!row) return;
|
|
11299
|
+
setSubContactId(cid);
|
|
11300
|
+
setSubContactName(row.contact.name ?? "");
|
|
11301
|
+
setSubContactEmail(row.contact.email ?? "");
|
|
11302
|
+
setSubContactPhone(row.contact.phone ?? "");
|
|
11303
|
+
loadContactAddresses(cid);
|
|
11304
|
+
}
|
|
11305
|
+
function handlePlaceForSomeoneElseToggle(checked) {
|
|
11306
|
+
setPlaceForSomeoneElse(checked);
|
|
11307
|
+
if (checked) {
|
|
11308
|
+
setBillingAddress({ ...emptyAddress });
|
|
11309
|
+
setShippingAddress({ ...emptyAddress });
|
|
11310
|
+
setSubContactId(null);
|
|
11311
|
+
setSubContactName("");
|
|
11312
|
+
setSubContactEmail("");
|
|
11313
|
+
setSubContactPhone("");
|
|
11314
|
+
return;
|
|
11315
|
+
}
|
|
11316
|
+
setSubContactId(null);
|
|
11317
|
+
setSubContactName("");
|
|
11318
|
+
setSubContactEmail("");
|
|
11319
|
+
setSubContactPhone("");
|
|
11320
|
+
if (contactEmail) {
|
|
11321
|
+
loadContactAddressesByEmail(contactEmail);
|
|
11322
|
+
} else {
|
|
11323
|
+
setBillingAddress({ ...emptyAddress });
|
|
11324
|
+
setShippingAddress({ ...emptyAddress });
|
|
11325
|
+
}
|
|
11326
|
+
}
|
|
11187
11327
|
const cartProductIds = useMemo6(() => new Set(lines.map((l) => l.productId)), [lines]);
|
|
11188
11328
|
useEffect25(() => {
|
|
11189
11329
|
const q = productQuery.trim();
|
|
@@ -11192,13 +11332,7 @@ function OrderPlacementPage({ editOrderId }) {
|
|
|
11192
11332
|
(async () => {
|
|
11193
11333
|
setHitsLoading(true);
|
|
11194
11334
|
try {
|
|
11195
|
-
const params = new URLSearchParams({
|
|
11196
|
-
limit: "50",
|
|
11197
|
-
page: "1",
|
|
11198
|
-
sortField: "name",
|
|
11199
|
-
sortOrder: "asc",
|
|
11200
|
-
status: "available"
|
|
11201
|
-
});
|
|
11335
|
+
const params = new URLSearchParams({ limit: "50", page: "1", sortField: "name", sortOrder: "asc", status: "available" });
|
|
11202
11336
|
if (q.length >= 2) params.set("search", q);
|
|
11203
11337
|
const res = await fetch(`/api/products?${params}`);
|
|
11204
11338
|
if (!res.ok) {
|
|
@@ -11279,53 +11413,34 @@ function OrderPlacementPage({ editOrderId }) {
|
|
|
11279
11413
|
const res = await fetch("/api/discounts/validate-coupon", {
|
|
11280
11414
|
method: "POST",
|
|
11281
11415
|
headers: { "Content-Type": "application/json" },
|
|
11282
|
-
body: JSON.stringify({
|
|
11283
|
-
discountId: coupon.discountId,
|
|
11284
|
-
isAutomatic: true,
|
|
11285
|
-
orderLines: nonRewardLines.map((l) => ({ productId: l.productId, quantity: l.quantity })),
|
|
11286
|
-
currency,
|
|
11287
|
-
contactId
|
|
11288
|
-
})
|
|
11416
|
+
body: JSON.stringify({ discountId: coupon.discountId, isAutomatic: true, orderLines: nonRewardLines.map((l) => ({ productId: l.productId, quantity: l.quantity })), currency, contactId })
|
|
11289
11417
|
});
|
|
11290
11418
|
if (cancelled) return;
|
|
11291
11419
|
const data = await res.json();
|
|
11292
11420
|
if (!data.valid) {
|
|
11293
11421
|
const rewardPids = new Set(coupon.rewardLines.map((r) => r.productId));
|
|
11294
11422
|
setCoupons((prev) => prev.filter((c) => c.discountId !== coupon.discountId));
|
|
11295
|
-
setLines(
|
|
11296
|
-
(
|
|
11297
|
-
|
|
11298
|
-
|
|
11299
|
-
|
|
11300
|
-
|
|
11301
|
-
|
|
11302
|
-
}).filter((l) => l !== null)
|
|
11303
|
-
);
|
|
11423
|
+
setLines((prev) => prev.map((l) => {
|
|
11424
|
+
if (!rewardPids.has(l.productId)) return l;
|
|
11425
|
+
const rewardLine = coupon.rewardLines.find((r) => r.productId === l.productId);
|
|
11426
|
+
if (!rewardLine) return l;
|
|
11427
|
+
const newQty = l.quantity - rewardLine.quantity;
|
|
11428
|
+
return newQty > 0 ? { ...l, quantity: newQty } : null;
|
|
11429
|
+
}).filter((l) => l !== null));
|
|
11304
11430
|
rewardPids.forEach((pid) => rewardProductIds.current.delete(pid));
|
|
11305
11431
|
rewardInjectedForDiscount.current.delete(coupon.discountId);
|
|
11306
11432
|
} else {
|
|
11307
11433
|
const newRewardLines = data.discount.rewardLines ?? [];
|
|
11308
|
-
setCoupons((prev) => prev.map(
|
|
11309
|
-
(c) => c.discountId !== coupon.discountId ? c : {
|
|
11310
|
-
...c,
|
|
11311
|
-
calculatedDiscount: data.discount.calculatedDiscount,
|
|
11312
|
-
rewardProductIds: data.discount.rewardProductIds ?? [],
|
|
11313
|
-
rewardLines: newRewardLines
|
|
11314
|
-
}
|
|
11315
|
-
));
|
|
11434
|
+
setCoupons((prev) => prev.map((c) => c.discountId !== coupon.discountId ? c : { ...c, calculatedDiscount: data.discount.calculatedDiscount, rewardProductIds: data.discount.rewardProductIds ?? [], rewardLines: newRewardLines }));
|
|
11316
11435
|
setLines((prev) => {
|
|
11317
11436
|
let next = [...prev];
|
|
11318
11437
|
for (const rewardLine of newRewardLines) {
|
|
11319
11438
|
const idx = next.findIndex((l) => l.productId === rewardLine.productId);
|
|
11320
|
-
if (idx >= 0 && rewardProductIds.current.has(rewardLine.productId)) {
|
|
11321
|
-
next[idx] = { ...next[idx], quantity: rewardLine.quantity };
|
|
11322
|
-
}
|
|
11439
|
+
if (idx >= 0 && rewardProductIds.current.has(rewardLine.productId)) next[idx] = { ...next[idx], quantity: rewardLine.quantity };
|
|
11323
11440
|
}
|
|
11324
11441
|
const newRewardPids = new Set(newRewardLines.map((r) => r.productId));
|
|
11325
11442
|
const oldRewardPids = new Set(coupon.rewardLines.map((r) => r.productId));
|
|
11326
|
-
next = next.filter(
|
|
11327
|
-
(l) => !oldRewardPids.has(l.productId) || newRewardPids.has(l.productId)
|
|
11328
|
-
);
|
|
11443
|
+
next = next.filter((l) => !oldRewardPids.has(l.productId) || newRewardPids.has(l.productId));
|
|
11329
11444
|
return next;
|
|
11330
11445
|
});
|
|
11331
11446
|
}
|
|
@@ -11340,126 +11455,28 @@ function OrderPlacementPage({ editOrderId }) {
|
|
|
11340
11455
|
lines.filter((l) => !rewardProductIds.current.has(l.productId)).map((l) => `${l.productId}:${l.quantity}`).join(","),
|
|
11341
11456
|
coupons.filter((c) => c.isAutomatic).map((c) => c.discountId).join(",")
|
|
11342
11457
|
]);
|
|
11343
|
-
async function handleApplyCoupon() {
|
|
11344
|
-
const code = couponInput.trim().toUpperCase();
|
|
11345
|
-
if (!code) return;
|
|
11346
|
-
if (coupons.some((c) => c.couponCode === code)) {
|
|
11347
|
-
setCouponError("Coupon already applied");
|
|
11348
|
-
return;
|
|
11349
|
-
}
|
|
11350
|
-
if (coupons.length > 0 && !coupons[0].canCombine) {
|
|
11351
|
-
setCouponError("Applied coupon cannot be combined with other discounts");
|
|
11352
|
-
return;
|
|
11353
|
-
}
|
|
11354
|
-
setCouponError(null);
|
|
11355
|
-
setCouponLoading(true);
|
|
11356
|
-
try {
|
|
11357
|
-
const orderLines = lines.map((l) => ({ productId: l.productId, quantity: l.quantity }));
|
|
11358
|
-
const res = await fetch("/api/discounts/validate-coupon", {
|
|
11359
|
-
method: "POST",
|
|
11360
|
-
headers: { "Content-Type": "application/json" },
|
|
11361
|
-
body: JSON.stringify({ couponCode: code, orderLines, currency, contactId })
|
|
11362
|
-
});
|
|
11363
|
-
const data = await res.json();
|
|
11364
|
-
if (!res.ok || !data.valid) {
|
|
11365
|
-
setCouponError(data.error ?? "Invalid coupon");
|
|
11366
|
-
return;
|
|
11367
|
-
}
|
|
11368
|
-
const d = data.discount;
|
|
11369
|
-
if (!d.canCombineWithOtherDiscounts && coupons.length > 0) {
|
|
11370
|
-
setCouponError("This coupon cannot be combined with other discounts");
|
|
11371
|
-
return;
|
|
11372
|
-
}
|
|
11373
|
-
setCoupons((prev) => [...prev, {
|
|
11374
|
-
couponCode: code,
|
|
11375
|
-
discountId: d.id,
|
|
11376
|
-
name: d.name,
|
|
11377
|
-
value: d.value,
|
|
11378
|
-
type: d.discountType,
|
|
11379
|
-
canCombine: d.canCombineWithOtherDiscounts,
|
|
11380
|
-
calculatedDiscount: d.calculatedDiscount,
|
|
11381
|
-
rewardProductIds: d.rewardProductIds ?? [],
|
|
11382
|
-
rewardLines: d.rewardLines ?? [],
|
|
11383
|
-
isAutomatic: false
|
|
11384
|
-
}]);
|
|
11385
|
-
setCouponInput("");
|
|
11386
|
-
toast5.success(`Coupon "${code}" applied`);
|
|
11387
|
-
} catch {
|
|
11388
|
-
setCouponError("Failed to validate coupon");
|
|
11389
|
-
} finally {
|
|
11390
|
-
setCouponLoading(false);
|
|
11391
|
-
}
|
|
11392
|
-
}
|
|
11393
11458
|
function handleRemoveCoupon(couponCode) {
|
|
11394
11459
|
const coupon = coupons.find((c) => c.couponCode === couponCode);
|
|
11395
11460
|
if (coupon) {
|
|
11396
|
-
const
|
|
11397
|
-
const rewardKeyForDiscount = new Set(
|
|
11398
|
-
(coupon.rewardLines ?? []).map((r) => `reward-${r.productId}-${coupon.discountId}`)
|
|
11399
|
-
);
|
|
11461
|
+
const rewardKeyForDiscount = new Set((coupon.rewardLines ?? []).map((r) => `reward-${r.productId}-${coupon.discountId}`));
|
|
11400
11462
|
if (rewardKeyForDiscount.size > 0) {
|
|
11401
|
-
setLines(
|
|
11402
|
-
(prev) => prev.filter((l) => !rewardKeyForDiscount.has(l.key))
|
|
11403
|
-
);
|
|
11463
|
+
setLines((prev) => prev.filter((l) => !rewardKeyForDiscount.has(l.key)));
|
|
11404
11464
|
coupon.rewardLines.forEach((r) => {
|
|
11405
|
-
const stillRewardByOther = coupons.some(
|
|
11406
|
-
(c) => c.couponCode !== couponCode && c.rewardLines.some((rl) => rl.productId === r.productId)
|
|
11407
|
-
);
|
|
11465
|
+
const stillRewardByOther = coupons.some((c) => c.couponCode !== couponCode && c.rewardLines.some((rl) => rl.productId === r.productId));
|
|
11408
11466
|
if (!stillRewardByOther) rewardProductIds.current.delete(r.productId);
|
|
11409
11467
|
});
|
|
11410
11468
|
}
|
|
11411
11469
|
rewardInjectedForDiscount.current.delete(coupon.discountId);
|
|
11412
11470
|
}
|
|
11413
11471
|
setCoupons((prev) => prev.filter((c) => c.couponCode !== couponCode));
|
|
11414
|
-
setCouponError(null);
|
|
11415
11472
|
}
|
|
11416
11473
|
function mapAddressToForm(addr) {
|
|
11417
|
-
return {
|
|
11418
|
-
line1: addr.line1 ?? "",
|
|
11419
|
-
line2: addr.line2 ?? "",
|
|
11420
|
-
city: addr.city ?? "",
|
|
11421
|
-
state: addr.state ?? "",
|
|
11422
|
-
country: addr.country ?? "",
|
|
11423
|
-
postalCode: addr.postalCode ?? ""
|
|
11424
|
-
};
|
|
11474
|
+
return { line1: addr.line1 ?? "", line2: addr.line2 ?? "", city: addr.city ?? "", state: addr.state ?? "", country: addr.country ?? "", postalCode: addr.postalCode ?? "" };
|
|
11425
11475
|
}
|
|
11426
11476
|
function updateAddress(type, field, value) {
|
|
11427
11477
|
if (type === "billing") setBillingAddress((prev) => ({ ...prev, [field]: value }));
|
|
11428
11478
|
else setShippingAddress((prev) => ({ ...prev, [field]: value }));
|
|
11429
11479
|
}
|
|
11430
|
-
function handleCustomerSelect(value) {
|
|
11431
|
-
if (value === MANUAL_CUSTOMER) {
|
|
11432
|
-
setContactId(null);
|
|
11433
|
-
return;
|
|
11434
|
-
}
|
|
11435
|
-
const id = Number(value);
|
|
11436
|
-
if (!Number.isFinite(id)) return;
|
|
11437
|
-
const customer = customers.find((c) => c.id === id);
|
|
11438
|
-
if (!customer) return;
|
|
11439
|
-
setContactId(id);
|
|
11440
|
-
setContactName(customer.name ?? "");
|
|
11441
|
-
setContactEmail(customer.email ?? "");
|
|
11442
|
-
setContactPhone(customer.phone ?? "");
|
|
11443
|
-
loadCustomerAddresses(id);
|
|
11444
|
-
}
|
|
11445
|
-
async function loadCustomerAddresses(customerId) {
|
|
11446
|
-
try {
|
|
11447
|
-
const res = await fetch(`/api/order_addresses?contactId=${customerId}&limit=100&sortField=createdAt&sortOrder=desc`);
|
|
11448
|
-
if (!res.ok) return;
|
|
11449
|
-
const body = await res.json();
|
|
11450
|
-
const rows = Array.isArray(body) ? body : Array.isArray(body?.data) ? body.data : [];
|
|
11451
|
-
const billing = rows.find((a) => a.addressType === "billing_address");
|
|
11452
|
-
const shipping = rows.find((a) => a.addressType === "shipping_address");
|
|
11453
|
-
if (billing) setBillingAddress(mapAddressToForm(billing));
|
|
11454
|
-
else setBillingAddress({ ...emptyAddress });
|
|
11455
|
-
if (sameAsBilling) setShippingAddress(billing ? mapAddressToForm(billing) : { ...emptyAddress });
|
|
11456
|
-
else setShippingAddress(shipping ? mapAddressToForm(shipping) : { ...emptyAddress });
|
|
11457
|
-
} catch {
|
|
11458
|
-
setBillingAddress(emptyAddress);
|
|
11459
|
-
setShippingAddress(emptyAddress);
|
|
11460
|
-
}
|
|
11461
|
-
}
|
|
11462
|
-
const customerSelectValue = contactId != null ? String(contactId) : MANUAL_CUSTOMER;
|
|
11463
11480
|
function toggleStaged(id) {
|
|
11464
11481
|
setStagedIds((prev) => {
|
|
11465
11482
|
const next = new Set(prev);
|
|
@@ -11496,9 +11513,7 @@ function OrderPlacementPage({ editOrderId }) {
|
|
|
11496
11513
|
if (idx >= 0) {
|
|
11497
11514
|
const row = next[idx];
|
|
11498
11515
|
next[idx] = { ...row, quantity: row.quantity + 1 };
|
|
11499
|
-
} else {
|
|
11500
|
-
next.push({ key: String(id), productId: id, label: hit.name ?? `Product #${id}`, sku: hit.sku, quantity: 1 });
|
|
11501
|
-
}
|
|
11516
|
+
} else next.push({ key: String(id), productId: id, label: hit.name ?? `Product #${id}`, sku: hit.sku, quantity: 1 });
|
|
11502
11517
|
}
|
|
11503
11518
|
return next;
|
|
11504
11519
|
});
|
|
@@ -11527,9 +11542,12 @@ function OrderPlacementPage({ editOrderId }) {
|
|
|
11527
11542
|
}, [preview]);
|
|
11528
11543
|
async function handleSubmit(e) {
|
|
11529
11544
|
e.preventDefault();
|
|
11530
|
-
const
|
|
11531
|
-
|
|
11532
|
-
|
|
11545
|
+
const effectiveEmail = placeForSomeoneElse ? subContactEmail.trim() : contactEmail.trim();
|
|
11546
|
+
const effectiveName = placeForSomeoneElse ? subContactName.trim() : contactName.trim();
|
|
11547
|
+
const effectivePhone = placeForSomeoneElse ? subContactPhone.trim() : contactPhone.trim();
|
|
11548
|
+
const effectiveContactId = placeForSomeoneElse ? subContactId : contactId;
|
|
11549
|
+
if (effectiveContactId == null && !effectiveEmail) {
|
|
11550
|
+
toast5.error(placeForSomeoneElse ? "Enter the contact's email address" : "Select a customer or enter an email address");
|
|
11533
11551
|
return;
|
|
11534
11552
|
}
|
|
11535
11553
|
if (lines.length === 0) {
|
|
@@ -11543,46 +11561,67 @@ function OrderPlacementPage({ editOrderId }) {
|
|
|
11543
11561
|
}
|
|
11544
11562
|
setSubmitting(true);
|
|
11545
11563
|
try {
|
|
11564
|
+
let resolvedContactId = placeForSomeoneElse ? subContactId : null;
|
|
11565
|
+
if (!resolvedContactId && effectiveEmail) {
|
|
11566
|
+
try {
|
|
11567
|
+
const res2 = await fetch(`/api/contacts?search=${encodeURIComponent(effectiveEmail)}&limit=1`);
|
|
11568
|
+
if (res2.ok) {
|
|
11569
|
+
const data = await res2.json();
|
|
11570
|
+
const match = data.data?.find((c) => c.email?.toLowerCase() === effectiveEmail.toLowerCase());
|
|
11571
|
+
if (match) resolvedContactId = match.id;
|
|
11572
|
+
}
|
|
11573
|
+
} catch {
|
|
11574
|
+
}
|
|
11575
|
+
}
|
|
11576
|
+
let orderContactId = resolvedContactId;
|
|
11577
|
+
if (placeForSomeoneElse) {
|
|
11578
|
+
if (contactEmail) {
|
|
11579
|
+
try {
|
|
11580
|
+
const res2 = await fetch(`/api/contacts?search=${encodeURIComponent(contactEmail)}&limit=5`);
|
|
11581
|
+
if (res2.ok) {
|
|
11582
|
+
const data = await res2.json();
|
|
11583
|
+
const match = data.data?.find((c) => c.email?.toLowerCase() === contactEmail.toLowerCase());
|
|
11584
|
+
if (match) orderContactId = match.id;
|
|
11585
|
+
}
|
|
11586
|
+
} catch {
|
|
11587
|
+
}
|
|
11588
|
+
}
|
|
11589
|
+
}
|
|
11546
11590
|
const payload = {
|
|
11547
11591
|
status,
|
|
11548
11592
|
currency,
|
|
11549
|
-
"contact.name":
|
|
11550
|
-
"contact.email":
|
|
11551
|
-
"contact.phone":
|
|
11593
|
+
"contact.name": effectiveName || effectiveEmail.split("@")[0] || "Customer",
|
|
11594
|
+
"contact.email": effectiveEmail || "",
|
|
11595
|
+
"contact.phone": effectivePhone || null,
|
|
11552
11596
|
billingAddress,
|
|
11553
11597
|
shippingAddress: sameAsBilling ? billingAddress : shippingAddress,
|
|
11554
11598
|
orderLines: lines.map((l) => {
|
|
11555
11599
|
const calc = preview?.lines.find((pl) => pl.productId === l.productId);
|
|
11556
|
-
return {
|
|
11557
|
-
productId: l.productId,
|
|
11558
|
-
quantity: l.quantity,
|
|
11559
|
-
unitPrice: calc?.unitPrice ?? productCache.current.get(l.productId)?.price ?? 0
|
|
11560
|
-
};
|
|
11600
|
+
return { productId: l.productId, quantity: l.quantity, unitPrice: calc?.unitPrice ?? productCache.current.get(l.productId)?.price ?? 0 };
|
|
11561
11601
|
})
|
|
11562
11602
|
};
|
|
11563
|
-
if (
|
|
11603
|
+
if (orderContactId != null) payload.contactId = orderContactId;
|
|
11604
|
+
if (!placeForSomeoneElse && contactId != null) payload.customerId = contactId;
|
|
11564
11605
|
if (coupons.length > 0) payload.discountId = coupons[0].discountId;
|
|
11565
11606
|
const url = editOrderId ? `/api/orders/${editOrderId}` : "/api/orders";
|
|
11566
11607
|
const method = editOrderId ? "PUT" : "POST";
|
|
11567
|
-
const res = await fetch(url, {
|
|
11568
|
-
method,
|
|
11569
|
-
headers: { "Content-Type": "application/json" },
|
|
11570
|
-
body: JSON.stringify(payload)
|
|
11571
|
-
});
|
|
11608
|
+
const res = await fetch(url, { method, headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload) });
|
|
11572
11609
|
const body = await res.json().catch(() => ({}));
|
|
11573
11610
|
if (!res.ok) {
|
|
11574
11611
|
toast5.error(body.error ?? (editOrderId ? "Failed to update order" : "Failed to create order"));
|
|
11575
11612
|
return;
|
|
11576
11613
|
}
|
|
11577
|
-
if (
|
|
11578
|
-
const
|
|
11614
|
+
if (resolvedContactId == null) {
|
|
11615
|
+
const serverContactId = body.contactId;
|
|
11616
|
+
if (serverContactId != null && Number.isFinite(serverContactId)) {
|
|
11617
|
+
resolvedContactId = serverContactId;
|
|
11618
|
+
}
|
|
11619
|
+
}
|
|
11620
|
+
if (editOrderId && effectiveContactId != null) {
|
|
11621
|
+
const cr = await fetch(`/api/contacts/${effectiveContactId}`, {
|
|
11579
11622
|
method: "PUT",
|
|
11580
11623
|
headers: { "Content-Type": "application/json" },
|
|
11581
|
-
body: JSON.stringify({
|
|
11582
|
-
name: contactName.trim() || email.split("@")[0] || "Customer",
|
|
11583
|
-
email: email || void 0,
|
|
11584
|
-
phone: contactPhone.trim() || null
|
|
11585
|
-
})
|
|
11624
|
+
body: JSON.stringify({ name: effectiveName || effectiveEmail.split("@")[0] || "Customer", email: effectiveEmail || void 0, phone: effectivePhone || null })
|
|
11586
11625
|
});
|
|
11587
11626
|
if (!cr.ok) {
|
|
11588
11627
|
const cb = await cr.json().catch(() => ({}));
|
|
@@ -11594,6 +11633,25 @@ function OrderPlacementPage({ editOrderId }) {
|
|
|
11594
11633
|
router.push(withAdminListFromParam(listReturnUrl, `/admin/orders/${editOrderId}/view`));
|
|
11595
11634
|
return;
|
|
11596
11635
|
}
|
|
11636
|
+
if (selectedCustomerId != null && resolvedContactId != null) {
|
|
11637
|
+
try {
|
|
11638
|
+
const linkCheck = await fetch(`/api/customer_contacts?customerId=${selectedCustomerId}&limit=200`);
|
|
11639
|
+
if (linkCheck.ok) {
|
|
11640
|
+
const linkData = await linkCheck.json();
|
|
11641
|
+
const existingRows = Array.isArray(linkData?.data) ? linkData.data : Array.isArray(linkData) ? linkData : [];
|
|
11642
|
+
const alreadyLinked = existingRows.some((r) => Number(r.contactId) === resolvedContactId);
|
|
11643
|
+
if (!alreadyLinked) {
|
|
11644
|
+
await fetch("/api/customer_contacts", {
|
|
11645
|
+
method: "POST",
|
|
11646
|
+
headers: { "Content-Type": "application/json" },
|
|
11647
|
+
body: JSON.stringify({ customerId: selectedCustomerId, contactId: resolvedContactId })
|
|
11648
|
+
});
|
|
11649
|
+
}
|
|
11650
|
+
}
|
|
11651
|
+
} catch {
|
|
11652
|
+
console.warn("[OrderPlacement] Could not link contact to customer");
|
|
11653
|
+
}
|
|
11654
|
+
}
|
|
11597
11655
|
const id = body.id;
|
|
11598
11656
|
toast5.success("Order created");
|
|
11599
11657
|
if (id != null) router.push(withAdminListFromParam(listReturnUrl, `/admin/orders/${id}/view`));
|
|
@@ -11605,6 +11663,8 @@ function OrderPlacementPage({ editOrderId }) {
|
|
|
11605
11663
|
}
|
|
11606
11664
|
}
|
|
11607
11665
|
const allVisibleStaged = productHits.length > 0 && productHits.every((p) => stagedIds.has(p.id));
|
|
11666
|
+
const customerSelectValue = contactId != null ? String(contactId) : MANUAL_CUSTOMER;
|
|
11667
|
+
const subContactSelectValue = subContactId != null ? String(subContactId) : MANUAL_CONTACT;
|
|
11608
11668
|
if (editOrderId && loadingOrder) {
|
|
11609
11669
|
return /* @__PURE__ */ jsx55("div", { className: "rounded-lg bg-white shadow-md min-w-0", children: /* @__PURE__ */ jsx55("div", { className: "flex justify-center items-center py-16 text-gray-500 text-sm", children: "Loading order\u2026" }) });
|
|
11610
11670
|
}
|
|
@@ -11649,74 +11709,168 @@ function OrderPlacementPage({ editOrderId }) {
|
|
|
11649
11709
|
] }),
|
|
11650
11710
|
/* @__PURE__ */ jsxs44("div", { className: "space-y-2 sm:col-span-2", children: [
|
|
11651
11711
|
/* @__PURE__ */ jsx55(Label3, { htmlFor: "c-email", children: "Email" }),
|
|
11652
|
-
/* @__PURE__ */ jsx55(Input, { id: "c-email", type: "email", value: contactEmail, onChange: (e) => setContactEmail(e.target.value), placeholder: "name@example.com", required: contactId == null })
|
|
11712
|
+
/* @__PURE__ */ jsx55(Input, { id: "c-email", type: "email", value: contactEmail, onChange: (e) => setContactEmail(e.target.value), placeholder: "name@example.com", required: contactId == null && !placeForSomeoneElse })
|
|
11653
11713
|
] }),
|
|
11654
11714
|
/* @__PURE__ */ jsxs44("div", { className: "space-y-2 sm:col-span-2", children: [
|
|
11655
11715
|
/* @__PURE__ */ jsx55(Label3, { htmlFor: "c-phone", children: "Phone" }),
|
|
11656
11716
|
/* @__PURE__ */ jsx55(Input, { id: "c-phone", value: contactPhone, onChange: (e) => setContactPhone(e.target.value), placeholder: "phone number" })
|
|
11717
|
+
] })
|
|
11718
|
+
] }),
|
|
11719
|
+
/* @__PURE__ */ jsxs44("div", { className: "flex items-start gap-3 rounded-lg border border-dashed border-gray-300 bg-gray-50/60 px-4 py-3 mt-1", children: [
|
|
11720
|
+
/* @__PURE__ */ jsx55(
|
|
11721
|
+
Checkbox,
|
|
11722
|
+
{
|
|
11723
|
+
id: "place-for-someone-else",
|
|
11724
|
+
checked: placeForSomeoneElse,
|
|
11725
|
+
onCheckedChange: (checked) => handlePlaceForSomeoneElseToggle(Boolean(checked)),
|
|
11726
|
+
disabled: contactId == null
|
|
11727
|
+
}
|
|
11728
|
+
),
|
|
11729
|
+
/* @__PURE__ */ jsxs44("div", { className: "space-y-0.5", children: [
|
|
11730
|
+
/* @__PURE__ */ jsx55(
|
|
11731
|
+
"label",
|
|
11732
|
+
{
|
|
11733
|
+
htmlFor: "place-for-someone-else",
|
|
11734
|
+
className: `text-sm font-medium leading-none cursor-pointer ${contactId == null ? "text-gray-400" : "text-gray-700"}`,
|
|
11735
|
+
children: "Place this order for someone else"
|
|
11736
|
+
}
|
|
11737
|
+
),
|
|
11738
|
+
/* @__PURE__ */ jsx55("p", { className: "text-xs text-gray-500", children: contactId == null ? "Select a customer above to enable this option." : "Select a linked contact or enter their details below. Addresses will be filled from the selected contact." })
|
|
11739
|
+
] })
|
|
11740
|
+
] }),
|
|
11741
|
+
placeForSomeoneElse && contactId != null && /* @__PURE__ */ jsxs44("div", { className: "rounded-lg border border-blue-200 bg-blue-50/40 p-4 space-y-3", children: [
|
|
11742
|
+
/* @__PURE__ */ jsxs44("div", { className: "flex items-center gap-2", children: [
|
|
11743
|
+
/* @__PURE__ */ jsx55(Users6, { className: "h-4 w-4 text-blue-600" }),
|
|
11744
|
+
/* @__PURE__ */ jsx55("h3", { className: "text-sm font-semibold text-blue-800", children: "Order recipient" })
|
|
11657
11745
|
] }),
|
|
11658
|
-
/* @__PURE__ */
|
|
11659
|
-
/* @__PURE__ */ jsx55(
|
|
11660
|
-
/* @__PURE__ */ jsxs44(
|
|
11661
|
-
|
|
11662
|
-
|
|
11663
|
-
|
|
11664
|
-
|
|
11665
|
-
|
|
11666
|
-
|
|
11667
|
-
|
|
11668
|
-
|
|
11669
|
-
|
|
11670
|
-
|
|
11671
|
-
|
|
11672
|
-
|
|
11673
|
-
|
|
11674
|
-
|
|
11675
|
-
|
|
11676
|
-
|
|
11677
|
-
|
|
11678
|
-
|
|
11679
|
-
|
|
11680
|
-
|
|
11681
|
-
/* @__PURE__ */
|
|
11682
|
-
|
|
11683
|
-
|
|
11684
|
-
|
|
11746
|
+
customerContactsLoading ? /* @__PURE__ */ jsx55("p", { className: "text-xs text-gray-500", children: "Loading contacts\u2026" }) : /* @__PURE__ */ jsxs44("div", { className: "space-y-2", children: [
|
|
11747
|
+
/* @__PURE__ */ jsx55(Label3, { htmlFor: "sc-select", children: "Select contact" }),
|
|
11748
|
+
/* @__PURE__ */ jsxs44(
|
|
11749
|
+
"select",
|
|
11750
|
+
{
|
|
11751
|
+
id: "sc-select",
|
|
11752
|
+
value: subContactSelectValue,
|
|
11753
|
+
onChange: (e) => handleSubContactSelect(e.target.value),
|
|
11754
|
+
className: "w-full h-10 rounded-md border border-gray-300 bg-white px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
|
|
11755
|
+
children: [
|
|
11756
|
+
/* @__PURE__ */ jsx55("option", { value: MANUAL_CONTACT, children: "Enter manually (new contact)" }),
|
|
11757
|
+
customerContacts.map((r) => /* @__PURE__ */ jsxs44("option", { value: String(r.contactId), children: [
|
|
11758
|
+
r.contact.name,
|
|
11759
|
+
r.contact.email ? ` \u2014 ${r.contact.email}` : ""
|
|
11760
|
+
] }, r.contactId))
|
|
11761
|
+
]
|
|
11762
|
+
}
|
|
11763
|
+
),
|
|
11764
|
+
customerContacts.length === 0 && /* @__PURE__ */ jsx55("p", { className: "text-xs text-amber-700 bg-amber-50 border border-amber-200 rounded px-3 py-2", children: "No linked contacts found for this customer. Fill in the details below." })
|
|
11765
|
+
] }),
|
|
11766
|
+
/* @__PURE__ */ jsxs44("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-3", children: [
|
|
11767
|
+
/* @__PURE__ */ jsxs44("div", { className: "space-y-2 sm:col-span-2", children: [
|
|
11768
|
+
/* @__PURE__ */ jsx55(Label3, { htmlFor: "sc-name", children: "Recipient name" }),
|
|
11769
|
+
/* @__PURE__ */ jsx55(
|
|
11770
|
+
Input,
|
|
11771
|
+
{
|
|
11772
|
+
id: "sc-name",
|
|
11773
|
+
value: subContactName,
|
|
11774
|
+
onChange: (e) => setSubContactName(e.target.value),
|
|
11775
|
+
placeholder: "Full name",
|
|
11776
|
+
readOnly: subContactId != null,
|
|
11777
|
+
className: subContactId != null ? "bg-gray-100 cursor-not-allowed" : ""
|
|
11778
|
+
}
|
|
11779
|
+
)
|
|
11780
|
+
] }),
|
|
11781
|
+
/* @__PURE__ */ jsxs44("div", { className: "space-y-2 sm:col-span-2", children: [
|
|
11782
|
+
/* @__PURE__ */ jsx55(Label3, { htmlFor: "sc-email", children: "Recipient email" }),
|
|
11783
|
+
/* @__PURE__ */ jsx55(
|
|
11784
|
+
Input,
|
|
11785
|
+
{
|
|
11786
|
+
id: "sc-email",
|
|
11787
|
+
type: "email",
|
|
11788
|
+
value: subContactEmail,
|
|
11789
|
+
onChange: (e) => setSubContactEmail(e.target.value),
|
|
11790
|
+
placeholder: "email@example.com",
|
|
11791
|
+
required: placeForSomeoneElse && subContactId == null,
|
|
11792
|
+
readOnly: subContactId != null,
|
|
11793
|
+
className: subContactId != null ? "bg-gray-100 cursor-not-allowed" : ""
|
|
11794
|
+
}
|
|
11795
|
+
)
|
|
11796
|
+
] }),
|
|
11797
|
+
/* @__PURE__ */ jsxs44("div", { className: "space-y-2 sm:col-span-2", children: [
|
|
11798
|
+
/* @__PURE__ */ jsx55(Label3, { htmlFor: "sc-phone", children: "Recipient phone" }),
|
|
11799
|
+
/* @__PURE__ */ jsx55(
|
|
11800
|
+
Input,
|
|
11801
|
+
{
|
|
11802
|
+
id: "sc-phone",
|
|
11803
|
+
value: subContactPhone,
|
|
11804
|
+
onChange: (e) => setSubContactPhone(e.target.value),
|
|
11805
|
+
placeholder: "phone number",
|
|
11806
|
+
readOnly: subContactId != null,
|
|
11807
|
+
className: subContactId != null ? "bg-gray-100 cursor-not-allowed" : ""
|
|
11808
|
+
}
|
|
11809
|
+
)
|
|
11810
|
+
] })
|
|
11811
|
+
] })
|
|
11812
|
+
] }),
|
|
11813
|
+
/* @__PURE__ */ jsxs44("div", { className: "space-y-4 border rounded-lg p-4", children: [
|
|
11814
|
+
/* @__PURE__ */ jsx55("h3", { className: "text-sm font-semibold", children: "Billing Address" }),
|
|
11815
|
+
/* @__PURE__ */ jsxs44("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-3", children: [
|
|
11816
|
+
/* @__PURE__ */ jsxs44("div", { className: "space-y-2 md:col-span-2", children: [
|
|
11817
|
+
/* @__PURE__ */ jsx55(Label3, { children: "Address Line 1" }),
|
|
11818
|
+
/* @__PURE__ */ jsx55(Input, { value: billingAddress.line1, onChange: (e) => updateAddress("billing", "line1", e.target.value), placeholder: "Street Address" })
|
|
11819
|
+
] }),
|
|
11820
|
+
/* @__PURE__ */ jsxs44("div", { className: "space-y-2 md:col-span-2", children: [
|
|
11821
|
+
/* @__PURE__ */ jsx55(Label3, { children: "Address Line 2" }),
|
|
11822
|
+
/* @__PURE__ */ jsx55(Input, { value: billingAddress.line2, onChange: (e) => updateAddress("billing", "line2", e.target.value), placeholder: "Apartment, Suite, Floor, etc." })
|
|
11823
|
+
] }),
|
|
11824
|
+
/* @__PURE__ */ jsxs44("div", { className: "space-y-2", children: [
|
|
11825
|
+
/* @__PURE__ */ jsx55(Label3, { children: "City" }),
|
|
11826
|
+
/* @__PURE__ */ jsx55(Input, { value: billingAddress.city, onChange: (e) => updateAddress("billing", "city", e.target.value), placeholder: "City" })
|
|
11827
|
+
] }),
|
|
11828
|
+
/* @__PURE__ */ jsxs44("div", { className: "space-y-2", children: [
|
|
11829
|
+
/* @__PURE__ */ jsx55(Label3, { children: "State" }),
|
|
11830
|
+
/* @__PURE__ */ jsx55(Input, { value: billingAddress.state, onChange: (e) => updateAddress("billing", "state", e.target.value), placeholder: "State" })
|
|
11831
|
+
] }),
|
|
11832
|
+
/* @__PURE__ */ jsxs44("div", { className: "space-y-2", children: [
|
|
11833
|
+
/* @__PURE__ */ jsx55(Label3, { children: "Country" }),
|
|
11834
|
+
/* @__PURE__ */ jsx55(Input, { value: billingAddress.country, onChange: (e) => updateAddress("billing", "country", e.target.value), placeholder: "Country" })
|
|
11835
|
+
] }),
|
|
11836
|
+
/* @__PURE__ */ jsxs44("div", { className: "space-y-2", children: [
|
|
11837
|
+
/* @__PURE__ */ jsx55(Label3, { children: "Postal Code" }),
|
|
11838
|
+
/* @__PURE__ */ jsx55(Input, { value: billingAddress.postalCode, onChange: (e) => updateAddress("billing", "postalCode", e.target.value), placeholder: "Postal Code" })
|
|
11839
|
+
] })
|
|
11840
|
+
] })
|
|
11841
|
+
] }),
|
|
11842
|
+
/* @__PURE__ */ jsxs44("div", { className: "space-y-4 border rounded-lg p-4", children: [
|
|
11843
|
+
/* @__PURE__ */ jsxs44("div", { className: "flex items-center justify-between", children: [
|
|
11844
|
+
/* @__PURE__ */ jsx55("h3", { className: "text-sm font-semibold", children: "Shipping Address" }),
|
|
11845
|
+
/* @__PURE__ */ jsxs44("div", { className: "flex items-center gap-2", children: [
|
|
11846
|
+
/* @__PURE__ */ jsx55(Checkbox, { checked: sameAsBilling, onCheckedChange: (checked) => setSameAsBilling(Boolean(checked)) }),
|
|
11847
|
+
/* @__PURE__ */ jsx55("span", { className: "text-sm text-gray-600", children: "Same as Billing" })
|
|
11685
11848
|
] })
|
|
11686
11849
|
] }),
|
|
11687
|
-
/* @__PURE__ */ jsxs44("div", { className: "
|
|
11688
|
-
/* @__PURE__ */ jsxs44("div", { className: "
|
|
11689
|
-
/* @__PURE__ */ jsx55(
|
|
11690
|
-
/* @__PURE__ */
|
|
11691
|
-
/* @__PURE__ */ jsx55(Checkbox, { checked: sameAsBilling, onCheckedChange: (checked) => setSameAsBilling(Boolean(checked)) }),
|
|
11692
|
-
/* @__PURE__ */ jsx55("span", { className: "text-sm text-gray-600", children: "Same as Billing" })
|
|
11693
|
-
] })
|
|
11850
|
+
!sameAsBilling && /* @__PURE__ */ jsxs44("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-3", children: [
|
|
11851
|
+
/* @__PURE__ */ jsxs44("div", { className: "space-y-2 md:col-span-2", children: [
|
|
11852
|
+
/* @__PURE__ */ jsx55(Label3, { children: "Address Line 1" }),
|
|
11853
|
+
/* @__PURE__ */ jsx55(Input, { value: shippingAddress.line1, onChange: (e) => updateAddress("shipping", "line1", e.target.value), placeholder: "Street Address" })
|
|
11694
11854
|
] }),
|
|
11695
|
-
|
|
11696
|
-
/* @__PURE__ */
|
|
11697
|
-
|
|
11698
|
-
|
|
11699
|
-
|
|
11700
|
-
/* @__PURE__ */
|
|
11701
|
-
|
|
11702
|
-
|
|
11703
|
-
|
|
11704
|
-
/* @__PURE__ */
|
|
11705
|
-
|
|
11706
|
-
|
|
11707
|
-
|
|
11708
|
-
/* @__PURE__ */
|
|
11709
|
-
|
|
11710
|
-
|
|
11711
|
-
|
|
11712
|
-
/* @__PURE__ */
|
|
11713
|
-
|
|
11714
|
-
/* @__PURE__ */ jsx55(Input, { value: shippingAddress.country, onChange: (e) => updateAddress("shipping", "country", e.target.value), placeholder: "Country" })
|
|
11715
|
-
] }),
|
|
11716
|
-
/* @__PURE__ */ jsxs44("div", { className: "space-y-2 md:col-span-2", children: [
|
|
11717
|
-
/* @__PURE__ */ jsx55(Label3, { children: "Postal Code" }),
|
|
11718
|
-
/* @__PURE__ */ jsx55(Input, { value: shippingAddress.postalCode, onChange: (e) => updateAddress("shipping", "postalCode", e.target.value), placeholder: "Postal Code" })
|
|
11719
|
-
] })
|
|
11855
|
+
/* @__PURE__ */ jsxs44("div", { className: "space-y-2 md:col-span-2", children: [
|
|
11856
|
+
/* @__PURE__ */ jsx55(Label3, { children: "Address Line 2" }),
|
|
11857
|
+
/* @__PURE__ */ jsx55(Input, { value: shippingAddress.line2, onChange: (e) => updateAddress("shipping", "line2", e.target.value), placeholder: "Apartment, Suite, Floor, etc." })
|
|
11858
|
+
] }),
|
|
11859
|
+
/* @__PURE__ */ jsxs44("div", { className: "space-y-2 md:col-span-2", children: [
|
|
11860
|
+
/* @__PURE__ */ jsx55(Label3, { children: "City" }),
|
|
11861
|
+
/* @__PURE__ */ jsx55(Input, { value: shippingAddress.city, onChange: (e) => updateAddress("shipping", "city", e.target.value), placeholder: "City" })
|
|
11862
|
+
] }),
|
|
11863
|
+
/* @__PURE__ */ jsxs44("div", { className: "space-y-2 md:col-span-2", children: [
|
|
11864
|
+
/* @__PURE__ */ jsx55(Label3, { children: "State" }),
|
|
11865
|
+
/* @__PURE__ */ jsx55(Input, { value: shippingAddress.state, onChange: (e) => updateAddress("shipping", "state", e.target.value), placeholder: "State" })
|
|
11866
|
+
] }),
|
|
11867
|
+
/* @__PURE__ */ jsxs44("div", { className: "space-y-2 md:col-span-2", children: [
|
|
11868
|
+
/* @__PURE__ */ jsx55(Label3, { children: "Country" }),
|
|
11869
|
+
/* @__PURE__ */ jsx55(Input, { value: shippingAddress.country, onChange: (e) => updateAddress("shipping", "country", e.target.value), placeholder: "Country" })
|
|
11870
|
+
] }),
|
|
11871
|
+
/* @__PURE__ */ jsxs44("div", { className: "space-y-2 md:col-span-2", children: [
|
|
11872
|
+
/* @__PURE__ */ jsx55(Label3, { children: "Postal Code" }),
|
|
11873
|
+
/* @__PURE__ */ jsx55(Input, { value: shippingAddress.postalCode, onChange: (e) => updateAddress("shipping", "postalCode", e.target.value), placeholder: "Postal Code" })
|
|
11720
11874
|
] })
|
|
11721
11875
|
] })
|
|
11722
11876
|
] })
|
|
@@ -11814,51 +11968,21 @@ function OrderPlacementPage({ editOrderId }) {
|
|
|
11814
11968
|
const active = selectedKey === line.key;
|
|
11815
11969
|
const calc = calcByProductId.get(line.productId);
|
|
11816
11970
|
const isReward = line.key.startsWith("reward-");
|
|
11817
|
-
return /* @__PURE__ */ jsxs44(
|
|
11818
|
-
|
|
11819
|
-
|
|
11820
|
-
|
|
11821
|
-
|
|
11822
|
-
|
|
11823
|
-
|
|
11824
|
-
|
|
11825
|
-
|
|
11826
|
-
|
|
11827
|
-
|
|
11828
|
-
|
|
11829
|
-
|
|
11830
|
-
|
|
11831
|
-
|
|
11832
|
-
min: 1,
|
|
11833
|
-
className: "h-8 w-14 ml-auto text-right",
|
|
11834
|
-
value: line.quantity,
|
|
11835
|
-
onChange: (e) => updateQty(line.key, Number(e.target.value)),
|
|
11836
|
-
onClick: (e) => e.stopPropagation(),
|
|
11837
|
-
readOnly: isReward,
|
|
11838
|
-
disabled: isReward
|
|
11839
|
-
}
|
|
11840
|
-
) }),
|
|
11841
|
-
/* @__PURE__ */ jsx55(TableCell, { className: "align-top text-right text-sm hidden sm:table-cell whitespace-nowrap", children: calc ? formatMoney3(calc.unitPrice, currency) : previewLoading ? "\u2026" : "\u2014" }),
|
|
11842
|
-
/* @__PURE__ */ jsx55(TableCell, { className: "align-top text-right text-sm hidden md:table-cell whitespace-nowrap", children: calc ? formatMoney3(calc.tax, currency) : previewLoading ? "\u2026" : "\u2014" }),
|
|
11843
|
-
/* @__PURE__ */ jsx55(TableCell, { className: "align-top text-right font-medium text-sm whitespace-nowrap", children: calc ? formatMoney3(calc.total, currency) : previewLoading ? "\u2026" : "\u2014" }),
|
|
11844
|
-
/* @__PURE__ */ jsx55(TableCell, { className: "align-top", children: !isReward && /* @__PURE__ */ jsx55(
|
|
11845
|
-
Button,
|
|
11846
|
-
{
|
|
11847
|
-
type: "button",
|
|
11848
|
-
variant: "ghost",
|
|
11849
|
-
size: "icon",
|
|
11850
|
-
className: "h-8 w-8 text-red-600",
|
|
11851
|
-
onClick: (e) => {
|
|
11852
|
-
e.stopPropagation();
|
|
11853
|
-
removeLine(line.key);
|
|
11854
|
-
},
|
|
11855
|
-
children: /* @__PURE__ */ jsx55(Trash25, { className: "h-4 w-4" })
|
|
11856
|
-
}
|
|
11857
|
-
) })
|
|
11858
|
-
]
|
|
11859
|
-
},
|
|
11860
|
-
line.key
|
|
11861
|
-
);
|
|
11971
|
+
return /* @__PURE__ */ jsxs44(TableRow, { className: active ? "bg-blue-50/80 cursor-pointer" : "cursor-pointer", onClick: () => setSelectedKey(line.key), children: [
|
|
11972
|
+
/* @__PURE__ */ jsxs44(TableCell, { className: "align-top min-w-0", children: [
|
|
11973
|
+
/* @__PURE__ */ jsx55("p", { className: "font-medium text-gray-900 break-words", children: line.label }),
|
|
11974
|
+
/* @__PURE__ */ jsx55("p", { className: "text-xs text-gray-500 font-mono", children: line.sku ?? "\u2014" }),
|
|
11975
|
+
isReward && /* @__PURE__ */ jsx55("span", { className: "text-[10px] text-purple-600 font-medium", children: "\u{1F381} Reward" })
|
|
11976
|
+
] }),
|
|
11977
|
+
/* @__PURE__ */ jsx55(TableCell, { className: "align-top text-right", children: /* @__PURE__ */ jsx55(Input, { type: "number", min: 1, className: "h-8 w-14 ml-auto text-right", value: line.quantity, onChange: (e) => updateQty(line.key, Number(e.target.value)), onClick: (e) => e.stopPropagation(), readOnly: isReward, disabled: isReward }) }),
|
|
11978
|
+
/* @__PURE__ */ jsx55(TableCell, { className: "align-top text-right text-sm hidden sm:table-cell whitespace-nowrap", children: calc ? formatMoney3(calc.unitPrice, currency) : previewLoading ? "\u2026" : "\u2014" }),
|
|
11979
|
+
/* @__PURE__ */ jsx55(TableCell, { className: "align-top text-right text-sm hidden md:table-cell whitespace-nowrap", children: calc ? formatMoney3(calc.tax, currency) : previewLoading ? "\u2026" : "\u2014" }),
|
|
11980
|
+
/* @__PURE__ */ jsx55(TableCell, { className: "align-top text-right font-medium text-sm whitespace-nowrap", children: calc ? formatMoney3(calc.total, currency) : previewLoading ? "\u2026" : "\u2014" }),
|
|
11981
|
+
/* @__PURE__ */ jsx55(TableCell, { className: "align-top", children: !isReward && /* @__PURE__ */ jsx55(Button, { type: "button", variant: "ghost", size: "icon", className: "h-8 w-8 text-red-600", onClick: (e) => {
|
|
11982
|
+
e.stopPropagation();
|
|
11983
|
+
removeLine(line.key);
|
|
11984
|
+
}, children: /* @__PURE__ */ jsx55(Trash25, { className: "h-4 w-4" }) }) })
|
|
11985
|
+
] }, line.key);
|
|
11862
11986
|
}) })
|
|
11863
11987
|
] }) }),
|
|
11864
11988
|
/* @__PURE__ */ jsxs44("div", { className: "flex flex-wrap items-center gap-4 justify-between border border-gray-200 rounded-lg p-4 bg-gray-50/70 text-sm", children: [
|
|
@@ -11925,21 +12049,13 @@ function OrderPlacementPage({ editOrderId }) {
|
|
|
11925
12049
|
if (!hit) return;
|
|
11926
12050
|
const productHit = hit;
|
|
11927
12051
|
setLines((prev) => {
|
|
11928
|
-
const existingRewardIdx = prev.findIndex(
|
|
11929
|
-
(l) => l.productId === pid && rewardProductIds.current.has(pid)
|
|
11930
|
-
);
|
|
12052
|
+
const existingRewardIdx = prev.findIndex((l) => l.productId === pid && rewardProductIds.current.has(pid));
|
|
11931
12053
|
if (existingRewardIdx >= 0) {
|
|
11932
12054
|
const next = [...prev];
|
|
11933
12055
|
next[existingRewardIdx] = { ...next[existingRewardIdx], quantity: qty };
|
|
11934
12056
|
return next;
|
|
11935
12057
|
}
|
|
11936
|
-
return [...prev, {
|
|
11937
|
-
key: `reward-${pid}-${coupon.discountId}`,
|
|
11938
|
-
productId: pid,
|
|
11939
|
-
label: productHit.name ?? `Product #${pid}`,
|
|
11940
|
-
sku: productHit.sku,
|
|
11941
|
-
quantity: qty
|
|
11942
|
-
}];
|
|
12058
|
+
return [...prev, { key: `reward-${pid}-${coupon.discountId}`, productId: pid, label: productHit.name ?? `Product #${pid}`, sku: productHit.sku, quantity: qty }];
|
|
11943
12059
|
});
|
|
11944
12060
|
});
|
|
11945
12061
|
}
|
|
@@ -12113,7 +12229,7 @@ import { useEffect as useEffect27, useState as useState30 } from "react";
|
|
|
12113
12229
|
import Link12 from "next/link";
|
|
12114
12230
|
import { useRouter as useRouter10, useSearchParams as useSearchParams8 } from "next/navigation";
|
|
12115
12231
|
import { X as X17 } from "lucide-react";
|
|
12116
|
-
import { Fragment as
|
|
12232
|
+
import { Fragment as Fragment12, jsx as jsx57, jsxs as jsxs46 } from "react/jsx-runtime";
|
|
12117
12233
|
function formatMoney4(amount, currency = "INR") {
|
|
12118
12234
|
return new Intl.NumberFormat("en-IN", {
|
|
12119
12235
|
style: "currency",
|
|
@@ -12177,7 +12293,7 @@ function PaymentDetailPage({ paymentId }) {
|
|
|
12177
12293
|
/* @__PURE__ */ jsx57(
|
|
12178
12294
|
DetailPageLayout,
|
|
12179
12295
|
{
|
|
12180
|
-
main: /* @__PURE__ */ jsxs46(
|
|
12296
|
+
main: /* @__PURE__ */ jsxs46(Fragment12, { children: [
|
|
12181
12297
|
/* @__PURE__ */ jsxs46("section", { children: [
|
|
12182
12298
|
/* @__PURE__ */ jsx57("h2", { className: "text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2", children: "Payment details" }),
|
|
12183
12299
|
/* @__PURE__ */ jsx57("div", { className: "min-w-0 overflow-hidden border border-gray-200 rounded-lg p-4 bg-gray-50/50", children: /* @__PURE__ */ jsxs46("dl", { className: "min-w-0 grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-3 text-sm", children: [
|
|
@@ -12240,7 +12356,7 @@ function PaymentDetailPage({ paymentId }) {
|
|
|
12240
12356
|
] })
|
|
12241
12357
|
] })
|
|
12242
12358
|
] }),
|
|
12243
|
-
sidebar: /* @__PURE__ */ jsx57(
|
|
12359
|
+
sidebar: /* @__PURE__ */ jsx57(Fragment12, { children: customer && /* @__PURE__ */ jsxs46("section", { children: [
|
|
12244
12360
|
/* @__PURE__ */ jsx57("h2", { className: "text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2", children: "Customer" }),
|
|
12245
12361
|
/* @__PURE__ */ jsx57("div", { className: "min-w-0 overflow-hidden border border-gray-200 rounded-lg p-4 bg-gray-50/50", children: /* @__PURE__ */ jsxs46("dl", { className: "min-w-0 grid grid-cols-1 sm:grid-cols-3 gap-3 text-sm", children: [
|
|
12246
12362
|
/* @__PURE__ */ jsxs46("div", { className: "min-w-0", children: [
|
|
@@ -12276,7 +12392,7 @@ import { useState as useState31, useEffect as useEffect28, useContext as useCont
|
|
|
12276
12392
|
import { useSearchParams as useSearchParams9 } from "next/navigation";
|
|
12277
12393
|
import { toast as toast6 } from "sonner";
|
|
12278
12394
|
import { Save as Save3, RotateCcw, ArrowLeftRight, Plus as Plus8, Trash2 as Trash26, X as X18 } from "lucide-react";
|
|
12279
|
-
import { Fragment as
|
|
12395
|
+
import { Fragment as Fragment13, jsx as jsx58, jsxs as jsxs47 } from "react/jsx-runtime";
|
|
12280
12396
|
var DEFAULT_CURRENCY = "INR";
|
|
12281
12397
|
var DEFAULTS = {
|
|
12282
12398
|
primaryColor: "#313996",
|
|
@@ -12607,7 +12723,7 @@ function SettingsPage() {
|
|
|
12607
12723
|
/* @__PURE__ */ jsx58("span", { className: "text-[11px] text-gray-400", children: "Smaller spacing in admin" })
|
|
12608
12724
|
] }) })
|
|
12609
12725
|
] }),
|
|
12610
|
-
tab === "navbar" && /* @__PURE__ */ jsx58("div", { className: "space-y-6", children: themeSettingsLoading ? /* @__PURE__ */ jsx58("div", { className: "flex items-center gap-2 text-gray-500", children: "Loading..." }) : /* @__PURE__ */ jsxs47(
|
|
12726
|
+
tab === "navbar" && /* @__PURE__ */ jsx58("div", { className: "space-y-6", children: themeSettingsLoading ? /* @__PURE__ */ jsx58("div", { className: "flex items-center gap-2 text-gray-500", children: "Loading..." }) : /* @__PURE__ */ jsxs47(Fragment13, { children: [
|
|
12611
12727
|
/* @__PURE__ */ jsxs47("div", { children: [
|
|
12612
12728
|
/* @__PURE__ */ jsx58("h2", { className: "text-lg font-semibold text-gray-900 mb-2", children: "Navbar & pages" }),
|
|
12613
12729
|
/* @__PURE__ */ jsx58("p", { className: "text-sm text-gray-500 mb-4", children: "Set logo and menu items." }),
|
|
@@ -12615,7 +12731,7 @@ function SettingsPage() {
|
|
|
12615
12731
|
] }),
|
|
12616
12732
|
/* @__PURE__ */ jsx58(Button, { onClick: handleSaveNavbar, disabled: saving, children: saving ? "Saving..." : "Save navbar" })
|
|
12617
12733
|
] }) }),
|
|
12618
|
-
tab === "store" && /* @__PURE__ */ jsx58("div", { className: "space-y-6", children: storeSettingsLoading ? /* @__PURE__ */ jsx58("div", { className: "flex items-center gap-2 text-gray-500", children: "Loading..." }) : /* @__PURE__ */ jsxs47(
|
|
12734
|
+
tab === "store" && /* @__PURE__ */ jsx58("div", { className: "space-y-6", children: storeSettingsLoading ? /* @__PURE__ */ jsx58("div", { className: "flex items-center gap-2 text-gray-500", children: "Loading..." }) : /* @__PURE__ */ jsxs47(Fragment13, { children: [
|
|
12619
12735
|
/* @__PURE__ */ jsxs47("div", { children: [
|
|
12620
12736
|
/* @__PURE__ */ jsx58("h2", { className: "text-lg font-semibold text-gray-900 mb-2", children: "Store / E-commerce" }),
|
|
12621
12737
|
/* @__PURE__ */ jsx58("p", { className: "text-sm text-gray-500 mb-4", children: "Enable e-commerce functionality to manage products, orders, payments, and more." }),
|
|
@@ -13175,7 +13291,7 @@ import {
|
|
|
13175
13291
|
Check as Check9
|
|
13176
13292
|
} from "lucide-react";
|
|
13177
13293
|
import { toast as toast8 } from "sonner";
|
|
13178
|
-
import { Fragment as
|
|
13294
|
+
import { Fragment as Fragment14, jsx as jsx60, jsxs as jsxs49 } from "react/jsx-runtime";
|
|
13179
13295
|
function getTypeCategory(mime, kind, filename) {
|
|
13180
13296
|
if (kind === "folder" || mime === "inode/directory") return "folder";
|
|
13181
13297
|
if (isZipMedia(mime, filename ?? "")) return "zip";
|
|
@@ -13389,7 +13505,7 @@ function VideoGridThumb({ src, label }) {
|
|
|
13389
13505
|
if (broken) {
|
|
13390
13506
|
return /* @__PURE__ */ jsx60("div", { ref: wrapRef, className: "absolute inset-0 flex items-center justify-center bg-gray-200", children: /* @__PURE__ */ jsx60(Film, { className: "h-12 w-12 text-slate-600", "aria-hidden": true }) });
|
|
13391
13507
|
}
|
|
13392
|
-
return /* @__PURE__ */ jsx60("div", { ref: wrapRef, className: "absolute inset-0 bg-neutral-900", children: !visible ? /* @__PURE__ */ jsx60("div", { className: "flex h-full w-full items-center justify-center bg-neutral-800", children: /* @__PURE__ */ jsx60(Film, { className: "h-12 w-12 text-slate-400", "aria-hidden": true }) }) : /* @__PURE__ */ jsxs49(
|
|
13508
|
+
return /* @__PURE__ */ jsx60("div", { ref: wrapRef, className: "absolute inset-0 bg-neutral-900", children: !visible ? /* @__PURE__ */ jsx60("div", { className: "flex h-full w-full items-center justify-center bg-neutral-800", children: /* @__PURE__ */ jsx60(Film, { className: "h-12 w-12 text-slate-400", "aria-hidden": true }) }) : /* @__PURE__ */ jsxs49(Fragment14, { children: [
|
|
13393
13509
|
/* @__PURE__ */ jsx60(
|
|
13394
13510
|
"video",
|
|
13395
13511
|
{
|
|
@@ -14262,7 +14378,7 @@ function MediaLibraryPage() {
|
|
|
14262
14378
|
editModal && /* @__PURE__ */ jsx60("div", { className: "space-y-4 py-2", children: editModal.kind === "folder" ? /* @__PURE__ */ jsxs49("div", { children: [
|
|
14263
14379
|
/* @__PURE__ */ jsx60("label", { className: "text-sm font-medium", children: "Name" }),
|
|
14264
14380
|
/* @__PURE__ */ jsx60(Input, { value: editFilename, onChange: (e) => setEditFilename(e.target.value), className: "mt-1" })
|
|
14265
|
-
] }) : /* @__PURE__ */ jsxs49(
|
|
14381
|
+
] }) : /* @__PURE__ */ jsxs49(Fragment14, { children: [
|
|
14266
14382
|
/* @__PURE__ */ jsxs49("div", { children: [
|
|
14267
14383
|
/* @__PURE__ */ jsx60("label", { className: "text-sm font-medium", children: "Alt text" }),
|
|
14268
14384
|
/* @__PURE__ */ jsx60(
|
|
@@ -14301,7 +14417,7 @@ function MediaLibraryPage() {
|
|
|
14301
14417
|
previewItem.size ? ` \xB7 ${formatMediaBytes(previewItem.size)}` : ""
|
|
14302
14418
|
] })
|
|
14303
14419
|
] }),
|
|
14304
|
-
previewItem && previewAbsUrl && /* @__PURE__ */ jsxs49(
|
|
14420
|
+
previewItem && previewAbsUrl && /* @__PURE__ */ jsxs49(Fragment14, { children: [
|
|
14305
14421
|
/* @__PURE__ */ jsx60("div", { className: "min-h-0 flex-1 overflow-auto rounded-md border bg-muted/15 p-2", children: /* @__PURE__ */ jsx60(MediaPreviewBody, { item: previewItem, absoluteUrl: previewAbsUrl }) }),
|
|
14306
14422
|
/* @__PURE__ */ jsxs49("div", { className: "flex shrink-0 flex-col-reverse gap-2 border-t pt-3 sm:flex-row sm:flex-wrap sm:items-center sm:justify-between", children: [
|
|
14307
14423
|
/* @__PURE__ */ jsxs49("div", { className: "flex flex-wrap gap-2", children: [
|
|
@@ -14413,7 +14529,7 @@ function getCatalog(theme) {
|
|
|
14413
14529
|
// src/admin/pages/PageBuilderPage.tsx
|
|
14414
14530
|
import * as LucideIcons from "lucide-react";
|
|
14415
14531
|
import React20 from "react";
|
|
14416
|
-
import { Fragment as
|
|
14532
|
+
import { Fragment as Fragment15, jsx as jsx61, jsxs as jsxs50 } from "react/jsx-runtime";
|
|
14417
14533
|
function createSelectable(Comp) {
|
|
14418
14534
|
function SelectableWrapper(props) {
|
|
14419
14535
|
const { id, connectors, displayName, isHovered } = useNode((node) => ({
|
|
@@ -14827,7 +14943,7 @@ function RightSidebar({ theme, resolver, activeTab, setActiveTab, seoProps }) {
|
|
|
14827
14943
|
tab
|
|
14828
14944
|
)) }),
|
|
14829
14945
|
/* @__PURE__ */ jsxs50("div", { className: "flex-1 overflow-y-auto flex flex-col min-h-0", children: [
|
|
14830
|
-
activeTab === "designer" && /* @__PURE__ */ jsxs50(
|
|
14946
|
+
activeTab === "designer" && /* @__PURE__ */ jsxs50(Fragment15, { children: [
|
|
14831
14947
|
/* @__PURE__ */ jsx61(
|
|
14832
14948
|
CollapsibleSection,
|
|
14833
14949
|
{
|
|
@@ -15183,6 +15299,7 @@ import {
|
|
|
15183
15299
|
Save as Save6,
|
|
15184
15300
|
X as X20,
|
|
15185
15301
|
Plus as Plus10,
|
|
15302
|
+
Trash2 as Trash29,
|
|
15186
15303
|
Smartphone,
|
|
15187
15304
|
Bot,
|
|
15188
15305
|
FileUp,
|
|
@@ -15671,7 +15788,7 @@ function JobScheduleTypeTabs({
|
|
|
15671
15788
|
}
|
|
15672
15789
|
|
|
15673
15790
|
// src/admin/JobSchedulesTool.tsx
|
|
15674
|
-
import { Fragment as
|
|
15791
|
+
import { Fragment as Fragment16, jsx as jsx65, jsxs as jsxs54 } from "react/jsx-runtime";
|
|
15675
15792
|
var WEEKDAY_LABELS = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
|
15676
15793
|
var EMPTY_DRAFT = {
|
|
15677
15794
|
name: "",
|
|
@@ -16036,7 +16153,7 @@ function JobSchedulesTool({
|
|
|
16036
16153
|
),
|
|
16037
16154
|
/* @__PURE__ */ jsx65("p", { className: "text-[11px] text-gray-500", children: "Standard 5-field cron (minute hour dom month dow)." })
|
|
16038
16155
|
] }) : null,
|
|
16039
|
-
activeJobType === "blog_generate" ? /* @__PURE__ */ jsxs54(
|
|
16156
|
+
activeJobType === "blog_generate" ? /* @__PURE__ */ jsxs54(Fragment16, { children: [
|
|
16040
16157
|
/* @__PURE__ */ jsxs54("div", { className: "space-y-1", children: [
|
|
16041
16158
|
/* @__PURE__ */ jsx65(Label3, { className: "text-sm", children: "Author (blog drafts)" }),
|
|
16042
16159
|
/* @__PURE__ */ jsx65(
|
|
@@ -16131,7 +16248,156 @@ function serializeEmailRecipients(emails) {
|
|
|
16131
16248
|
init_button();
|
|
16132
16249
|
init_input();
|
|
16133
16250
|
import { toast as toast10 } from "sonner";
|
|
16134
|
-
|
|
16251
|
+
|
|
16252
|
+
// src/plugins/llm/chat-email-intent.ts
|
|
16253
|
+
function normalizeIntentKey(raw) {
|
|
16254
|
+
return raw.trim().toUpperCase().replace(/[^A-Z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
16255
|
+
}
|
|
16256
|
+
function parseIntentsJson(raw) {
|
|
16257
|
+
if (!raw?.trim()) return null;
|
|
16258
|
+
try {
|
|
16259
|
+
const parsed = JSON.parse(raw);
|
|
16260
|
+
if (!Array.isArray(parsed)) return null;
|
|
16261
|
+
const out = [];
|
|
16262
|
+
for (const row of parsed) {
|
|
16263
|
+
if (!row || typeof row !== "object") continue;
|
|
16264
|
+
const o = row;
|
|
16265
|
+
const intent = normalizeIntentKey(String(o.intent ?? o.id ?? ""));
|
|
16266
|
+
const description = String(o.description ?? "").trim();
|
|
16267
|
+
const emailTo = String(o.emailTo ?? o.email ?? "").trim();
|
|
16268
|
+
if (!intent || !description || !emailTo) continue;
|
|
16269
|
+
out.push({ intent, description, emailTo });
|
|
16270
|
+
}
|
|
16271
|
+
return out.length > 0 ? out : null;
|
|
16272
|
+
} catch {
|
|
16273
|
+
return null;
|
|
16274
|
+
}
|
|
16275
|
+
}
|
|
16276
|
+
function dedupeIntents(intents) {
|
|
16277
|
+
const seen = /* @__PURE__ */ new Set();
|
|
16278
|
+
const out = [];
|
|
16279
|
+
for (const row of intents) {
|
|
16280
|
+
const key = normalizeIntentKey(row.intent);
|
|
16281
|
+
if (!key || seen.has(key)) continue;
|
|
16282
|
+
seen.add(key);
|
|
16283
|
+
out.push({
|
|
16284
|
+
intent: key,
|
|
16285
|
+
description: row.description.trim(),
|
|
16286
|
+
emailTo: row.emailTo.trim()
|
|
16287
|
+
});
|
|
16288
|
+
}
|
|
16289
|
+
return out;
|
|
16290
|
+
}
|
|
16291
|
+
function parseEmailIntentsFromSettings(raw) {
|
|
16292
|
+
return dedupeIntents(parseIntentsJson(raw) ?? []);
|
|
16293
|
+
}
|
|
16294
|
+
function serializeChatLeadIntents(intents) {
|
|
16295
|
+
return JSON.stringify(
|
|
16296
|
+
dedupeIntents(intents).map((r) => ({
|
|
16297
|
+
intent: r.intent,
|
|
16298
|
+
description: r.description,
|
|
16299
|
+
emailTo: r.emailTo
|
|
16300
|
+
}))
|
|
16301
|
+
);
|
|
16302
|
+
}
|
|
16303
|
+
var EMAIL_TOOL_VALIDATION_KEY = "emailTool";
|
|
16304
|
+
function parseEmailToolObject(raw) {
|
|
16305
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return null;
|
|
16306
|
+
const o = raw;
|
|
16307
|
+
const intentsRaw = o.intents;
|
|
16308
|
+
let intents;
|
|
16309
|
+
if (Array.isArray(intentsRaw)) {
|
|
16310
|
+
const parsed = parseIntentsJson(JSON.stringify(intentsRaw));
|
|
16311
|
+
if (parsed?.length) intents = parsed;
|
|
16312
|
+
}
|
|
16313
|
+
return {
|
|
16314
|
+
enabled: o.enabled === true,
|
|
16315
|
+
classifierInstructions: typeof o.classifierInstructions === "string" ? o.classifierInstructions.trim() : void 0,
|
|
16316
|
+
toolPrompt: typeof o.toolPrompt === "string" ? o.toolPrompt.trim() : void 0,
|
|
16317
|
+
intents
|
|
16318
|
+
};
|
|
16319
|
+
}
|
|
16320
|
+
function splitValidationRulesForAdmin(validationRulesText) {
|
|
16321
|
+
const raw = validationRulesText?.trim() ?? "";
|
|
16322
|
+
if (!raw) return { guardrailsJson: "", emailTool: null };
|
|
16323
|
+
try {
|
|
16324
|
+
const parsed = JSON.parse(raw);
|
|
16325
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
16326
|
+
return { guardrailsJson: raw, emailTool: null };
|
|
16327
|
+
}
|
|
16328
|
+
const emailTool = parseEmailToolObject(parsed[EMAIL_TOOL_VALIDATION_KEY]);
|
|
16329
|
+
const rest = { ...parsed };
|
|
16330
|
+
delete rest[EMAIL_TOOL_VALIDATION_KEY];
|
|
16331
|
+
const guardrailsJson = Object.keys(rest).length > 0 ? JSON.stringify(rest, null, 2) : "";
|
|
16332
|
+
return { guardrailsJson, emailTool };
|
|
16333
|
+
} catch {
|
|
16334
|
+
return { guardrailsJson: raw, emailTool: null };
|
|
16335
|
+
}
|
|
16336
|
+
}
|
|
16337
|
+
function mergeEmailToolIntoValidationRules(guardrailsJson, emailTool) {
|
|
16338
|
+
const intents = dedupeIntents(emailTool.intents);
|
|
16339
|
+
const hasEmail = intents.length > 0 || emailTool.classifierInstructions.trim() !== "" || emailTool.toolPrompt.trim() !== "";
|
|
16340
|
+
let base = {};
|
|
16341
|
+
const raw = guardrailsJson?.trim();
|
|
16342
|
+
if (raw) {
|
|
16343
|
+
try {
|
|
16344
|
+
const parsed = JSON.parse(raw);
|
|
16345
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
16346
|
+
base = { ...parsed };
|
|
16347
|
+
delete base[EMAIL_TOOL_VALIDATION_KEY];
|
|
16348
|
+
} else {
|
|
16349
|
+
return raw;
|
|
16350
|
+
}
|
|
16351
|
+
} catch {
|
|
16352
|
+
return raw;
|
|
16353
|
+
}
|
|
16354
|
+
}
|
|
16355
|
+
if (!hasEmail) {
|
|
16356
|
+
return Object.keys(base).length > 0 ? JSON.stringify(base, null, 2) : null;
|
|
16357
|
+
}
|
|
16358
|
+
base[EMAIL_TOOL_VALIDATION_KEY] = {
|
|
16359
|
+
enabled: true,
|
|
16360
|
+
classifierInstructions: emailTool.classifierInstructions.trim(),
|
|
16361
|
+
toolPrompt: emailTool.toolPrompt.trim(),
|
|
16362
|
+
intents: intents.map((r) => ({
|
|
16363
|
+
intent: r.intent,
|
|
16364
|
+
description: r.description,
|
|
16365
|
+
emailTo: r.emailTo
|
|
16366
|
+
}))
|
|
16367
|
+
};
|
|
16368
|
+
return JSON.stringify(base, null, 2);
|
|
16369
|
+
}
|
|
16370
|
+
|
|
16371
|
+
// src/plugins/llm/llm-agent-scope.ts
|
|
16372
|
+
var LLM_AGENT_SCOPE_CHATBOT = "chatbot";
|
|
16373
|
+
var LLM_AGENT_SCOPE_BLOG_CREATION = "blog_creation";
|
|
16374
|
+
var LLM_AGENT_SCOPE_SOCIAL_MEDIA_POST = "social_media_post";
|
|
16375
|
+
var LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT = "email_intent_chatbot";
|
|
16376
|
+
var LLM_AGENT_SCOPE_BLOG_METADATA = "blog_metadata";
|
|
16377
|
+
var LLM_AGENT_DEFAULT_SLUG_BY_SCOPE = {
|
|
16378
|
+
[LLM_AGENT_SCOPE_CHATBOT]: "site-chat-assistant",
|
|
16379
|
+
[LLM_AGENT_SCOPE_BLOG_CREATION]: "blog-generator",
|
|
16380
|
+
[LLM_AGENT_SCOPE_SOCIAL_MEDIA_POST]: "blog-generator-social",
|
|
16381
|
+
[LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT]: "email-intent-chatbot",
|
|
16382
|
+
[LLM_AGENT_SCOPE_BLOG_METADATA]: "blog-generator-metadata"
|
|
16383
|
+
};
|
|
16384
|
+
var LLM_AGENT_DEFAULT_NAME_BY_SCOPE = {
|
|
16385
|
+
[LLM_AGENT_SCOPE_CHATBOT]: "Site Chat Assistant",
|
|
16386
|
+
[LLM_AGENT_SCOPE_BLOG_CREATION]: "Blog Generator",
|
|
16387
|
+
[LLM_AGENT_SCOPE_SOCIAL_MEDIA_POST]: "Blog Generator (Social)",
|
|
16388
|
+
[LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT]: "Chat Lead Intent Classifier",
|
|
16389
|
+
[LLM_AGENT_SCOPE_BLOG_METADATA]: "Blog Generator (Metadata)"
|
|
16390
|
+
};
|
|
16391
|
+
var SITE_CHAT_ASSISTANT_SLUG = LLM_AGENT_DEFAULT_SLUG_BY_SCOPE[LLM_AGENT_SCOPE_CHATBOT];
|
|
16392
|
+
var SITE_CHAT_ASSISTANT_NAME = LLM_AGENT_DEFAULT_NAME_BY_SCOPE[LLM_AGENT_SCOPE_CHATBOT];
|
|
16393
|
+
var BLOG_LLM_AGENT_SLUGS = [
|
|
16394
|
+
LLM_AGENT_DEFAULT_SLUG_BY_SCOPE[LLM_AGENT_SCOPE_BLOG_CREATION],
|
|
16395
|
+
LLM_AGENT_DEFAULT_SLUG_BY_SCOPE[LLM_AGENT_SCOPE_BLOG_METADATA],
|
|
16396
|
+
LLM_AGENT_DEFAULT_SLUG_BY_SCOPE[LLM_AGENT_SCOPE_SOCIAL_MEDIA_POST]
|
|
16397
|
+
];
|
|
16398
|
+
|
|
16399
|
+
// src/admin/pages/PluginsPage.tsx
|
|
16400
|
+
import { Fragment as Fragment17, jsx as jsx66, jsxs as jsxs55 } from "react/jsx-runtime";
|
|
16135
16401
|
function normalizeLinkedInOrganizations(payload) {
|
|
16136
16402
|
if (!payload || typeof payload !== "object") return [];
|
|
16137
16403
|
const orgs = payload.organizations;
|
|
@@ -16170,10 +16436,6 @@ function normalizeFacebookGraphPages(graph) {
|
|
|
16170
16436
|
}
|
|
16171
16437
|
return out;
|
|
16172
16438
|
}
|
|
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
16439
|
function normalizeChatMode(raw) {
|
|
16178
16440
|
if (raw === "external" || raw === "llm") return raw;
|
|
16179
16441
|
return "whatsapp";
|
|
@@ -16312,6 +16574,8 @@ function PluginSettingsPanel({
|
|
|
16312
16574
|
descriptor,
|
|
16313
16575
|
onSaved
|
|
16314
16576
|
}) {
|
|
16577
|
+
const { pluginDescriptors = [] } = useContext7(AdminConfigContext);
|
|
16578
|
+
const emailPluginAvailable = pluginDescriptors.some((p) => p.name === "email" && p.enabled !== false);
|
|
16315
16579
|
const settingsGroup = descriptor.settingsGroup;
|
|
16316
16580
|
const isLlm = settingsGroup === "llm";
|
|
16317
16581
|
const isEmail = settingsGroup === "email";
|
|
@@ -16347,9 +16611,19 @@ function PluginSettingsPanel({
|
|
|
16347
16611
|
const [agentTemp, setAgentTemp] = useState37("");
|
|
16348
16612
|
const [agentMaxTokens, setAgentMaxTokens] = useState37("");
|
|
16349
16613
|
const [agentValidationJson, setAgentValidationJson] = useState37("");
|
|
16614
|
+
const [emailToolEnabled, setEmailToolEnabled] = useState37(false);
|
|
16615
|
+
const [emailIntents, setEmailIntents] = useState37([]);
|
|
16616
|
+
const [emailToolPrompt, setEmailToolPrompt] = useState37("");
|
|
16350
16617
|
const [agentLoading, setAgentLoading] = useState37(false);
|
|
16351
16618
|
const [agentSaving, setAgentSaving] = useState37(false);
|
|
16352
16619
|
const [agentProvisionError, setAgentProvisionError] = useState37(null);
|
|
16620
|
+
const [llmConfigTab, setLlmConfigTab] = useState37("chat");
|
|
16621
|
+
const [notifyEmailAgentId, setNotifyEmailAgentId] = useState37(null);
|
|
16622
|
+
const [notifyEmailName, setNotifyEmailName] = useState37("");
|
|
16623
|
+
const [notifyEmailSystem, setNotifyEmailSystem] = useState37("");
|
|
16624
|
+
const [notifyEmailLoading, setNotifyEmailLoading] = useState37(false);
|
|
16625
|
+
const [notifyEmailSaving, setNotifyEmailSaving] = useState37(false);
|
|
16626
|
+
const [notifyEmailProvisionError, setNotifyEmailProvisionError] = useState37(null);
|
|
16353
16627
|
const [kbCatalog, setKbCatalog] = useState37([]);
|
|
16354
16628
|
const [attachedAgentKnowledge, setAttachedAgentKnowledge] = useState37([]);
|
|
16355
16629
|
const [attachedKbLoading, setAttachedKbLoading] = useState37(false);
|
|
@@ -16571,7 +16845,12 @@ function PluginSettingsPanel({
|
|
|
16571
16845
|
setIconImageUrl(data.iconImageUrl ?? "");
|
|
16572
16846
|
setIconBackgroundColor(data.iconBackgroundColor ?? "#6366f1");
|
|
16573
16847
|
setHeaderColor(data.headerColor ?? "#6366f1");
|
|
16574
|
-
setAttachedAgentSlug(data.attachedAgentSlug ?? "");
|
|
16848
|
+
setAttachedAgentSlug((data.attachedAgentSlug ?? "").trim());
|
|
16849
|
+
setEmailToolEnabled(data.emailToolEnabled === "true");
|
|
16850
|
+
setEmailIntents(parseEmailIntentsFromSettings(data.emailIntents));
|
|
16851
|
+
const legacyClassifier = data.emailClassifierInstructions ?? [data.emailIntentPrompt, data.emailNegativeIntentPrompt].filter(Boolean).join("\n\n") ?? "";
|
|
16852
|
+
if (legacyClassifier) setNotifyEmailSystem(legacyClassifier);
|
|
16853
|
+
setEmailToolPrompt(data.emailToolPrompt ?? "");
|
|
16575
16854
|
}
|
|
16576
16855
|
if (isErp) {
|
|
16577
16856
|
setErpPipelineName(data.pipelineName ?? data.pipelineId ?? "");
|
|
@@ -16657,33 +16936,116 @@ function PluginSettingsPanel({
|
|
|
16657
16936
|
}).catch(() => setErpFormsCatalog([]));
|
|
16658
16937
|
}, [isErp, loading]);
|
|
16659
16938
|
const fetchLlmAgents = useCallback12(async () => {
|
|
16660
|
-
const res = await fetch(
|
|
16939
|
+
const res = await fetch(
|
|
16940
|
+
`/api/llm_agents?scope=${LLM_AGENT_SCOPE_CHATBOT}&limit=5&sortField=name&sortOrder=asc`
|
|
16941
|
+
);
|
|
16661
16942
|
if (!res.ok) {
|
|
16662
16943
|
setLlmAgents([]);
|
|
16944
|
+
setAgentId(null);
|
|
16663
16945
|
return;
|
|
16664
16946
|
}
|
|
16665
16947
|
const j = await res.json();
|
|
16666
|
-
const
|
|
16948
|
+
const chatRows = (j.data ?? []).filter(
|
|
16949
|
+
(r) => String(r.scope ?? "").trim() === LLM_AGENT_SCOPE_CHATBOT || String(r.slug ?? "").trim() === LLM_AGENT_DEFAULT_SLUG_BY_SCOPE[LLM_AGENT_SCOPE_CHATBOT]
|
|
16950
|
+
);
|
|
16951
|
+
const list = chatRows.map((r) => ({
|
|
16667
16952
|
id: r.id,
|
|
16668
16953
|
name: String(r.name ?? ""),
|
|
16669
16954
|
slug: String(r.slug ?? ""),
|
|
16955
|
+
scope: LLM_AGENT_SCOPE_CHATBOT,
|
|
16670
16956
|
enabled: r.enabled !== false
|
|
16671
16957
|
}));
|
|
16672
16958
|
setLlmAgents(list);
|
|
16673
16959
|
const pick = list.find((a) => a.enabled) ?? list[0];
|
|
16674
|
-
const fullRow =
|
|
16960
|
+
const fullRow = pick ? chatRows.find((r) => r.id === pick.id) : void 0;
|
|
16675
16961
|
if (pick && fullRow) {
|
|
16676
16962
|
setAgentId(pick.id);
|
|
16677
16963
|
setAgentName(pick.name);
|
|
16678
16964
|
setAgentSlug(pick.slug);
|
|
16965
|
+
setAttachedAgentSlug(pick.slug);
|
|
16679
16966
|
setAgentSystem(String(fullRow.systemInstruction ?? ""));
|
|
16680
16967
|
setAgentModel(String(fullRow.model ?? ""));
|
|
16681
16968
|
setAgentTemp(fullRow.temperature != null ? String(fullRow.temperature) : "");
|
|
16682
16969
|
setAgentMaxTokens(fullRow.maxTokens != null ? String(fullRow.maxTokens) : "");
|
|
16683
|
-
|
|
16684
|
-
|
|
16970
|
+
const { guardrailsJson } = splitValidationRulesForAdmin(fullRow.validationRules ?? null);
|
|
16971
|
+
setAgentValidationJson(guardrailsJson);
|
|
16972
|
+
} else {
|
|
16973
|
+
setAgentId(null);
|
|
16974
|
+
setAgentName(botName.trim() || LLM_AGENT_DEFAULT_NAME_BY_SCOPE[LLM_AGENT_SCOPE_CHATBOT]);
|
|
16975
|
+
setAgentSlug(LLM_AGENT_DEFAULT_SLUG_BY_SCOPE[LLM_AGENT_SCOPE_CHATBOT]);
|
|
16976
|
+
setAgentSystem("");
|
|
16977
|
+
setAgentModel("");
|
|
16978
|
+
setAgentTemp("");
|
|
16979
|
+
setAgentMaxTokens("");
|
|
16980
|
+
setAgentValidationJson("");
|
|
16981
|
+
}
|
|
16982
|
+
}, [botName]);
|
|
16983
|
+
const fetchNotifyEmailAgent = useCallback12(async () => {
|
|
16984
|
+
const res = await fetch(
|
|
16985
|
+
`/api/llm_agents?scope=${LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT}&limit=1&sortField=name&sortOrder=asc`
|
|
16986
|
+
);
|
|
16987
|
+
if (!res.ok) {
|
|
16988
|
+
setNotifyEmailAgentId(null);
|
|
16989
|
+
return;
|
|
16990
|
+
}
|
|
16991
|
+
const j = await res.json();
|
|
16992
|
+
const row = j.data?.find((r) => String(r.scope ?? "").trim() === LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT) ?? j.data?.find(
|
|
16993
|
+
(r) => String(r.slug ?? "").trim() === LLM_AGENT_DEFAULT_SLUG_BY_SCOPE[LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT]
|
|
16994
|
+
) ?? j.data?.[0];
|
|
16995
|
+
if (!row || String(row.scope ?? "").trim() !== LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT) {
|
|
16996
|
+
setNotifyEmailAgentId(null);
|
|
16997
|
+
setNotifyEmailName(LLM_AGENT_DEFAULT_NAME_BY_SCOPE[LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT]);
|
|
16998
|
+
setNotifyEmailSystem("");
|
|
16999
|
+
return;
|
|
17000
|
+
}
|
|
17001
|
+
setNotifyEmailAgentId(row.id);
|
|
17002
|
+
setNotifyEmailName(String(row.name ?? ""));
|
|
17003
|
+
setNotifyEmailSystem(String(row.systemInstruction ?? ""));
|
|
17004
|
+
const { emailTool } = splitValidationRulesForAdmin(row.validationRules ?? null);
|
|
17005
|
+
if (emailTool?.intents?.length) setEmailIntents(emailTool.intents);
|
|
17006
|
+
if (emailTool?.toolPrompt) setEmailToolPrompt(emailTool.toolPrompt);
|
|
17007
|
+
if (!row.systemInstruction?.trim() && emailTool?.classifierInstructions) {
|
|
17008
|
+
setNotifyEmailSystem(emailTool.classifierInstructions);
|
|
16685
17009
|
}
|
|
16686
17010
|
}, []);
|
|
17011
|
+
const bootstrapNotifyEmailAgent = useCallback12(async () => {
|
|
17012
|
+
setNotifyEmailProvisionError(null);
|
|
17013
|
+
const listRes = await fetch(
|
|
17014
|
+
`/api/llm_agents?scope=${LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT}&limit=1`
|
|
17015
|
+
);
|
|
17016
|
+
if (!listRes.ok) {
|
|
17017
|
+
const message = `Could not load notify email agent (HTTP ${listRes.status}).`;
|
|
17018
|
+
setNotifyEmailProvisionError(message);
|
|
17019
|
+
await fetchNotifyEmailAgent();
|
|
17020
|
+
return { ok: false, message };
|
|
17021
|
+
}
|
|
17022
|
+
const listJ = await listRes.json();
|
|
17023
|
+
const notifyRow = listJ.data?.find((a) => a.scope === LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT);
|
|
17024
|
+
if (notifyRow) {
|
|
17025
|
+
await fetchNotifyEmailAgent();
|
|
17026
|
+
return { ok: true };
|
|
17027
|
+
}
|
|
17028
|
+
const createRes = await fetch("/api/llm_agents", {
|
|
17029
|
+
method: "POST",
|
|
17030
|
+
headers: { "Content-Type": "application/json" },
|
|
17031
|
+
body: JSON.stringify({
|
|
17032
|
+
name: LLM_AGENT_DEFAULT_NAME_BY_SCOPE[LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT],
|
|
17033
|
+
slug: LLM_AGENT_DEFAULT_SLUG_BY_SCOPE[LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT],
|
|
17034
|
+
scope: LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT,
|
|
17035
|
+
systemInstruction: "",
|
|
17036
|
+
enabled: true
|
|
17037
|
+
})
|
|
17038
|
+
});
|
|
17039
|
+
if (!createRes.ok) {
|
|
17040
|
+
const errBody = await createRes.json().catch(() => ({}));
|
|
17041
|
+
const message = errBody.error ?? `Could not create notify email agent (HTTP ${createRes.status}).`;
|
|
17042
|
+
setNotifyEmailProvisionError(message);
|
|
17043
|
+
await fetchNotifyEmailAgent();
|
|
17044
|
+
return { ok: false, message };
|
|
17045
|
+
}
|
|
17046
|
+
await fetchNotifyEmailAgent();
|
|
17047
|
+
return { ok: true };
|
|
17048
|
+
}, [fetchNotifyEmailAgent]);
|
|
16687
17049
|
const fetchKbCatalog = useCallback12(async () => {
|
|
16688
17050
|
try {
|
|
16689
17051
|
const res = await fetch("/api/knowledge_base_documents?limit=300&sortField=name&sortOrder=asc");
|
|
@@ -16729,7 +17091,9 @@ function PluginSettingsPanel({
|
|
|
16729
17091
|
}, []);
|
|
16730
17092
|
const bootstrapLlmAgentForPlugins = useCallback12(async () => {
|
|
16731
17093
|
setAgentProvisionError(null);
|
|
16732
|
-
const listRes = await fetch(
|
|
17094
|
+
const listRes = await fetch(
|
|
17095
|
+
`/api/llm_agents?scope=${LLM_AGENT_SCOPE_CHATBOT}&limit=5&sortField=name&sortOrder=asc`
|
|
17096
|
+
);
|
|
16733
17097
|
if (!listRes.ok) {
|
|
16734
17098
|
const errBody = await listRes.json().catch(() => ({}));
|
|
16735
17099
|
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 +17102,25 @@ function PluginSettingsPanel({
|
|
|
16738
17102
|
return { ok: false, message };
|
|
16739
17103
|
}
|
|
16740
17104
|
const listJ = await listRes.json();
|
|
16741
|
-
|
|
17105
|
+
const chatRow = listJ.data?.find(
|
|
17106
|
+
(a) => String(a.scope ?? "").trim() === LLM_AGENT_SCOPE_CHATBOT || String(a.slug ?? "").trim() === LLM_AGENT_DEFAULT_SLUG_BY_SCOPE[LLM_AGENT_SCOPE_CHATBOT]
|
|
17107
|
+
);
|
|
17108
|
+
if (chatRow) {
|
|
16742
17109
|
await fetchLlmAgents();
|
|
16743
17110
|
return { ok: true };
|
|
16744
17111
|
}
|
|
16745
|
-
const defaultName = botName.trim() ||
|
|
16746
|
-
const defaultSlug =
|
|
17112
|
+
const defaultName = botName.trim() || LLM_AGENT_DEFAULT_NAME_BY_SCOPE[LLM_AGENT_SCOPE_CHATBOT];
|
|
17113
|
+
const defaultSlug = LLM_AGENT_DEFAULT_SLUG_BY_SCOPE[LLM_AGENT_SCOPE_CHATBOT];
|
|
16747
17114
|
const createRes = await fetch("/api/llm_agents", {
|
|
16748
17115
|
method: "POST",
|
|
16749
17116
|
headers: { "Content-Type": "application/json" },
|
|
16750
|
-
body: JSON.stringify({
|
|
17117
|
+
body: JSON.stringify({
|
|
17118
|
+
name: defaultName,
|
|
17119
|
+
slug: defaultSlug,
|
|
17120
|
+
scope: LLM_AGENT_SCOPE_CHATBOT,
|
|
17121
|
+
systemInstruction: "",
|
|
17122
|
+
enabled: true
|
|
17123
|
+
})
|
|
16751
17124
|
});
|
|
16752
17125
|
if (!createRes.ok) {
|
|
16753
17126
|
const errBody = await createRes.json().catch(() => ({}));
|
|
@@ -16773,11 +17146,7 @@ function PluginSettingsPanel({
|
|
|
16773
17146
|
}
|
|
16774
17147
|
};
|
|
16775
17148
|
const handleCreateAssistantFromForm = async () => {
|
|
16776
|
-
const name = agentName.trim() || botName.trim();
|
|
16777
|
-
if (!name) {
|
|
16778
|
-
toast10.error("Enter an assistant name");
|
|
16779
|
-
return;
|
|
16780
|
-
}
|
|
17149
|
+
const name = agentName.trim() || botName.trim() || LLM_AGENT_DEFAULT_NAME_BY_SCOPE[LLM_AGENT_SCOPE_CHATBOT];
|
|
16781
17150
|
const tempRaw = agentTemp.trim();
|
|
16782
17151
|
const maxRaw = agentMaxTokens.trim();
|
|
16783
17152
|
const temperature = tempRaw === "" ? null : Number(tempRaw);
|
|
@@ -16790,7 +17159,7 @@ function PluginSettingsPanel({
|
|
|
16790
17159
|
toast10.error("Max tokens must be a positive integer");
|
|
16791
17160
|
return;
|
|
16792
17161
|
}
|
|
16793
|
-
const slug =
|
|
17162
|
+
const slug = LLM_AGENT_DEFAULT_SLUG_BY_SCOPE[LLM_AGENT_SCOPE_CHATBOT];
|
|
16794
17163
|
setAgentSaving(true);
|
|
16795
17164
|
try {
|
|
16796
17165
|
const res = await fetch("/api/llm_agents", {
|
|
@@ -16799,6 +17168,7 @@ function PluginSettingsPanel({
|
|
|
16799
17168
|
body: JSON.stringify({
|
|
16800
17169
|
name,
|
|
16801
17170
|
slug,
|
|
17171
|
+
scope: LLM_AGENT_SCOPE_CHATBOT,
|
|
16802
17172
|
systemInstruction: agentSystem.trim(),
|
|
16803
17173
|
model: agentModel.trim() || null,
|
|
16804
17174
|
temperature,
|
|
@@ -16825,18 +17195,19 @@ function PluginSettingsPanel({
|
|
|
16825
17195
|
useEffect34(() => {
|
|
16826
17196
|
if (!isLlm || loading || chatMode !== "llm") return;
|
|
16827
17197
|
setAgentLoading(true);
|
|
17198
|
+
setNotifyEmailLoading(true);
|
|
16828
17199
|
void (async () => {
|
|
16829
17200
|
try {
|
|
16830
17201
|
await bootstrapLlmAgentForPlugins();
|
|
17202
|
+
await bootstrapNotifyEmailAgent();
|
|
17203
|
+
await fetchNotifyEmailAgent();
|
|
17204
|
+
await fetchKbCatalog();
|
|
16831
17205
|
} finally {
|
|
16832
17206
|
setAgentLoading(false);
|
|
17207
|
+
setNotifyEmailLoading(false);
|
|
16833
17208
|
}
|
|
16834
17209
|
})();
|
|
16835
|
-
}, [isLlm, loading, chatMode, bootstrapLlmAgentForPlugins]);
|
|
16836
|
-
useEffect34(() => {
|
|
16837
|
-
if (!isLlm || loading || chatMode !== "llm") return;
|
|
16838
|
-
void fetchKbCatalog();
|
|
16839
|
-
}, [isLlm, loading, chatMode, fetchKbCatalog]);
|
|
17210
|
+
}, [isLlm, loading, chatMode, bootstrapLlmAgentForPlugins, bootstrapNotifyEmailAgent, fetchNotifyEmailAgent, fetchKbCatalog]);
|
|
16840
17211
|
useEffect34(() => {
|
|
16841
17212
|
if (!isLlm || loading || chatMode !== "llm" || !attachedAgentSlug.trim()) {
|
|
16842
17213
|
setAttachedAgentKnowledge([]);
|
|
@@ -16927,7 +17298,13 @@ function PluginSettingsPanel({
|
|
|
16927
17298
|
payload.iconImageUrl = { value: iconImageUrl, type: "public" };
|
|
16928
17299
|
payload.iconBackgroundColor = { value: iconBackgroundColor, type: "public" };
|
|
16929
17300
|
payload.headerColor = { value: headerColor, type: "public" };
|
|
16930
|
-
payload.attachedAgentSlug = {
|
|
17301
|
+
payload.attachedAgentSlug = {
|
|
17302
|
+
value: agentSlug.trim() || attachedAgentSlug.trim() || LLM_AGENT_DEFAULT_SLUG_BY_SCOPE[LLM_AGENT_SCOPE_CHATBOT],
|
|
17303
|
+
type: "public"
|
|
17304
|
+
};
|
|
17305
|
+
payload.emailToolEnabled = { value: emailToolEnabled ? "true" : "false", type: "public" };
|
|
17306
|
+
payload.emailIntents = { value: serializeChatLeadIntents(emailIntents), type: "public" };
|
|
17307
|
+
payload.emailToolPrompt = { value: emailToolPrompt, type: "public" };
|
|
16931
17308
|
}
|
|
16932
17309
|
if (isEmail) {
|
|
16933
17310
|
payload.salesTeamEmails = { value: serializeEmailRecipients(salesTeamEmails), type: "public" };
|
|
@@ -16943,65 +17320,169 @@ function PluginSettingsPanel({
|
|
|
16943
17320
|
}
|
|
16944
17321
|
return payload;
|
|
16945
17322
|
};
|
|
16946
|
-
const
|
|
16947
|
-
|
|
16948
|
-
|
|
16949
|
-
|
|
16950
|
-
|
|
16951
|
-
|
|
16952
|
-
|
|
16953
|
-
|
|
16954
|
-
|
|
16955
|
-
}
|
|
17323
|
+
const savePluginSettings = async () => {
|
|
17324
|
+
const res = await fetch(`/api/settings/${settingsGroup}`, {
|
|
17325
|
+
method: "PUT",
|
|
17326
|
+
headers: { "Content-Type": "application/json" },
|
|
17327
|
+
body: JSON.stringify(buildPayload())
|
|
17328
|
+
});
|
|
17329
|
+
return res.ok;
|
|
17330
|
+
};
|
|
17331
|
+
const validateChatAgentNumbers = () => {
|
|
16956
17332
|
const tempRaw = agentTemp.trim();
|
|
16957
17333
|
const maxRaw = agentMaxTokens.trim();
|
|
16958
17334
|
const temperature = tempRaw === "" ? null : Number(tempRaw);
|
|
16959
17335
|
const maxTokens = maxRaw === "" ? null : parseInt(maxRaw, 10);
|
|
16960
17336
|
if (tempRaw !== "" && !Number.isFinite(temperature)) {
|
|
16961
17337
|
toast10.error("Temperature must be a number");
|
|
16962
|
-
return;
|
|
17338
|
+
return null;
|
|
16963
17339
|
}
|
|
16964
17340
|
if (maxRaw !== "" && (!Number.isFinite(maxTokens) || maxTokens < 1)) {
|
|
16965
17341
|
toast10.error("Max tokens must be a positive integer");
|
|
16966
|
-
return;
|
|
17342
|
+
return null;
|
|
16967
17343
|
}
|
|
16968
|
-
|
|
17344
|
+
return { temperature, maxTokens };
|
|
17345
|
+
};
|
|
17346
|
+
const persistChatAgent = async () => {
|
|
17347
|
+
if (!agentId) return false;
|
|
17348
|
+
const nums = validateChatAgentNumbers();
|
|
17349
|
+
if (!nums) return false;
|
|
17350
|
+
const name = agentName.trim() || botName.trim() || LLM_AGENT_DEFAULT_NAME_BY_SCOPE[LLM_AGENT_SCOPE_CHATBOT];
|
|
17351
|
+
const res = await fetch(`/api/llm_agents/${agentId}`, {
|
|
17352
|
+
method: "PUT",
|
|
17353
|
+
headers: { "Content-Type": "application/json" },
|
|
17354
|
+
body: JSON.stringify({
|
|
17355
|
+
name,
|
|
17356
|
+
systemInstruction: agentSystem.trim(),
|
|
17357
|
+
model: agentModel.trim() || null,
|
|
17358
|
+
temperature: nums.temperature,
|
|
17359
|
+
maxTokens: nums.maxTokens,
|
|
17360
|
+
validationRules: agentValidationJson.trim() || null,
|
|
17361
|
+
enabled: true
|
|
17362
|
+
})
|
|
17363
|
+
});
|
|
17364
|
+
if (!res.ok) return false;
|
|
17365
|
+
setAttachedAgentSlug(agentSlug);
|
|
17366
|
+
return true;
|
|
17367
|
+
};
|
|
17368
|
+
const persistNotifyEmailAgent = async (agentIdOverride) => {
|
|
17369
|
+
const id = agentIdOverride ?? notifyEmailAgentId;
|
|
17370
|
+
if (!id) return false;
|
|
17371
|
+
const validationRules = mergeEmailToolIntoValidationRules(null, {
|
|
17372
|
+
classifierInstructions: "",
|
|
17373
|
+
toolPrompt: emailToolPrompt,
|
|
17374
|
+
intents: emailIntents
|
|
17375
|
+
});
|
|
17376
|
+
const res = await fetch(`/api/llm_agents/${id}`, {
|
|
17377
|
+
method: "PUT",
|
|
17378
|
+
headers: { "Content-Type": "application/json" },
|
|
17379
|
+
body: JSON.stringify({
|
|
17380
|
+
name: notifyEmailName.trim() || LLM_AGENT_DEFAULT_NAME_BY_SCOPE[LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT],
|
|
17381
|
+
systemInstruction: notifyEmailSystem.trim(),
|
|
17382
|
+
validationRules,
|
|
17383
|
+
enabled: true
|
|
17384
|
+
})
|
|
17385
|
+
});
|
|
17386
|
+
return res.ok;
|
|
17387
|
+
};
|
|
17388
|
+
const saveLlmPluginSettingsOnly = async () => {
|
|
17389
|
+
const res = await fetch(`/api/settings/${settingsGroup}`, {
|
|
17390
|
+
method: "PUT",
|
|
17391
|
+
headers: { "Content-Type": "application/json" },
|
|
17392
|
+
body: JSON.stringify(buildPayload())
|
|
17393
|
+
});
|
|
17394
|
+
return res.ok;
|
|
17395
|
+
};
|
|
17396
|
+
const handleSaveLlmChatTab = async () => {
|
|
17397
|
+
if (!agentId) {
|
|
17398
|
+
toast10.error("Wait for the assistant to load, or click Create assistant");
|
|
17399
|
+
return;
|
|
17400
|
+
}
|
|
17401
|
+
if (!validateChatAgentNumbers()) return;
|
|
17402
|
+
setSaving(true);
|
|
16969
17403
|
try {
|
|
16970
|
-
const
|
|
16971
|
-
|
|
16972
|
-
|
|
16973
|
-
body: JSON.stringify({
|
|
16974
|
-
name,
|
|
16975
|
-
systemInstruction: agentSystem.trim(),
|
|
16976
|
-
model: agentModel.trim() || null,
|
|
16977
|
-
temperature,
|
|
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");
|
|
17404
|
+
const chatOk = await persistChatAgent();
|
|
17405
|
+
if (!chatOk) {
|
|
17406
|
+
toast10.error("Failed to save assistant");
|
|
16986
17407
|
return;
|
|
16987
17408
|
}
|
|
16988
|
-
|
|
16989
|
-
|
|
17409
|
+
const settingsOk = await saveLlmPluginSettingsOnly();
|
|
17410
|
+
if (!settingsOk) {
|
|
17411
|
+
toast10.error("Failed to save widget settings");
|
|
17412
|
+
return;
|
|
17413
|
+
}
|
|
17414
|
+
toast10.success("Chat settings saved");
|
|
16990
17415
|
} catch {
|
|
16991
|
-
toast10.error("Failed to
|
|
17416
|
+
toast10.error("Failed to save");
|
|
16992
17417
|
} finally {
|
|
16993
|
-
|
|
17418
|
+
setSaving(false);
|
|
17419
|
+
}
|
|
17420
|
+
};
|
|
17421
|
+
const handleSaveLlmNotifyTab = async () => {
|
|
17422
|
+
if (!emailPluginAvailable) {
|
|
17423
|
+
toast10.error("Enable the Email plugin (SMTP) first");
|
|
17424
|
+
return;
|
|
17425
|
+
}
|
|
17426
|
+
const filledIntents = emailIntents.filter(
|
|
17427
|
+
(r) => r.intent.trim() && r.description.trim() && r.emailTo.trim()
|
|
17428
|
+
);
|
|
17429
|
+
if (filledIntents.length === 0) {
|
|
17430
|
+
toast10.error("Add at least one intent with Intent, Description, and Email To");
|
|
17431
|
+
return;
|
|
17432
|
+
}
|
|
17433
|
+
setEmailIntents(filledIntents);
|
|
17434
|
+
setNotifyEmailSaving(true);
|
|
17435
|
+
try {
|
|
17436
|
+
let notifyId = notifyEmailAgentId;
|
|
17437
|
+
if (!notifyId) {
|
|
17438
|
+
await bootstrapNotifyEmailAgent();
|
|
17439
|
+
const nr = await fetch(
|
|
17440
|
+
`/api/llm_agents?scope=${LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT}&limit=1`
|
|
17441
|
+
);
|
|
17442
|
+
if (nr.ok) {
|
|
17443
|
+
const nj = await nr.json();
|
|
17444
|
+
const row = nj.data?.find(
|
|
17445
|
+
(r) => String(r.scope ?? "").trim() === LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT
|
|
17446
|
+
);
|
|
17447
|
+
if (row) {
|
|
17448
|
+
notifyId = row.id;
|
|
17449
|
+
setNotifyEmailAgentId(row.id);
|
|
17450
|
+
}
|
|
17451
|
+
}
|
|
17452
|
+
}
|
|
17453
|
+
if (!notifyId) {
|
|
17454
|
+
toast10.error("Could not set up lead email \u2014 try again");
|
|
17455
|
+
return;
|
|
17456
|
+
}
|
|
17457
|
+
setEmailToolEnabled(true);
|
|
17458
|
+
const notifyOk = await persistNotifyEmailAgent(notifyId);
|
|
17459
|
+
if (!notifyOk) {
|
|
17460
|
+
toast10.error("Failed to save lead email settings");
|
|
17461
|
+
return;
|
|
17462
|
+
}
|
|
17463
|
+
const settingsOk = await saveLlmPluginSettingsOnly();
|
|
17464
|
+
if (!settingsOk) {
|
|
17465
|
+
toast10.warning("Routing saved, but enable flag failed to save in settings");
|
|
17466
|
+
return;
|
|
17467
|
+
}
|
|
17468
|
+
toast10.success("Lead email routing saved");
|
|
17469
|
+
await fetchNotifyEmailAgent();
|
|
17470
|
+
} catch {
|
|
17471
|
+
toast10.error("Failed to save");
|
|
17472
|
+
} finally {
|
|
17473
|
+
setNotifyEmailSaving(false);
|
|
16994
17474
|
}
|
|
16995
17475
|
};
|
|
16996
17476
|
const handleSave = async () => {
|
|
17477
|
+
if (isLlm && chatMode === "llm") {
|
|
17478
|
+
if (llmConfigTab === "notify") await handleSaveLlmNotifyTab();
|
|
17479
|
+
else await handleSaveLlmChatTab();
|
|
17480
|
+
return;
|
|
17481
|
+
}
|
|
16997
17482
|
setSaving(true);
|
|
16998
17483
|
try {
|
|
16999
|
-
const
|
|
17000
|
-
|
|
17001
|
-
headers: { "Content-Type": "application/json" },
|
|
17002
|
-
body: JSON.stringify(buildPayload())
|
|
17003
|
-
});
|
|
17004
|
-
if (!res.ok) throw new Error();
|
|
17484
|
+
const ok = await savePluginSettings();
|
|
17485
|
+
if (!ok) throw new Error();
|
|
17005
17486
|
if (isSocialMedia && (linkedinAccessToken.trim() || linkedinHasSavedToken)) {
|
|
17006
17487
|
if (linkedinAccessToken.trim()) {
|
|
17007
17488
|
setLinkedinHasSavedToken(true);
|
|
@@ -17708,7 +18189,7 @@ function PluginSettingsPanel({
|
|
|
17708
18189
|
}
|
|
17709
18190
|
}
|
|
17710
18191
|
})(),
|
|
17711
|
-
children: linkedinFetchLoading ? /* @__PURE__ */ jsxs55(
|
|
18192
|
+
children: linkedinFetchLoading ? /* @__PURE__ */ jsxs55(Fragment17, { children: [
|
|
17712
18193
|
/* @__PURE__ */ jsx66(Loader25, { className: "h-3.5 w-3.5 animate-spin" }),
|
|
17713
18194
|
"Fetching\u2026"
|
|
17714
18195
|
] }) : "Fetch pages"
|
|
@@ -17861,7 +18342,7 @@ function PluginSettingsPanel({
|
|
|
17861
18342
|
await persistMetaFacebookPageId(fr.selectedPageId);
|
|
17862
18343
|
}
|
|
17863
18344
|
})(),
|
|
17864
|
-
children: fbFetchLoading ? /* @__PURE__ */ jsxs55(
|
|
18345
|
+
children: fbFetchLoading ? /* @__PURE__ */ jsxs55(Fragment17, { children: [
|
|
17865
18346
|
/* @__PURE__ */ jsx66(Loader25, { className: "h-3.5 w-3.5 animate-spin" }),
|
|
17866
18347
|
"Fetching\u2026"
|
|
17867
18348
|
] }) : "Fetch managed pages"
|
|
@@ -17922,329 +18403,459 @@ function PluginSettingsPanel({
|
|
|
17922
18403
|
),
|
|
17923
18404
|
/* @__PURE__ */ jsx66("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: "Only paste code from sources you trust." })
|
|
17924
18405
|
] }),
|
|
17925
|
-
chatMode === "llm" && /* @__PURE__ */ jsxs55(
|
|
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
|
-
|
|
18406
|
+
chatMode === "llm" && /* @__PURE__ */ jsxs55(Fragment17, { children: [
|
|
18407
|
+
/* @__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: [
|
|
18408
|
+
/* @__PURE__ */ jsxs55(
|
|
18409
|
+
"button",
|
|
18410
|
+
{
|
|
18411
|
+
type: "button",
|
|
18412
|
+
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"}`,
|
|
18413
|
+
onClick: () => setLlmConfigTab("chat"),
|
|
18414
|
+
children: [
|
|
18415
|
+
/* @__PURE__ */ jsx66(MessageCircle, { className: "h-3.5 w-3.5 shrink-0" }),
|
|
18416
|
+
"Chat"
|
|
18417
|
+
]
|
|
18418
|
+
}
|
|
18419
|
+
),
|
|
18420
|
+
/* @__PURE__ */ jsxs55(
|
|
18421
|
+
"button",
|
|
18422
|
+
{
|
|
18423
|
+
type: "button",
|
|
18424
|
+
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"}`,
|
|
18425
|
+
onClick: () => setLlmConfigTab("notify"),
|
|
18426
|
+
children: [
|
|
18427
|
+
/* @__PURE__ */ jsx66(Mail2, { className: "h-3.5 w-3.5 shrink-0" }),
|
|
18428
|
+
"Notify"
|
|
18429
|
+
]
|
|
18430
|
+
}
|
|
18431
|
+
)
|
|
18432
|
+
] }),
|
|
18433
|
+
llmConfigTab === "chat" ? /* @__PURE__ */ jsxs55(Fragment17, { children: [
|
|
18434
|
+
/* @__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: [
|
|
18435
|
+
/* @__PURE__ */ jsx66("p", { className: "text-sm font-medium text-gray-900 dark:text-white", children: "Widget on your site" }),
|
|
18436
|
+
/* @__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
18437
|
/* @__PURE__ */ jsxs55("div", { className: "space-y-1", children: [
|
|
17940
|
-
/* @__PURE__ */ jsx66(Label3, { htmlFor:
|
|
18438
|
+
/* @__PURE__ */ jsx66(Label3, { htmlFor: `${settingsGroup}-botName`, className: "text-sm", children: "Widget title" }),
|
|
17941
18439
|
/* @__PURE__ */ jsx66(
|
|
17942
18440
|
Input,
|
|
17943
18441
|
{
|
|
17944
|
-
id:
|
|
17945
|
-
value:
|
|
17946
|
-
onChange: (e) =>
|
|
18442
|
+
id: `${settingsGroup}-botName`,
|
|
18443
|
+
value: botName,
|
|
18444
|
+
onChange: (e) => setBotName(e.target.value),
|
|
17947
18445
|
placeholder: "e.g. JM Buddy",
|
|
17948
18446
|
className: "h-8 text-sm"
|
|
17949
18447
|
}
|
|
17950
18448
|
)
|
|
17951
18449
|
] }),
|
|
17952
18450
|
/* @__PURE__ */ jsxs55("div", { className: "space-y-1", children: [
|
|
17953
|
-
/* @__PURE__ */ jsx66(Label3, { htmlFor:
|
|
18451
|
+
/* @__PURE__ */ jsx66(Label3, { htmlFor: `${settingsGroup}-iconImageUrl`, className: "text-sm", children: "Icon image URL" }),
|
|
17954
18452
|
/* @__PURE__ */ jsx66(
|
|
17955
18453
|
Input,
|
|
17956
18454
|
{
|
|
17957
|
-
id:
|
|
17958
|
-
value:
|
|
17959
|
-
|
|
17960
|
-
|
|
18455
|
+
id: `${settingsGroup}-iconImageUrl`,
|
|
18456
|
+
value: iconImageUrl,
|
|
18457
|
+
onChange: (e) => setIconImageUrl(e.target.value),
|
|
18458
|
+
placeholder: "https://\u2026 or /images/chat-icon.png",
|
|
18459
|
+
className: "h-8 text-sm"
|
|
17961
18460
|
}
|
|
17962
18461
|
),
|
|
17963
|
-
/* @__PURE__ */ jsx66("p", { className: "text-
|
|
18462
|
+
/* @__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
18463
|
] }),
|
|
17965
18464
|
/* @__PURE__ */ jsxs55("div", { className: "space-y-1", children: [
|
|
17966
|
-
/* @__PURE__ */ jsx66(Label3, { htmlFor:
|
|
18465
|
+
/* @__PURE__ */ jsx66(Label3, { htmlFor: `${settingsGroup}-icon`, className: "text-sm", children: "Icon fallback (emoji)" }),
|
|
17967
18466
|
/* @__PURE__ */ jsx66(
|
|
17968
|
-
|
|
18467
|
+
Input,
|
|
17969
18468
|
{
|
|
17970
|
-
id:
|
|
17971
|
-
value:
|
|
17972
|
-
onChange: (e) =>
|
|
17973
|
-
|
|
17974
|
-
|
|
17975
|
-
className: "text-sm"
|
|
18469
|
+
id: `${settingsGroup}-icon`,
|
|
18470
|
+
value: icon,
|
|
18471
|
+
onChange: (e) => setIcon(e.target.value),
|
|
18472
|
+
placeholder: "e.g. \u{1F4AC}",
|
|
18473
|
+
className: "h-8 text-sm w-20"
|
|
17976
18474
|
}
|
|
17977
18475
|
)
|
|
17978
18476
|
] }),
|
|
17979
|
-
/* @__PURE__ */ jsxs55("div", { className: "
|
|
18477
|
+
/* @__PURE__ */ jsxs55("div", { className: "flex gap-4", children: [
|
|
18478
|
+
/* @__PURE__ */ jsxs55("div", { className: "space-y-1", children: [
|
|
18479
|
+
/* @__PURE__ */ jsx66(Label3, { htmlFor: `${settingsGroup}-iconBg`, className: "text-sm", children: "Icon background" }),
|
|
18480
|
+
/* @__PURE__ */ jsxs55("div", { className: "flex items-center gap-2", children: [
|
|
18481
|
+
/* @__PURE__ */ jsx66(
|
|
18482
|
+
"input",
|
|
18483
|
+
{
|
|
18484
|
+
type: "color",
|
|
18485
|
+
id: `${settingsGroup}-iconBg`,
|
|
18486
|
+
value: iconBackgroundColor,
|
|
18487
|
+
onChange: (e) => setIconBackgroundColor(e.target.value),
|
|
18488
|
+
className: "h-8 w-10 cursor-pointer rounded border border-gray-300 dark:border-gray-600"
|
|
18489
|
+
}
|
|
18490
|
+
),
|
|
18491
|
+
/* @__PURE__ */ jsx66(
|
|
18492
|
+
Input,
|
|
18493
|
+
{
|
|
18494
|
+
value: iconBackgroundColor,
|
|
18495
|
+
onChange: (e) => setIconBackgroundColor(e.target.value),
|
|
18496
|
+
className: "h-8 w-24 text-sm font-mono"
|
|
18497
|
+
}
|
|
18498
|
+
)
|
|
18499
|
+
] })
|
|
18500
|
+
] }),
|
|
18501
|
+
/* @__PURE__ */ jsxs55("div", { className: "space-y-1", children: [
|
|
18502
|
+
/* @__PURE__ */ jsx66(Label3, { htmlFor: `${settingsGroup}-headerColor`, className: "text-sm", children: "Header color" }),
|
|
18503
|
+
/* @__PURE__ */ jsxs55("div", { className: "flex items-center gap-2", children: [
|
|
18504
|
+
/* @__PURE__ */ jsx66(
|
|
18505
|
+
"input",
|
|
18506
|
+
{
|
|
18507
|
+
type: "color",
|
|
18508
|
+
id: `${settingsGroup}-headerColor`,
|
|
18509
|
+
value: headerColor,
|
|
18510
|
+
onChange: (e) => setHeaderColor(e.target.value),
|
|
18511
|
+
className: "h-8 w-10 cursor-pointer rounded border border-gray-300 dark:border-gray-600"
|
|
18512
|
+
}
|
|
18513
|
+
),
|
|
18514
|
+
/* @__PURE__ */ jsx66(
|
|
18515
|
+
Input,
|
|
18516
|
+
{
|
|
18517
|
+
value: headerColor,
|
|
18518
|
+
onChange: (e) => setHeaderColor(e.target.value),
|
|
18519
|
+
className: "h-8 w-24 text-sm font-mono"
|
|
18520
|
+
}
|
|
18521
|
+
)
|
|
18522
|
+
] })
|
|
18523
|
+
] })
|
|
18524
|
+
] })
|
|
18525
|
+
] }),
|
|
18526
|
+
/* @__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: [
|
|
18527
|
+
/* @__PURE__ */ jsxs55("div", { className: "space-y-1", children: [
|
|
18528
|
+
/* @__PURE__ */ jsxs55("div", { className: "flex items-center gap-2 text-sm font-medium text-gray-900 dark:text-white", children: [
|
|
18529
|
+
/* @__PURE__ */ jsx66(Bot, { className: "h-4 w-4" }),
|
|
18530
|
+
"Assistant"
|
|
18531
|
+
] }),
|
|
18532
|
+
/* @__PURE__ */ jsx66("p", { className: "text-[11px] text-gray-500 dark:text-gray-400", children: "Storefront assistant \u2014 model, instructions, and guardrails." })
|
|
18533
|
+
] }),
|
|
18534
|
+
agentLoading ? /* @__PURE__ */ jsxs55("div", { className: "flex items-center gap-2 text-sm text-gray-500", children: [
|
|
18535
|
+
/* @__PURE__ */ jsx66(Loader25, { className: "h-4 w-4 animate-spin" }),
|
|
18536
|
+
"Loading\u2026"
|
|
18537
|
+
] }) : /* @__PURE__ */ jsxs55(Fragment17, { children: [
|
|
18538
|
+
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
18539
|
/* @__PURE__ */ jsxs55("div", { className: "space-y-1", children: [
|
|
17981
|
-
/* @__PURE__ */ jsx66(Label3, { htmlFor: "agent-
|
|
18540
|
+
/* @__PURE__ */ jsx66(Label3, { htmlFor: "agent-system", className: "text-sm", children: "System instruction" }),
|
|
17982
18541
|
/* @__PURE__ */ jsx66(
|
|
17983
|
-
|
|
18542
|
+
Textarea,
|
|
17984
18543
|
{
|
|
17985
|
-
id: "agent-
|
|
17986
|
-
value:
|
|
17987
|
-
onChange: (e) =>
|
|
17988
|
-
|
|
17989
|
-
|
|
18544
|
+
id: "agent-system",
|
|
18545
|
+
value: agentSystem,
|
|
18546
|
+
onChange: (e) => setAgentSystem(e.target.value),
|
|
18547
|
+
rows: 5,
|
|
18548
|
+
placeholder: "How the model should behave\u2026",
|
|
18549
|
+
className: "text-sm"
|
|
17990
18550
|
}
|
|
17991
18551
|
)
|
|
17992
18552
|
] }),
|
|
18553
|
+
/* @__PURE__ */ jsxs55("div", { className: "grid grid-cols-2 gap-2", children: [
|
|
18554
|
+
/* @__PURE__ */ jsxs55("div", { className: "space-y-1", children: [
|
|
18555
|
+
/* @__PURE__ */ jsx66(Label3, { htmlFor: "agent-model", className: "text-sm", children: "Model (optional)" }),
|
|
18556
|
+
/* @__PURE__ */ jsx66(
|
|
18557
|
+
Input,
|
|
18558
|
+
{
|
|
18559
|
+
id: "agent-model",
|
|
18560
|
+
value: agentModel,
|
|
18561
|
+
onChange: (e) => setAgentModel(e.target.value),
|
|
18562
|
+
placeholder: "Gateway model id",
|
|
18563
|
+
className: "h-8 text-sm font-mono"
|
|
18564
|
+
}
|
|
18565
|
+
)
|
|
18566
|
+
] }),
|
|
18567
|
+
/* @__PURE__ */ jsxs55("div", { className: "space-y-1", children: [
|
|
18568
|
+
/* @__PURE__ */ jsx66(Label3, { htmlFor: "agent-temp", className: "text-sm", children: "Temperature" }),
|
|
18569
|
+
/* @__PURE__ */ jsx66(
|
|
18570
|
+
Input,
|
|
18571
|
+
{
|
|
18572
|
+
id: "agent-temp",
|
|
18573
|
+
value: agentTemp,
|
|
18574
|
+
onChange: (e) => setAgentTemp(e.target.value),
|
|
18575
|
+
placeholder: "e.g. 0.7",
|
|
18576
|
+
className: "h-8 text-sm"
|
|
18577
|
+
}
|
|
18578
|
+
)
|
|
18579
|
+
] })
|
|
18580
|
+
] }),
|
|
17993
18581
|
/* @__PURE__ */ jsxs55("div", { className: "space-y-1", children: [
|
|
17994
|
-
/* @__PURE__ */ jsx66(Label3, { htmlFor: "agent-
|
|
18582
|
+
/* @__PURE__ */ jsx66(Label3, { htmlFor: "agent-max", className: "text-sm", children: "Max tokens" }),
|
|
17995
18583
|
/* @__PURE__ */ jsx66(
|
|
17996
18584
|
Input,
|
|
17997
18585
|
{
|
|
17998
|
-
id: "agent-
|
|
17999
|
-
value:
|
|
18000
|
-
onChange: (e) =>
|
|
18001
|
-
placeholder: "e.g.
|
|
18586
|
+
id: "agent-max",
|
|
18587
|
+
value: agentMaxTokens,
|
|
18588
|
+
onChange: (e) => setAgentMaxTokens(e.target.value.replace(/\D/g, "")),
|
|
18589
|
+
placeholder: "e.g. 1024",
|
|
18002
18590
|
className: "h-8 text-sm"
|
|
18003
18591
|
}
|
|
18004
18592
|
)
|
|
18005
|
-
] })
|
|
18006
|
-
|
|
18007
|
-
|
|
18008
|
-
|
|
18009
|
-
|
|
18010
|
-
|
|
18011
|
-
|
|
18012
|
-
|
|
18013
|
-
|
|
18014
|
-
|
|
18015
|
-
|
|
18016
|
-
|
|
18017
|
-
|
|
18018
|
-
|
|
18593
|
+
] }),
|
|
18594
|
+
/* @__PURE__ */ jsxs55("div", { className: "space-y-1", children: [
|
|
18595
|
+
/* @__PURE__ */ jsx66(Label3, { htmlFor: "agent-validation", className: "text-sm", children: "Validation & output guardrails" }),
|
|
18596
|
+
/* @__PURE__ */ jsx66(
|
|
18597
|
+
Textarea,
|
|
18598
|
+
{
|
|
18599
|
+
id: "agent-validation",
|
|
18600
|
+
value: agentValidationJson,
|
|
18601
|
+
onChange: (e) => setAgentValidationJson(e.target.value),
|
|
18602
|
+
rows: 4,
|
|
18603
|
+
placeholder: 'Plain text or JSON: {"guardrails":"Never promise refunds.","maxUserChars":2000}',
|
|
18604
|
+
className: "text-xs font-mono"
|
|
18605
|
+
}
|
|
18606
|
+
)
|
|
18607
|
+
] }),
|
|
18608
|
+
!agentId ? /* @__PURE__ */ jsxs55("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
18609
|
+
/* @__PURE__ */ jsx66(
|
|
18610
|
+
Button,
|
|
18611
|
+
{
|
|
18612
|
+
type: "button",
|
|
18613
|
+
size: "sm",
|
|
18614
|
+
className: "gap-1",
|
|
18615
|
+
disabled: agentSaving,
|
|
18616
|
+
onClick: () => void handleCreateAssistantFromForm(),
|
|
18617
|
+
children: agentSaving ? /* @__PURE__ */ jsxs55("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
18618
|
+
/* @__PURE__ */ jsx66(Loader25, { className: "h-3.5 w-3.5 animate-spin" }),
|
|
18619
|
+
"Creating\u2026"
|
|
18620
|
+
] }) : /* @__PURE__ */ jsxs55(Fragment17, { children: [
|
|
18621
|
+
/* @__PURE__ */ jsx66(Bot, { className: "h-3.5 w-3.5" }),
|
|
18622
|
+
"Create assistant"
|
|
18623
|
+
] })
|
|
18624
|
+
}
|
|
18625
|
+
),
|
|
18626
|
+
/* @__PURE__ */ jsx66(
|
|
18627
|
+
Button,
|
|
18628
|
+
{
|
|
18629
|
+
type: "button",
|
|
18630
|
+
size: "sm",
|
|
18631
|
+
variant: "secondary",
|
|
18632
|
+
className: "gap-1",
|
|
18633
|
+
disabled: agentSaving || agentLoading,
|
|
18634
|
+
onClick: () => void handleRetryBootstrapAgent(),
|
|
18635
|
+
children: "Retry auto-setup"
|
|
18636
|
+
}
|
|
18637
|
+
)
|
|
18638
|
+
] }) : null
|
|
18019
18639
|
] }),
|
|
18640
|
+
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: [
|
|
18641
|
+
/* @__PURE__ */ jsxs55("div", { className: "flex items-center gap-2 text-xs font-medium text-gray-800 dark:text-gray-200", children: [
|
|
18642
|
+
/* @__PURE__ */ jsx66(FileUp, { className: "h-3.5 w-3.5 shrink-0" }),
|
|
18643
|
+
"Knowledge for this agent"
|
|
18644
|
+
] }),
|
|
18645
|
+
/* @__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." }),
|
|
18646
|
+
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: [
|
|
18647
|
+
/* @__PURE__ */ jsx66("span", { className: "min-w-0 truncate", title: d.name, children: d.name }),
|
|
18648
|
+
/* @__PURE__ */ jsx66(
|
|
18649
|
+
Button,
|
|
18650
|
+
{
|
|
18651
|
+
type: "button",
|
|
18652
|
+
variant: "ghost",
|
|
18653
|
+
size: "sm",
|
|
18654
|
+
className: "h-7 shrink-0 text-xs text-red-600 hover:text-red-700 dark:text-red-400",
|
|
18655
|
+
onClick: () => void handleUnlinkKbDoc(d.id),
|
|
18656
|
+
children: "Remove"
|
|
18657
|
+
}
|
|
18658
|
+
)
|
|
18659
|
+
] }, d.id)) }),
|
|
18660
|
+
/* @__PURE__ */ jsxs55("div", { className: "min-w-[180px] space-y-1", children: [
|
|
18661
|
+
/* @__PURE__ */ jsx66(Label3, { className: "text-xs", children: "Upload file" }),
|
|
18662
|
+
/* @__PURE__ */ jsxs55("div", { className: "relative", children: [
|
|
18663
|
+
/* @__PURE__ */ jsx66(
|
|
18664
|
+
Input,
|
|
18665
|
+
{
|
|
18666
|
+
type: "file",
|
|
18667
|
+
accept: ".txt,.md,.json,.pdf,text/plain,text/markdown,application/json,application/pdf",
|
|
18668
|
+
disabled: uploadingAttachedKbFile || uploadingAttachedKbLink,
|
|
18669
|
+
className: "h-8 cursor-pointer text-xs disabled:opacity-60",
|
|
18670
|
+
onChange: onAttachedKbFileChange
|
|
18671
|
+
},
|
|
18672
|
+
attachedKbInputKey
|
|
18673
|
+
),
|
|
18674
|
+
uploadingAttachedKbFile ? /* @__PURE__ */ jsxs55(
|
|
18675
|
+
"div",
|
|
18676
|
+
{
|
|
18677
|
+
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",
|
|
18678
|
+
"aria-live": "polite",
|
|
18679
|
+
children: [
|
|
18680
|
+
/* @__PURE__ */ jsx66(Loader25, { className: "h-4 w-4 shrink-0 animate-spin" }),
|
|
18681
|
+
"Saving & linking\u2026"
|
|
18682
|
+
]
|
|
18683
|
+
}
|
|
18684
|
+
) : null
|
|
18685
|
+
] }),
|
|
18686
|
+
/* @__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)." })
|
|
18687
|
+
] }),
|
|
18688
|
+
/* @__PURE__ */ jsxs55("div", { className: "flex flex-wrap items-end gap-2", children: [
|
|
18689
|
+
/* @__PURE__ */ jsxs55("div", { className: "min-w-[200px] flex-1 space-y-1", children: [
|
|
18690
|
+
/* @__PURE__ */ jsx66(Label3, { className: "text-xs", children: "Attach existing document" }),
|
|
18691
|
+
/* @__PURE__ */ jsxs55(Select, { value: attachExistingDocId, onValueChange: setAttachExistingDocId, children: [
|
|
18692
|
+
/* @__PURE__ */ jsx66(SelectTrigger, { className: "h-8 text-xs", children: /* @__PURE__ */ jsx66(SelectValue, { placeholder: "Choose a document" }) }),
|
|
18693
|
+
/* @__PURE__ */ jsxs55(SelectContent, { children: [
|
|
18694
|
+
/* @__PURE__ */ jsx66(SelectItem, { value: "__none__", children: "\u2014 Select \u2014" }),
|
|
18695
|
+
kbCatalog.filter((d) => !attachedAgentKnowledge.some((a) => a.id === d.id)).map((d) => /* @__PURE__ */ jsx66(SelectItem, { value: String(d.id), children: d.name }, d.id))
|
|
18696
|
+
] })
|
|
18697
|
+
] })
|
|
18698
|
+
] }),
|
|
18699
|
+
/* @__PURE__ */ jsx66(
|
|
18700
|
+
Button,
|
|
18701
|
+
{
|
|
18702
|
+
type: "button",
|
|
18703
|
+
size: "sm",
|
|
18704
|
+
className: "h-8",
|
|
18705
|
+
disabled: uploadingAttachedKbFile || uploadingAttachedKbLink || attachExistingDocId === "__none__",
|
|
18706
|
+
onClick: () => void handleAttachExistingToAttached(),
|
|
18707
|
+
children: uploadingAttachedKbLink ? /* @__PURE__ */ jsxs55("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
18708
|
+
/* @__PURE__ */ jsx66(Loader25, { className: "h-3.5 w-3.5 animate-spin" }),
|
|
18709
|
+
"Linking\u2026"
|
|
18710
|
+
] }) : "Attach"
|
|
18711
|
+
}
|
|
18712
|
+
)
|
|
18713
|
+
] })
|
|
18714
|
+
] }) : null
|
|
18715
|
+
] }),
|
|
18716
|
+
/* @__PURE__ */ jsxs55(
|
|
18717
|
+
Button,
|
|
18718
|
+
{
|
|
18719
|
+
type: "button",
|
|
18720
|
+
size: "sm",
|
|
18721
|
+
onClick: () => void handleSaveLlmChatTab(),
|
|
18722
|
+
disabled: saving,
|
|
18723
|
+
className: "gap-1",
|
|
18724
|
+
children: [
|
|
18725
|
+
saving ? /* @__PURE__ */ jsx66(Loader25, { className: "h-3.5 w-3.5 animate-spin" }) : /* @__PURE__ */ jsx66(Save6, { className: "h-3.5 w-3.5" }),
|
|
18726
|
+
"Save"
|
|
18727
|
+
]
|
|
18728
|
+
}
|
|
18729
|
+
)
|
|
18730
|
+
] }) : /* @__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: [
|
|
18731
|
+
/* @__PURE__ */ jsxs55("div", { children: [
|
|
18732
|
+
/* @__PURE__ */ jsx66("p", { className: "text-sm font-medium text-gray-900 dark:text-white", children: "Lead email routing" }),
|
|
18733
|
+
/* @__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." })
|
|
18734
|
+
] }),
|
|
18735
|
+
!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: [
|
|
18736
|
+
/* @__PURE__ */ jsx66(Loader25, { className: "h-4 w-4 animate-spin" }),
|
|
18737
|
+
"Loading\u2026"
|
|
18738
|
+
] }) : /* @__PURE__ */ jsxs55(Fragment17, { children: [
|
|
18739
|
+
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
18740
|
/* @__PURE__ */ jsxs55("div", { className: "space-y-1", children: [
|
|
18021
|
-
/* @__PURE__ */ jsx66(Label3, { htmlFor: "
|
|
18741
|
+
/* @__PURE__ */ jsx66(Label3, { htmlFor: "notify-email-system", className: "text-sm", children: "Routing instructions" }),
|
|
18022
18742
|
/* @__PURE__ */ jsx66(
|
|
18023
18743
|
Textarea,
|
|
18024
18744
|
{
|
|
18025
|
-
id: "
|
|
18026
|
-
value:
|
|
18027
|
-
onChange: (e) =>
|
|
18745
|
+
id: "notify-email-system",
|
|
18746
|
+
value: notifyEmailSystem,
|
|
18747
|
+
onChange: (e) => setNotifyEmailSystem(e.target.value),
|
|
18028
18748
|
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"
|
|
18749
|
+
placeholder: "When to treat a message as a lead, priority, when not to email\u2026",
|
|
18750
|
+
className: "text-sm"
|
|
18062
18751
|
}
|
|
18063
18752
|
)
|
|
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
18753
|
] }),
|
|
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",
|
|
18754
|
+
/* @__PURE__ */ jsxs55("div", { className: "space-y-2", children: [
|
|
18755
|
+
/* @__PURE__ */ jsxs55("div", { className: "flex items-center justify-between gap-2", children: [
|
|
18756
|
+
/* @__PURE__ */ jsx66(Label3, { className: "text-sm", children: "Intents" }),
|
|
18757
|
+
/* @__PURE__ */ jsxs55(
|
|
18758
|
+
Button,
|
|
18118
18759
|
{
|
|
18119
|
-
|
|
18120
|
-
|
|
18760
|
+
type: "button",
|
|
18761
|
+
size: "sm",
|
|
18762
|
+
variant: "outline",
|
|
18763
|
+
className: "h-7 gap-1 text-xs",
|
|
18764
|
+
onClick: () => setEmailIntents((rows) => [
|
|
18765
|
+
...rows,
|
|
18766
|
+
{ intent: "", description: "", emailTo: "" }
|
|
18767
|
+
]),
|
|
18121
18768
|
children: [
|
|
18122
|
-
/* @__PURE__ */ jsx66(
|
|
18123
|
-
"
|
|
18769
|
+
/* @__PURE__ */ jsx66(Plus10, { className: "h-3 w-3" }),
|
|
18770
|
+
"Add intent"
|
|
18124
18771
|
]
|
|
18125
18772
|
}
|
|
18126
|
-
)
|
|
18773
|
+
)
|
|
18127
18774
|
] }),
|
|
18128
|
-
/* @__PURE__ */ jsx66("
|
|
18129
|
-
|
|
18130
|
-
|
|
18131
|
-
|
|
18132
|
-
|
|
18133
|
-
|
|
18134
|
-
|
|
18135
|
-
|
|
18136
|
-
|
|
18137
|
-
|
|
18138
|
-
|
|
18775
|
+
/* @__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: [
|
|
18776
|
+
/* @__PURE__ */ jsx66("thead", { children: /* @__PURE__ */ jsxs55("tr", { className: "bg-gray-100/80 text-left dark:bg-gray-900/60", children: [
|
|
18777
|
+
/* @__PURE__ */ jsx66("th", { className: "w-[28%] p-2 font-medium", children: "Intent" }),
|
|
18778
|
+
/* @__PURE__ */ jsx66("th", { className: "w-[42%] p-2 font-medium", children: "Description" }),
|
|
18779
|
+
/* @__PURE__ */ jsx66("th", { className: "w-[26%] p-2 font-medium", children: "Email To" }),
|
|
18780
|
+
/* @__PURE__ */ jsx66("th", { className: "w-8 p-2" })
|
|
18781
|
+
] }) }),
|
|
18782
|
+
/* @__PURE__ */ jsxs55("tbody", { children: [
|
|
18783
|
+
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,
|
|
18784
|
+
emailIntents.map((row, idx) => /* @__PURE__ */ jsxs55("tr", { className: "border-t border-gray-200 dark:border-gray-700", children: [
|
|
18785
|
+
/* @__PURE__ */ jsx66("td", { className: "p-1.5 align-top", children: /* @__PURE__ */ jsx66(
|
|
18786
|
+
Input,
|
|
18787
|
+
{
|
|
18788
|
+
value: row.intent,
|
|
18789
|
+
onChange: (e) => {
|
|
18790
|
+
const v = e.target.value.toUpperCase().replace(/[^A-Z0-9_]/g, "");
|
|
18791
|
+
setEmailIntents(
|
|
18792
|
+
(rows) => rows.map((r, i) => i === idx ? { ...r, intent: v } : r)
|
|
18793
|
+
);
|
|
18794
|
+
},
|
|
18795
|
+
placeholder: "SALES_LEAD",
|
|
18796
|
+
className: "h-8 font-mono text-xs"
|
|
18797
|
+
}
|
|
18798
|
+
) }),
|
|
18799
|
+
/* @__PURE__ */ jsx66("td", { className: "p-1.5 align-top", children: /* @__PURE__ */ jsx66(
|
|
18800
|
+
Input,
|
|
18801
|
+
{
|
|
18802
|
+
value: row.description,
|
|
18803
|
+
onChange: (e) => setEmailIntents(
|
|
18804
|
+
(rows) => rows.map(
|
|
18805
|
+
(r, i) => i === idx ? { ...r, description: e.target.value } : r
|
|
18806
|
+
)
|
|
18807
|
+
),
|
|
18808
|
+
placeholder: "What this intent means",
|
|
18809
|
+
className: "h-8 text-xs"
|
|
18810
|
+
}
|
|
18811
|
+
) }),
|
|
18812
|
+
/* @__PURE__ */ jsx66("td", { className: "p-1.5 align-top", children: /* @__PURE__ */ jsx66(
|
|
18813
|
+
Input,
|
|
18814
|
+
{
|
|
18815
|
+
value: row.emailTo,
|
|
18816
|
+
onChange: (e) => setEmailIntents(
|
|
18817
|
+
(rows) => rows.map(
|
|
18818
|
+
(r, i) => i === idx ? { ...r, emailTo: e.target.value } : r
|
|
18819
|
+
)
|
|
18820
|
+
),
|
|
18821
|
+
placeholder: "team@company.com",
|
|
18822
|
+
className: "h-8 text-xs"
|
|
18823
|
+
}
|
|
18824
|
+
) }),
|
|
18825
|
+
/* @__PURE__ */ jsx66("td", { className: "p-1.5 align-top", children: /* @__PURE__ */ jsx66(
|
|
18826
|
+
Button,
|
|
18827
|
+
{
|
|
18828
|
+
type: "button",
|
|
18829
|
+
size: "icon",
|
|
18830
|
+
variant: "ghost",
|
|
18831
|
+
className: "h-8 w-8 text-red-600",
|
|
18832
|
+
onClick: () => setEmailIntents((rows) => rows.filter((_, i) => i !== idx)),
|
|
18833
|
+
"aria-label": "Remove intent",
|
|
18834
|
+
children: /* @__PURE__ */ jsx66(Trash29, { className: "h-3.5 w-3.5" })
|
|
18835
|
+
}
|
|
18836
|
+
) })
|
|
18837
|
+
] }, idx))
|
|
18139
18838
|
] })
|
|
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
|
-
)
|
|
18839
|
+
] }) })
|
|
18155
18840
|
] })
|
|
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,
|
|
18841
|
+
] }),
|
|
18842
|
+
/* @__PURE__ */ jsxs55(
|
|
18843
|
+
Button,
|
|
18189
18844
|
{
|
|
18190
|
-
|
|
18191
|
-
|
|
18192
|
-
|
|
18193
|
-
|
|
18194
|
-
className: "
|
|
18845
|
+
type: "button",
|
|
18846
|
+
size: "sm",
|
|
18847
|
+
onClick: () => void handleSaveLlmNotifyTab(),
|
|
18848
|
+
disabled: notifyEmailSaving || !emailPluginAvailable,
|
|
18849
|
+
className: "gap-1",
|
|
18850
|
+
children: [
|
|
18851
|
+
notifyEmailSaving ? /* @__PURE__ */ jsx66(Loader25, { className: "h-3.5 w-3.5 animate-spin" }) : /* @__PURE__ */ jsx66(Save6, { className: "h-3.5 w-3.5" }),
|
|
18852
|
+
"Save"
|
|
18853
|
+
]
|
|
18195
18854
|
}
|
|
18196
18855
|
)
|
|
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
18856
|
] })
|
|
18246
18857
|
] }),
|
|
18247
|
-
/* @__PURE__ */ jsxs55(Button, { size: "sm", onClick: handleSave, disabled: saving, className: "gap-1", children: [
|
|
18858
|
+
chatMode !== "llm" && /* @__PURE__ */ jsxs55(Button, { size: "sm", onClick: handleSave, disabled: saving, className: "gap-1", children: [
|
|
18248
18859
|
/* @__PURE__ */ jsx66(Save6, { className: "h-3.5 w-3.5" }),
|
|
18249
18860
|
"Save"
|
|
18250
18861
|
] })
|
|
@@ -18390,17 +19001,17 @@ function PluginsPage() {
|
|
|
18390
19001
|
/* @__PURE__ */ jsx66("div", { className: "min-w-0 flex-1", children: !selectedName ? /* @__PURE__ */ jsxs55("div", { className: "flex flex-col items-center justify-center py-12 text-center", children: [
|
|
18391
19002
|
/* @__PURE__ */ jsx66(Puzzle2, { className: "h-10 w-10 text-gray-300 dark:text-gray-600" }),
|
|
18392
19003
|
/* @__PURE__ */ jsx66("p", { className: "mt-3 text-sm text-gray-500 dark:text-gray-400", children: "Select a plugin to view or edit its configuration." })
|
|
18393
|
-
] }) : /* @__PURE__ */ jsx66("div", { className: "rounded-lg border border-gray-200 bg-gray-50/50 p-5 dark:border-gray-700 dark:bg-gray-800/50", children: selectedDescriptor?.name === "blog_generator" ? /* @__PURE__ */ jsxs55(
|
|
19004
|
+
] }) : /* @__PURE__ */ jsx66("div", { className: "rounded-lg border border-gray-200 bg-gray-50/50 p-5 dark:border-gray-700 dark:bg-gray-800/50", children: selectedDescriptor?.name === "blog_generator" ? /* @__PURE__ */ jsxs55(Fragment17, { children: [
|
|
18394
19005
|
/* @__PURE__ */ jsxs55("h2", { className: "text-sm font-medium text-gray-700 dark:text-gray-300 mb-1", children: [
|
|
18395
19006
|
selectedDescriptor.label || selectedDescriptor.name,
|
|
18396
19007
|
" \u2014 RSS preview"
|
|
18397
19008
|
] }),
|
|
18398
19009
|
/* @__PURE__ */ jsx66("p", { className: "text-xs text-gray-500 dark:text-gray-400 mb-4", children: "Paste a feed URL and click the button to load the newest entry here (read-only; does not create a blog)." }),
|
|
18399
19010
|
/* @__PURE__ */ jsx66(BlogGeneratorRssTool, { variant: "embedded", inputIdPrefix: "admin-plugins-blog-gen" })
|
|
18400
|
-
] }) : selectedDescriptor?.name === "pg_boss" ? /* @__PURE__ */ jsxs55(
|
|
19011
|
+
] }) : selectedDescriptor?.name === "pg_boss" ? /* @__PURE__ */ jsxs55(Fragment17, { children: [
|
|
18401
19012
|
/* @__PURE__ */ jsx66("h2", { className: "text-sm font-medium text-gray-700 dark:text-gray-300 mb-1", children: selectedDescriptor.label || selectedDescriptor.name }),
|
|
18402
19013
|
/* @__PURE__ */ jsx66(JobSchedulesTool, { variant: "embedded", inputIdPrefix: "admin-plugins-pg-boss" })
|
|
18403
|
-
] }) : selectedDescriptor?.settingsGroup ? /* @__PURE__ */ jsxs55(
|
|
19014
|
+
] }) : selectedDescriptor?.settingsGroup ? /* @__PURE__ */ jsxs55(Fragment17, { children: [
|
|
18404
19015
|
/* @__PURE__ */ jsxs55("h2", { className: "text-sm font-medium text-gray-700 dark:text-gray-300 mb-4", children: [
|
|
18405
19016
|
selectedDescriptor.label || selectedDescriptor.name,
|
|
18406
19017
|
" \u2014 Configuration"
|
|
@@ -18517,7 +19128,7 @@ async function fetchSeo(seoId) {
|
|
|
18517
19128
|
// src/admin/pages/BrandEditPage.tsx
|
|
18518
19129
|
init_DetailPageLayout();
|
|
18519
19130
|
init_DetailPageHeader();
|
|
18520
|
-
import { Fragment as
|
|
19131
|
+
import { Fragment as Fragment18, jsx as jsx68, jsxs as jsxs57 } from "react/jsx-runtime";
|
|
18521
19132
|
var isCreate = (id) => id === "create";
|
|
18522
19133
|
function BrandEditPage({ brandId }) {
|
|
18523
19134
|
const router = useRouter14();
|
|
@@ -18650,7 +19261,7 @@ function BrandEditPage({ brandId }) {
|
|
|
18650
19261
|
/* @__PURE__ */ jsx68(
|
|
18651
19262
|
DetailPageLayout,
|
|
18652
19263
|
{
|
|
18653
|
-
main: /* @__PURE__ */ jsxs57(
|
|
19264
|
+
main: /* @__PURE__ */ jsxs57(Fragment18, { children: [
|
|
18654
19265
|
/* @__PURE__ */ jsxs57("section", { children: [
|
|
18655
19266
|
/* @__PURE__ */ jsx68("h2", { className: "text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2", children: "Basic info" }),
|
|
18656
19267
|
/* @__PURE__ */ jsxs57("div", { className: "min-w-0 overflow-hidden border border-gray-200 rounded-lg p-4 bg-gray-50/50 space-y-4", children: [
|
|
@@ -18723,7 +19334,7 @@ function BrandEditPage({ brandId }) {
|
|
|
18723
19334
|
/* @__PURE__ */ jsx68("div", { className: "min-w-0 overflow-hidden border border-gray-200 rounded-lg p-4 bg-gray-50/50", children: /* @__PURE__ */ jsx68(SeoSection, { values: seo, onChange: (field, value) => setSeo((s) => ({ ...s, [field]: value })) }) })
|
|
18724
19335
|
] })
|
|
18725
19336
|
] }),
|
|
18726
|
-
sidebar: /* @__PURE__ */ jsx68(
|
|
19337
|
+
sidebar: /* @__PURE__ */ jsx68(Fragment18, { children: /* @__PURE__ */ jsxs57("section", { children: [
|
|
18727
19338
|
/* @__PURE__ */ jsx68("h2", { className: "text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2", children: "Status" }),
|
|
18728
19339
|
/* @__PURE__ */ jsx68("div", { className: "min-w-0 overflow-hidden border border-gray-200 rounded-lg p-4 bg-gray-50/50", children: /* @__PURE__ */ jsxs57("label", { className: "flex items-center gap-2 cursor-pointer", children: [
|
|
18729
19340
|
/* @__PURE__ */ jsx68(
|
|
@@ -18747,7 +19358,7 @@ function BrandEditPage({ brandId }) {
|
|
|
18747
19358
|
init_admin_list_return_url();
|
|
18748
19359
|
import { useState as useState40, useEffect as useEffect37, useMemo as useMemo8, useContext as useContext8 } from "react";
|
|
18749
19360
|
import { useRouter as useRouter15, useSearchParams as useSearchParams15 } from "next/navigation";
|
|
18750
|
-
import { AlertCircle as AlertCircle7, Plus as Plus11, Trash2 as
|
|
19361
|
+
import { AlertCircle as AlertCircle7, Plus as Plus11, Trash2 as Trash210, Star, Save as Save8 } from "lucide-react";
|
|
18751
19362
|
init_DetailPageLayout();
|
|
18752
19363
|
init_DetailPageHeader();
|
|
18753
19364
|
|
|
@@ -18893,7 +19504,7 @@ function AttributeFacetNameInput({
|
|
|
18893
19504
|
}
|
|
18894
19505
|
|
|
18895
19506
|
// src/admin/pages/ProductEditPage.tsx
|
|
18896
|
-
import { Fragment as
|
|
19507
|
+
import { Fragment as Fragment19, jsx as jsx70, jsxs as jsxs59 } from "react/jsx-runtime";
|
|
18897
19508
|
var isCreate2 = (id) => id === "create";
|
|
18898
19509
|
var sectionCls = "min-w-0 overflow-hidden border border-gray-200 rounded-lg p-4 bg-gray-50/50";
|
|
18899
19510
|
var labelCls = "block text-xs font-medium text-gray-600 mb-1";
|
|
@@ -19211,12 +19822,10 @@ function ProductEditPage({ productId }) {
|
|
|
19211
19822
|
setSaving(true);
|
|
19212
19823
|
try {
|
|
19213
19824
|
const activeCurrency = String(currency || "INR");
|
|
19214
|
-
console.log("DEBUG save:", { activeCurrency, price, compareAtPrice });
|
|
19215
19825
|
let saveRate = 1;
|
|
19216
19826
|
if (activeCurrency !== "INR") {
|
|
19217
19827
|
const displayRate = await fetchDisplayRate(activeCurrency);
|
|
19218
19828
|
saveRate = displayRate !== 0 && displayRate !== 1 ? 1 / displayRate : 1;
|
|
19219
|
-
console.log("DEBUG rate:", { displayRate, saveRate, priceInBase: Math.round(Number(price) * saveRate * 100) / 100 });
|
|
19220
19829
|
}
|
|
19221
19830
|
const priceInBase = Math.round(Number(price) * saveRate * 100) / 100;
|
|
19222
19831
|
const compareAtPriceInBase = compareAtPrice ? Math.round(Number(compareAtPrice) * saveRate * 100) / 100 : null;
|
|
@@ -19429,7 +20038,7 @@ function ProductEditPage({ productId }) {
|
|
|
19429
20038
|
/* @__PURE__ */ jsx70(
|
|
19430
20039
|
DetailPageLayout,
|
|
19431
20040
|
{
|
|
19432
|
-
main: /* @__PURE__ */ jsxs59(
|
|
20041
|
+
main: /* @__PURE__ */ jsxs59(Fragment19, { children: [
|
|
19433
20042
|
/* @__PURE__ */ jsxs59("section", { children: [
|
|
19434
20043
|
/* @__PURE__ */ jsx70("h2", { className: "text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2", children: "Product details" }),
|
|
19435
20044
|
/* @__PURE__ */ jsxs59("div", { className: `${sectionCls} space-y-4`, children: [
|
|
@@ -19623,7 +20232,7 @@ function ProductEditPage({ productId }) {
|
|
|
19623
20232
|
type: "button",
|
|
19624
20233
|
onClick: () => removeTaxRow(i),
|
|
19625
20234
|
className: "p-2 text-gray-400 hover:text-red-600 rounded shrink-0 mb-0.5",
|
|
19626
|
-
children: /* @__PURE__ */ jsx70(
|
|
20235
|
+
children: /* @__PURE__ */ jsx70(Trash210, { className: "h-4 w-4" })
|
|
19627
20236
|
}
|
|
19628
20237
|
)
|
|
19629
20238
|
] }, i);
|
|
@@ -19665,7 +20274,7 @@ function ProductEditPage({ productId }) {
|
|
|
19665
20274
|
className: `${inputCls} flex-1 min-w-[120px]`
|
|
19666
20275
|
}
|
|
19667
20276
|
),
|
|
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(
|
|
20277
|
+
/* @__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
20278
|
] }, i)),
|
|
19670
20279
|
/* @__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
20280
|
/* @__PURE__ */ jsx70(Plus11, { className: "h-3.5 w-3.5" }),
|
|
@@ -19712,7 +20321,7 @@ function ProductEditPage({ productId }) {
|
|
|
19712
20321
|
children: /* @__PURE__ */ jsx70(Star, { className: `h-4 w-4 ${row.isDefault ? "fill-amber-400 text-amber-500" : "text-gray-400"}` })
|
|
19713
20322
|
}
|
|
19714
20323
|
),
|
|
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(
|
|
20324
|
+
/* @__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
20325
|
] }, i)),
|
|
19717
20326
|
/* @__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
20327
|
/* @__PURE__ */ jsx70(Plus11, { className: "h-3.5 w-3.5" }),
|
|
@@ -19757,7 +20366,7 @@ function ProductEditPage({ productId }) {
|
|
|
19757
20366
|
className: `${inputCls} flex-1`
|
|
19758
20367
|
}
|
|
19759
20368
|
),
|
|
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(
|
|
20369
|
+
/* @__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
20370
|
] }, i)),
|
|
19762
20371
|
/* @__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
20372
|
/* @__PURE__ */ jsx70(Plus11, { className: "h-3.5 w-3.5" }),
|
|
@@ -19779,10 +20388,10 @@ function ProductEditPage({ productId }) {
|
|
|
19779
20388
|
init_admin_list_return_url();
|
|
19780
20389
|
import { useState as useState41, useEffect as useEffect38 } from "react";
|
|
19781
20390
|
import { useRouter as useRouter16, useSearchParams as useSearchParams16 } from "next/navigation";
|
|
19782
|
-
import { AlertCircle as AlertCircle8, Plus as Plus12, Trash2 as
|
|
20391
|
+
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
20392
|
init_DetailPageLayout();
|
|
19784
20393
|
init_DetailPageHeader();
|
|
19785
|
-
import { Fragment as
|
|
20394
|
+
import { Fragment as Fragment20, jsx as jsx71, jsxs as jsxs60 } from "react/jsx-runtime";
|
|
19786
20395
|
var isCreate3 = (id) => id === "create";
|
|
19787
20396
|
var emptySlide = () => ({ url: "", type: "image", caption: "" });
|
|
19788
20397
|
var emptyVariant = () => ({ name: "", price: "", extraSpecs: [] });
|
|
@@ -20027,7 +20636,7 @@ function CollectionEditPage({ collectionId }) {
|
|
|
20027
20636
|
/* @__PURE__ */ jsx71(
|
|
20028
20637
|
DetailPageLayout,
|
|
20029
20638
|
{
|
|
20030
|
-
main: /* @__PURE__ */ jsxs60(
|
|
20639
|
+
main: /* @__PURE__ */ jsxs60(Fragment20, { children: [
|
|
20031
20640
|
/* @__PURE__ */ jsxs60("section", { children: [
|
|
20032
20641
|
/* @__PURE__ */ jsx71("h2", { className: "text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2", children: "Basic info" }),
|
|
20033
20642
|
/* @__PURE__ */ jsxs60("div", { className: `${sectionCls2} space-y-4`, children: [
|
|
@@ -20106,7 +20715,7 @@ function CollectionEditPage({ collectionId }) {
|
|
|
20106
20715
|
/* @__PURE__ */ jsx71("option", { value: "video", children: "Video" })
|
|
20107
20716
|
] }),
|
|
20108
20717
|
/* @__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(
|
|
20718
|
+
/* @__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
20719
|
] }, i)),
|
|
20111
20720
|
/* @__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
20721
|
/* @__PURE__ */ jsx71(Plus12, { className: "h-3.5 w-3.5" }),
|
|
@@ -20119,12 +20728,12 @@ function CollectionEditPage({ collectionId }) {
|
|
|
20119
20728
|
/* @__PURE__ */ jsxs60("div", { className: "flex gap-2", children: [
|
|
20120
20729
|
/* @__PURE__ */ jsx71("input", { type: "text", value: v.name, onChange: (e) => updateVariant(i, "name", e.target.value), placeholder: "Name", className: `${inputCls2} w-40` }),
|
|
20121
20730
|
/* @__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(
|
|
20731
|
+
/* @__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
20732
|
] }),
|
|
20124
20733
|
v.extraSpecs.map((s, si) => /* @__PURE__ */ jsxs60("div", { className: "flex gap-2", children: [
|
|
20125
20734
|
/* @__PURE__ */ jsx71("input", { type: "text", value: s.key, onChange: (e) => updateVariantExtraSpec(i, si, "key", e.target.value), placeholder: "Key", className: `${inputCls2} flex-1` }),
|
|
20126
20735
|
/* @__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(
|
|
20736
|
+
/* @__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
20737
|
] }, si)),
|
|
20129
20738
|
/* @__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
20739
|
/* @__PURE__ */ jsx71(Plus12, { className: "h-3 w-3" }),
|
|
@@ -20147,7 +20756,7 @@ function CollectionEditPage({ collectionId }) {
|
|
|
20147
20756
|
] })
|
|
20148
20757
|
] })
|
|
20149
20758
|
] }),
|
|
20150
|
-
sidebar: /* @__PURE__ */ jsxs60(
|
|
20759
|
+
sidebar: /* @__PURE__ */ jsxs60(Fragment20, { children: [
|
|
20151
20760
|
/* @__PURE__ */ jsxs60("section", { children: [
|
|
20152
20761
|
/* @__PURE__ */ jsx71("h2", { className: "text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2", children: "Status" }),
|
|
20153
20762
|
/* @__PURE__ */ jsx71("div", { className: sectionCls2, children: /* @__PURE__ */ jsxs60("label", { className: "flex items-center gap-2 cursor-pointer", children: [
|
|
@@ -20170,7 +20779,7 @@ init_permission_entities();
|
|
|
20170
20779
|
init_vendor_scope();
|
|
20171
20780
|
import { useCallback as useCallback13, useEffect as useEffect39, useState as useState42 } from "react";
|
|
20172
20781
|
import { useSession as useSession8 } from "next-auth/react";
|
|
20173
|
-
import { Shield as Shield2, Save as Save10, Trash2 as
|
|
20782
|
+
import { Shield as Shield2, Save as Save10, Trash2 as Trash212 } from "lucide-react";
|
|
20174
20783
|
|
|
20175
20784
|
// src/auth/helpers.ts
|
|
20176
20785
|
init_rbac_debug();
|
|
@@ -20422,7 +21031,7 @@ function RolesPage() {
|
|
|
20422
21031
|
saving ? "Saving\u2026" : "Save"
|
|
20423
21032
|
] }),
|
|
20424
21033
|
!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(
|
|
21034
|
+
/* @__PURE__ */ jsx72(Trash212, { className: "h-3.5 w-3.5" }),
|
|
20426
21035
|
"Delete role"
|
|
20427
21036
|
] })
|
|
20428
21037
|
] }),
|
|
@@ -20513,10 +21122,14 @@ function SchedulesPage() {
|
|
|
20513
21122
|
|
|
20514
21123
|
// src/admin/pages/VendorOnboardPage.tsx
|
|
20515
21124
|
init_vendor_scope();
|
|
20516
|
-
init_button();
|
|
20517
|
-
init_input();
|
|
20518
21125
|
import { useState as useState43 } from "react";
|
|
21126
|
+
import { useRouter as useRouter18 } from "next/navigation";
|
|
20519
21127
|
import { useSession as useSession9 } from "next-auth/react";
|
|
21128
|
+
import { AlertCircle as AlertCircle9, Save as Save11 } from "lucide-react";
|
|
21129
|
+
init_DetailPageHeader();
|
|
21130
|
+
init_DetailPageLayout();
|
|
21131
|
+
init_button();
|
|
21132
|
+
init_input();
|
|
20520
21133
|
|
|
20521
21134
|
// src/components/ui/radio-group.tsx
|
|
20522
21135
|
init_utils();
|
|
@@ -20552,11 +21165,40 @@ var RadioGroupItem = React22.forwardRef(({ className, ...props }, ref) => {
|
|
|
20552
21165
|
RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName;
|
|
20553
21166
|
|
|
20554
21167
|
// src/admin/pages/VendorOnboardPage.tsx
|
|
20555
|
-
import { Fragment as
|
|
20556
|
-
|
|
20557
|
-
|
|
20558
|
-
|
|
20559
|
-
|
|
21168
|
+
import { Fragment as Fragment21, jsx as jsx76, jsxs as jsxs63 } from "react/jsx-runtime";
|
|
21169
|
+
var VENDOR_LIST_COLUMNS = [
|
|
21170
|
+
{ field: "name", displayName: "Name" },
|
|
21171
|
+
{ field: "slug", displayName: "Slug" },
|
|
21172
|
+
{ field: "email", displayName: "Email" },
|
|
21173
|
+
{ field: "phone", displayName: "Phone" },
|
|
21174
|
+
{ field: "active", displayName: "Active", type: "boolean" },
|
|
21175
|
+
{
|
|
21176
|
+
field: "inviteStatus",
|
|
21177
|
+
displayName: "Invite",
|
|
21178
|
+
type: "select",
|
|
21179
|
+
options: [
|
|
21180
|
+
{ value: "none", label: "None" },
|
|
21181
|
+
{ value: "pending", label: "Pending" },
|
|
21182
|
+
{ value: "expired", label: "Expired" },
|
|
21183
|
+
{ value: "accepted", label: "Accepted" }
|
|
21184
|
+
]
|
|
21185
|
+
},
|
|
21186
|
+
{ field: "createdAt", displayName: "Created", type: "date" }
|
|
21187
|
+
];
|
|
21188
|
+
function AccessDenied({ groupName }) {
|
|
21189
|
+
return /* @__PURE__ */ jsx76("div", { className: "rounded-lg bg-white p-6 shadow-md max-w-lg", children: /* @__PURE__ */ jsxs63("p", { className: "text-sm text-red-600", children: [
|
|
21190
|
+
"Only users in the ",
|
|
21191
|
+
/* @__PURE__ */ jsx76("strong", { children: "Administrator" }),
|
|
21192
|
+
" group can manage vendors.",
|
|
21193
|
+
groupName ? /* @__PURE__ */ jsxs63(Fragment21, { children: [
|
|
21194
|
+
" ",
|
|
21195
|
+
"Your group is ",
|
|
21196
|
+
/* @__PURE__ */ jsx76("strong", { children: groupName }),
|
|
21197
|
+
". Assign Administrator under System \u2192 Users, then sign out and sign in again."
|
|
21198
|
+
] }) : /* @__PURE__ */ jsx76(Fragment21, { children: " Assign the Administrator group under System \u2192 Users, then sign out and sign in again." })
|
|
21199
|
+
] }) });
|
|
21200
|
+
}
|
|
21201
|
+
function VendorOnboardForm({ onSuccess }) {
|
|
20560
21202
|
const [vendorName, setVendorName] = useState43("");
|
|
20561
21203
|
const [vendorSlug, setVendorSlug] = useState43("");
|
|
20562
21204
|
const [vendorEmail, setVendorEmail] = useState43("");
|
|
@@ -20564,44 +21206,31 @@ function VendorOnboardPage() {
|
|
|
20564
21206
|
const [ownerName, setOwnerName] = useState43("");
|
|
20565
21207
|
const [ownerEmail, setOwnerEmail] = useState43("");
|
|
20566
21208
|
const [activationMode, setActivationMode] = useState43("invite");
|
|
20567
|
-
const [
|
|
21209
|
+
const [sendOwnerEmail, setSendOwnerEmail] = useState43(true);
|
|
20568
21210
|
const [ownerPassword, setOwnerPassword] = useState43("");
|
|
20569
21211
|
const [ownerPasswordConfirm, setOwnerPasswordConfirm] = useState43("");
|
|
20570
21212
|
const [loading, setLoading] = useState43(false);
|
|
20571
21213
|
const [message, setMessage] = useState43(null);
|
|
20572
21214
|
const [inviteLink, setInviteLink] = useState43(null);
|
|
20573
|
-
const [
|
|
20574
|
-
|
|
20575
|
-
return /* @__PURE__ */ jsx76("div", { className: "p-6 max-w-lg", children: /* @__PURE__ */ jsxs63("p", { className: "text-sm text-red-600", children: [
|
|
20576
|
-
"Only users in the ",
|
|
20577
|
-
/* @__PURE__ */ jsx76("strong", { children: "Administrator" }),
|
|
20578
|
-
" group can onboard vendors.",
|
|
20579
|
-
sessionUser?.groupName ? /* @__PURE__ */ jsxs63(Fragment20, { children: [
|
|
20580
|
-
" Your group is ",
|
|
20581
|
-
/* @__PURE__ */ jsx76("strong", { children: sessionUser.groupName }),
|
|
20582
|
-
". Assign Administrator under System \u2192 Users, then sign out and sign in again."
|
|
20583
|
-
] }) : /* @__PURE__ */ jsx76(Fragment20, { children: " Assign the Administrator group under System \u2192 Users, then sign out and sign in again." })
|
|
20584
|
-
] }) });
|
|
20585
|
-
}
|
|
20586
|
-
const handleSubmit = async (e) => {
|
|
20587
|
-
e.preventDefault();
|
|
21215
|
+
const [errors, setErrors] = useState43([]);
|
|
21216
|
+
const handleSubmit = async () => {
|
|
20588
21217
|
setLoading(true);
|
|
20589
21218
|
setMessage(null);
|
|
20590
|
-
|
|
21219
|
+
setErrors([]);
|
|
20591
21220
|
setInviteLink(null);
|
|
20592
21221
|
if (activationMode === "password") {
|
|
20593
21222
|
if (!ownerPassword) {
|
|
20594
|
-
|
|
21223
|
+
setErrors(["Enter a password for the owner account"]);
|
|
20595
21224
|
setLoading(false);
|
|
20596
21225
|
return;
|
|
20597
21226
|
}
|
|
20598
21227
|
if (ownerPassword !== ownerPasswordConfirm) {
|
|
20599
|
-
|
|
21228
|
+
setErrors(["Passwords do not match"]);
|
|
20600
21229
|
setLoading(false);
|
|
20601
21230
|
return;
|
|
20602
21231
|
}
|
|
20603
21232
|
if (ownerPassword.length < 6) {
|
|
20604
|
-
|
|
21233
|
+
setErrors(["Password must be at least 6 characters"]);
|
|
20605
21234
|
setLoading(false);
|
|
20606
21235
|
return;
|
|
20607
21236
|
}
|
|
@@ -20612,7 +21241,7 @@ function VendorOnboardPage() {
|
|
|
20612
21241
|
headers: { "Content-Type": "application/json" },
|
|
20613
21242
|
body: JSON.stringify({
|
|
20614
21243
|
activation: activationMode,
|
|
20615
|
-
|
|
21244
|
+
sendOwnerEmail,
|
|
20616
21245
|
vendor: {
|
|
20617
21246
|
name: vendorName,
|
|
20618
21247
|
slug: vendorSlug || void 0,
|
|
@@ -20629,140 +21258,241 @@ function VendorOnboardPage() {
|
|
|
20629
21258
|
});
|
|
20630
21259
|
const data = await res.json();
|
|
20631
21260
|
if (!res.ok) {
|
|
20632
|
-
|
|
21261
|
+
setErrors([data.error || "Onboarding failed"]);
|
|
20633
21262
|
return;
|
|
20634
21263
|
}
|
|
20635
21264
|
setMessage(data.message || "Vendor created");
|
|
20636
21265
|
setInviteLink(data.inviteLink ?? null);
|
|
20637
|
-
|
|
20638
|
-
|
|
20639
|
-
|
|
20640
|
-
setVendorPhone("");
|
|
20641
|
-
setOwnerName("");
|
|
20642
|
-
setOwnerEmail("");
|
|
20643
|
-
setOwnerPassword("");
|
|
20644
|
-
setOwnerPasswordConfirm("");
|
|
21266
|
+
if (!data.inviteLink) {
|
|
21267
|
+
onSuccess();
|
|
21268
|
+
}
|
|
20645
21269
|
} catch {
|
|
20646
|
-
|
|
21270
|
+
setErrors(["Request failed"]);
|
|
20647
21271
|
} finally {
|
|
20648
21272
|
setLoading(false);
|
|
20649
21273
|
}
|
|
20650
21274
|
};
|
|
20651
|
-
const submitLabel = activationMode === "password" ? "Create vendor & set password" :
|
|
20652
|
-
|
|
20653
|
-
|
|
20654
|
-
/* @__PURE__ */ jsx76(
|
|
20655
|
-
|
|
20656
|
-
|
|
20657
|
-
|
|
20658
|
-
|
|
20659
|
-
|
|
20660
|
-
|
|
20661
|
-
|
|
20662
|
-
|
|
20663
|
-
|
|
20664
|
-
|
|
20665
|
-
|
|
20666
|
-
/* @__PURE__ */
|
|
20667
|
-
|
|
20668
|
-
|
|
20669
|
-
|
|
20670
|
-
|
|
20671
|
-
|
|
20672
|
-
|
|
20673
|
-
|
|
20674
|
-
|
|
20675
|
-
|
|
20676
|
-
/* @__PURE__ */ jsx76("h2", { className: "text-sm font-medium text-gray-900 dark:text-white", children: "Owner account" }),
|
|
20677
|
-
/* @__PURE__ */ jsxs63("div", { children: [
|
|
20678
|
-
/* @__PURE__ */ jsx76(Label3, { htmlFor: "ownerName", children: "Name" }),
|
|
20679
|
-
/* @__PURE__ */ jsx76(Input, { id: "ownerName", required: true, value: ownerName, onChange: (e) => setOwnerName(e.target.value), className: "mt-1" })
|
|
20680
|
-
] }),
|
|
20681
|
-
/* @__PURE__ */ jsxs63("div", { children: [
|
|
20682
|
-
/* @__PURE__ */ jsx76(Label3, { htmlFor: "ownerEmail", children: "Email" }),
|
|
20683
|
-
/* @__PURE__ */ jsx76(Input, { id: "ownerEmail", type: "email", required: true, value: ownerEmail, onChange: (e) => setOwnerEmail(e.target.value), className: "mt-1" })
|
|
20684
|
-
] })
|
|
21275
|
+
const submitLabel = activationMode === "password" ? sendOwnerEmail ? "Create vendor & send welcome email" : "Create vendor & set password" : sendOwnerEmail ? "Create vendor & send invite" : "Create vendor & copy invite link";
|
|
21276
|
+
const fieldClass = "w-full rounded-md border border-gray-300 px-3 py-2 text-sm";
|
|
21277
|
+
return /* @__PURE__ */ jsxs63("div", { className: "rounded-lg bg-white shadow-md", children: [
|
|
21278
|
+
/* @__PURE__ */ jsx76(
|
|
21279
|
+
DetailPageHeader,
|
|
21280
|
+
{
|
|
21281
|
+
title: "Create vendor",
|
|
21282
|
+
subtitle: "Creates a vendor store and a Vendor Owner account",
|
|
21283
|
+
closeHref: "/admin/vendor-onboard",
|
|
21284
|
+
menuItems: [{ label: loading ? "Creating\u2026" : submitLabel, icon: Save11, onClick: handleSubmit }]
|
|
21285
|
+
}
|
|
21286
|
+
),
|
|
21287
|
+
errors.length > 0 && /* @__PURE__ */ jsx76("div", { className: "bg-red-50 border-l-4 border-red-400 p-4 mx-6 mt-4", children: /* @__PURE__ */ jsxs63("div", { className: "flex", children: [
|
|
21288
|
+
/* @__PURE__ */ jsx76(AlertCircle9, { className: "h-5 w-5 text-red-400 flex-shrink-0" }),
|
|
21289
|
+
/* @__PURE__ */ jsxs63("div", { className: "ml-3", children: [
|
|
21290
|
+
/* @__PURE__ */ jsx76("h3", { className: "text-sm font-medium text-red-800", children: "Please fix the following errors:" }),
|
|
21291
|
+
/* @__PURE__ */ jsx76("ul", { className: "mt-2 text-sm text-red-700 list-disc pl-5 space-y-1", children: errors.map((e, i) => /* @__PURE__ */ jsx76("li", { children: e }, i)) })
|
|
21292
|
+
] })
|
|
21293
|
+
] }) }),
|
|
21294
|
+
message && /* @__PURE__ */ jsxs63("div", { className: "mx-6 mt-4 rounded-lg border border-green-200 bg-green-50 p-4 text-sm text-green-800", children: [
|
|
21295
|
+
/* @__PURE__ */ jsx76("p", { children: message }),
|
|
21296
|
+
inviteLink && /* @__PURE__ */ jsxs63("p", { className: "mt-2 text-xs break-all", children: [
|
|
21297
|
+
"Invite link:",
|
|
21298
|
+
" ",
|
|
21299
|
+
/* @__PURE__ */ jsx76("a", { href: inviteLink, className: "text-blue-600 underline", children: inviteLink })
|
|
20685
21300
|
] }),
|
|
20686
|
-
/* @__PURE__ */
|
|
20687
|
-
|
|
20688
|
-
|
|
20689
|
-
|
|
20690
|
-
|
|
20691
|
-
|
|
20692
|
-
|
|
20693
|
-
className: "
|
|
20694
|
-
children: [
|
|
20695
|
-
/* @__PURE__ */ jsxs63("div", {
|
|
20696
|
-
/* @__PURE__ */ jsx76(
|
|
20697
|
-
/* @__PURE__ */
|
|
20698
|
-
|
|
20699
|
-
|
|
20700
|
-
|
|
21301
|
+
/* @__PURE__ */ jsx76(Button, { type: "button", variant: "outline", size: "sm", className: "mt-3", onClick: onSuccess, children: "Back to vendors" })
|
|
21302
|
+
] }),
|
|
21303
|
+
!message && /* @__PURE__ */ jsx76(
|
|
21304
|
+
DetailPageLayout,
|
|
21305
|
+
{
|
|
21306
|
+
main: /* @__PURE__ */ jsxs63(Fragment21, { children: [
|
|
21307
|
+
/* @__PURE__ */ jsxs63("section", { children: [
|
|
21308
|
+
/* @__PURE__ */ jsx76("h2", { className: "text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2", children: "Store" }),
|
|
21309
|
+
/* @__PURE__ */ jsxs63("div", { className: "min-w-0 overflow-hidden border border-gray-200 rounded-lg p-4 bg-gray-50/50 space-y-4", children: [
|
|
21310
|
+
/* @__PURE__ */ jsxs63("div", { children: [
|
|
21311
|
+
/* @__PURE__ */ jsx76(Label3, { htmlFor: "vendorName", className: "text-xs font-medium text-gray-600", children: "Store name *" }),
|
|
21312
|
+
/* @__PURE__ */ jsx76(
|
|
21313
|
+
Input,
|
|
21314
|
+
{
|
|
21315
|
+
id: "vendorName",
|
|
21316
|
+
required: true,
|
|
21317
|
+
value: vendorName,
|
|
21318
|
+
onChange: (e) => setVendorName(e.target.value),
|
|
21319
|
+
className: `mt-1 ${fieldClass}`
|
|
21320
|
+
}
|
|
21321
|
+
)
|
|
20701
21322
|
] }),
|
|
20702
|
-
/* @__PURE__ */ jsxs63("div", {
|
|
20703
|
-
/* @__PURE__ */ jsx76(
|
|
20704
|
-
/* @__PURE__ */
|
|
20705
|
-
|
|
20706
|
-
|
|
20707
|
-
|
|
21323
|
+
/* @__PURE__ */ jsxs63("div", { children: [
|
|
21324
|
+
/* @__PURE__ */ jsx76(Label3, { htmlFor: "vendorSlug", className: "text-xs font-medium text-gray-600", children: "Slug (optional)" }),
|
|
21325
|
+
/* @__PURE__ */ jsx76(
|
|
21326
|
+
Input,
|
|
21327
|
+
{
|
|
21328
|
+
id: "vendorSlug",
|
|
21329
|
+
value: vendorSlug,
|
|
21330
|
+
onChange: (e) => setVendorSlug(e.target.value),
|
|
21331
|
+
placeholder: "auto from name",
|
|
21332
|
+
className: `mt-1 ${fieldClass}`
|
|
21333
|
+
}
|
|
21334
|
+
)
|
|
21335
|
+
] }),
|
|
21336
|
+
/* @__PURE__ */ jsxs63("div", { children: [
|
|
21337
|
+
/* @__PURE__ */ jsx76(Label3, { htmlFor: "vendorEmail", className: "text-xs font-medium text-gray-600", children: "Store email" }),
|
|
21338
|
+
/* @__PURE__ */ jsx76(
|
|
21339
|
+
Input,
|
|
21340
|
+
{
|
|
21341
|
+
id: "vendorEmail",
|
|
21342
|
+
type: "email",
|
|
21343
|
+
value: vendorEmail,
|
|
21344
|
+
onChange: (e) => setVendorEmail(e.target.value),
|
|
21345
|
+
className: `mt-1 ${fieldClass}`
|
|
21346
|
+
}
|
|
21347
|
+
)
|
|
21348
|
+
] }),
|
|
21349
|
+
/* @__PURE__ */ jsxs63("div", { children: [
|
|
21350
|
+
/* @__PURE__ */ jsx76(Label3, { htmlFor: "vendorPhone", className: "text-xs font-medium text-gray-600", children: "Phone" }),
|
|
21351
|
+
/* @__PURE__ */ jsx76(
|
|
21352
|
+
Input,
|
|
21353
|
+
{
|
|
21354
|
+
id: "vendorPhone",
|
|
21355
|
+
value: vendorPhone,
|
|
21356
|
+
onChange: (e) => setVendorPhone(e.target.value),
|
|
21357
|
+
className: `mt-1 ${fieldClass}`
|
|
21358
|
+
}
|
|
21359
|
+
)
|
|
20708
21360
|
] })
|
|
20709
|
-
]
|
|
20710
|
-
}
|
|
20711
|
-
),
|
|
20712
|
-
activationMode === "invite" && /* @__PURE__ */ jsxs63("div", { className: "flex items-center gap-2 pt-1", children: [
|
|
20713
|
-
/* @__PURE__ */ jsx76(
|
|
20714
|
-
Checkbox,
|
|
20715
|
-
{
|
|
20716
|
-
id: "sendInviteEmail",
|
|
20717
|
-
checked: sendInviteEmail,
|
|
20718
|
-
onCheckedChange: (checked) => setSendInviteEmail(checked === true)
|
|
20719
|
-
}
|
|
20720
|
-
),
|
|
20721
|
-
/* @__PURE__ */ jsx76(Label3, { htmlFor: "sendInviteEmail", className: "font-normal cursor-pointer text-sm", children: "Send invite email to owner" })
|
|
20722
|
-
] }),
|
|
20723
|
-
activationMode === "password" && /* @__PURE__ */ jsxs63("div", { className: "space-y-3 pt-1", children: [
|
|
20724
|
-
/* @__PURE__ */ jsxs63("div", { children: [
|
|
20725
|
-
/* @__PURE__ */ jsx76(Label3, { htmlFor: "ownerPassword", children: "Password" }),
|
|
20726
|
-
/* @__PURE__ */ jsx76(
|
|
20727
|
-
Input,
|
|
20728
|
-
{
|
|
20729
|
-
id: "ownerPassword",
|
|
20730
|
-
type: "password",
|
|
20731
|
-
required: true,
|
|
20732
|
-
autoComplete: "new-password",
|
|
20733
|
-
value: ownerPassword,
|
|
20734
|
-
onChange: (e) => setOwnerPassword(e.target.value),
|
|
20735
|
-
className: "mt-1"
|
|
20736
|
-
}
|
|
20737
|
-
)
|
|
21361
|
+
] })
|
|
20738
21362
|
] }),
|
|
20739
|
-
/* @__PURE__ */ jsxs63("
|
|
20740
|
-
/* @__PURE__ */ jsx76(
|
|
20741
|
-
/* @__PURE__ */
|
|
20742
|
-
|
|
21363
|
+
/* @__PURE__ */ jsxs63("section", { children: [
|
|
21364
|
+
/* @__PURE__ */ jsx76("h2", { className: "text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2", children: "Owner account" }),
|
|
21365
|
+
/* @__PURE__ */ jsxs63("div", { className: "min-w-0 overflow-hidden border border-gray-200 rounded-lg p-4 bg-gray-50/50 space-y-4", children: [
|
|
21366
|
+
/* @__PURE__ */ jsxs63("div", { children: [
|
|
21367
|
+
/* @__PURE__ */ jsx76(Label3, { htmlFor: "ownerName", className: "text-xs font-medium text-gray-600", children: "Name *" }),
|
|
21368
|
+
/* @__PURE__ */ jsx76(
|
|
21369
|
+
Input,
|
|
21370
|
+
{
|
|
21371
|
+
id: "ownerName",
|
|
21372
|
+
required: true,
|
|
21373
|
+
value: ownerName,
|
|
21374
|
+
onChange: (e) => setOwnerName(e.target.value),
|
|
21375
|
+
className: `mt-1 ${fieldClass}`
|
|
21376
|
+
}
|
|
21377
|
+
)
|
|
21378
|
+
] }),
|
|
21379
|
+
/* @__PURE__ */ jsxs63("div", { children: [
|
|
21380
|
+
/* @__PURE__ */ jsx76(Label3, { htmlFor: "ownerEmail", className: "text-xs font-medium text-gray-600", children: "Email *" }),
|
|
21381
|
+
/* @__PURE__ */ jsx76(
|
|
21382
|
+
Input,
|
|
21383
|
+
{
|
|
21384
|
+
id: "ownerEmail",
|
|
21385
|
+
type: "email",
|
|
21386
|
+
required: true,
|
|
21387
|
+
value: ownerEmail,
|
|
21388
|
+
onChange: (e) => setOwnerEmail(e.target.value),
|
|
21389
|
+
className: `mt-1 ${fieldClass}`
|
|
21390
|
+
}
|
|
21391
|
+
)
|
|
21392
|
+
] })
|
|
21393
|
+
] })
|
|
21394
|
+
] })
|
|
21395
|
+
] }),
|
|
21396
|
+
sidebar: /* @__PURE__ */ jsxs63("section", { children: [
|
|
21397
|
+
/* @__PURE__ */ jsx76("h2", { className: "text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2", children: "Owner access" }),
|
|
21398
|
+
/* @__PURE__ */ jsxs63("div", { className: "min-w-0 overflow-hidden border border-gray-200 rounded-lg p-4 bg-gray-50/50 space-y-4", children: [
|
|
21399
|
+
/* @__PURE__ */ jsxs63(
|
|
21400
|
+
RadioGroup2,
|
|
20743
21401
|
{
|
|
20744
|
-
|
|
20745
|
-
|
|
20746
|
-
|
|
20747
|
-
|
|
20748
|
-
|
|
20749
|
-
|
|
20750
|
-
|
|
21402
|
+
value: activationMode,
|
|
21403
|
+
onValueChange: (v) => setActivationMode(v),
|
|
21404
|
+
className: "gap-3",
|
|
21405
|
+
children: [
|
|
21406
|
+
/* @__PURE__ */ jsxs63("div", { className: "flex items-start gap-2", children: [
|
|
21407
|
+
/* @__PURE__ */ jsx76(RadioGroupItem, { value: "invite", id: "activation-invite", className: "mt-0.5" }),
|
|
21408
|
+
/* @__PURE__ */ jsxs63("div", { children: [
|
|
21409
|
+
/* @__PURE__ */ jsx76(Label3, { htmlFor: "activation-invite", className: "font-normal cursor-pointer text-sm", children: "Send invite link" }),
|
|
21410
|
+
/* @__PURE__ */ jsx76("p", { className: "text-xs text-gray-500 mt-0.5", children: "Owner sets their own password via email or the link below." })
|
|
21411
|
+
] })
|
|
21412
|
+
] }),
|
|
21413
|
+
/* @__PURE__ */ jsxs63("div", { className: "flex items-start gap-2", children: [
|
|
21414
|
+
/* @__PURE__ */ jsx76(RadioGroupItem, { value: "password", id: "activation-password", className: "mt-0.5" }),
|
|
21415
|
+
/* @__PURE__ */ jsxs63("div", { children: [
|
|
21416
|
+
/* @__PURE__ */ jsx76(Label3, { htmlFor: "activation-password", className: "font-normal cursor-pointer text-sm", children: "Set password now" }),
|
|
21417
|
+
/* @__PURE__ */ jsx76("p", { className: "text-xs text-gray-500 mt-0.5", children: "Account is active immediately; share the password with the owner securely." })
|
|
21418
|
+
] })
|
|
21419
|
+
] })
|
|
21420
|
+
]
|
|
20751
21421
|
}
|
|
20752
|
-
)
|
|
21422
|
+
),
|
|
21423
|
+
/* @__PURE__ */ jsxs63("div", { className: "flex items-center gap-2 pt-1", children: [
|
|
21424
|
+
/* @__PURE__ */ jsx76(
|
|
21425
|
+
Checkbox,
|
|
21426
|
+
{
|
|
21427
|
+
id: "sendOwnerEmail",
|
|
21428
|
+
checked: sendOwnerEmail,
|
|
21429
|
+
onCheckedChange: (checked) => setSendOwnerEmail(checked === true)
|
|
21430
|
+
}
|
|
21431
|
+
),
|
|
21432
|
+
/* @__PURE__ */ jsx76(Label3, { htmlFor: "sendOwnerEmail", className: "font-normal cursor-pointer text-sm", children: activationMode === "invite" ? "Send invite email to owner" : "Send welcome email to owner" })
|
|
21433
|
+
] }),
|
|
21434
|
+
activationMode === "password" && /* @__PURE__ */ jsxs63("div", { className: "space-y-3 pt-1", children: [
|
|
21435
|
+
/* @__PURE__ */ jsxs63("div", { children: [
|
|
21436
|
+
/* @__PURE__ */ jsx76(Label3, { htmlFor: "ownerPassword", className: "text-xs font-medium text-gray-600", children: "Password *" }),
|
|
21437
|
+
/* @__PURE__ */ jsx76(
|
|
21438
|
+
Input,
|
|
21439
|
+
{
|
|
21440
|
+
id: "ownerPassword",
|
|
21441
|
+
type: "password",
|
|
21442
|
+
required: true,
|
|
21443
|
+
autoComplete: "new-password",
|
|
21444
|
+
value: ownerPassword,
|
|
21445
|
+
onChange: (e) => setOwnerPassword(e.target.value),
|
|
21446
|
+
className: `mt-1 ${fieldClass}`
|
|
21447
|
+
}
|
|
21448
|
+
)
|
|
21449
|
+
] }),
|
|
21450
|
+
/* @__PURE__ */ jsxs63("div", { children: [
|
|
21451
|
+
/* @__PURE__ */ jsx76(Label3, { htmlFor: "ownerPasswordConfirm", className: "text-xs font-medium text-gray-600", children: "Confirm password *" }),
|
|
21452
|
+
/* @__PURE__ */ jsx76(
|
|
21453
|
+
Input,
|
|
21454
|
+
{
|
|
21455
|
+
id: "ownerPasswordConfirm",
|
|
21456
|
+
type: "password",
|
|
21457
|
+
required: true,
|
|
21458
|
+
autoComplete: "new-password",
|
|
21459
|
+
value: ownerPasswordConfirm,
|
|
21460
|
+
onChange: (e) => setOwnerPasswordConfirm(e.target.value),
|
|
21461
|
+
className: `mt-1 ${fieldClass}`
|
|
21462
|
+
}
|
|
21463
|
+
)
|
|
21464
|
+
] })
|
|
21465
|
+
] }),
|
|
21466
|
+
/* @__PURE__ */ jsx76(Button, { type: "button", disabled: loading, onClick: handleSubmit, className: "w-full", children: loading ? "Creating\u2026" : submitLabel })
|
|
20753
21467
|
] })
|
|
20754
21468
|
] })
|
|
20755
|
-
|
|
20756
|
-
|
|
20757
|
-
message && /* @__PURE__ */ jsx76("p", { className: "text-sm text-green-700", children: message }),
|
|
20758
|
-
inviteLink && /* @__PURE__ */ jsxs63("p", { className: "text-xs text-gray-600 break-all", children: [
|
|
20759
|
-
"Invite link: ",
|
|
20760
|
-
/* @__PURE__ */ jsx76("a", { href: inviteLink, className: "text-blue-600 underline", children: inviteLink })
|
|
20761
|
-
] }),
|
|
20762
|
-
/* @__PURE__ */ jsx76(Button, { type: "submit", disabled: loading, children: loading ? "Creating\u2026" : submitLabel })
|
|
20763
|
-
] })
|
|
21469
|
+
}
|
|
21470
|
+
)
|
|
20764
21471
|
] });
|
|
20765
21472
|
}
|
|
21473
|
+
function VendorOnboardPage({ showCreateForm }) {
|
|
21474
|
+
const router = useRouter18();
|
|
21475
|
+
const { data: session } = useSession9();
|
|
21476
|
+
const sessionUser = session?.user;
|
|
21477
|
+
const isAdmin = canOnboardVendors(session?.user);
|
|
21478
|
+
if (!isAdmin) {
|
|
21479
|
+
return /* @__PURE__ */ jsx76(AccessDenied, { groupName: sessionUser?.groupName });
|
|
21480
|
+
}
|
|
21481
|
+
if (showCreateForm) {
|
|
21482
|
+
return /* @__PURE__ */ jsx76(VendorOnboardForm, { onSuccess: () => router.push("/admin/vendor-onboard") });
|
|
21483
|
+
}
|
|
21484
|
+
return /* @__PURE__ */ jsx76(
|
|
21485
|
+
AdminCRUD,
|
|
21486
|
+
{
|
|
21487
|
+
title: "Vendors",
|
|
21488
|
+
apiEndpoint: "/api/vendors",
|
|
21489
|
+
columns: [...VENDOR_LIST_COLUMNS],
|
|
21490
|
+
addEditPageUrl: "/admin/vendor-onboard",
|
|
21491
|
+
defaultSortField: "createdAt",
|
|
21492
|
+
defaultSortOrder: "desc"
|
|
21493
|
+
}
|
|
21494
|
+
);
|
|
21495
|
+
}
|
|
20766
21496
|
|
|
20767
21497
|
// src/admin/pages/VendorTeamPage.tsx
|
|
20768
21498
|
init_button();
|
|
@@ -21280,9 +22010,9 @@ init_DetailPageLayout();
|
|
|
21280
22010
|
init_DetailPageHeader();
|
|
21281
22011
|
import { useEffect as useEffect42, useState as useState45 } from "react";
|
|
21282
22012
|
import Link14 from "next/link";
|
|
21283
|
-
import { useRouter as
|
|
22013
|
+
import { useRouter as useRouter19, useSearchParams as useSearchParams17 } from "next/navigation";
|
|
21284
22014
|
import { X as X21, Pencil as Pencil3, ChevronDown as ChevronDown7, ChevronRight as ChevronRight6, Zap as Zap2 } from "lucide-react";
|
|
21285
|
-
import { Fragment as
|
|
22015
|
+
import { Fragment as Fragment22, jsx as jsx78, jsxs as jsxs65 } from "react/jsx-runtime";
|
|
21286
22016
|
function statusBadge2(status) {
|
|
21287
22017
|
const map = {
|
|
21288
22018
|
ACTIVE: "bg-green-100 text-green-800",
|
|
@@ -21359,7 +22089,7 @@ function RuleTreeNode({ node, depth = 0 }) {
|
|
|
21359
22089
|
const borderColor = depth % 2 === 0 ? "border-blue-200" : "border-purple-200";
|
|
21360
22090
|
const bgColor = depth % 2 === 0 ? "bg-blue-50/30" : "bg-purple-50/30";
|
|
21361
22091
|
return /* @__PURE__ */ jsxs65("div", { className: `border rounded-lg p-3 ${borderColor} ${bgColor}`, children: [
|
|
21362
|
-
/* @__PURE__ */ jsx78("div", { className: "flex items-center gap-2 text-sm flex-wrap", children: isGroup ? /* @__PURE__ */ jsxs65(
|
|
22092
|
+
/* @__PURE__ */ jsx78("div", { className: "flex items-center gap-2 text-sm flex-wrap", children: isGroup ? /* @__PURE__ */ jsxs65(Fragment22, { children: [
|
|
21363
22093
|
/* @__PURE__ */ jsx78(
|
|
21364
22094
|
"button",
|
|
21365
22095
|
{
|
|
@@ -21371,17 +22101,17 @@ function RuleTreeNode({ node, depth = 0 }) {
|
|
|
21371
22101
|
),
|
|
21372
22102
|
/* @__PURE__ */ jsx78("span", { className: "font-semibold text-xs uppercase text-gray-500", children: "Group" }),
|
|
21373
22103
|
/* @__PURE__ */ jsx78("span", { className: "rounded bg-white border border-gray-200 px-2 py-0.5 text-xs font-mono font-semibold text-gray-700", children: (node.conditionOperator ?? "and").toUpperCase() })
|
|
21374
|
-
] }) : /* @__PURE__ */ jsxs65(
|
|
22104
|
+
] }) : /* @__PURE__ */ jsxs65(Fragment22, { children: [
|
|
21375
22105
|
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
22106
|
node.subType && /* @__PURE__ */ jsx78("span", { className: "text-gray-400 text-xs", children: node.subType }),
|
|
21377
22107
|
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) })
|
|
22108
|
+
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
22109
|
] }) }),
|
|
21380
22110
|
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
22111
|
] });
|
|
21382
22112
|
}
|
|
21383
22113
|
function DiscountDetailPage({ discountId }) {
|
|
21384
|
-
const router =
|
|
22114
|
+
const router = useRouter19();
|
|
21385
22115
|
const searchParams = useSearchParams17();
|
|
21386
22116
|
const listReturnUrl = safeAdminListReturnUrl(searchParams.get("from")) ?? "/admin/discounts";
|
|
21387
22117
|
const [discount, setDiscount] = useState45(null);
|
|
@@ -21466,7 +22196,7 @@ function DiscountDetailPage({ discountId }) {
|
|
|
21466
22196
|
/* @__PURE__ */ jsx78(
|
|
21467
22197
|
DetailPageLayout,
|
|
21468
22198
|
{
|
|
21469
|
-
main: /* @__PURE__ */ jsxs65(
|
|
22199
|
+
main: /* @__PURE__ */ jsxs65(Fragment22, { children: [
|
|
21470
22200
|
/* @__PURE__ */ jsxs65("section", { children: [
|
|
21471
22201
|
/* @__PURE__ */ jsx78("h2", { className: "text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2", children: "Discount details" }),
|
|
21472
22202
|
/* @__PURE__ */ jsxs65("div", { className: "border border-gray-200 rounded-lg p-4 bg-gray-50/50", children: [
|
|
@@ -21541,7 +22271,7 @@ function DiscountDetailPage({ discountId }) {
|
|
|
21541
22271
|
/* @__PURE__ */ jsx78("div", { className: "border border-gray-200 rounded-lg p-4 bg-gray-50/50 space-y-2", children: ruleTree.length === 0 ? /* @__PURE__ */ jsx78("p", { className: "text-sm text-gray-400", children: "No conditions \u2014 applies to all orders." }) : ruleTree.map((node) => /* @__PURE__ */ jsx78(RuleTreeNode, { node }, node.id)) })
|
|
21542
22272
|
] })
|
|
21543
22273
|
] }),
|
|
21544
|
-
sidebar: /* @__PURE__ */ jsxs65(
|
|
22274
|
+
sidebar: /* @__PURE__ */ jsxs65(Fragment22, { children: [
|
|
21545
22275
|
/* @__PURE__ */ jsxs65("section", { children: [
|
|
21546
22276
|
/* @__PURE__ */ jsx78("h2", { className: "text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2", children: "Usage" }),
|
|
21547
22277
|
/* @__PURE__ */ jsxs65("div", { className: "border border-gray-200 rounded-lg p-4 bg-gray-50/50 space-y-3 text-sm", children: [
|
|
@@ -21613,13 +22343,13 @@ init_admin_list_return_url();
|
|
|
21613
22343
|
init_DetailPageLayout();
|
|
21614
22344
|
init_DetailPageHeader();
|
|
21615
22345
|
import { useState as useState47, useEffect as useEffect44 } from "react";
|
|
21616
|
-
import { useRouter as
|
|
21617
|
-
import { AlertCircle as
|
|
22346
|
+
import { useRouter as useRouter20, useSearchParams as useSearchParams18 } from "next/navigation";
|
|
22347
|
+
import { AlertCircle as AlertCircle10, Save as Save12, Zap as Zap3 } from "lucide-react";
|
|
21618
22348
|
|
|
21619
22349
|
// src/admin/pages/DiscountsConditionsBuilder.tsx
|
|
21620
22350
|
init_button();
|
|
21621
22351
|
import { useState as useState46, useEffect as useEffect43 } from "react";
|
|
21622
|
-
import { Plus as Plus13, Trash2 as
|
|
22352
|
+
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
22353
|
import { jsx as jsx79, jsxs as jsxs66 } from "react/jsx-runtime";
|
|
21624
22354
|
function uid() {
|
|
21625
22355
|
return Math.random().toString(36).slice(2, 10);
|
|
@@ -21635,10 +22365,10 @@ function conditionToRule(c) {
|
|
|
21635
22365
|
return { ...base, type: "minAmount", comparisonOperator: "gte", value: { v: c.amount ?? "0" } };
|
|
21636
22366
|
case "minQuantity":
|
|
21637
22367
|
return { ...base, type: "quantity", comparisonOperator: "gte", value: { v: c.quantity ?? "1" } };
|
|
21638
|
-
case "
|
|
21639
|
-
return { ...base, type: "
|
|
22368
|
+
case "productMinQuantity":
|
|
22369
|
+
return { ...base, type: "quantity", subType: "productId", comparisonOperator: "gte", value: { v: c.quantity ?? "1", productId: String(c.productId ?? "") } };
|
|
21640
22370
|
case "nthOrder":
|
|
21641
|
-
return { ...base, type: "order", subType: "nthOrder", comparisonOperator: "
|
|
22371
|
+
return { ...base, type: "order", subType: "nthOrder", comparisonOperator: "eq", value: { v: c.nthOrder ?? "1" } };
|
|
21642
22372
|
case "userType":
|
|
21643
22373
|
return { ...base, type: "user", subType: "userType", comparisonOperator: "eq", value: { v: c.userType ?? "" } };
|
|
21644
22374
|
case "paymentMethod":
|
|
@@ -21704,9 +22434,16 @@ function ruleTreeToFriendly(rules) {
|
|
|
21704
22434
|
case "minAmount":
|
|
21705
22435
|
return { id: rule._clientId ?? uid(), kind: "minAmount", amount: v };
|
|
21706
22436
|
case "quantity":
|
|
22437
|
+
if (rule.subType === "productId") {
|
|
22438
|
+
return {
|
|
22439
|
+
id: rule._clientId ?? uid(),
|
|
22440
|
+
kind: "productMinQuantity",
|
|
22441
|
+
quantity: v,
|
|
22442
|
+
productId: Number(rule.value?.productId) || null,
|
|
22443
|
+
productName: void 0
|
|
22444
|
+
};
|
|
22445
|
+
}
|
|
21707
22446
|
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
22447
|
case "order":
|
|
21711
22448
|
return { id: rule._clientId ?? uid(), kind: "nthOrder", nthOrder: v };
|
|
21712
22449
|
case "user":
|
|
@@ -22030,7 +22767,7 @@ function ConditionCard({
|
|
|
22030
22767
|
const iconMap = {
|
|
22031
22768
|
minAmount: /* @__PURE__ */ jsx79(DollarSign, { className: "h-3.5 w-3.5 text-blue-500" }),
|
|
22032
22769
|
minQuantity: /* @__PURE__ */ jsx79(Hash, { className: "h-3.5 w-3.5 text-purple-500" }),
|
|
22033
|
-
|
|
22770
|
+
productMinQuantity: /* @__PURE__ */ jsx79(Hash, { className: "h-3.5 w-3.5 text-green-600" }),
|
|
22034
22771
|
nthOrder: /* @__PURE__ */ jsx79(ShoppingCart5, { className: "h-3.5 w-3.5 text-orange-500" }),
|
|
22035
22772
|
userType: /* @__PURE__ */ jsx79(User3, { className: "h-3.5 w-3.5 text-pink-500" }),
|
|
22036
22773
|
paymentMethod: /* @__PURE__ */ jsx79(DollarSign, { className: "h-3.5 w-3.5 text-indigo-500" }),
|
|
@@ -22052,7 +22789,7 @@ function ConditionCard({
|
|
|
22052
22789
|
/* @__PURE__ */ jsxs66(SelectContent, { children: [
|
|
22053
22790
|
/* @__PURE__ */ jsx79(SelectItem, { value: "minAmount", children: "Minimum order amount" }),
|
|
22054
22791
|
/* @__PURE__ */ jsx79(SelectItem, { value: "minQuantity", children: "Minimum quantity" }),
|
|
22055
|
-
/* @__PURE__ */ jsx79(SelectItem, { value: "
|
|
22792
|
+
/* @__PURE__ */ jsx79(SelectItem, { value: "productMinQuantity", children: "Product" }),
|
|
22056
22793
|
/* @__PURE__ */ jsx79(SelectItem, { value: "nthOrder", children: "Customer's Nth order" }),
|
|
22057
22794
|
/* @__PURE__ */ jsx79(SelectItem, { value: "userType", children: "User type" }),
|
|
22058
22795
|
/* @__PURE__ */ jsx79(SelectItem, { value: "paymentMethod", children: "Payment method" }),
|
|
@@ -22072,9 +22809,33 @@ function ConditionCard({
|
|
|
22072
22809
|
/* @__PURE__ */ jsx79("span", { className: "text-xs text-gray-500 shrink-0", children: "Qty \u2265" }),
|
|
22073
22810
|
/* @__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
22811
|
] }),
|
|
22075
|
-
condition.kind === "
|
|
22812
|
+
condition.kind === "productMinQuantity" && /* @__PURE__ */ jsxs66("div", { className: "space-y-2", children: [
|
|
22813
|
+
/* @__PURE__ */ jsx79(
|
|
22814
|
+
ProductPicker,
|
|
22815
|
+
{
|
|
22816
|
+
value: condition.productId,
|
|
22817
|
+
label: condition.productName,
|
|
22818
|
+
onChange: (id, name) => onChange({ ...condition, productId: id, productName: name })
|
|
22819
|
+
}
|
|
22820
|
+
),
|
|
22821
|
+
/* @__PURE__ */ jsxs66("div", { className: "flex items-center gap-2", children: [
|
|
22822
|
+
/* @__PURE__ */ jsx79("span", { className: "text-xs text-gray-500 shrink-0", children: "Minimum quantity of this product" }),
|
|
22823
|
+
/* @__PURE__ */ jsx79(
|
|
22824
|
+
"input",
|
|
22825
|
+
{
|
|
22826
|
+
type: "number",
|
|
22827
|
+
min: 1,
|
|
22828
|
+
step: "1",
|
|
22829
|
+
value: condition.quantity ?? "",
|
|
22830
|
+
onChange: (e) => onChange({ ...condition, quantity: e.target.value }),
|
|
22831
|
+
className: inputCls3,
|
|
22832
|
+
placeholder: "2"
|
|
22833
|
+
}
|
|
22834
|
+
)
|
|
22835
|
+
] })
|
|
22836
|
+
] }),
|
|
22076
22837
|
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
|
|
22838
|
+
/* @__PURE__ */ jsx79("span", { className: "text-xs text-gray-500 shrink-0", children: "Order number =" }),
|
|
22078
22839
|
/* @__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
22840
|
/* @__PURE__ */ jsx79("span", { className: "text-xs text-gray-400 shrink-0", children: "(e.g. 2 = 2nd+ order)" })
|
|
22080
22841
|
] }),
|
|
@@ -22102,7 +22863,7 @@ function ConditionCard({
|
|
|
22102
22863
|
condition.kind === "shipping" && /* @__PURE__ */ jsx79("p", { className: "text-xs text-gray-400 italic", children: "Applied when any shipping method is selected." }),
|
|
22103
22864
|
condition.kind === "referral" && /* @__PURE__ */ jsx79("p", { className: "text-xs text-gray-400 italic", children: "Applied when order comes from a referral." })
|
|
22104
22865
|
] }),
|
|
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(
|
|
22866
|
+
/* @__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
22867
|
] });
|
|
22107
22868
|
}
|
|
22108
22869
|
function RewardCard({
|
|
@@ -22127,7 +22888,7 @@ function RewardCard({
|
|
|
22127
22888
|
] }),
|
|
22128
22889
|
/* @__PURE__ */ jsx79("p", { className: "text-[11px] text-purple-600", children: "This product will be automatically added to cart when the discount is applied." })
|
|
22129
22890
|
] }),
|
|
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(
|
|
22891
|
+
/* @__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
22892
|
] });
|
|
22132
22893
|
}
|
|
22133
22894
|
function DiscountConditionsBuilder({
|
|
@@ -22144,7 +22905,7 @@ function DiscountConditionsBuilder({
|
|
|
22144
22905
|
const missingNameIds = [];
|
|
22145
22906
|
for (const g of groups) {
|
|
22146
22907
|
for (const c of g.conditions) {
|
|
22147
|
-
if (c.kind === "
|
|
22908
|
+
if (c.kind === "productMinQuantity" && c.productId && !c.productName)
|
|
22148
22909
|
missingNameIds.push({ type: "product", id: c.id, entityId: c.productId, groupId: g.id });
|
|
22149
22910
|
if (c.kind === "category" && c.categoryId && !c.categoryName)
|
|
22150
22911
|
missingNameIds.push({ type: "category", id: c.id, entityId: c.categoryId, groupId: g.id });
|
|
@@ -22284,7 +23045,7 @@ function DiscountConditionsBuilder({
|
|
|
22284
23045
|
type: "button",
|
|
22285
23046
|
onClick: () => removeGroup(group.id),
|
|
22286
23047
|
className: "text-gray-300 hover:text-red-500 transition-colors",
|
|
22287
|
-
children: /* @__PURE__ */ jsx79(
|
|
23048
|
+
children: /* @__PURE__ */ jsx79(Trash213, { className: "h-3.5 w-3.5" })
|
|
22288
23049
|
}
|
|
22289
23050
|
)
|
|
22290
23051
|
] }),
|
|
@@ -22373,7 +23134,7 @@ function DiscountConditionsBuilder({
|
|
|
22373
23134
|
}
|
|
22374
23135
|
|
|
22375
23136
|
// src/admin/pages/DiscountEditPage.tsx
|
|
22376
|
-
import { Fragment as
|
|
23137
|
+
import { Fragment as Fragment23, jsx as jsx80, jsxs as jsxs67 } from "react/jsx-runtime";
|
|
22377
23138
|
function uid2() {
|
|
22378
23139
|
return Math.random().toString(36).slice(2, 10);
|
|
22379
23140
|
}
|
|
@@ -22441,7 +23202,7 @@ function useConvertedValue2(value, fromCurrency, toCurrency, discountType) {
|
|
|
22441
23202
|
var inputCls4 = "w-full rounded-md border border-gray-300 px-3 py-1.5 text-sm focus:outline-none focus:ring-1 focus:ring-gray-400";
|
|
22442
23203
|
var isCreate4 = (id) => id === "create";
|
|
22443
23204
|
function DiscountEditPage({ discountId }) {
|
|
22444
|
-
const router =
|
|
23205
|
+
const router = useRouter20();
|
|
22445
23206
|
const searchParams = useSearchParams18();
|
|
22446
23207
|
const listReturnUrl = safeAdminListReturnUrl(searchParams.get("from")) ?? "/admin/discounts";
|
|
22447
23208
|
const create = isCreate4(discountId);
|
|
@@ -22603,12 +23364,12 @@ function DiscountEditPage({ discountId }) {
|
|
|
22603
23364
|
subtitle: create ? "Create a new discount coupon" : `Editing: ${couponCode || discountId}`,
|
|
22604
23365
|
closeHref: listReturnUrl,
|
|
22605
23366
|
menuItems: [
|
|
22606
|
-
{ label: saving ? "Saving..." : "Save", icon:
|
|
23367
|
+
{ label: saving ? "Saving..." : "Save", icon: Save12, onClick: handleSave }
|
|
22607
23368
|
]
|
|
22608
23369
|
}
|
|
22609
23370
|
),
|
|
22610
23371
|
errors.length > 0 && /* @__PURE__ */ jsx80("div", { className: "bg-red-50 border-l-4 border-red-400 p-4 mx-6 mt-4", children: /* @__PURE__ */ jsxs67("div", { className: "flex", children: [
|
|
22611
|
-
/* @__PURE__ */ jsx80(
|
|
23372
|
+
/* @__PURE__ */ jsx80(AlertCircle10, { className: "h-5 w-5 text-red-400 flex-shrink-0" }),
|
|
22612
23373
|
/* @__PURE__ */ jsxs67("div", { className: "ml-3", children: [
|
|
22613
23374
|
/* @__PURE__ */ jsx80("h3", { className: "text-sm font-medium text-red-800", children: "Please fix the following errors:" }),
|
|
22614
23375
|
/* @__PURE__ */ jsx80("ul", { className: "mt-2 text-sm text-red-700 list-disc pl-5 space-y-1", children: errors.map((e, i) => /* @__PURE__ */ jsx80("li", { children: e }, i)) })
|
|
@@ -22617,7 +23378,7 @@ function DiscountEditPage({ discountId }) {
|
|
|
22617
23378
|
/* @__PURE__ */ jsx80(
|
|
22618
23379
|
DetailPageLayout,
|
|
22619
23380
|
{
|
|
22620
|
-
main: /* @__PURE__ */ jsxs67(
|
|
23381
|
+
main: /* @__PURE__ */ jsxs67(Fragment23, { children: [
|
|
22621
23382
|
/* @__PURE__ */ jsxs67("section", { children: [
|
|
22622
23383
|
/* @__PURE__ */ jsx80("h2", { className: "text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2", children: "Basic info" }),
|
|
22623
23384
|
/* @__PURE__ */ jsxs67("div", { className: "border border-gray-200 rounded-lg p-4 bg-gray-50/50 space-y-4", children: [
|
|
@@ -22845,7 +23606,7 @@ function DiscountEditPage({ discountId }) {
|
|
|
22845
23606
|
) })
|
|
22846
23607
|
] })
|
|
22847
23608
|
] }),
|
|
22848
|
-
sidebar: /* @__PURE__ */ jsxs67(
|
|
23609
|
+
sidebar: /* @__PURE__ */ jsxs67(Fragment23, { children: [
|
|
22849
23610
|
/* @__PURE__ */ jsxs67("section", { children: [
|
|
22850
23611
|
/* @__PURE__ */ jsx80("h2", { className: "text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2", children: "Status" }),
|
|
22851
23612
|
/* @__PURE__ */ jsxs67("div", { className: "border border-gray-200 rounded-lg p-4 bg-gray-50/50 space-y-3", children: [
|
|
@@ -22882,7 +23643,7 @@ function DiscountEditPage({ discountId }) {
|
|
|
22882
23643
|
value && !isNaN(Number(value)) && /* @__PURE__ */ jsxs67("section", { children: [
|
|
22883
23644
|
/* @__PURE__ */ jsx80("h2", { className: "text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2", children: "Preview" }),
|
|
22884
23645
|
/* @__PURE__ */ jsxs67("div", { className: "border border-gray-200 rounded-lg p-4 bg-gray-50/50 space-y-1 text-sm", children: [
|
|
22885
|
-
!isAutomatic && /* @__PURE__ */ jsxs67(
|
|
23646
|
+
!isAutomatic && /* @__PURE__ */ jsxs67(Fragment23, { children: [
|
|
22886
23647
|
/* @__PURE__ */ jsx80("p", { className: "text-gray-500", children: "Code" }),
|
|
22887
23648
|
/* @__PURE__ */ jsx80("p", { className: "font-mono font-semibold text-gray-900", children: couponCode || "\u2014" })
|
|
22888
23649
|
] }),
|
|
@@ -22923,7 +23684,6 @@ var PAGE_MAP = {
|
|
|
22923
23684
|
roles: RolesPage,
|
|
22924
23685
|
"blog-generator": BlogGeneratorPage,
|
|
22925
23686
|
schedules: SchedulesPage,
|
|
22926
|
-
"vendor-onboard": VendorOnboardPage,
|
|
22927
23687
|
"vendor-team": VendorTeamPage
|
|
22928
23688
|
};
|
|
22929
23689
|
var CRUD_CONFIGS = {
|
|
@@ -23079,7 +23839,7 @@ function BlogEditorWrapper({
|
|
|
23079
23839
|
);
|
|
23080
23840
|
}
|
|
23081
23841
|
function AdminPageResolver({ slug }) {
|
|
23082
|
-
const router =
|
|
23842
|
+
const router = useRouter22();
|
|
23083
23843
|
const searchParams = useSearchParams20();
|
|
23084
23844
|
const { customCrudConfigs, storeEnabled } = useContext9(AdminConfigContext);
|
|
23085
23845
|
const key = slug?.[0] || "dashboard";
|
|
@@ -23123,6 +23883,10 @@ function AdminPageResolver({ slug }) {
|
|
|
23123
23883
|
/* @__PURE__ */ jsx83("span", { className: "ml-2", children: "Opening Plugins\u2026" })
|
|
23124
23884
|
] });
|
|
23125
23885
|
}
|
|
23886
|
+
if (key === "vendor-onboard") {
|
|
23887
|
+
const sub = slug?.[1];
|
|
23888
|
+
return /* @__PURE__ */ jsx83(VendorOnboardPage, { showCreateForm: sub === "create" });
|
|
23889
|
+
}
|
|
23126
23890
|
const Page = PAGE_MAP[key];
|
|
23127
23891
|
if (Page) {
|
|
23128
23892
|
return /* @__PURE__ */ jsx83(Page, {});
|
|
@@ -23213,7 +23977,7 @@ function AdminPageResolver({ slug }) {
|
|
|
23213
23977
|
// src/admin/pages/LayoutSettingsPage.tsx
|
|
23214
23978
|
init_button();
|
|
23215
23979
|
import { useState as useState51, useEffect as useEffect48, useContext as useContext10 } from "react";
|
|
23216
|
-
import { Save as
|
|
23980
|
+
import { Save as Save13 } from "lucide-react";
|
|
23217
23981
|
import { jsx as jsx84, jsxs as jsxs71 } from "react/jsx-runtime";
|
|
23218
23982
|
function LayoutSettingsPage() {
|
|
23219
23983
|
const { theme } = useContext10(AdminConfigContext);
|
|
@@ -23285,7 +24049,7 @@ function LayoutSettingsPage() {
|
|
|
23285
24049
|
disabled: saving,
|
|
23286
24050
|
className: "bg-white text-gray-800 hover:bg-gray-100 border-0 text-xs",
|
|
23287
24051
|
children: [
|
|
23288
|
-
/* @__PURE__ */ jsx84(
|
|
24052
|
+
/* @__PURE__ */ jsx84(Save13, { className: "h-4 w-4 mr-2" }),
|
|
23289
24053
|
saving ? "Saving..." : "Save"
|
|
23290
24054
|
]
|
|
23291
24055
|
}
|