@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.
Files changed (41) hide show
  1. package/README.md +12 -8
  2. package/dist/admin.cjs +1907 -1144
  3. package/dist/admin.cjs.map +1 -1
  4. package/dist/admin.d.cts +7 -2
  5. package/dist/admin.d.ts +7 -2
  6. package/dist/admin.js +1955 -1191
  7. package/dist/admin.js.map +1 -1
  8. package/dist/api.cjs +2704 -914
  9. package/dist/api.cjs.map +1 -1
  10. package/dist/api.d.cts +1 -1
  11. package/dist/api.d.ts +1 -1
  12. package/dist/api.js +2664 -875
  13. package/dist/api.js.map +1 -1
  14. package/dist/auth.cjs +251 -23
  15. package/dist/auth.cjs.map +1 -1
  16. package/dist/auth.d.cts +53 -22
  17. package/dist/auth.d.ts +53 -22
  18. package/dist/auth.js +240 -23
  19. package/dist/auth.js.map +1 -1
  20. package/dist/cli.cjs +42 -2
  21. package/dist/cli.cjs.map +1 -1
  22. package/dist/cli.js +42 -2
  23. package/dist/cli.js.map +1 -1
  24. package/dist/{index-BcMRGNjS.d.cts → index-Bf5GO8fu.d.cts} +4 -3
  25. package/dist/{index-Bda8D1Rm.d.ts → index-DOiJuMQA.d.ts} +4 -3
  26. package/dist/index.cjs +3408 -1284
  27. package/dist/index.cjs.map +1 -1
  28. package/dist/index.d.cts +121 -35
  29. package/dist/index.d.ts +121 -35
  30. package/dist/index.js +3334 -1226
  31. package/dist/index.js.map +1 -1
  32. package/dist/migrations/1778660000003-AddQrTokenToOrders.ts +32 -0
  33. package/dist/migrations/1778660000004-CreateCustomerAndCustomerContacts.ts +99 -0
  34. package/dist/migrations/1778660000005-AddCustomerIdToVendorCustomers.ts +39 -0
  35. package/dist/migrations/1778660000006-UpdateVendorCustomersContactNullable.ts +36 -0
  36. package/dist/migrations/1778660000007-VendorOwnerCustomerContactsPermission.ts +39 -0
  37. package/dist/migrations/1779100000000-ChatConversationLeadEmailSent.ts +16 -0
  38. package/dist/migrations/1779200000000-LlmAgentScope.ts +72 -0
  39. package/dist/migrations/1779300000000-VendorOwnerContactsPermission.ts +39 -0
  40. package/dist/migrations/1779400000000-AddCustomerContactIdToOrders.ts +33 -0
  41. 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 !!(user.isRBACAdmin || isSuperAdminGroupName(user.groupName));
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.vendorIds?.length ?? 0) > 0) return true;
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
- init_permission_entities();
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 Fragment9, jsx as jsx49, jsxs as jsxs39 } from "react/jsx-runtime";
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(Fragment9, { children: [
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 useRouter20, useSearchParams as useSearchParams19 } from "next/navigation";
778
- import { Plus as Plus15, Trash2 as Trash214, X as X22 } from "lucide-react";
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 Fragment23, jsx as jsx82, jsxs as jsxs69 } from "react/jsx-runtime";
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 = useRouter20();
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(Fragment23, { children: [
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(Fragment23, { children: [
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(Trash214, { className: "h-4 w-4" })
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(Fragment23, { children: [
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.31" : "0.0.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
- "Onboard vendor"
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
- "Content-Type": "application/json"
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
- ...prev,
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
- throw new Error("Failed to save data");
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
- "form",
2987
- {
2988
- onSubmit: handleSubmit,
2989
- className: "flex flex-col flex-1 min-h-0",
2990
- children: [
2991
- /* @__PURE__ */ jsx17("div", { className: "flex-1 min-h-0 overflow-y-auto p-6 space-y-4", children: visibleColumns.map((col) => {
2992
- const path = col.field || col.key;
2993
- if (!path) return null;
2994
- const disabled = isFieldDisabled(path);
2995
- const optionSet = col.type === "select" && Array.isArray(col.options) ? new Set(
2996
- col.options.map(
2997
- (o) => String(o.value)
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" && /* @__PURE__ */ jsxs11("div", { children: [
3166
- /* @__PURE__ */ jsx17(Label3, { className: "block text-sm font-medium mb-1", children: "Name" }),
3167
- /* @__PURE__ */ jsx17(
3168
- Input,
3169
- {
3170
- type: "text",
3171
- placeholder: "Customer name",
3172
- value: formData["contact.name"] ?? "",
3173
- onChange: (e) => setFormData(
3174
- (prev) => ({
3175
- ...prev,
3176
- "contact.name": e.target.value
3177
- })
3178
- )
3179
- }
3180
- )
3181
- ] })
3182
- ] }, path);
3183
- }) }),
3184
- /* @__PURE__ */ jsxs11("div", { className: "flex gap-2 p-4 border-t border-gray-200 shrink-0 bg-white", children: [
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
- Button,
3180
+ Input,
3187
3181
  {
3188
- type: "submit",
3189
- className: "flex-1",
3190
- children: "Save"
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
- Button,
3193
+ Input,
3195
3194
  {
3196
- type: "button",
3197
- variant: "outline",
3198
- onClick: onClose,
3199
- className: "flex-1",
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 Fragment3, jsx as jsx22, jsxs as jsxs15 } from "react/jsx-runtime";
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(Fragment3, { children: [
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 Fragment4, jsx as jsx23, jsxs as jsxs16 } from "react/jsx-runtime";
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(Fragment4, { children: /* @__PURE__ */ jsxs16("div", { className: "rounded-lg bg-white shadow-md min-w-0", children: [
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 Fragment5, jsx as jsx29, jsxs as jsxs20 } from "react/jsx-runtime";
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(Fragment5, { children: [
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 Fragment6, jsx as jsx31, jsxs as jsxs21 } from "react/jsx-runtime";
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(Fragment6, { children: [
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 Fragment7, jsx as jsx41, jsxs as jsxs31 } from "react/jsx-runtime";
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(Fragment7, { children: [
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(Fragment7, { children: [
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(Fragment7, { children: [
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(Fragment7, { children: [
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 Fragment8, jsx as jsx48, jsxs as jsxs38 } from "react/jsx-runtime";
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(Fragment8, { children: [
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(Fragment8, { children: [
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(Fragment8, { children: [
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 useRouter21, useSearchParams as useSearchParams20 } from "next/navigation";
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 { Fragment as Fragment10, jsx as jsx52, jsxs as jsxs42 } from "react/jsx-runtime";
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(Fragment10, { children: [
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(Fragment10, { children: [
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(Fragment10, { children: [
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 [couponInput, setCouponInput] = useState28("");
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.contactId ?? row.contact?.id);
11177
+ const id = Number(row.id);
11168
11178
  if (!Number.isFinite(id)) return null;
11169
- return {
11170
- id,
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
- (prev) => prev.map((l) => {
11297
- if (!rewardPids.has(l.productId)) return l;
11298
- const rewardLine = coupon.rewardLines.find((r) => r.productId === l.productId);
11299
- if (!rewardLine) return l;
11300
- const newQty = l.quantity - rewardLine.quantity;
11301
- return newQty > 0 ? { ...l, quantity: newQty } : null;
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 rewardKeyPrefix = `reward-`;
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 email = contactEmail.trim();
11531
- if (contactId == null && !email) {
11532
- toast5.error("Select a customer or enter an email address");
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": contactName.trim() || email.split("@")[0] || "Customer",
11550
- "contact.email": email || (contactId != null ? customers.find((c) => c.id === contactId)?.email : "") || "",
11551
- "contact.phone": contactPhone.trim() || null,
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 (contactId != null) payload.contactId = contactId;
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 (editOrderId && contactId != null) {
11578
- const cr = await fetch(`/api/contacts/${contactId}`, {
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__ */ jsxs44("div", { className: "space-y-4 sm:col-span-2 border rounded-lg p-4", children: [
11659
- /* @__PURE__ */ jsx55("h3", { className: "text-sm font-semibold", children: "Billing Address" }),
11660
- /* @__PURE__ */ jsxs44("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-3", children: [
11661
- /* @__PURE__ */ jsxs44("div", { className: "space-y-2 md:col-span-2", children: [
11662
- /* @__PURE__ */ jsx55(Label3, { children: "Address Line 1" }),
11663
- /* @__PURE__ */ jsx55(Input, { value: billingAddress.line1, onChange: (e) => updateAddress("billing", "line1", e.target.value), placeholder: "Street Address" })
11664
- ] }),
11665
- /* @__PURE__ */ jsxs44("div", { className: "space-y-2 md:col-span-2", children: [
11666
- /* @__PURE__ */ jsx55(Label3, { children: "Address Line 2" }),
11667
- /* @__PURE__ */ jsx55(Input, { value: billingAddress.line2, onChange: (e) => updateAddress("billing", "line2", e.target.value), placeholder: "Apartment, Suite, floor, etc." })
11668
- ] }),
11669
- /* @__PURE__ */ jsxs44("div", { className: "space-y-2", children: [
11670
- /* @__PURE__ */ jsx55(Label3, { children: "City" }),
11671
- /* @__PURE__ */ jsx55(Input, { value: billingAddress.city, onChange: (e) => updateAddress("billing", "city", e.target.value), placeholder: "City" })
11672
- ] }),
11673
- /* @__PURE__ */ jsxs44("div", { className: "space-y-2", children: [
11674
- /* @__PURE__ */ jsx55(Label3, { children: "State" }),
11675
- /* @__PURE__ */ jsx55(Input, { value: billingAddress.state, onChange: (e) => updateAddress("billing", "state", e.target.value), placeholder: "State" })
11676
- ] }),
11677
- /* @__PURE__ */ jsxs44("div", { className: "space-y-2", children: [
11678
- /* @__PURE__ */ jsx55(Label3, { children: "Country" }),
11679
- /* @__PURE__ */ jsx55(Input, { value: billingAddress.country, onChange: (e) => updateAddress("billing", "country", e.target.value), placeholder: "Country" })
11680
- ] }),
11681
- /* @__PURE__ */ jsxs44("div", { className: "space-y-2", children: [
11682
- /* @__PURE__ */ jsx55(Label3, { children: "Postal Code" }),
11683
- /* @__PURE__ */ jsx55(Input, { value: billingAddress.postalCode, onChange: (e) => updateAddress("billing", "postalCode", e.target.value), placeholder: "Postal Code" })
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: "space-y-4 sm:col-span-2 border rounded-lg p-4", children: [
11688
- /* @__PURE__ */ jsxs44("div", { className: "flex items-center justify-between", children: [
11689
- /* @__PURE__ */ jsx55("h3", { className: "text-sm font-semibold", children: "Shipping Address" }),
11690
- /* @__PURE__ */ jsxs44("div", { className: "flex items-center gap-2", children: [
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
- !sameAsBilling && /* @__PURE__ */ jsxs44("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-3", children: [
11696
- /* @__PURE__ */ jsxs44("div", { className: "space-y-2 md:col-span-2", children: [
11697
- /* @__PURE__ */ jsx55(Label3, { children: "Address Line 1" }),
11698
- /* @__PURE__ */ jsx55(Input, { value: shippingAddress.line1, onChange: (e) => updateAddress("shipping", "line1", e.target.value), placeholder: "Street Address" })
11699
- ] }),
11700
- /* @__PURE__ */ jsxs44("div", { className: "space-y-2 md:col-span-2", children: [
11701
- /* @__PURE__ */ jsx55(Label3, { children: "Address Line 2" }),
11702
- /* @__PURE__ */ jsx55(Input, { value: shippingAddress.line2, onChange: (e) => updateAddress("shipping", "line2", e.target.value), placeholder: "Apartment, Suite, Floor, etc." })
11703
- ] }),
11704
- /* @__PURE__ */ jsxs44("div", { className: "space-y-2 md:col-span-2", children: [
11705
- /* @__PURE__ */ jsx55(Label3, { children: "City" }),
11706
- /* @__PURE__ */ jsx55(Input, { value: shippingAddress.city, onChange: (e) => updateAddress("shipping", "city", e.target.value), placeholder: "City" })
11707
- ] }),
11708
- /* @__PURE__ */ jsxs44("div", { className: "space-y-2 md:col-span-2", children: [
11709
- /* @__PURE__ */ jsx55(Label3, { children: "State" }),
11710
- /* @__PURE__ */ jsx55(Input, { value: shippingAddress.state, onChange: (e) => updateAddress("shipping", "state", e.target.value), placeholder: "State" })
11711
- ] }),
11712
- /* @__PURE__ */ jsxs44("div", { className: "space-y-2 md:col-span-2", children: [
11713
- /* @__PURE__ */ jsx55(Label3, { children: "Country" }),
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
- TableRow,
11819
- {
11820
- className: active ? "bg-blue-50/80 cursor-pointer" : "cursor-pointer",
11821
- onClick: () => setSelectedKey(line.key),
11822
- children: [
11823
- /* @__PURE__ */ jsxs44(TableCell, { className: "align-top min-w-0", children: [
11824
- /* @__PURE__ */ jsx55("p", { className: "font-medium text-gray-900 break-words", children: line.label }),
11825
- /* @__PURE__ */ jsx55("p", { className: "text-xs text-gray-500 font-mono", children: line.sku ?? "\u2014" }),
11826
- isReward && /* @__PURE__ */ jsx55("span", { className: "text-[10px] text-purple-600 font-medium", children: "\u{1F381} Reward" })
11827
- ] }),
11828
- /* @__PURE__ */ jsx55(TableCell, { className: "align-top text-right", children: /* @__PURE__ */ jsx55(
11829
- Input,
11830
- {
11831
- type: "number",
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 Fragment11, jsx as jsx57, jsxs as jsxs46 } from "react/jsx-runtime";
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(Fragment11, { children: [
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(Fragment11, { children: customer && /* @__PURE__ */ jsxs46("section", { children: [
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 Fragment12, jsx as jsx58, jsxs as jsxs47 } from "react/jsx-runtime";
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(Fragment12, { children: [
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(Fragment12, { children: [
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 Fragment13, jsx as jsx60, jsxs as jsxs49 } from "react/jsx-runtime";
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(Fragment13, { children: [
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(Fragment13, { children: [
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(Fragment13, { children: [
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 Fragment14, jsx as jsx61, jsxs as jsxs50 } from "react/jsx-runtime";
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(Fragment14, { children: [
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 Fragment15, jsx as jsx65, jsxs as jsxs54 } from "react/jsx-runtime";
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(Fragment15, { children: [
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
- import { Fragment as Fragment16, jsx as jsx66, jsxs as jsxs55 } from "react/jsx-runtime";
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("/api/llm_agents?limit=100&sortField=name&sortOrder=asc");
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 list = (j.data ?? []).map((r) => ({
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 = (j.data ?? []).find((r) => r.id === pick?.id);
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
- setAgentValidationJson(String(fullRow.validationRules ?? ""));
16684
- setAttachedAgentSlug(pick.slug);
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("/api/llm_agents?limit=100&sortField=name&sortOrder=asc");
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
- if (listJ.data?.length) {
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() || "Assistant";
16746
- const defaultSlug = slugifyAgentKey(defaultName);
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({ name: defaultName, slug: defaultSlug, systemInstruction: "", enabled: true })
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 = slugifyAgentKey(name);
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 = { value: attachedAgentSlug.trim(), type: "public" };
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 handleSaveAgent = async () => {
16947
- if (!agentId) {
16948
- toast10.error("No agent to save");
16949
- return;
16950
- }
16951
- const name = agentName.trim();
16952
- if (!name) {
16953
- toast10.error("Agent name is required");
16954
- return;
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
- setAgentSaving(true);
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 res = await fetch(`/api/llm_agents/${agentId}`, {
16971
- method: "PUT",
16972
- headers: { "Content-Type": "application/json" },
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
- setAttachedAgentSlug(agentSlug);
16989
- toast10.success("Agent saved");
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 update agent");
17416
+ toast10.error("Failed to save");
16992
17417
  } finally {
16993
- setAgentSaving(false);
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 res = await fetch(`/api/settings/${settingsGroup}`, {
17000
- method: "PUT",
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(Fragment16, { children: [
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(Fragment16, { children: [
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(Fragment16, { children: [
17926
- /* @__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-3", children: [
17927
- /* @__PURE__ */ jsxs55("div", { className: "space-y-1", children: [
17928
- /* @__PURE__ */ jsxs55("div", { className: "flex items-center gap-2 text-sm font-medium text-gray-900 dark:text-white", children: [
17929
- /* @__PURE__ */ jsx66(Bot, { className: "h-4 w-4" }),
17930
- "Chat assistant (single agent)"
17931
- ] }),
17932
- /* @__PURE__ */ jsx66("p", { className: "text-[11px] text-gray-500 dark:text-gray-400", children: "Configure one assistant for this site here. After it exists, attach knowledge files in the section below." })
17933
- ] }),
17934
- agentLoading ? /* @__PURE__ */ jsxs55("div", { className: "flex items-center gap-2 text-sm text-gray-500", children: [
17935
- /* @__PURE__ */ jsx66(Loader25, { className: "h-4 w-4 animate-spin" }),
17936
- "Loading assistant\u2026"
17937
- ] }) : /* @__PURE__ */ jsxs55(Fragment16, { children: [
17938
- 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,
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: "agent-name", className: "text-sm", children: "Assistant name" }),
18438
+ /* @__PURE__ */ jsx66(Label3, { htmlFor: `${settingsGroup}-botName`, className: "text-sm", children: "Widget title" }),
17941
18439
  /* @__PURE__ */ jsx66(
17942
18440
  Input,
17943
18441
  {
17944
- id: "agent-name",
17945
- value: agentName,
17946
- onChange: (e) => setAgentName(e.target.value),
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: "agent-slug", className: "text-sm", children: "Slug" }),
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: "agent-slug",
17958
- value: agentId ? agentSlug : slugifyAgentKey((agentName || botName).trim() || "assistant"),
17959
- disabled: true,
17960
- className: "h-8 text-sm font-mono bg-gray-100 dark:bg-gray-700"
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-[11px] text-gray-500", children: "Derived from the name. Used in API routes." })
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: "agent-system", className: "text-sm", children: "System instruction" }),
18465
+ /* @__PURE__ */ jsx66(Label3, { htmlFor: `${settingsGroup}-icon`, className: "text-sm", children: "Icon fallback (emoji)" }),
17967
18466
  /* @__PURE__ */ jsx66(
17968
- Textarea,
18467
+ Input,
17969
18468
  {
17970
- id: "agent-system",
17971
- value: agentSystem,
17972
- onChange: (e) => setAgentSystem(e.target.value),
17973
- rows: 5,
17974
- placeholder: "How the model should behave\u2026",
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: "grid grid-cols-2 gap-2", children: [
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-model", className: "text-sm", children: "Model (optional)" }),
18540
+ /* @__PURE__ */ jsx66(Label3, { htmlFor: "agent-system", className: "text-sm", children: "System instruction" }),
17982
18541
  /* @__PURE__ */ jsx66(
17983
- Input,
18542
+ Textarea,
17984
18543
  {
17985
- id: "agent-model",
17986
- value: agentModel,
17987
- onChange: (e) => setAgentModel(e.target.value),
17988
- placeholder: "Gateway model id",
17989
- className: "h-8 text-sm font-mono"
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-temp", className: "text-sm", children: "Temperature" }),
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-temp",
17999
- value: agentTemp,
18000
- onChange: (e) => setAgentTemp(e.target.value),
18001
- placeholder: "e.g. 0.7",
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
- /* @__PURE__ */ jsxs55("div", { className: "space-y-1", children: [
18008
- /* @__PURE__ */ jsx66(Label3, { htmlFor: "agent-max", className: "text-sm", children: "Max tokens" }),
18009
- /* @__PURE__ */ jsx66(
18010
- Input,
18011
- {
18012
- id: "agent-max",
18013
- value: agentMaxTokens,
18014
- onChange: (e) => setAgentMaxTokens(e.target.value.replace(/\D/g, "")),
18015
- placeholder: "e.g. 1024",
18016
- className: "h-8 text-sm"
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: "agent-validation", className: "text-sm", children: "Validation & output guardrails" }),
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: "agent-validation",
18026
- value: agentValidationJson,
18027
- onChange: (e) => setAgentValidationJson(e.target.value),
18745
+ id: "notify-email-system",
18746
+ value: notifyEmailSystem,
18747
+ onChange: (e) => setNotifyEmailSystem(e.target.value),
18028
18748
  rows: 4,
18029
- placeholder: 'Plain text or JSON: {"guardrails":"Never promise refunds.","maxUserChars":2000}',
18030
- className: "text-xs font-mono"
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__ */ 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." }),
18088
- 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: [
18089
- /* @__PURE__ */ jsx66("span", { className: "min-w-0 truncate", title: d.name, children: d.name }),
18090
- /* @__PURE__ */ jsx66(
18091
- Button,
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
- 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",
18120
- "aria-live": "polite",
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(Loader25, { className: "h-4 w-4 shrink-0 animate-spin" }),
18123
- "Saving & linking\u2026"
18769
+ /* @__PURE__ */ jsx66(Plus10, { className: "h-3 w-3" }),
18770
+ "Add intent"
18124
18771
  ]
18125
18772
  }
18126
- ) : null
18773
+ )
18127
18774
  ] }),
18128
- /* @__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)." })
18129
- ] }),
18130
- /* @__PURE__ */ jsxs55("div", { className: "flex flex-wrap items-end gap-2", children: [
18131
- /* @__PURE__ */ jsxs55("div", { className: "min-w-[200px] flex-1 space-y-1", children: [
18132
- /* @__PURE__ */ jsx66(Label3, { className: "text-xs", children: "Attach existing document" }),
18133
- /* @__PURE__ */ jsxs55(Select, { value: attachExistingDocId, onValueChange: setAttachExistingDocId, children: [
18134
- /* @__PURE__ */ jsx66(SelectTrigger, { className: "h-8 text-xs", children: /* @__PURE__ */ jsx66(SelectValue, { placeholder: "Choose a document" }) }),
18135
- /* @__PURE__ */ jsxs55(SelectContent, { children: [
18136
- /* @__PURE__ */ jsx66(SelectItem, { value: "__none__", children: "\u2014 Select \u2014" }),
18137
- kbCatalog.filter((d) => !attachedAgentKnowledge.some((a) => a.id === d.id)).map((d) => /* @__PURE__ */ jsx66(SelectItem, { value: String(d.id), children: d.name }, d.id))
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
- ] }) : null
18157
- ] }),
18158
- /* @__PURE__ */ jsxs55("div", { className: "space-y-1", children: [
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
- id: `${settingsGroup}-icon`,
18191
- value: icon,
18192
- onChange: (e) => setIcon(e.target.value),
18193
- placeholder: "e.g. \u{1F4AC}",
18194
- className: "h-8 text-sm w-20"
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(Fragment16, { children: [
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(Fragment16, { children: [
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(Fragment16, { children: [
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 Fragment17, jsx as jsx68, jsxs as jsxs57 } from "react/jsx-runtime";
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(Fragment17, { children: [
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(Fragment17, { children: /* @__PURE__ */ jsxs57("section", { children: [
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 Trash29, Star, Save as Save8 } from "lucide-react";
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 Fragment18, jsx as jsx70, jsxs as jsxs59 } from "react/jsx-runtime";
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(Fragment18, { children: [
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(Trash29, { className: "h-4 w-4" })
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(Trash29, { className: "h-4 w-4" }) })
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(Trash29, { className: "h-4 w-4" }) })
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(Trash29, { className: "h-4 w-4" }) })
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 Trash210, ChevronDown as ChevronDown6, ChevronUp as ChevronUp2, Save as Save9, Power as Power2 } from "lucide-react";
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 Fragment19, jsx as jsx71, jsxs as jsxs60 } from "react/jsx-runtime";
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(Fragment19, { children: [
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(Trash210, { className: "h-4 w-4" }) })
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(Trash210, { className: "h-4 w-4" }) })
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(Trash210, { className: "h-4 w-4" }) })
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(Fragment19, { children: [
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 Trash211 } from "lucide-react";
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(Trash211, { className: "h-3.5 w-3.5" }),
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 Fragment20, jsx as jsx76, jsxs as jsxs63 } from "react/jsx-runtime";
20556
- function VendorOnboardPage() {
20557
- const { data: session } = useSession9();
20558
- const sessionUser = session?.user;
20559
- const isAdmin = canOnboardVendors(session?.user);
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 [sendInviteEmail, setSendInviteEmail] = useState43(true);
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 [error, setError] = useState43(null);
20574
- if (!isAdmin) {
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
- setError(null);
21219
+ setErrors([]);
20591
21220
  setInviteLink(null);
20592
21221
  if (activationMode === "password") {
20593
21222
  if (!ownerPassword) {
20594
- setError("Enter a password for the owner account");
21223
+ setErrors(["Enter a password for the owner account"]);
20595
21224
  setLoading(false);
20596
21225
  return;
20597
21226
  }
20598
21227
  if (ownerPassword !== ownerPasswordConfirm) {
20599
- setError("Passwords do not match");
21228
+ setErrors(["Passwords do not match"]);
20600
21229
  setLoading(false);
20601
21230
  return;
20602
21231
  }
20603
21232
  if (ownerPassword.length < 6) {
20604
- setError("Password must be at least 6 characters");
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
- sendInviteEmail: activationMode === "invite" ? sendInviteEmail : false,
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
- setError(data.error || "Onboarding failed");
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
- setVendorName("");
20638
- setVendorSlug("");
20639
- setVendorEmail("");
20640
- setVendorPhone("");
20641
- setOwnerName("");
20642
- setOwnerEmail("");
20643
- setOwnerPassword("");
20644
- setOwnerPasswordConfirm("");
21266
+ if (!data.inviteLink) {
21267
+ onSuccess();
21268
+ }
20645
21269
  } catch {
20646
- setError("Request failed");
21270
+ setErrors(["Request failed"]);
20647
21271
  } finally {
20648
21272
  setLoading(false);
20649
21273
  }
20650
21274
  };
20651
- const submitLabel = activationMode === "password" ? "Create vendor & set password" : sendInviteEmail ? "Create vendor & send invite" : "Create vendor & copy invite link";
20652
- return /* @__PURE__ */ jsxs63("div", { className: "p-6 max-w-xl", children: [
20653
- /* @__PURE__ */ jsx76("h1", { className: "text-xl font-semibold text-gray-900 dark:text-white", children: "Onboard vendor" }),
20654
- /* @__PURE__ */ jsx76("p", { className: "mt-1 text-sm text-gray-600 dark:text-gray-400", children: "Creates a vendor store and a Vendor Owner account. Choose how the owner gets access." }),
20655
- /* @__PURE__ */ jsxs63("form", { onSubmit: handleSubmit, className: "mt-6 space-y-6", children: [
20656
- /* @__PURE__ */ jsxs63("div", { className: "space-y-3", children: [
20657
- /* @__PURE__ */ jsx76("h2", { className: "text-sm font-medium text-gray-900 dark:text-white", children: "Store" }),
20658
- /* @__PURE__ */ jsxs63("div", { children: [
20659
- /* @__PURE__ */ jsx76(Label3, { htmlFor: "vendorName", children: "Store name" }),
20660
- /* @__PURE__ */ jsx76(Input, { id: "vendorName", required: true, value: vendorName, onChange: (e) => setVendorName(e.target.value), className: "mt-1" })
20661
- ] }),
20662
- /* @__PURE__ */ jsxs63("div", { children: [
20663
- /* @__PURE__ */ jsx76(Label3, { htmlFor: "vendorSlug", children: "Slug (optional)" }),
20664
- /* @__PURE__ */ jsx76(Input, { id: "vendorSlug", value: vendorSlug, onChange: (e) => setVendorSlug(e.target.value), placeholder: "auto from name", className: "mt-1" })
20665
- ] }),
20666
- /* @__PURE__ */ jsxs63("div", { children: [
20667
- /* @__PURE__ */ jsx76(Label3, { htmlFor: "vendorEmail", children: "Store email" }),
20668
- /* @__PURE__ */ jsx76(Input, { id: "vendorEmail", type: "email", value: vendorEmail, onChange: (e) => setVendorEmail(e.target.value), className: "mt-1" })
20669
- ] }),
20670
- /* @__PURE__ */ jsxs63("div", { children: [
20671
- /* @__PURE__ */ jsx76(Label3, { htmlFor: "vendorPhone", children: "Phone" }),
20672
- /* @__PURE__ */ jsx76(Input, { id: "vendorPhone", value: vendorPhone, onChange: (e) => setVendorPhone(e.target.value), className: "mt-1" })
20673
- ] })
20674
- ] }),
20675
- /* @__PURE__ */ jsxs63("div", { className: "space-y-3", children: [
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__ */ jsxs63("div", { className: "space-y-3 rounded-lg border border-gray-200 p-4", children: [
20687
- /* @__PURE__ */ jsx76("h2", { className: "text-sm font-medium text-gray-900 dark:text-white", children: "Owner access" }),
20688
- /* @__PURE__ */ jsxs63(
20689
- RadioGroup2,
20690
- {
20691
- value: activationMode,
20692
- onValueChange: (v) => setActivationMode(v),
20693
- className: "gap-3",
20694
- children: [
20695
- /* @__PURE__ */ jsxs63("div", { className: "flex items-start gap-2", children: [
20696
- /* @__PURE__ */ jsx76(RadioGroupItem, { value: "invite", id: "activation-invite", className: "mt-0.5" }),
20697
- /* @__PURE__ */ jsxs63("div", { children: [
20698
- /* @__PURE__ */ jsx76(Label3, { htmlFor: "activation-invite", className: "font-normal cursor-pointer", children: "Send invite link" }),
20699
- /* @__PURE__ */ jsx76("p", { className: "text-xs text-gray-500 mt-0.5", children: "Owner sets their own password via email or the link below." })
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", { className: "flex items-start gap-2", children: [
20703
- /* @__PURE__ */ jsx76(RadioGroupItem, { value: "password", id: "activation-password", className: "mt-0.5" }),
20704
- /* @__PURE__ */ jsxs63("div", { children: [
20705
- /* @__PURE__ */ jsx76(Label3, { htmlFor: "activation-password", className: "font-normal cursor-pointer", children: "Set password now" }),
20706
- /* @__PURE__ */ jsx76("p", { className: "text-xs text-gray-500 mt-0.5", children: "Account is active immediately; share the password with the owner securely." })
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("div", { children: [
20740
- /* @__PURE__ */ jsx76(Label3, { htmlFor: "ownerPasswordConfirm", children: "Confirm password" }),
20741
- /* @__PURE__ */ jsx76(
20742
- Input,
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
- id: "ownerPasswordConfirm",
20745
- type: "password",
20746
- required: true,
20747
- autoComplete: "new-password",
20748
- value: ownerPasswordConfirm,
20749
- onChange: (e) => setOwnerPasswordConfirm(e.target.value),
20750
- className: "mt-1"
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
- error && /* @__PURE__ */ jsx76("p", { className: "text-sm text-red-600", children: error }),
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 useRouter18, useSearchParams as useSearchParams17 } from "next/navigation";
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 Fragment21, jsx as jsx78, jsxs as jsxs65 } from "react/jsx-runtime";
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(Fragment21, { children: [
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(Fragment21, { children: [
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 = useRouter18();
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(Fragment21, { children: [
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(Fragment21, { children: [
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 useRouter19, useSearchParams as useSearchParams18 } from "next/navigation";
21617
- import { AlertCircle as AlertCircle9, Save as Save11, Zap as Zap3 } from "lucide-react";
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 Trash212, Search as Search5, Package as Package2, ShoppingCart as ShoppingCart5, User as User3, Hash, DollarSign, Gift } from "lucide-react";
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 "Product":
21639
- return { ...base, type: "product", subType: "productId", comparisonOperator: "eq", value: { v: String(c.productId ?? "") } };
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: "gte", value: { v: c.nthOrder ?? "1" } };
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
- Product: /* @__PURE__ */ jsx79(Package2, { className: "h-3.5 w-3.5 text-green-500" }),
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: "Product", children: "Product" }),
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 === "Product" && /* @__PURE__ */ jsx79(ProductPicker, { value: condition.productId, label: condition.productName, onChange: (id, name) => onChange({ ...condition, productId: id, productName: name }) }),
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 \u2265" }),
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(Trash212, { className: "h-4 w-4" }) })
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(Trash212, { className: "h-4 w-4" }) })
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 === "Product" && c.productId && !c.productName)
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(Trash212, { className: "h-3.5 w-3.5" })
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 Fragment22, jsx as jsx80, jsxs as jsxs67 } from "react/jsx-runtime";
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 = useRouter19();
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: Save11, onClick: handleSave }
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(AlertCircle9, { className: "h-5 w-5 text-red-400 flex-shrink-0" }),
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(Fragment22, { children: [
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(Fragment22, { children: [
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(Fragment22, { children: [
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 = useRouter21();
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 Save12 } from "lucide-react";
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(Save12, { className: "h-4 w-4 mr-2" }),
24052
+ /* @__PURE__ */ jsx84(Save13, { className: "h-4 w-4 mr-2" }),
23289
24053
  saving ? "Saving..." : "Save"
23290
24054
  ]
23291
24055
  }