@infuro/cms-core 1.0.33 → 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 (38) hide show
  1. package/README.md +9 -6
  2. package/dist/admin.cjs +980 -801
  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 +1021 -842
  7. package/dist/admin.js.map +1 -1
  8. package/dist/api.cjs +1858 -848
  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 +1824 -815
  13. package/dist/api.js.map +1 -1
  14. package/dist/auth.cjs +94 -11
  15. package/dist/auth.cjs.map +1 -1
  16. package/dist/auth.d.cts +17 -1
  17. package/dist/auth.d.ts +17 -1
  18. package/dist/auth.js +89 -11
  19. package/dist/auth.js.map +1 -1
  20. package/dist/cli.cjs +39 -0
  21. package/dist/cli.cjs.map +1 -1
  22. package/dist/cli.js +39 -0
  23. package/dist/cli.js.map +1 -1
  24. package/dist/{index-rZTnpK7y.d.cts → index-Bf5GO8fu.d.cts} +3 -2
  25. package/dist/{index-DWd5Gjc4.d.ts → index-DOiJuMQA.d.ts} +3 -2
  26. package/dist/index.cjs +2078 -841
  27. package/dist/index.cjs.map +1 -1
  28. package/dist/index.d.cts +83 -8
  29. package/dist/index.d.ts +83 -8
  30. package/dist/index.js +2013 -786
  31. package/dist/index.js.map +1 -1
  32. package/dist/migrations/1778660000004-CreateCustomerAndCustomerContacts.ts +99 -0
  33. package/dist/migrations/1778660000005-AddCustomerIdToVendorCustomers.ts +39 -0
  34. package/dist/migrations/1778660000006-UpdateVendorCustomersContactNullable.ts +36 -0
  35. package/dist/migrations/1778660000007-VendorOwnerCustomerContactsPermission.ts +39 -0
  36. package/dist/migrations/1779300000000-VendorOwnerContactsPermission.ts +39 -0
  37. package/dist/migrations/1779400000000-AddCustomerContactIdToOrders.ts +33 -0
  38. package/package.json +4 -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";
801
+ import { useRouter as useRouter21, useSearchParams as useSearchParams19 } from "next/navigation";
778
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) })
@@ -1030,7 +1054,7 @@ function ContactDetailPage({ contactId }) {
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.33" : "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
  ) }),
@@ -2703,7 +2727,7 @@ function RelationAutocomplete({
2703
2727
 
2704
2728
  // src/components/Admin/CreateEditForm.tsx
2705
2729
  import { toast } from "sonner";
2706
- 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";
2707
2731
  function todayLocalDateString() {
2708
2732
  const d = /* @__PURE__ */ new Date();
2709
2733
  const y = d.getFullYear();
@@ -2745,7 +2769,8 @@ function CreateEditForm({
2745
2769
  apiEndpoint,
2746
2770
  columns,
2747
2771
  existingData,
2748
- duplicateSeed
2772
+ duplicateSeed,
2773
+ resource
2749
2774
  }) {
2750
2775
  const isMobile = useIsMobile();
2751
2776
  const { currency } = useContext3(AdminConfigContext);
@@ -2753,6 +2778,9 @@ function CreateEditForm({
2753
2778
  currency: currency || "INR"
2754
2779
  });
2755
2780
  const [errors, setErrors] = useState6({});
2781
+ const [password, setPassword] = useState6("");
2782
+ const [confirmPassword, setConfirmPassword] = useState6("");
2783
+ const isCustomerCreate = resource === "vendor_customers" && !existingData;
2756
2784
  useEffect4(() => {
2757
2785
  fetch("/api/settings/store").then((res) => res.json()).then((data) => {
2758
2786
  setFormData((prev) => ({
@@ -2782,14 +2810,10 @@ function CreateEditForm({
2782
2810
  };
2783
2811
  }).filter(Boolean)
2784
2812
  );
2785
- }).catch(
2786
- (err) => console.error("Failed to load customers", err)
2787
- );
2813
+ }).catch((err) => console.error("Failed to load customers", err));
2788
2814
  }, [columns]);
2789
2815
  const handleCustomerSelect = (customerId) => {
2790
- const customer = customers.find(
2791
- (c) => String(c.id) === customerId
2792
- );
2816
+ const customer = customers.find((c) => String(c.id) === customerId);
2793
2817
  if (!customer) return;
2794
2818
  setFormData((prev) => ({
2795
2819
  ...prev,
@@ -2803,23 +2827,14 @@ function CreateEditForm({
2803
2827
  const [totalLoading, setTotalLoading] = useState6(false);
2804
2828
  useEffect4(() => {
2805
2829
  return () => {
2806
- if (debounceRef.current) {
2807
- clearTimeout(debounceRef.current);
2808
- }
2830
+ if (debounceRef.current) clearTimeout(debounceRef.current);
2809
2831
  };
2810
2832
  }, []);
2811
2833
  const recalculateTotal = (itemsSummaryValue) => {
2812
- if (debounceRef.current) {
2813
- clearTimeout(debounceRef.current);
2814
- }
2834
+ if (debounceRef.current) clearTimeout(debounceRef.current);
2815
2835
  const names = itemsSummaryValue.split(",").map((s) => s.trim()).filter(Boolean);
2816
2836
  if (names.length === 0) {
2817
- setFormData((prev) => ({
2818
- ...prev,
2819
- subtotal: "",
2820
- tax: "",
2821
- total: ""
2822
- }));
2837
+ setFormData((prev) => ({ ...prev, subtotal: "", tax: "", total: "" }));
2823
2838
  return;
2824
2839
  }
2825
2840
  debounceRef.current = setTimeout(async () => {
@@ -2827,12 +2842,8 @@ function CreateEditForm({
2827
2842
  try {
2828
2843
  const res = await fetch("/api/orders/calculate", {
2829
2844
  method: "POST",
2830
- headers: {
2831
- "Content-Type": "application/json"
2832
- },
2833
- body: JSON.stringify({
2834
- itemsSummary: itemsSummaryValue
2835
- })
2845
+ headers: { "Content-Type": "application/json" },
2846
+ body: JSON.stringify({ itemsSummary: itemsSummaryValue })
2836
2847
  });
2837
2848
  if (!res.ok) return;
2838
2849
  const data = await res.json();
@@ -2857,13 +2868,9 @@ function CreateEditForm({
2857
2868
  const path = col.field || col.key;
2858
2869
  if (!path) return;
2859
2870
  const v = getNestedValue(ex, path);
2860
- if (v !== void 0) {
2861
- merged[path] = v === null ? "" : v;
2862
- }
2871
+ if (v !== void 0) merged[path] = v === null ? "" : v;
2863
2872
  });
2864
- columns.filter(
2865
- (col) => !col.hideInForm && isDateFormColumn(col.type)
2866
- ).forEach((col) => {
2873
+ columns.filter((col) => !col.hideInForm && isDateFormColumn(col.type)).forEach((col) => {
2867
2874
  const path = col.field || col.key;
2868
2875
  if (!path) return;
2869
2876
  const raw = merged[path];
@@ -2879,9 +2886,7 @@ function CreateEditForm({
2879
2886
  ).forEach((col) => {
2880
2887
  const path = col.field || col.key;
2881
2888
  if (!path) return;
2882
- const allowed = new Set(
2883
- col.options.map((o) => String(o.value))
2884
- );
2889
+ const allowed = new Set(col.options.map((o) => String(o.value)));
2885
2890
  const raw = merged[path];
2886
2891
  if (raw != null && raw !== "" && !allowed.has(String(raw))) {
2887
2892
  merged[path] = "";
@@ -2889,6 +2894,8 @@ function CreateEditForm({
2889
2894
  });
2890
2895
  setFormData(merged);
2891
2896
  } else {
2897
+ setPassword("");
2898
+ setConfirmPassword("");
2892
2899
  setFormData(
2893
2900
  columns.filter((col) => !col.hideInForm).reduce((acc, col) => {
2894
2901
  const path = col.field || col.key;
@@ -2897,29 +2904,18 @@ function CreateEditForm({
2897
2904
  if (isDateFormColumn(col.type) && (initial === "" || initial == null)) {
2898
2905
  initial = todayLocalDateString();
2899
2906
  }
2900
- return {
2901
- ...acc,
2902
- [path]: initial
2903
- };
2907
+ return { ...acc, [path]: initial };
2904
2908
  }, {})
2905
2909
  );
2906
2910
  }
2907
2911
  }, [existingData, duplicateSeed, columns]);
2908
2912
  const handleChange = (e, field) => {
2909
2913
  const value = e.target.value;
2910
- setFormData((prev) => ({
2911
- ...prev,
2912
- [field]: value
2913
- }));
2914
- if (field === "itemsSummary") {
2915
- recalculateTotal(value);
2916
- }
2914
+ setFormData((prev) => ({ ...prev, [field]: value }));
2915
+ if (field === "itemsSummary") recalculateTotal(value);
2917
2916
  };
2918
2917
  const handleFileUpload = (field, url) => {
2919
- setFormData({
2920
- ...formData,
2921
- [field]: url
2922
- });
2918
+ setFormData({ ...formData, [field]: url });
2923
2919
  };
2924
2920
  const isValidPhoneFieldValue = (value) => {
2925
2921
  const v = String(value ?? "").trim();
@@ -2943,6 +2939,18 @@ function CreateEditForm({
2943
2939
  }
2944
2940
  }
2945
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
+ }
2946
2954
  setErrors(newErrors);
2947
2955
  return Object.keys(newErrors).length === 0;
2948
2956
  };
@@ -2960,16 +2968,19 @@ function CreateEditForm({
2960
2968
  if (!existingData) {
2961
2969
  delete payload.id;
2962
2970
  }
2971
+ if (isCustomerCreate) {
2972
+ payload._password = password;
2973
+ }
2963
2974
  try {
2964
2975
  const res = await fetch(url, {
2965
2976
  method,
2966
- headers: {
2967
- "Content-Type": "application/json"
2968
- },
2977
+ headers: { "Content-Type": "application/json" },
2969
2978
  body: JSON.stringify(payload)
2970
2979
  });
2971
2980
  if (!res.ok) {
2972
- 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;
2973
2984
  }
2974
2985
  const result = await res.json();
2975
2986
  if (result.inviteLink) {
@@ -2983,13 +2994,12 @@ Note: ${result.note}`
2983
2994
  onClose();
2984
2995
  } catch (error) {
2985
2996
  console.error("Error saving data:", error);
2997
+ toast.error("An unexpected error occurred. Please try again.");
2986
2998
  }
2987
2999
  };
2988
3000
  const visibleColumns = columns.filter((col) => {
2989
3001
  if (col.hideInForm) return false;
2990
- if (!existingData && col.hideInCreate) {
2991
- return false;
2992
- }
3002
+ if (!existingData && col.hideInCreate) return false;
2993
3003
  return true;
2994
3004
  });
2995
3005
  const isFieldDisabled = (path) => {
@@ -3019,228 +3029,193 @@ Note: ${result.note}`
3019
3029
  }
3020
3030
  )
3021
3031
  ] }),
3022
- /* @__PURE__ */ jsxs11(
3023
- "form",
3024
- {
3025
- onSubmit: handleSubmit,
3026
- className: "flex flex-col flex-1 min-h-0",
3027
- children: [
3028
- /* @__PURE__ */ jsx17("div", { className: "flex-1 min-h-0 overflow-y-auto p-6 space-y-4", children: visibleColumns.map((col) => {
3029
- const path = col.field || col.key;
3030
- if (!path) return null;
3031
- const disabled = isFieldDisabled(path);
3032
- const optionSet = col.type === "select" && Array.isArray(col.options) ? new Set(
3033
- col.options.map(
3034
- (o) => String(o.value)
3035
- )
3036
- ) : null;
3037
- const rawStr = formData[path] != null && formData[path] !== "" ? String(formData[path]) : "";
3038
- const selectValue = optionSet ? rawStr !== "" && optionSet.has(rawStr) ? rawStr : col.defaultValue : void 0;
3039
- return /* @__PURE__ */ jsxs11(React12.Fragment, { children: [
3040
- /* @__PURE__ */ jsxs11("div", { children: [
3041
- /* @__PURE__ */ jsxs11(Label3, { className: "block text-sm font-medium mb-1", children: [
3042
- col.displayName,
3043
- ["subtotal", "tax", "total"].includes(path) && totalLoading && /* @__PURE__ */ jsx17("span", { className: "ml-2 text-xs text-gray-400 font-normal", children: "Calculating\u2026" })
3044
- ] }),
3045
- col.type === "customerDropdown" ? /* @__PURE__ */ jsxs11(
3046
- Select,
3047
- {
3048
- value: (() => {
3049
- const match = customers.find(
3050
- (c) => String(c.id) === String(
3051
- formData["contactId"]
3052
- ) || 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(
3060
- SelectItem,
3061
- {
3062
- value: "__loading__",
3063
- disabled: true,
3064
- children: "Loading\u2026"
3065
- }
3066
- ) : customers.map((c) => /* @__PURE__ */ jsx17(
3067
- SelectItem,
3068
- {
3069
- value: String(
3070
- c.id
3071
- ),
3072
- children: c.name
3073
- },
3074
- c.id
3075
- )) })
3076
- ]
3077
- }
3078
- ) : col.relationApi ? /* @__PURE__ */ jsx17(
3079
- RelationAutocomplete,
3080
- {
3081
- apiEndpoint: col.relationApi,
3082
- value: formData[path] ?? "",
3083
- onChange: (v) => setFormData({
3084
- ...formData,
3085
- [path]: v
3086
- }),
3087
- labelField: col.relationLabelField ?? "name",
3088
- valueField: col.relationValueField ?? "id",
3089
- queryParams: col.relationQueryParams,
3090
- placeholder: `Select ${col.displayName}`
3091
- }
3092
- ) : col.type === "textarea" ? /* @__PURE__ */ jsx17(
3093
- Textarea,
3094
- {
3095
- rows: typeof col.textareaRows === "number" ? col.textareaRows : 4,
3096
- className: "min-h-[80px] font-mono text-sm",
3097
- value: formData[path] ?? "",
3098
- onChange: (e) => handleChange(e, path),
3099
- placeholder: col.placeholder,
3100
- disabled
3101
- }
3102
- ) : col.type === "select" && Array.isArray(
3103
- col.options
3104
- ) && col.options.length > 0 ? /* @__PURE__ */ jsxs11(
3105
- Select,
3106
- {
3107
- value: selectValue,
3108
- onValueChange: (value) => setFormData({
3109
- ...formData,
3110
- [path]: value
3111
- }),
3112
- disabled,
3113
- children: [
3114
- /* @__PURE__ */ jsx17(SelectTrigger, { children: /* @__PURE__ */ jsx17(
3115
- SelectValue,
3116
- {
3117
- placeholder: selectValue ? void 0 : "Select an option"
3118
- }
3119
- ) }),
3120
- /* @__PURE__ */ jsx17(SelectContent, { children: col.options.map(
3121
- (option) => /* @__PURE__ */ jsx17(
3122
- SelectItem,
3123
- {
3124
- value: option.value,
3125
- children: option.label
3126
- },
3127
- option.value
3128
- )
3129
- ) })
3130
- ]
3131
- }
3132
- ) : col.type === "boolean" ? /* @__PURE__ */ jsx17(
3133
- Switch,
3134
- {
3135
- checked: Boolean(
3136
- formData[path]
3137
- ),
3138
- onCheckedChange: (checked) => setFormData({
3139
- ...formData,
3140
- [path]: checked
3141
- }),
3142
- disabled
3143
- }
3144
- ) : isDateFormColumn(
3145
- col.type
3146
- ) ? /* @__PURE__ */ jsx17(
3147
- Input,
3148
- {
3149
- type: "date",
3150
- value: formData[path] ?? "",
3151
- onChange: (e) => handleChange(e, path),
3152
- disabled
3153
- }
3154
- ) : col.type === "password" ? /* @__PURE__ */ jsx17(
3155
- Input,
3156
- {
3157
- type: "password",
3158
- value: formData[path] || "",
3159
- onChange: (e) => handleChange(e, path),
3160
- disabled
3161
- }
3162
- ) : col.type === "number" ? /* @__PURE__ */ jsx17(
3163
- Input,
3164
- {
3165
- type: "number",
3166
- placeholder: col.placeholder,
3167
- value: formData[path] ?? "",
3168
- onChange: (e) => handleChange(e, path),
3169
- disabled
3170
- }
3171
- ) : col.type === "phone" || col.type === "tel" ? /* @__PURE__ */ jsx17(
3172
- Input,
3173
- {
3174
- type: "tel",
3175
- inputMode: "tel",
3176
- autoComplete: "tel",
3177
- placeholder: col.placeholder ?? "e.g. +1 555 123 4567",
3178
- value: formData[path] ?? "",
3179
- onChange: (e) => handleChange(e, path),
3180
- disabled
3181
- }
3182
- ) : col.type === "file" ? /* @__PURE__ */ jsx17(
3183
- FileUpload,
3184
- {
3185
- onUploadSuccess: (url) => handleFileUpload(
3186
- path,
3187
- url
3188
- )
3189
- }
3190
- ) : /* @__PURE__ */ jsx17(
3191
- Input,
3192
- {
3193
- type: col.type || "text",
3194
- placeholder: ["subtotal", "tax", "total"].includes(path) ? "Auto-calculated from items" : col.placeholder,
3195
- value: formData[path] ?? "",
3196
- onChange: (e) => handleChange(e, path),
3197
- disabled
3198
- }
3199
- ),
3200
- 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" })
3201
3046
  ] }),
3202
- col.type === "customerDropdown" && /* @__PURE__ */ jsxs11("div", { children: [
3203
- /* @__PURE__ */ jsx17(Label3, { className: "block text-sm font-medium mb-1", children: "Name" }),
3204
- /* @__PURE__ */ jsx17(
3205
- Input,
3206
- {
3207
- type: "text",
3208
- placeholder: "Customer name",
3209
- value: formData["contact.name"] ?? "",
3210
- onChange: (e) => setFormData(
3211
- (prev) => ({
3212
- ...prev,
3213
- "contact.name": e.target.value
3214
- })
3215
- )
3216
- }
3217
- )
3218
- ] })
3219
- ] }, path);
3220
- }) }),
3221
- /* @__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" }),
3222
3179
  /* @__PURE__ */ jsx17(
3223
- Button,
3180
+ Input,
3224
3181
  {
3225
- type: "submit",
3226
- className: "flex-1",
3227
- children: "Save"
3182
+ type: "password",
3183
+ value: password,
3184
+ onChange: (e) => setPassword(e.target.value),
3185
+ placeholder: "Min. 6 characters"
3228
3186
  }
3229
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" }),
3230
3192
  /* @__PURE__ */ jsx17(
3231
- Button,
3193
+ Input,
3232
3194
  {
3233
- type: "button",
3234
- variant: "outline",
3235
- onClick: onClose,
3236
- className: "flex-1",
3237
- children: "Cancel"
3195
+ type: "password",
3196
+ value: confirmPassword,
3197
+ onChange: (e) => setConfirmPassword(e.target.value),
3198
+ placeholder: "Re-enter password"
3238
3199
  }
3239
- )
3200
+ ),
3201
+ errors["_confirmPassword"] && /* @__PURE__ */ jsx17("p", { className: "text-red-500 text-sm mt-1", children: errors["_confirmPassword"] })
3240
3202
  ] })
3241
- ]
3242
- }
3243
- )
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
+ ] })
3244
3219
  ]
3245
3220
  }
3246
3221
  ) }) : null;
@@ -3783,7 +3758,7 @@ init_input();
3783
3758
  import { useCallback as useCallback2, useEffect as useEffect6, useMemo as useMemo2, useRef as useRef4, useState as useState8 } from "react";
3784
3759
  init_utils();
3785
3760
  import { Filter, Search, X as X5 } from "lucide-react";
3786
- 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";
3787
3762
  var FILTER_BY_NONE = "__filter_by_none__";
3788
3763
  var SELECT_VALUE_ALL = "__select_all__";
3789
3764
  function isPointerOnRadixOverlayTarget(target, shell) {
@@ -4067,7 +4042,7 @@ function CrudSearchFilterBar({
4067
4042
  }
4068
4043
  )
4069
4044
  ] }),
4070
- activeDef ? /* @__PURE__ */ jsxs15(Fragment3, { children: [
4045
+ activeDef ? /* @__PURE__ */ jsxs15(Fragment4, { children: [
4071
4046
  activeDef.type === "select" ? /* @__PURE__ */ jsxs15("div", { className: "w-full min-w-0 flex-1 sm:min-w-[200px] sm:max-w-md", children: [
4072
4047
  /* @__PURE__ */ jsx22(Label3, { className: "mb-1.5 block text-xs font-medium text-gray-500", children: "Value" }),
4073
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(
@@ -4423,7 +4398,7 @@ function prepareRecordForDuplicate(resourceName, row) {
4423
4398
  var CRUD_NO_DUPLICATE_RESOURCES = /* @__PURE__ */ new Set(["form-submissions", "payments"]);
4424
4399
 
4425
4400
  // src/components/Admin/CRUD.tsx
4426
- 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";
4427
4402
  function getNestedValue2(obj, path) {
4428
4403
  return path.split(".").reduce((current, key) => {
4429
4404
  return current && current[key] !== void 0 ? current[key] : null;
@@ -5084,7 +5059,7 @@ function AdminCRUD({
5084
5059
  /* @__PURE__ */ jsx23(Button, { onClick: () => window.location.reload(), children: "Retry" })
5085
5060
  ] }) });
5086
5061
  }
5087
- 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: [
5088
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: [
5089
5064
  /* @__PURE__ */ jsxs16("div", { className: "min-w-0 flex-1", children: [
5090
5065
  /* @__PURE__ */ jsx23("h1", { className: "text-base font-semibold text-white truncate", children: title }),
@@ -5486,7 +5461,8 @@ function AdminCRUD({
5486
5461
  apiEndpoint,
5487
5462
  columns,
5488
5463
  existingData: editingItem,
5489
- duplicateSeed
5464
+ duplicateSeed,
5465
+ resource: resourceName
5490
5466
  }
5491
5467
  ),
5492
5468
  /* @__PURE__ */ jsx23(
@@ -6561,7 +6537,7 @@ init_input();
6561
6537
  init_button();
6562
6538
  import { useState as useState13, useEffect as useEffect9, useRef as useRef7, useCallback as useCallback6 } from "react";
6563
6539
  import { X as X10, Plus as Plus4, Search as Search2 } from "lucide-react";
6564
- 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";
6565
6541
  function TagAutocomplete({
6566
6542
  selectedTags,
6567
6543
  onTagsChange,
@@ -6704,7 +6680,7 @@ function TagAutocomplete({
6704
6680
  onClick: handleCreateTag,
6705
6681
  disabled: isCreating || selectedTags.includes(inputValue.trim()),
6706
6682
  className: "absolute right-1 top-1/2 -translate-y-1/2 h-7 px-2",
6707
- children: isCreating ? "Creating..." : /* @__PURE__ */ jsxs20(Fragment5, { children: [
6683
+ children: isCreating ? "Creating..." : /* @__PURE__ */ jsxs20(Fragment6, { children: [
6708
6684
  /* @__PURE__ */ jsx29(Plus4, { className: "h-3 w-3 mr-1" }),
6709
6685
  "Create"
6710
6686
  ] })
@@ -6834,7 +6810,7 @@ init_input();
6834
6810
  init_button();
6835
6811
  import { useState as useState14, useEffect as useEffect10, useRef as useRef8 } from "react";
6836
6812
  import { X as X11, Plus as Plus5, Search as Search3, Check as Check5 } from "lucide-react";
6837
- 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";
6838
6814
  function CategoryAutocomplete({
6839
6815
  selectedCategory,
6840
6816
  onCategoryChange,
@@ -6972,7 +6948,7 @@ function CategoryAutocomplete({
6972
6948
  onClick: handleCreateCategory,
6973
6949
  disabled: isCreating,
6974
6950
  className: "absolute right-1 top-1/2 -translate-y-1/2 h-7 px-2",
6975
- children: isCreating ? "Creating..." : /* @__PURE__ */ jsxs21(Fragment6, { children: [
6951
+ children: isCreating ? "Creating..." : /* @__PURE__ */ jsxs21(Fragment7, { children: [
6976
6952
  /* @__PURE__ */ jsx31(Plus5, { className: "h-3 w-3 mr-1" }),
6977
6953
  "Create"
6978
6954
  ] })
@@ -8493,7 +8469,7 @@ var BLOG_GENERATOR_DEFAULT_VALIDATION_RULES = JSON.stringify(
8493
8469
  );
8494
8470
 
8495
8471
  // src/components/Admin/BlogGeneratorRssTool.tsx
8496
- 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";
8497
8473
  function BlogGeneratorRssTool({
8498
8474
  inputIdPrefix = "blog-gen-rss",
8499
8475
  variant = "page"
@@ -8956,11 +8932,11 @@ function BlogGeneratorRssTool({
8956
8932
  " row \u2014 model",
8957
8933
  " ",
8958
8934
  /* @__PURE__ */ jsx41("span", { className: "font-mono", children: llmAgentInfo.model ?? "(gateway default)" }),
8959
- llmAgentInfo.temperature != null && /* @__PURE__ */ jsxs31(Fragment7, { children: [
8935
+ llmAgentInfo.temperature != null && /* @__PURE__ */ jsxs31(Fragment8, { children: [
8960
8936
  ", temperature ",
8961
8937
  /* @__PURE__ */ jsx41("span", { className: "font-mono", children: String(llmAgentInfo.temperature) })
8962
8938
  ] }),
8963
- llmAgentInfo.maxTokens != null && /* @__PURE__ */ jsxs31(Fragment7, { children: [
8939
+ llmAgentInfo.maxTokens != null && /* @__PURE__ */ jsxs31(Fragment8, { children: [
8964
8940
  ", max_tokens ",
8965
8941
  /* @__PURE__ */ jsx41("span", { className: "font-mono", children: String(llmAgentInfo.maxTokens) })
8966
8942
  ] }),
@@ -8983,11 +8959,11 @@ function BlogGeneratorRssTool({
8983
8959
  " \u2014 model",
8984
8960
  " ",
8985
8961
  /* @__PURE__ */ jsx41("span", { className: "font-mono", children: metadataLlmAgentInfo.model ?? "(gateway default)" }),
8986
- metadataLlmAgentInfo.temperature != null && /* @__PURE__ */ jsxs31(Fragment7, { children: [
8962
+ metadataLlmAgentInfo.temperature != null && /* @__PURE__ */ jsxs31(Fragment8, { children: [
8987
8963
  ", temperature ",
8988
8964
  /* @__PURE__ */ jsx41("span", { className: "font-mono", children: String(metadataLlmAgentInfo.temperature) })
8989
8965
  ] }),
8990
- metadataLlmAgentInfo.maxTokens != null && /* @__PURE__ */ jsxs31(Fragment7, { children: [
8966
+ metadataLlmAgentInfo.maxTokens != null && /* @__PURE__ */ jsxs31(Fragment8, { children: [
8991
8967
  ", max_tokens ",
8992
8968
  /* @__PURE__ */ jsx41("span", { className: "font-mono", children: String(metadataLlmAgentInfo.maxTokens) })
8993
8969
  ] }),
@@ -9395,7 +9371,7 @@ import { useRouter as useRouter6 } from "next/navigation";
9395
9371
  import { Chart as ChartJS2, ArcElement, Tooltip as Tooltip2, Legend as Legend2 } from "chart.js";
9396
9372
  import { Doughnut } from "react-chartjs-2";
9397
9373
  import { Users as Users4, Eye, MousePointer, Globe, FileText, ClipboardList as ClipboardList2, UserCheck, TrendingUp, BarChart3, Activity } from "lucide-react";
9398
- 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";
9399
9375
  ChartJS2.register(ArcElement, Tooltip2, Legend2);
9400
9376
  function DashboardPage() {
9401
9377
  const { data: session } = useSession6();
@@ -9739,7 +9715,7 @@ function DashboardPage() {
9739
9715
  ) })
9740
9716
  ] })
9741
9717
  ] }),
9742
- activeTab === "overview" && analyticsEnabled && !isLoading && analyticsData && /* @__PURE__ */ jsxs38(Fragment8, { children: [
9718
+ activeTab === "overview" && analyticsEnabled && !isLoading && analyticsData && /* @__PURE__ */ jsxs38(Fragment9, { children: [
9743
9719
  /* @__PURE__ */ jsxs38("div", { className: "mb-4", children: [
9744
9720
  /* @__PURE__ */ jsxs38("div", { className: "flex items-center mb-2", children: [
9745
9721
  /* @__PURE__ */ jsx48(Globe, { className: "w-4 h-4 text-gray-600 mr-2" }),
@@ -9825,7 +9801,7 @@ function DashboardPage() {
9825
9801
  /* @__PURE__ */ jsx48("div", { className: "border-t-2 border-dotted border-gray-200 my-6" }),
9826
9802
  /* @__PURE__ */ jsx48("div", { className: "mb-6", children: /* @__PURE__ */ jsx48(GeographicMap, { data: analyticsData.geographicData }) })
9827
9803
  ] }),
9828
- activeTab === "crm" && !isLoading && /* @__PURE__ */ jsxs38(Fragment8, { children: [
9804
+ activeTab === "crm" && !isLoading && /* @__PURE__ */ jsxs38(Fragment9, { children: [
9829
9805
  /* @__PURE__ */ jsxs38("div", { className: "mb-4", children: [
9830
9806
  /* @__PURE__ */ jsxs38("div", { className: "flex items-center mb-2", children: [
9831
9807
  /* @__PURE__ */ jsx48(Users4, { className: "w-4 h-4 text-gray-600 mr-2" }),
@@ -9943,7 +9919,7 @@ function DashboardPage() {
9943
9919
  ] })
9944
9920
  ] })
9945
9921
  ] }),
9946
- activeTab === "sales" && !isLoading && storeEnabled && ecommerceData && /* @__PURE__ */ jsxs38(Fragment8, { children: [
9922
+ activeTab === "sales" && !isLoading && storeEnabled && ecommerceData && /* @__PURE__ */ jsxs38(Fragment9, { children: [
9947
9923
  /* @__PURE__ */ jsx48("div", { className: "border-t-2 border-dotted border-gray-200 my-6" }),
9948
9924
  /* @__PURE__ */ jsxs38("div", { className: "mb-4", children: [
9949
9925
  /* @__PURE__ */ jsxs38("div", { className: "flex items-center mb-2", children: [
@@ -10089,7 +10065,7 @@ function DashboardPage() {
10089
10065
  // src/admin/pages/AdminPageResolver.tsx
10090
10066
  import { useState as useState50, useEffect as useEffect47, useContext as useContext9, useMemo as useMemo10, Suspense as Suspense3 } from "react";
10091
10067
  import dynamic2 from "next/dynamic";
10092
- import { useRouter as useRouter21, useSearchParams as useSearchParams20 } from "next/navigation";
10068
+ import { useRouter as useRouter22, useSearchParams as useSearchParams20 } from "next/navigation";
10093
10069
 
10094
10070
  // src/admin/pages/SubmissionDetailPage.tsx
10095
10071
  init_admin_list_return_url();
@@ -10226,7 +10202,7 @@ import Link10 from "next/link";
10226
10202
  import { useRouter as useRouter8, useSearchParams as useSearchParams5 } from "next/navigation";
10227
10203
  import { X as X15, RefreshCw as RefreshCw2, Pencil } from "lucide-react";
10228
10204
  import { QRCode } from "react-qr-code";
10229
- import { Fragment as Fragment10, jsx as jsx52, jsxs as jsxs42 } from "react/jsx-runtime";
10205
+ import { Fragment as Fragment11, jsx as jsx52, jsxs as jsxs42 } from "react/jsx-runtime";
10230
10206
  function formatMoney(amount, currency = "INR") {
10231
10207
  return new Intl.NumberFormat("en-IN", {
10232
10208
  style: "currency",
@@ -10357,7 +10333,7 @@ function OrderDetailPage({ orderId }) {
10357
10333
  /* @__PURE__ */ jsx52(
10358
10334
  DetailPageLayout,
10359
10335
  {
10360
- main: /* @__PURE__ */ jsxs42(Fragment10, { children: [
10336
+ main: /* @__PURE__ */ jsxs42(Fragment11, { children: [
10361
10337
  /* @__PURE__ */ jsxs42("section", { children: [
10362
10338
  /* @__PURE__ */ jsx52("h2", { className: "text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2", children: "Order details" }),
10363
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: [
@@ -10389,7 +10365,7 @@ function OrderDetailPage({ orderId }) {
10389
10365
  /* @__PURE__ */ jsx52("dt", { className: "text-gray-500", children: "Total" }),
10390
10366
  /* @__PURE__ */ jsx52("dd", { className: "font-medium text-gray-900", children: formatMoney(Number(order.total), currency) })
10391
10367
  ] }),
10392
- (order.orderKind || order.parentOrderId != null) && /* @__PURE__ */ jsxs42(Fragment10, { children: [
10368
+ (order.orderKind || order.parentOrderId != null) && /* @__PURE__ */ jsxs42(Fragment11, { children: [
10393
10369
  /* @__PURE__ */ jsxs42("div", { className: "min-w-0", children: [
10394
10370
  /* @__PURE__ */ jsx52("dt", { className: "text-gray-500", children: "Kind" }),
10395
10371
  /* @__PURE__ */ jsx52("dd", { className: "font-medium text-gray-900 capitalize", children: order.orderKind ?? "sale" })
@@ -10512,7 +10488,7 @@ function OrderDetailPage({ orderId }) {
10512
10488
  ] })
10513
10489
  ] }) })
10514
10490
  ] }),
10515
- sidebar: /* @__PURE__ */ jsxs42(Fragment10, { children: [
10491
+ sidebar: /* @__PURE__ */ jsxs42(Fragment11, { children: [
10516
10492
  contact && /* @__PURE__ */ jsxs42("section", { children: [
10517
10493
  /* @__PURE__ */ jsx52("h2", { className: "text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2", children: "Customer" }),
10518
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: [
@@ -10641,7 +10617,7 @@ Checkbox.displayName = CheckboxPrimitive.Root.displayName;
10641
10617
  init_table();
10642
10618
  init_DetailPageHeader();
10643
10619
  import { toast as toast5 } from "sonner";
10644
- import { Trash2 as Trash25, ShoppingCart as ShoppingCart4 } from "lucide-react";
10620
+ import { Trash2 as Trash25, ShoppingCart as ShoppingCart4, Users as Users6 } from "lucide-react";
10645
10621
 
10646
10622
  // src/admin/pages/OrderDiscountPanel.tsx
10647
10623
  init_input();
@@ -11053,6 +11029,7 @@ function formatMoney3(amount, currency) {
11053
11029
  }).format(Number(amount));
11054
11030
  }
11055
11031
  var MANUAL_CUSTOMER = "__manual__";
11032
+ var MANUAL_CONTACT = "__manual__";
11056
11033
  function OrderPlacementPage({ editOrderId }) {
11057
11034
  const router = useRouter9();
11058
11035
  const searchParams = useSearchParams6();
@@ -11060,25 +11037,23 @@ function OrderPlacementPage({ editOrderId }) {
11060
11037
  const [customers, setCustomers] = useState28([]);
11061
11038
  const [customersLoading, setCustomersLoading] = useState28(true);
11062
11039
  const [contactId, setContactId] = useState28(null);
11040
+ const [selectedCustomerId, setSelectedCustomerId] = useState28(null);
11063
11041
  const [contactName, setContactName] = useState28("");
11064
11042
  const [contactEmail, setContactEmail] = useState28("");
11065
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("");
11066
11051
  const [status, setStatus] = useState28("pending");
11067
11052
  const [currency, setCurrency] = useState28("INR");
11068
11053
  const [loadingOrder, setLoadingOrder] = useState28(Boolean(editOrderId));
11069
11054
  const [orderLoadError, setOrderLoadError] = useState28(null);
11070
- const [couponError, setCouponError] = useState28(null);
11071
- const [couponLoading, setCouponLoading] = useState28(false);
11072
11055
  const [coupons, setCoupons] = useState28([]);
11073
- const [couponInput, setCouponInput] = useState28("");
11074
- const emptyAddress = {
11075
- line1: "",
11076
- line2: "",
11077
- city: "",
11078
- state: "",
11079
- country: "",
11080
- postalCode: ""
11081
- };
11056
+ const emptyAddress = { line1: "", line2: "", city: "", state: "", country: "", postalCode: "" };
11082
11057
  const [billingAddress, setBillingAddress] = useState28(emptyAddress);
11083
11058
  const [shippingAddress, setShippingAddress] = useState28(emptyAddress);
11084
11059
  const [sameAsBilling, setSameAsBilling] = useState28(true);
@@ -11141,9 +11116,7 @@ function OrderPlacementPage({ editOrderId }) {
11141
11116
  setSameAsBilling(true);
11142
11117
  }
11143
11118
  const loadedCid = typeof cid === "number" && Number.isFinite(cid) ? cid : null;
11144
- if (loadedCid && !o.billingAddress && !o.shippingAddress) {
11145
- void loadCustomerAddresses(loadedCid);
11146
- }
11119
+ if (loadedCid && !o.billingAddress && !o.shippingAddress) void loadContactAddresses(loadedCid);
11147
11120
  setStatus(String(o.status ?? "pending"));
11148
11121
  const cur = String(o.currency ?? "INR").trim().toUpperCase().slice(0, 8);
11149
11122
  if (cur) setCurrency(cur);
@@ -11153,13 +11126,7 @@ function OrderPlacementPage({ editOrderId }) {
11153
11126
  const coll = p?.collection?.name;
11154
11127
  const nm = p?.name;
11155
11128
  const label = [coll, nm].filter(Boolean).join(" \u2014 ") || nm || `Product #${pid}`;
11156
- return {
11157
- key: `line-${it.id}`,
11158
- productId: pid,
11159
- label,
11160
- sku: p?.sku ?? null,
11161
- quantity: Math.max(1, Math.floor(Number(it.quantity) || 1))
11162
- };
11129
+ return { key: `line-${it.id}`, productId: pid, label, sku: p?.sku ?? null, quantity: Math.max(1, Math.floor(Number(it.quantity) || 1)) };
11163
11130
  });
11164
11131
  setLines(draft);
11165
11132
  try {
@@ -11172,18 +11139,7 @@ function OrderPlacementPage({ editOrderId }) {
11172
11139
  if (dr.ok) {
11173
11140
  const d = await dr.json();
11174
11141
  if (d?.id) {
11175
- setCoupons([{
11176
- couponCode: d.couponCode ?? "",
11177
- discountId: d.id,
11178
- name: d.name,
11179
- value: d.value,
11180
- type: d.discountType,
11181
- canCombine: !!d.canCombineWithOtherDiscounts,
11182
- calculatedDiscount: 0,
11183
- rewardProductIds: [],
11184
- rewardLines: [],
11185
- isAutomatic: d.isAutomatic ?? false
11186
- }]);
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 }]);
11187
11143
  }
11188
11144
  }
11189
11145
  }
@@ -11194,12 +11150,7 @@ function OrderPlacementPage({ editOrderId }) {
11194
11150
  const pid = Number(it.productId);
11195
11151
  const p = it.product;
11196
11152
  const unit = Number(it.unitPrice ?? 0);
11197
- productCache.current.set(pid, {
11198
- id: pid,
11199
- name: p?.name ?? null,
11200
- sku: p?.sku ?? null,
11201
- price: Number.isFinite(unit) ? unit : 0
11202
- });
11153
+ productCache.current.set(pid, { id: pid, name: p?.name ?? null, sku: p?.sku ?? null, price: Number.isFinite(unit) ? unit : 0 });
11203
11154
  }
11204
11155
  } catch {
11205
11156
  if (!cancelled) setOrderLoadError("Failed to load order");
@@ -11216,23 +11167,17 @@ function OrderPlacementPage({ editOrderId }) {
11216
11167
  (async () => {
11217
11168
  setCustomersLoading(true);
11218
11169
  try {
11219
- const res = await fetch(
11220
- "/api/vendor_customers?limit=500&sortField=createdAt&sortOrder=asc"
11221
- );
11170
+ const res = await fetch("/api/vendor_customers?limit=500&sortField=createdAt&sortOrder=asc");
11222
11171
  if (!res.ok) {
11223
11172
  if (!cancelled) setCustomers([]);
11224
11173
  return;
11225
11174
  }
11226
11175
  const data = await res.json();
11227
11176
  const rows = (Array.isArray(data?.data) ? data.data : []).map((row) => {
11228
- const id = Number(row.contactId ?? row.contact?.id);
11177
+ const id = Number(row.id);
11229
11178
  if (!Number.isFinite(id)) return null;
11230
- return {
11231
- id,
11232
- name: row.name ?? row.contact?.name ?? null,
11233
- email: row.email ?? row.contact?.email ?? null,
11234
- phone: row.phone ?? row.contact?.phone ?? null
11235
- };
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 };
11236
11181
  }).filter((r) => r != null);
11237
11182
  if (!cancelled) setCustomers(rows);
11238
11183
  } catch {
@@ -11245,6 +11190,140 @@ function OrderPlacementPage({ editOrderId }) {
11245
11190
  cancelled = true;
11246
11191
  };
11247
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
+ }
11248
11327
  const cartProductIds = useMemo6(() => new Set(lines.map((l) => l.productId)), [lines]);
11249
11328
  useEffect25(() => {
11250
11329
  const q = productQuery.trim();
@@ -11253,13 +11332,7 @@ function OrderPlacementPage({ editOrderId }) {
11253
11332
  (async () => {
11254
11333
  setHitsLoading(true);
11255
11334
  try {
11256
- const params = new URLSearchParams({
11257
- limit: "50",
11258
- page: "1",
11259
- sortField: "name",
11260
- sortOrder: "asc",
11261
- status: "available"
11262
- });
11335
+ const params = new URLSearchParams({ limit: "50", page: "1", sortField: "name", sortOrder: "asc", status: "available" });
11263
11336
  if (q.length >= 2) params.set("search", q);
11264
11337
  const res = await fetch(`/api/products?${params}`);
11265
11338
  if (!res.ok) {
@@ -11340,53 +11413,34 @@ function OrderPlacementPage({ editOrderId }) {
11340
11413
  const res = await fetch("/api/discounts/validate-coupon", {
11341
11414
  method: "POST",
11342
11415
  headers: { "Content-Type": "application/json" },
11343
- body: JSON.stringify({
11344
- discountId: coupon.discountId,
11345
- isAutomatic: true,
11346
- orderLines: nonRewardLines.map((l) => ({ productId: l.productId, quantity: l.quantity })),
11347
- currency,
11348
- contactId
11349
- })
11416
+ body: JSON.stringify({ discountId: coupon.discountId, isAutomatic: true, orderLines: nonRewardLines.map((l) => ({ productId: l.productId, quantity: l.quantity })), currency, contactId })
11350
11417
  });
11351
11418
  if (cancelled) return;
11352
11419
  const data = await res.json();
11353
11420
  if (!data.valid) {
11354
11421
  const rewardPids = new Set(coupon.rewardLines.map((r) => r.productId));
11355
11422
  setCoupons((prev) => prev.filter((c) => c.discountId !== coupon.discountId));
11356
- setLines(
11357
- (prev) => prev.map((l) => {
11358
- if (!rewardPids.has(l.productId)) return l;
11359
- const rewardLine = coupon.rewardLines.find((r) => r.productId === l.productId);
11360
- if (!rewardLine) return l;
11361
- const newQty = l.quantity - rewardLine.quantity;
11362
- return newQty > 0 ? { ...l, quantity: newQty } : null;
11363
- }).filter((l) => l !== null)
11364
- );
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));
11365
11430
  rewardPids.forEach((pid) => rewardProductIds.current.delete(pid));
11366
11431
  rewardInjectedForDiscount.current.delete(coupon.discountId);
11367
11432
  } else {
11368
11433
  const newRewardLines = data.discount.rewardLines ?? [];
11369
- setCoupons((prev) => prev.map(
11370
- (c) => c.discountId !== coupon.discountId ? c : {
11371
- ...c,
11372
- calculatedDiscount: data.discount.calculatedDiscount,
11373
- rewardProductIds: data.discount.rewardProductIds ?? [],
11374
- rewardLines: newRewardLines
11375
- }
11376
- ));
11434
+ setCoupons((prev) => prev.map((c) => c.discountId !== coupon.discountId ? c : { ...c, calculatedDiscount: data.discount.calculatedDiscount, rewardProductIds: data.discount.rewardProductIds ?? [], rewardLines: newRewardLines }));
11377
11435
  setLines((prev) => {
11378
11436
  let next = [...prev];
11379
11437
  for (const rewardLine of newRewardLines) {
11380
11438
  const idx = next.findIndex((l) => l.productId === rewardLine.productId);
11381
- if (idx >= 0 && rewardProductIds.current.has(rewardLine.productId)) {
11382
- next[idx] = { ...next[idx], quantity: rewardLine.quantity };
11383
- }
11439
+ if (idx >= 0 && rewardProductIds.current.has(rewardLine.productId)) next[idx] = { ...next[idx], quantity: rewardLine.quantity };
11384
11440
  }
11385
11441
  const newRewardPids = new Set(newRewardLines.map((r) => r.productId));
11386
11442
  const oldRewardPids = new Set(coupon.rewardLines.map((r) => r.productId));
11387
- next = next.filter(
11388
- (l) => !oldRewardPids.has(l.productId) || newRewardPids.has(l.productId)
11389
- );
11443
+ next = next.filter((l) => !oldRewardPids.has(l.productId) || newRewardPids.has(l.productId));
11390
11444
  return next;
11391
11445
  });
11392
11446
  }
@@ -11401,126 +11455,28 @@ function OrderPlacementPage({ editOrderId }) {
11401
11455
  lines.filter((l) => !rewardProductIds.current.has(l.productId)).map((l) => `${l.productId}:${l.quantity}`).join(","),
11402
11456
  coupons.filter((c) => c.isAutomatic).map((c) => c.discountId).join(",")
11403
11457
  ]);
11404
- async function handleApplyCoupon() {
11405
- const code = couponInput.trim().toUpperCase();
11406
- if (!code) return;
11407
- if (coupons.some((c) => c.couponCode === code)) {
11408
- setCouponError("Coupon already applied");
11409
- return;
11410
- }
11411
- if (coupons.length > 0 && !coupons[0].canCombine) {
11412
- setCouponError("Applied coupon cannot be combined with other discounts");
11413
- return;
11414
- }
11415
- setCouponError(null);
11416
- setCouponLoading(true);
11417
- try {
11418
- const orderLines = lines.map((l) => ({ productId: l.productId, quantity: l.quantity }));
11419
- const res = await fetch("/api/discounts/validate-coupon", {
11420
- method: "POST",
11421
- headers: { "Content-Type": "application/json" },
11422
- body: JSON.stringify({ couponCode: code, orderLines, currency, contactId })
11423
- });
11424
- const data = await res.json();
11425
- if (!res.ok || !data.valid) {
11426
- setCouponError(data.error ?? "Invalid coupon");
11427
- return;
11428
- }
11429
- const d = data.discount;
11430
- if (!d.canCombineWithOtherDiscounts && coupons.length > 0) {
11431
- setCouponError("This coupon cannot be combined with other discounts");
11432
- return;
11433
- }
11434
- setCoupons((prev) => [...prev, {
11435
- couponCode: code,
11436
- discountId: d.id,
11437
- name: d.name,
11438
- value: d.value,
11439
- type: d.discountType,
11440
- canCombine: d.canCombineWithOtherDiscounts,
11441
- calculatedDiscount: d.calculatedDiscount,
11442
- rewardProductIds: d.rewardProductIds ?? [],
11443
- rewardLines: d.rewardLines ?? [],
11444
- isAutomatic: false
11445
- }]);
11446
- setCouponInput("");
11447
- toast5.success(`Coupon "${code}" applied`);
11448
- } catch {
11449
- setCouponError("Failed to validate coupon");
11450
- } finally {
11451
- setCouponLoading(false);
11452
- }
11453
- }
11454
11458
  function handleRemoveCoupon(couponCode) {
11455
11459
  const coupon = coupons.find((c) => c.couponCode === couponCode);
11456
11460
  if (coupon) {
11457
- const rewardKeyPrefix = `reward-`;
11458
- const rewardKeyForDiscount = new Set(
11459
- (coupon.rewardLines ?? []).map((r) => `reward-${r.productId}-${coupon.discountId}`)
11460
- );
11461
+ const rewardKeyForDiscount = new Set((coupon.rewardLines ?? []).map((r) => `reward-${r.productId}-${coupon.discountId}`));
11461
11462
  if (rewardKeyForDiscount.size > 0) {
11462
- setLines(
11463
- (prev) => prev.filter((l) => !rewardKeyForDiscount.has(l.key))
11464
- );
11463
+ setLines((prev) => prev.filter((l) => !rewardKeyForDiscount.has(l.key)));
11465
11464
  coupon.rewardLines.forEach((r) => {
11466
- const stillRewardByOther = coupons.some(
11467
- (c) => c.couponCode !== couponCode && c.rewardLines.some((rl) => rl.productId === r.productId)
11468
- );
11465
+ const stillRewardByOther = coupons.some((c) => c.couponCode !== couponCode && c.rewardLines.some((rl) => rl.productId === r.productId));
11469
11466
  if (!stillRewardByOther) rewardProductIds.current.delete(r.productId);
11470
11467
  });
11471
- }
11472
- rewardInjectedForDiscount.current.delete(coupon.discountId);
11473
- }
11474
- setCoupons((prev) => prev.filter((c) => c.couponCode !== couponCode));
11475
- setCouponError(null);
11476
- }
11477
- function mapAddressToForm(addr) {
11478
- return {
11479
- line1: addr.line1 ?? "",
11480
- line2: addr.line2 ?? "",
11481
- city: addr.city ?? "",
11482
- state: addr.state ?? "",
11483
- country: addr.country ?? "",
11484
- postalCode: addr.postalCode ?? ""
11485
- };
11486
- }
11487
- function updateAddress(type, field, value) {
11488
- if (type === "billing") setBillingAddress((prev) => ({ ...prev, [field]: value }));
11489
- else setShippingAddress((prev) => ({ ...prev, [field]: value }));
11490
- }
11491
- function handleCustomerSelect(value) {
11492
- if (value === MANUAL_CUSTOMER) {
11493
- setContactId(null);
11494
- return;
11495
- }
11496
- const id = Number(value);
11497
- if (!Number.isFinite(id)) return;
11498
- const customer = customers.find((c) => c.id === id);
11499
- if (!customer) return;
11500
- setContactId(id);
11501
- setContactName(customer.name ?? "");
11502
- setContactEmail(customer.email ?? "");
11503
- setContactPhone(customer.phone ?? "");
11504
- loadCustomerAddresses(id);
11505
- }
11506
- async function loadCustomerAddresses(customerId) {
11507
- try {
11508
- const res = await fetch(`/api/order_addresses?contactId=${customerId}&limit=100&sortField=createdAt&sortOrder=desc`);
11509
- if (!res.ok) return;
11510
- const body = await res.json();
11511
- const rows = Array.isArray(body) ? body : Array.isArray(body?.data) ? body.data : [];
11512
- const billing = rows.find((a) => a.addressType === "billing_address");
11513
- const shipping = rows.find((a) => a.addressType === "shipping_address");
11514
- if (billing) setBillingAddress(mapAddressToForm(billing));
11515
- else setBillingAddress({ ...emptyAddress });
11516
- if (sameAsBilling) setShippingAddress(billing ? mapAddressToForm(billing) : { ...emptyAddress });
11517
- else setShippingAddress(shipping ? mapAddressToForm(shipping) : { ...emptyAddress });
11518
- } catch {
11519
- setBillingAddress(emptyAddress);
11520
- setShippingAddress(emptyAddress);
11468
+ }
11469
+ rewardInjectedForDiscount.current.delete(coupon.discountId);
11521
11470
  }
11471
+ setCoupons((prev) => prev.filter((c) => c.couponCode !== couponCode));
11472
+ }
11473
+ function mapAddressToForm(addr) {
11474
+ return { line1: addr.line1 ?? "", line2: addr.line2 ?? "", city: addr.city ?? "", state: addr.state ?? "", country: addr.country ?? "", postalCode: addr.postalCode ?? "" };
11475
+ }
11476
+ function updateAddress(type, field, value) {
11477
+ if (type === "billing") setBillingAddress((prev) => ({ ...prev, [field]: value }));
11478
+ else setShippingAddress((prev) => ({ ...prev, [field]: value }));
11522
11479
  }
11523
- const customerSelectValue = contactId != null ? String(contactId) : MANUAL_CUSTOMER;
11524
11480
  function toggleStaged(id) {
11525
11481
  setStagedIds((prev) => {
11526
11482
  const next = new Set(prev);
@@ -11557,9 +11513,7 @@ function OrderPlacementPage({ editOrderId }) {
11557
11513
  if (idx >= 0) {
11558
11514
  const row = next[idx];
11559
11515
  next[idx] = { ...row, quantity: row.quantity + 1 };
11560
- } else {
11561
- next.push({ key: String(id), productId: id, label: hit.name ?? `Product #${id}`, sku: hit.sku, quantity: 1 });
11562
- }
11516
+ } else next.push({ key: String(id), productId: id, label: hit.name ?? `Product #${id}`, sku: hit.sku, quantity: 1 });
11563
11517
  }
11564
11518
  return next;
11565
11519
  });
@@ -11588,9 +11542,12 @@ function OrderPlacementPage({ editOrderId }) {
11588
11542
  }, [preview]);
11589
11543
  async function handleSubmit(e) {
11590
11544
  e.preventDefault();
11591
- const email = contactEmail.trim();
11592
- if (contactId == null && !email) {
11593
- 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");
11594
11551
  return;
11595
11552
  }
11596
11553
  if (lines.length === 0) {
@@ -11604,46 +11561,67 @@ function OrderPlacementPage({ editOrderId }) {
11604
11561
  }
11605
11562
  setSubmitting(true);
11606
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
+ }
11607
11590
  const payload = {
11608
11591
  status,
11609
11592
  currency,
11610
- "contact.name": contactName.trim() || email.split("@")[0] || "Customer",
11611
- "contact.email": email || (contactId != null ? customers.find((c) => c.id === contactId)?.email : "") || "",
11612
- "contact.phone": contactPhone.trim() || null,
11593
+ "contact.name": effectiveName || effectiveEmail.split("@")[0] || "Customer",
11594
+ "contact.email": effectiveEmail || "",
11595
+ "contact.phone": effectivePhone || null,
11613
11596
  billingAddress,
11614
11597
  shippingAddress: sameAsBilling ? billingAddress : shippingAddress,
11615
11598
  orderLines: lines.map((l) => {
11616
11599
  const calc = preview?.lines.find((pl) => pl.productId === l.productId);
11617
- return {
11618
- productId: l.productId,
11619
- quantity: l.quantity,
11620
- unitPrice: calc?.unitPrice ?? productCache.current.get(l.productId)?.price ?? 0
11621
- };
11600
+ return { productId: l.productId, quantity: l.quantity, unitPrice: calc?.unitPrice ?? productCache.current.get(l.productId)?.price ?? 0 };
11622
11601
  })
11623
11602
  };
11624
- if (contactId != null) payload.contactId = contactId;
11603
+ if (orderContactId != null) payload.contactId = orderContactId;
11604
+ if (!placeForSomeoneElse && contactId != null) payload.customerId = contactId;
11625
11605
  if (coupons.length > 0) payload.discountId = coupons[0].discountId;
11626
11606
  const url = editOrderId ? `/api/orders/${editOrderId}` : "/api/orders";
11627
11607
  const method = editOrderId ? "PUT" : "POST";
11628
- const res = await fetch(url, {
11629
- method,
11630
- headers: { "Content-Type": "application/json" },
11631
- body: JSON.stringify(payload)
11632
- });
11608
+ const res = await fetch(url, { method, headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload) });
11633
11609
  const body = await res.json().catch(() => ({}));
11634
11610
  if (!res.ok) {
11635
11611
  toast5.error(body.error ?? (editOrderId ? "Failed to update order" : "Failed to create order"));
11636
11612
  return;
11637
11613
  }
11638
- if (editOrderId && contactId != null) {
11639
- 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}`, {
11640
11622
  method: "PUT",
11641
11623
  headers: { "Content-Type": "application/json" },
11642
- body: JSON.stringify({
11643
- name: contactName.trim() || email.split("@")[0] || "Customer",
11644
- email: email || void 0,
11645
- phone: contactPhone.trim() || null
11646
- })
11624
+ body: JSON.stringify({ name: effectiveName || effectiveEmail.split("@")[0] || "Customer", email: effectiveEmail || void 0, phone: effectivePhone || null })
11647
11625
  });
11648
11626
  if (!cr.ok) {
11649
11627
  const cb = await cr.json().catch(() => ({}));
@@ -11655,6 +11633,25 @@ function OrderPlacementPage({ editOrderId }) {
11655
11633
  router.push(withAdminListFromParam(listReturnUrl, `/admin/orders/${editOrderId}/view`));
11656
11634
  return;
11657
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
+ }
11658
11655
  const id = body.id;
11659
11656
  toast5.success("Order created");
11660
11657
  if (id != null) router.push(withAdminListFromParam(listReturnUrl, `/admin/orders/${id}/view`));
@@ -11666,6 +11663,8 @@ function OrderPlacementPage({ editOrderId }) {
11666
11663
  }
11667
11664
  }
11668
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;
11669
11668
  if (editOrderId && loadingOrder) {
11670
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" }) });
11671
11670
  }
@@ -11710,74 +11709,168 @@ function OrderPlacementPage({ editOrderId }) {
11710
11709
  ] }),
11711
11710
  /* @__PURE__ */ jsxs44("div", { className: "space-y-2 sm:col-span-2", children: [
11712
11711
  /* @__PURE__ */ jsx55(Label3, { htmlFor: "c-email", children: "Email" }),
11713
- /* @__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 })
11714
11713
  ] }),
11715
11714
  /* @__PURE__ */ jsxs44("div", { className: "space-y-2 sm:col-span-2", children: [
11716
11715
  /* @__PURE__ */ jsx55(Label3, { htmlFor: "c-phone", children: "Phone" }),
11717
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" })
11718
11745
  ] }),
11719
- /* @__PURE__ */ jsxs44("div", { className: "space-y-4 sm:col-span-2 border rounded-lg p-4", children: [
11720
- /* @__PURE__ */ jsx55("h3", { className: "text-sm font-semibold", children: "Billing Address" }),
11721
- /* @__PURE__ */ jsxs44("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-3", children: [
11722
- /* @__PURE__ */ jsxs44("div", { className: "space-y-2 md:col-span-2", children: [
11723
- /* @__PURE__ */ jsx55(Label3, { children: "Address Line 1" }),
11724
- /* @__PURE__ */ jsx55(Input, { value: billingAddress.line1, onChange: (e) => updateAddress("billing", "line1", e.target.value), placeholder: "Street Address" })
11725
- ] }),
11726
- /* @__PURE__ */ jsxs44("div", { className: "space-y-2 md:col-span-2", children: [
11727
- /* @__PURE__ */ jsx55(Label3, { children: "Address Line 2" }),
11728
- /* @__PURE__ */ jsx55(Input, { value: billingAddress.line2, onChange: (e) => updateAddress("billing", "line2", e.target.value), placeholder: "Apartment, Suite, floor, etc." })
11729
- ] }),
11730
- /* @__PURE__ */ jsxs44("div", { className: "space-y-2", children: [
11731
- /* @__PURE__ */ jsx55(Label3, { children: "City" }),
11732
- /* @__PURE__ */ jsx55(Input, { value: billingAddress.city, onChange: (e) => updateAddress("billing", "city", e.target.value), placeholder: "City" })
11733
- ] }),
11734
- /* @__PURE__ */ jsxs44("div", { className: "space-y-2", children: [
11735
- /* @__PURE__ */ jsx55(Label3, { children: "State" }),
11736
- /* @__PURE__ */ jsx55(Input, { value: billingAddress.state, onChange: (e) => updateAddress("billing", "state", e.target.value), placeholder: "State" })
11737
- ] }),
11738
- /* @__PURE__ */ jsxs44("div", { className: "space-y-2", children: [
11739
- /* @__PURE__ */ jsx55(Label3, { children: "Country" }),
11740
- /* @__PURE__ */ jsx55(Input, { value: billingAddress.country, onChange: (e) => updateAddress("billing", "country", e.target.value), placeholder: "Country" })
11741
- ] }),
11742
- /* @__PURE__ */ jsxs44("div", { className: "space-y-2", children: [
11743
- /* @__PURE__ */ jsx55(Label3, { children: "Postal Code" }),
11744
- /* @__PURE__ */ jsx55(Input, { value: billingAddress.postalCode, onChange: (e) => updateAddress("billing", "postalCode", e.target.value), placeholder: "Postal Code" })
11745
- ] })
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" })
11746
11848
  ] })
11747
11849
  ] }),
11748
- /* @__PURE__ */ jsxs44("div", { className: "space-y-4 sm:col-span-2 border rounded-lg p-4", children: [
11749
- /* @__PURE__ */ jsxs44("div", { className: "flex items-center justify-between", children: [
11750
- /* @__PURE__ */ jsx55("h3", { className: "text-sm font-semibold", children: "Shipping Address" }),
11751
- /* @__PURE__ */ jsxs44("div", { className: "flex items-center gap-2", children: [
11752
- /* @__PURE__ */ jsx55(Checkbox, { checked: sameAsBilling, onCheckedChange: (checked) => setSameAsBilling(Boolean(checked)) }),
11753
- /* @__PURE__ */ jsx55("span", { className: "text-sm text-gray-600", children: "Same as Billing" })
11754
- ] })
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" })
11755
11854
  ] }),
11756
- !sameAsBilling && /* @__PURE__ */ jsxs44("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-3", children: [
11757
- /* @__PURE__ */ jsxs44("div", { className: "space-y-2 md:col-span-2", children: [
11758
- /* @__PURE__ */ jsx55(Label3, { children: "Address Line 1" }),
11759
- /* @__PURE__ */ jsx55(Input, { value: shippingAddress.line1, onChange: (e) => updateAddress("shipping", "line1", e.target.value), placeholder: "Street Address" })
11760
- ] }),
11761
- /* @__PURE__ */ jsxs44("div", { className: "space-y-2 md:col-span-2", children: [
11762
- /* @__PURE__ */ jsx55(Label3, { children: "Address Line 2" }),
11763
- /* @__PURE__ */ jsx55(Input, { value: shippingAddress.line2, onChange: (e) => updateAddress("shipping", "line2", e.target.value), placeholder: "Apartment, Suite, Floor, etc." })
11764
- ] }),
11765
- /* @__PURE__ */ jsxs44("div", { className: "space-y-2 md:col-span-2", children: [
11766
- /* @__PURE__ */ jsx55(Label3, { children: "City" }),
11767
- /* @__PURE__ */ jsx55(Input, { value: shippingAddress.city, onChange: (e) => updateAddress("shipping", "city", e.target.value), placeholder: "City" })
11768
- ] }),
11769
- /* @__PURE__ */ jsxs44("div", { className: "space-y-2 md:col-span-2", children: [
11770
- /* @__PURE__ */ jsx55(Label3, { children: "State" }),
11771
- /* @__PURE__ */ jsx55(Input, { value: shippingAddress.state, onChange: (e) => updateAddress("shipping", "state", e.target.value), placeholder: "State" })
11772
- ] }),
11773
- /* @__PURE__ */ jsxs44("div", { className: "space-y-2 md:col-span-2", children: [
11774
- /* @__PURE__ */ jsx55(Label3, { children: "Country" }),
11775
- /* @__PURE__ */ jsx55(Input, { value: shippingAddress.country, onChange: (e) => updateAddress("shipping", "country", e.target.value), placeholder: "Country" })
11776
- ] }),
11777
- /* @__PURE__ */ jsxs44("div", { className: "space-y-2 md:col-span-2", children: [
11778
- /* @__PURE__ */ jsx55(Label3, { children: "Postal Code" }),
11779
- /* @__PURE__ */ jsx55(Input, { value: shippingAddress.postalCode, onChange: (e) => updateAddress("shipping", "postalCode", e.target.value), placeholder: "Postal Code" })
11780
- ] })
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" })
11781
11874
  ] })
11782
11875
  ] })
11783
11876
  ] })
@@ -11875,51 +11968,21 @@ function OrderPlacementPage({ editOrderId }) {
11875
11968
  const active = selectedKey === line.key;
11876
11969
  const calc = calcByProductId.get(line.productId);
11877
11970
  const isReward = line.key.startsWith("reward-");
11878
- return /* @__PURE__ */ jsxs44(
11879
- TableRow,
11880
- {
11881
- className: active ? "bg-blue-50/80 cursor-pointer" : "cursor-pointer",
11882
- onClick: () => setSelectedKey(line.key),
11883
- children: [
11884
- /* @__PURE__ */ jsxs44(TableCell, { className: "align-top min-w-0", children: [
11885
- /* @__PURE__ */ jsx55("p", { className: "font-medium text-gray-900 break-words", children: line.label }),
11886
- /* @__PURE__ */ jsx55("p", { className: "text-xs text-gray-500 font-mono", children: line.sku ?? "\u2014" }),
11887
- isReward && /* @__PURE__ */ jsx55("span", { className: "text-[10px] text-purple-600 font-medium", children: "\u{1F381} Reward" })
11888
- ] }),
11889
- /* @__PURE__ */ jsx55(TableCell, { className: "align-top text-right", children: /* @__PURE__ */ jsx55(
11890
- Input,
11891
- {
11892
- type: "number",
11893
- min: 1,
11894
- className: "h-8 w-14 ml-auto text-right",
11895
- value: line.quantity,
11896
- onChange: (e) => updateQty(line.key, Number(e.target.value)),
11897
- onClick: (e) => e.stopPropagation(),
11898
- readOnly: isReward,
11899
- disabled: isReward
11900
- }
11901
- ) }),
11902
- /* @__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" }),
11903
- /* @__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" }),
11904
- /* @__PURE__ */ jsx55(TableCell, { className: "align-top text-right font-medium text-sm whitespace-nowrap", children: calc ? formatMoney3(calc.total, currency) : previewLoading ? "\u2026" : "\u2014" }),
11905
- /* @__PURE__ */ jsx55(TableCell, { className: "align-top", children: !isReward && /* @__PURE__ */ jsx55(
11906
- Button,
11907
- {
11908
- type: "button",
11909
- variant: "ghost",
11910
- size: "icon",
11911
- className: "h-8 w-8 text-red-600",
11912
- onClick: (e) => {
11913
- e.stopPropagation();
11914
- removeLine(line.key);
11915
- },
11916
- children: /* @__PURE__ */ jsx55(Trash25, { className: "h-4 w-4" })
11917
- }
11918
- ) })
11919
- ]
11920
- },
11921
- line.key
11922
- );
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);
11923
11986
  }) })
11924
11987
  ] }) }),
11925
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: [
@@ -11986,21 +12049,13 @@ function OrderPlacementPage({ editOrderId }) {
11986
12049
  if (!hit) return;
11987
12050
  const productHit = hit;
11988
12051
  setLines((prev) => {
11989
- const existingRewardIdx = prev.findIndex(
11990
- (l) => l.productId === pid && rewardProductIds.current.has(pid)
11991
- );
12052
+ const existingRewardIdx = prev.findIndex((l) => l.productId === pid && rewardProductIds.current.has(pid));
11992
12053
  if (existingRewardIdx >= 0) {
11993
12054
  const next = [...prev];
11994
12055
  next[existingRewardIdx] = { ...next[existingRewardIdx], quantity: qty };
11995
12056
  return next;
11996
12057
  }
11997
- return [...prev, {
11998
- key: `reward-${pid}-${coupon.discountId}`,
11999
- productId: pid,
12000
- label: productHit.name ?? `Product #${pid}`,
12001
- sku: productHit.sku,
12002
- quantity: qty
12003
- }];
12058
+ return [...prev, { key: `reward-${pid}-${coupon.discountId}`, productId: pid, label: productHit.name ?? `Product #${pid}`, sku: productHit.sku, quantity: qty }];
12004
12059
  });
12005
12060
  });
12006
12061
  }
@@ -12174,7 +12229,7 @@ import { useEffect as useEffect27, useState as useState30 } from "react";
12174
12229
  import Link12 from "next/link";
12175
12230
  import { useRouter as useRouter10, useSearchParams as useSearchParams8 } from "next/navigation";
12176
12231
  import { X as X17 } from "lucide-react";
12177
- 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";
12178
12233
  function formatMoney4(amount, currency = "INR") {
12179
12234
  return new Intl.NumberFormat("en-IN", {
12180
12235
  style: "currency",
@@ -12238,7 +12293,7 @@ function PaymentDetailPage({ paymentId }) {
12238
12293
  /* @__PURE__ */ jsx57(
12239
12294
  DetailPageLayout,
12240
12295
  {
12241
- main: /* @__PURE__ */ jsxs46(Fragment11, { children: [
12296
+ main: /* @__PURE__ */ jsxs46(Fragment12, { children: [
12242
12297
  /* @__PURE__ */ jsxs46("section", { children: [
12243
12298
  /* @__PURE__ */ jsx57("h2", { className: "text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2", children: "Payment details" }),
12244
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: [
@@ -12301,7 +12356,7 @@ function PaymentDetailPage({ paymentId }) {
12301
12356
  ] })
12302
12357
  ] })
12303
12358
  ] }),
12304
- sidebar: /* @__PURE__ */ jsx57(Fragment11, { children: customer && /* @__PURE__ */ jsxs46("section", { children: [
12359
+ sidebar: /* @__PURE__ */ jsx57(Fragment12, { children: customer && /* @__PURE__ */ jsxs46("section", { children: [
12305
12360
  /* @__PURE__ */ jsx57("h2", { className: "text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2", children: "Customer" }),
12306
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: [
12307
12362
  /* @__PURE__ */ jsxs46("div", { className: "min-w-0", children: [
@@ -12337,7 +12392,7 @@ import { useState as useState31, useEffect as useEffect28, useContext as useCont
12337
12392
  import { useSearchParams as useSearchParams9 } from "next/navigation";
12338
12393
  import { toast as toast6 } from "sonner";
12339
12394
  import { Save as Save3, RotateCcw, ArrowLeftRight, Plus as Plus8, Trash2 as Trash26, X as X18 } from "lucide-react";
12340
- 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";
12341
12396
  var DEFAULT_CURRENCY = "INR";
12342
12397
  var DEFAULTS = {
12343
12398
  primaryColor: "#313996",
@@ -12668,7 +12723,7 @@ function SettingsPage() {
12668
12723
  /* @__PURE__ */ jsx58("span", { className: "text-[11px] text-gray-400", children: "Smaller spacing in admin" })
12669
12724
  ] }) })
12670
12725
  ] }),
12671
- 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: [
12672
12727
  /* @__PURE__ */ jsxs47("div", { children: [
12673
12728
  /* @__PURE__ */ jsx58("h2", { className: "text-lg font-semibold text-gray-900 mb-2", children: "Navbar & pages" }),
12674
12729
  /* @__PURE__ */ jsx58("p", { className: "text-sm text-gray-500 mb-4", children: "Set logo and menu items." }),
@@ -12676,7 +12731,7 @@ function SettingsPage() {
12676
12731
  ] }),
12677
12732
  /* @__PURE__ */ jsx58(Button, { onClick: handleSaveNavbar, disabled: saving, children: saving ? "Saving..." : "Save navbar" })
12678
12733
  ] }) }),
12679
- 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: [
12680
12735
  /* @__PURE__ */ jsxs47("div", { children: [
12681
12736
  /* @__PURE__ */ jsx58("h2", { className: "text-lg font-semibold text-gray-900 mb-2", children: "Store / E-commerce" }),
12682
12737
  /* @__PURE__ */ jsx58("p", { className: "text-sm text-gray-500 mb-4", children: "Enable e-commerce functionality to manage products, orders, payments, and more." }),
@@ -13236,7 +13291,7 @@ import {
13236
13291
  Check as Check9
13237
13292
  } from "lucide-react";
13238
13293
  import { toast as toast8 } from "sonner";
13239
- 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";
13240
13295
  function getTypeCategory(mime, kind, filename) {
13241
13296
  if (kind === "folder" || mime === "inode/directory") return "folder";
13242
13297
  if (isZipMedia(mime, filename ?? "")) return "zip";
@@ -13450,7 +13505,7 @@ function VideoGridThumb({ src, label }) {
13450
13505
  if (broken) {
13451
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 }) });
13452
13507
  }
13453
- 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: [
13454
13509
  /* @__PURE__ */ jsx60(
13455
13510
  "video",
13456
13511
  {
@@ -14323,7 +14378,7 @@ function MediaLibraryPage() {
14323
14378
  editModal && /* @__PURE__ */ jsx60("div", { className: "space-y-4 py-2", children: editModal.kind === "folder" ? /* @__PURE__ */ jsxs49("div", { children: [
14324
14379
  /* @__PURE__ */ jsx60("label", { className: "text-sm font-medium", children: "Name" }),
14325
14380
  /* @__PURE__ */ jsx60(Input, { value: editFilename, onChange: (e) => setEditFilename(e.target.value), className: "mt-1" })
14326
- ] }) : /* @__PURE__ */ jsxs49(Fragment13, { children: [
14381
+ ] }) : /* @__PURE__ */ jsxs49(Fragment14, { children: [
14327
14382
  /* @__PURE__ */ jsxs49("div", { children: [
14328
14383
  /* @__PURE__ */ jsx60("label", { className: "text-sm font-medium", children: "Alt text" }),
14329
14384
  /* @__PURE__ */ jsx60(
@@ -14362,7 +14417,7 @@ function MediaLibraryPage() {
14362
14417
  previewItem.size ? ` \xB7 ${formatMediaBytes(previewItem.size)}` : ""
14363
14418
  ] })
14364
14419
  ] }),
14365
- previewItem && previewAbsUrl && /* @__PURE__ */ jsxs49(Fragment13, { children: [
14420
+ previewItem && previewAbsUrl && /* @__PURE__ */ jsxs49(Fragment14, { children: [
14366
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 }) }),
14367
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: [
14368
14423
  /* @__PURE__ */ jsxs49("div", { className: "flex flex-wrap gap-2", children: [
@@ -14474,7 +14529,7 @@ function getCatalog(theme) {
14474
14529
  // src/admin/pages/PageBuilderPage.tsx
14475
14530
  import * as LucideIcons from "lucide-react";
14476
14531
  import React20 from "react";
14477
- 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";
14478
14533
  function createSelectable(Comp) {
14479
14534
  function SelectableWrapper(props) {
14480
14535
  const { id, connectors, displayName, isHovered } = useNode((node) => ({
@@ -14888,7 +14943,7 @@ function RightSidebar({ theme, resolver, activeTab, setActiveTab, seoProps }) {
14888
14943
  tab
14889
14944
  )) }),
14890
14945
  /* @__PURE__ */ jsxs50("div", { className: "flex-1 overflow-y-auto flex flex-col min-h-0", children: [
14891
- activeTab === "designer" && /* @__PURE__ */ jsxs50(Fragment14, { children: [
14946
+ activeTab === "designer" && /* @__PURE__ */ jsxs50(Fragment15, { children: [
14892
14947
  /* @__PURE__ */ jsx61(
14893
14948
  CollapsibleSection,
14894
14949
  {
@@ -15733,7 +15788,7 @@ function JobScheduleTypeTabs({
15733
15788
  }
15734
15789
 
15735
15790
  // src/admin/JobSchedulesTool.tsx
15736
- 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";
15737
15792
  var WEEKDAY_LABELS = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
15738
15793
  var EMPTY_DRAFT = {
15739
15794
  name: "",
@@ -16098,7 +16153,7 @@ function JobSchedulesTool({
16098
16153
  ),
16099
16154
  /* @__PURE__ */ jsx65("p", { className: "text-[11px] text-gray-500", children: "Standard 5-field cron (minute hour dom month dow)." })
16100
16155
  ] }) : null,
16101
- activeJobType === "blog_generate" ? /* @__PURE__ */ jsxs54(Fragment15, { children: [
16156
+ activeJobType === "blog_generate" ? /* @__PURE__ */ jsxs54(Fragment16, { children: [
16102
16157
  /* @__PURE__ */ jsxs54("div", { className: "space-y-1", children: [
16103
16158
  /* @__PURE__ */ jsx65(Label3, { className: "text-sm", children: "Author (blog drafts)" }),
16104
16159
  /* @__PURE__ */ jsx65(
@@ -16342,7 +16397,7 @@ var BLOG_LLM_AGENT_SLUGS = [
16342
16397
  ];
16343
16398
 
16344
16399
  // src/admin/pages/PluginsPage.tsx
16345
- import { Fragment as Fragment16, jsx as jsx66, jsxs as jsxs55 } from "react/jsx-runtime";
16400
+ import { Fragment as Fragment17, jsx as jsx66, jsxs as jsxs55 } from "react/jsx-runtime";
16346
16401
  function normalizeLinkedInOrganizations(payload) {
16347
16402
  if (!payload || typeof payload !== "object") return [];
16348
16403
  const orgs = payload.organizations;
@@ -18134,7 +18189,7 @@ function PluginSettingsPanel({
18134
18189
  }
18135
18190
  }
18136
18191
  })(),
18137
- children: linkedinFetchLoading ? /* @__PURE__ */ jsxs55(Fragment16, { children: [
18192
+ children: linkedinFetchLoading ? /* @__PURE__ */ jsxs55(Fragment17, { children: [
18138
18193
  /* @__PURE__ */ jsx66(Loader25, { className: "h-3.5 w-3.5 animate-spin" }),
18139
18194
  "Fetching\u2026"
18140
18195
  ] }) : "Fetch pages"
@@ -18287,7 +18342,7 @@ function PluginSettingsPanel({
18287
18342
  await persistMetaFacebookPageId(fr.selectedPageId);
18288
18343
  }
18289
18344
  })(),
18290
- children: fbFetchLoading ? /* @__PURE__ */ jsxs55(Fragment16, { children: [
18345
+ children: fbFetchLoading ? /* @__PURE__ */ jsxs55(Fragment17, { children: [
18291
18346
  /* @__PURE__ */ jsx66(Loader25, { className: "h-3.5 w-3.5 animate-spin" }),
18292
18347
  "Fetching\u2026"
18293
18348
  ] }) : "Fetch managed pages"
@@ -18348,7 +18403,7 @@ function PluginSettingsPanel({
18348
18403
  ),
18349
18404
  /* @__PURE__ */ jsx66("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: "Only paste code from sources you trust." })
18350
18405
  ] }),
18351
- chatMode === "llm" && /* @__PURE__ */ jsxs55(Fragment16, { children: [
18406
+ chatMode === "llm" && /* @__PURE__ */ jsxs55(Fragment17, { children: [
18352
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: [
18353
18408
  /* @__PURE__ */ jsxs55(
18354
18409
  "button",
@@ -18375,7 +18430,7 @@ function PluginSettingsPanel({
18375
18430
  }
18376
18431
  )
18377
18432
  ] }),
18378
- llmConfigTab === "chat" ? /* @__PURE__ */ jsxs55(Fragment16, { children: [
18433
+ llmConfigTab === "chat" ? /* @__PURE__ */ jsxs55(Fragment17, { children: [
18379
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: [
18380
18435
  /* @__PURE__ */ jsx66("p", { className: "text-sm font-medium text-gray-900 dark:text-white", children: "Widget on your site" }),
18381
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." }),
@@ -18479,7 +18534,7 @@ function PluginSettingsPanel({
18479
18534
  agentLoading ? /* @__PURE__ */ jsxs55("div", { className: "flex items-center gap-2 text-sm text-gray-500", children: [
18480
18535
  /* @__PURE__ */ jsx66(Loader25, { className: "h-4 w-4 animate-spin" }),
18481
18536
  "Loading\u2026"
18482
- ] }) : /* @__PURE__ */ jsxs55(Fragment16, { children: [
18537
+ ] }) : /* @__PURE__ */ jsxs55(Fragment17, { children: [
18483
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,
18484
18539
  /* @__PURE__ */ jsxs55("div", { className: "space-y-1", children: [
18485
18540
  /* @__PURE__ */ jsx66(Label3, { htmlFor: "agent-system", className: "text-sm", children: "System instruction" }),
@@ -18562,7 +18617,7 @@ function PluginSettingsPanel({
18562
18617
  children: agentSaving ? /* @__PURE__ */ jsxs55("span", { className: "inline-flex items-center gap-1.5", children: [
18563
18618
  /* @__PURE__ */ jsx66(Loader25, { className: "h-3.5 w-3.5 animate-spin" }),
18564
18619
  "Creating\u2026"
18565
- ] }) : /* @__PURE__ */ jsxs55(Fragment16, { children: [
18620
+ ] }) : /* @__PURE__ */ jsxs55(Fragment17, { children: [
18566
18621
  /* @__PURE__ */ jsx66(Bot, { className: "h-3.5 w-3.5" }),
18567
18622
  "Create assistant"
18568
18623
  ] })
@@ -18680,7 +18735,7 @@ function PluginSettingsPanel({
18680
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: [
18681
18736
  /* @__PURE__ */ jsx66(Loader25, { className: "h-4 w-4 animate-spin" }),
18682
18737
  "Loading\u2026"
18683
- ] }) : /* @__PURE__ */ jsxs55(Fragment16, { children: [
18738
+ ] }) : /* @__PURE__ */ jsxs55(Fragment17, { children: [
18684
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,
18685
18740
  /* @__PURE__ */ jsxs55("div", { className: "space-y-1", children: [
18686
18741
  /* @__PURE__ */ jsx66(Label3, { htmlFor: "notify-email-system", className: "text-sm", children: "Routing instructions" }),
@@ -18946,17 +19001,17 @@ function PluginsPage() {
18946
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: [
18947
19002
  /* @__PURE__ */ jsx66(Puzzle2, { className: "h-10 w-10 text-gray-300 dark:text-gray-600" }),
18948
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." })
18949
- ] }) : /* @__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: [
18950
19005
  /* @__PURE__ */ jsxs55("h2", { className: "text-sm font-medium text-gray-700 dark:text-gray-300 mb-1", children: [
18951
19006
  selectedDescriptor.label || selectedDescriptor.name,
18952
19007
  " \u2014 RSS preview"
18953
19008
  ] }),
18954
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)." }),
18955
19010
  /* @__PURE__ */ jsx66(BlogGeneratorRssTool, { variant: "embedded", inputIdPrefix: "admin-plugins-blog-gen" })
18956
- ] }) : selectedDescriptor?.name === "pg_boss" ? /* @__PURE__ */ jsxs55(Fragment16, { children: [
19011
+ ] }) : selectedDescriptor?.name === "pg_boss" ? /* @__PURE__ */ jsxs55(Fragment17, { children: [
18957
19012
  /* @__PURE__ */ jsx66("h2", { className: "text-sm font-medium text-gray-700 dark:text-gray-300 mb-1", children: selectedDescriptor.label || selectedDescriptor.name }),
18958
19013
  /* @__PURE__ */ jsx66(JobSchedulesTool, { variant: "embedded", inputIdPrefix: "admin-plugins-pg-boss" })
18959
- ] }) : selectedDescriptor?.settingsGroup ? /* @__PURE__ */ jsxs55(Fragment16, { children: [
19014
+ ] }) : selectedDescriptor?.settingsGroup ? /* @__PURE__ */ jsxs55(Fragment17, { children: [
18960
19015
  /* @__PURE__ */ jsxs55("h2", { className: "text-sm font-medium text-gray-700 dark:text-gray-300 mb-4", children: [
18961
19016
  selectedDescriptor.label || selectedDescriptor.name,
18962
19017
  " \u2014 Configuration"
@@ -19073,7 +19128,7 @@ async function fetchSeo(seoId) {
19073
19128
  // src/admin/pages/BrandEditPage.tsx
19074
19129
  init_DetailPageLayout();
19075
19130
  init_DetailPageHeader();
19076
- 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";
19077
19132
  var isCreate = (id) => id === "create";
19078
19133
  function BrandEditPage({ brandId }) {
19079
19134
  const router = useRouter14();
@@ -19206,7 +19261,7 @@ function BrandEditPage({ brandId }) {
19206
19261
  /* @__PURE__ */ jsx68(
19207
19262
  DetailPageLayout,
19208
19263
  {
19209
- main: /* @__PURE__ */ jsxs57(Fragment17, { children: [
19264
+ main: /* @__PURE__ */ jsxs57(Fragment18, { children: [
19210
19265
  /* @__PURE__ */ jsxs57("section", { children: [
19211
19266
  /* @__PURE__ */ jsx68("h2", { className: "text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2", children: "Basic info" }),
19212
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: [
@@ -19279,7 +19334,7 @@ function BrandEditPage({ brandId }) {
19279
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 })) }) })
19280
19335
  ] })
19281
19336
  ] }),
19282
- sidebar: /* @__PURE__ */ jsx68(Fragment17, { children: /* @__PURE__ */ jsxs57("section", { children: [
19337
+ sidebar: /* @__PURE__ */ jsx68(Fragment18, { children: /* @__PURE__ */ jsxs57("section", { children: [
19283
19338
  /* @__PURE__ */ jsx68("h2", { className: "text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2", children: "Status" }),
19284
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: [
19285
19340
  /* @__PURE__ */ jsx68(
@@ -19449,7 +19504,7 @@ function AttributeFacetNameInput({
19449
19504
  }
19450
19505
 
19451
19506
  // src/admin/pages/ProductEditPage.tsx
19452
- 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";
19453
19508
  var isCreate2 = (id) => id === "create";
19454
19509
  var sectionCls = "min-w-0 overflow-hidden border border-gray-200 rounded-lg p-4 bg-gray-50/50";
19455
19510
  var labelCls = "block text-xs font-medium text-gray-600 mb-1";
@@ -19983,7 +20038,7 @@ function ProductEditPage({ productId }) {
19983
20038
  /* @__PURE__ */ jsx70(
19984
20039
  DetailPageLayout,
19985
20040
  {
19986
- main: /* @__PURE__ */ jsxs59(Fragment18, { children: [
20041
+ main: /* @__PURE__ */ jsxs59(Fragment19, { children: [
19987
20042
  /* @__PURE__ */ jsxs59("section", { children: [
19988
20043
  /* @__PURE__ */ jsx70("h2", { className: "text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2", children: "Product details" }),
19989
20044
  /* @__PURE__ */ jsxs59("div", { className: `${sectionCls} space-y-4`, children: [
@@ -20336,7 +20391,7 @@ import { useRouter as useRouter16, useSearchParams as useSearchParams16 } from "
20336
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";
20337
20392
  init_DetailPageLayout();
20338
20393
  init_DetailPageHeader();
20339
- 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";
20340
20395
  var isCreate3 = (id) => id === "create";
20341
20396
  var emptySlide = () => ({ url: "", type: "image", caption: "" });
20342
20397
  var emptyVariant = () => ({ name: "", price: "", extraSpecs: [] });
@@ -20581,7 +20636,7 @@ function CollectionEditPage({ collectionId }) {
20581
20636
  /* @__PURE__ */ jsx71(
20582
20637
  DetailPageLayout,
20583
20638
  {
20584
- main: /* @__PURE__ */ jsxs60(Fragment19, { children: [
20639
+ main: /* @__PURE__ */ jsxs60(Fragment20, { children: [
20585
20640
  /* @__PURE__ */ jsxs60("section", { children: [
20586
20641
  /* @__PURE__ */ jsx71("h2", { className: "text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2", children: "Basic info" }),
20587
20642
  /* @__PURE__ */ jsxs60("div", { className: `${sectionCls2} space-y-4`, children: [
@@ -20701,7 +20756,7 @@ function CollectionEditPage({ collectionId }) {
20701
20756
  ] })
20702
20757
  ] })
20703
20758
  ] }),
20704
- sidebar: /* @__PURE__ */ jsxs60(Fragment19, { children: [
20759
+ sidebar: /* @__PURE__ */ jsxs60(Fragment20, { children: [
20705
20760
  /* @__PURE__ */ jsxs60("section", { children: [
20706
20761
  /* @__PURE__ */ jsx71("h2", { className: "text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2", children: "Status" }),
20707
20762
  /* @__PURE__ */ jsx71("div", { className: sectionCls2, children: /* @__PURE__ */ jsxs60("label", { className: "flex items-center gap-2 cursor-pointer", children: [
@@ -21067,10 +21122,14 @@ function SchedulesPage() {
21067
21122
 
21068
21123
  // src/admin/pages/VendorOnboardPage.tsx
21069
21124
  init_vendor_scope();
21070
- init_button();
21071
- init_input();
21072
21125
  import { useState as useState43 } from "react";
21126
+ import { useRouter as useRouter18 } from "next/navigation";
21073
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();
21074
21133
 
21075
21134
  // src/components/ui/radio-group.tsx
21076
21135
  init_utils();
@@ -21106,11 +21165,40 @@ var RadioGroupItem = React22.forwardRef(({ className, ...props }, ref) => {
21106
21165
  RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName;
21107
21166
 
21108
21167
  // src/admin/pages/VendorOnboardPage.tsx
21109
- import { Fragment as Fragment20, jsx as jsx76, jsxs as jsxs63 } from "react/jsx-runtime";
21110
- function VendorOnboardPage() {
21111
- const { data: session } = useSession9();
21112
- const sessionUser = session?.user;
21113
- 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 }) {
21114
21202
  const [vendorName, setVendorName] = useState43("");
21115
21203
  const [vendorSlug, setVendorSlug] = useState43("");
21116
21204
  const [vendorEmail, setVendorEmail] = useState43("");
@@ -21118,44 +21206,31 @@ function VendorOnboardPage() {
21118
21206
  const [ownerName, setOwnerName] = useState43("");
21119
21207
  const [ownerEmail, setOwnerEmail] = useState43("");
21120
21208
  const [activationMode, setActivationMode] = useState43("invite");
21121
- const [sendInviteEmail, setSendInviteEmail] = useState43(true);
21209
+ const [sendOwnerEmail, setSendOwnerEmail] = useState43(true);
21122
21210
  const [ownerPassword, setOwnerPassword] = useState43("");
21123
21211
  const [ownerPasswordConfirm, setOwnerPasswordConfirm] = useState43("");
21124
21212
  const [loading, setLoading] = useState43(false);
21125
21213
  const [message, setMessage] = useState43(null);
21126
21214
  const [inviteLink, setInviteLink] = useState43(null);
21127
- const [error, setError] = useState43(null);
21128
- if (!isAdmin) {
21129
- return /* @__PURE__ */ jsx76("div", { className: "p-6 max-w-lg", children: /* @__PURE__ */ jsxs63("p", { className: "text-sm text-red-600", children: [
21130
- "Only users in the ",
21131
- /* @__PURE__ */ jsx76("strong", { children: "Administrator" }),
21132
- " group can onboard vendors.",
21133
- sessionUser?.groupName ? /* @__PURE__ */ jsxs63(Fragment20, { children: [
21134
- " Your group is ",
21135
- /* @__PURE__ */ jsx76("strong", { children: sessionUser.groupName }),
21136
- ". Assign Administrator under System \u2192 Users, then sign out and sign in again."
21137
- ] }) : /* @__PURE__ */ jsx76(Fragment20, { children: " Assign the Administrator group under System \u2192 Users, then sign out and sign in again." })
21138
- ] }) });
21139
- }
21140
- const handleSubmit = async (e) => {
21141
- e.preventDefault();
21215
+ const [errors, setErrors] = useState43([]);
21216
+ const handleSubmit = async () => {
21142
21217
  setLoading(true);
21143
21218
  setMessage(null);
21144
- setError(null);
21219
+ setErrors([]);
21145
21220
  setInviteLink(null);
21146
21221
  if (activationMode === "password") {
21147
21222
  if (!ownerPassword) {
21148
- setError("Enter a password for the owner account");
21223
+ setErrors(["Enter a password for the owner account"]);
21149
21224
  setLoading(false);
21150
21225
  return;
21151
21226
  }
21152
21227
  if (ownerPassword !== ownerPasswordConfirm) {
21153
- setError("Passwords do not match");
21228
+ setErrors(["Passwords do not match"]);
21154
21229
  setLoading(false);
21155
21230
  return;
21156
21231
  }
21157
21232
  if (ownerPassword.length < 6) {
21158
- setError("Password must be at least 6 characters");
21233
+ setErrors(["Password must be at least 6 characters"]);
21159
21234
  setLoading(false);
21160
21235
  return;
21161
21236
  }
@@ -21166,7 +21241,7 @@ function VendorOnboardPage() {
21166
21241
  headers: { "Content-Type": "application/json" },
21167
21242
  body: JSON.stringify({
21168
21243
  activation: activationMode,
21169
- sendInviteEmail: activationMode === "invite" ? sendInviteEmail : false,
21244
+ sendOwnerEmail,
21170
21245
  vendor: {
21171
21246
  name: vendorName,
21172
21247
  slug: vendorSlug || void 0,
@@ -21183,140 +21258,241 @@ function VendorOnboardPage() {
21183
21258
  });
21184
21259
  const data = await res.json();
21185
21260
  if (!res.ok) {
21186
- setError(data.error || "Onboarding failed");
21261
+ setErrors([data.error || "Onboarding failed"]);
21187
21262
  return;
21188
21263
  }
21189
21264
  setMessage(data.message || "Vendor created");
21190
21265
  setInviteLink(data.inviteLink ?? null);
21191
- setVendorName("");
21192
- setVendorSlug("");
21193
- setVendorEmail("");
21194
- setVendorPhone("");
21195
- setOwnerName("");
21196
- setOwnerEmail("");
21197
- setOwnerPassword("");
21198
- setOwnerPasswordConfirm("");
21266
+ if (!data.inviteLink) {
21267
+ onSuccess();
21268
+ }
21199
21269
  } catch {
21200
- setError("Request failed");
21270
+ setErrors(["Request failed"]);
21201
21271
  } finally {
21202
21272
  setLoading(false);
21203
21273
  }
21204
21274
  };
21205
- const submitLabel = activationMode === "password" ? "Create vendor & set password" : sendInviteEmail ? "Create vendor & send invite" : "Create vendor & copy invite link";
21206
- return /* @__PURE__ */ jsxs63("div", { className: "p-6 max-w-xl", children: [
21207
- /* @__PURE__ */ jsx76("h1", { className: "text-xl font-semibold text-gray-900 dark:text-white", children: "Onboard vendor" }),
21208
- /* @__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." }),
21209
- /* @__PURE__ */ jsxs63("form", { onSubmit: handleSubmit, className: "mt-6 space-y-6", children: [
21210
- /* @__PURE__ */ jsxs63("div", { className: "space-y-3", children: [
21211
- /* @__PURE__ */ jsx76("h2", { className: "text-sm font-medium text-gray-900 dark:text-white", children: "Store" }),
21212
- /* @__PURE__ */ jsxs63("div", { children: [
21213
- /* @__PURE__ */ jsx76(Label3, { htmlFor: "vendorName", children: "Store name" }),
21214
- /* @__PURE__ */ jsx76(Input, { id: "vendorName", required: true, value: vendorName, onChange: (e) => setVendorName(e.target.value), className: "mt-1" })
21215
- ] }),
21216
- /* @__PURE__ */ jsxs63("div", { children: [
21217
- /* @__PURE__ */ jsx76(Label3, { htmlFor: "vendorSlug", children: "Slug (optional)" }),
21218
- /* @__PURE__ */ jsx76(Input, { id: "vendorSlug", value: vendorSlug, onChange: (e) => setVendorSlug(e.target.value), placeholder: "auto from name", className: "mt-1" })
21219
- ] }),
21220
- /* @__PURE__ */ jsxs63("div", { children: [
21221
- /* @__PURE__ */ jsx76(Label3, { htmlFor: "vendorEmail", children: "Store email" }),
21222
- /* @__PURE__ */ jsx76(Input, { id: "vendorEmail", type: "email", value: vendorEmail, onChange: (e) => setVendorEmail(e.target.value), className: "mt-1" })
21223
- ] }),
21224
- /* @__PURE__ */ jsxs63("div", { children: [
21225
- /* @__PURE__ */ jsx76(Label3, { htmlFor: "vendorPhone", children: "Phone" }),
21226
- /* @__PURE__ */ jsx76(Input, { id: "vendorPhone", value: vendorPhone, onChange: (e) => setVendorPhone(e.target.value), className: "mt-1" })
21227
- ] })
21228
- ] }),
21229
- /* @__PURE__ */ jsxs63("div", { className: "space-y-3", children: [
21230
- /* @__PURE__ */ jsx76("h2", { className: "text-sm font-medium text-gray-900 dark:text-white", children: "Owner account" }),
21231
- /* @__PURE__ */ jsxs63("div", { children: [
21232
- /* @__PURE__ */ jsx76(Label3, { htmlFor: "ownerName", children: "Name" }),
21233
- /* @__PURE__ */ jsx76(Input, { id: "ownerName", required: true, value: ownerName, onChange: (e) => setOwnerName(e.target.value), className: "mt-1" })
21234
- ] }),
21235
- /* @__PURE__ */ jsxs63("div", { children: [
21236
- /* @__PURE__ */ jsx76(Label3, { htmlFor: "ownerEmail", children: "Email" }),
21237
- /* @__PURE__ */ jsx76(Input, { id: "ownerEmail", type: "email", required: true, value: ownerEmail, onChange: (e) => setOwnerEmail(e.target.value), className: "mt-1" })
21238
- ] })
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 })
21239
21300
  ] }),
21240
- /* @__PURE__ */ jsxs63("div", { className: "space-y-3 rounded-lg border border-gray-200 p-4", children: [
21241
- /* @__PURE__ */ jsx76("h2", { className: "text-sm font-medium text-gray-900 dark:text-white", children: "Owner access" }),
21242
- /* @__PURE__ */ jsxs63(
21243
- RadioGroup2,
21244
- {
21245
- value: activationMode,
21246
- onValueChange: (v) => setActivationMode(v),
21247
- className: "gap-3",
21248
- children: [
21249
- /* @__PURE__ */ jsxs63("div", { className: "flex items-start gap-2", children: [
21250
- /* @__PURE__ */ jsx76(RadioGroupItem, { value: "invite", id: "activation-invite", className: "mt-0.5" }),
21251
- /* @__PURE__ */ jsxs63("div", { children: [
21252
- /* @__PURE__ */ jsx76(Label3, { htmlFor: "activation-invite", className: "font-normal cursor-pointer", children: "Send invite link" }),
21253
- /* @__PURE__ */ jsx76("p", { className: "text-xs text-gray-500 mt-0.5", children: "Owner sets their own password via email or the link below." })
21254
- ] })
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
+ )
21255
21322
  ] }),
21256
- /* @__PURE__ */ jsxs63("div", { className: "flex items-start gap-2", children: [
21257
- /* @__PURE__ */ jsx76(RadioGroupItem, { value: "password", id: "activation-password", className: "mt-0.5" }),
21258
- /* @__PURE__ */ jsxs63("div", { children: [
21259
- /* @__PURE__ */ jsx76(Label3, { htmlFor: "activation-password", className: "font-normal cursor-pointer", children: "Set password now" }),
21260
- /* @__PURE__ */ jsx76("p", { className: "text-xs text-gray-500 mt-0.5", children: "Account is active immediately; share the password with the owner securely." })
21261
- ] })
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
+ )
21262
21360
  ] })
21263
- ]
21264
- }
21265
- ),
21266
- activationMode === "invite" && /* @__PURE__ */ jsxs63("div", { className: "flex items-center gap-2 pt-1", children: [
21267
- /* @__PURE__ */ jsx76(
21268
- Checkbox,
21269
- {
21270
- id: "sendInviteEmail",
21271
- checked: sendInviteEmail,
21272
- onCheckedChange: (checked) => setSendInviteEmail(checked === true)
21273
- }
21274
- ),
21275
- /* @__PURE__ */ jsx76(Label3, { htmlFor: "sendInviteEmail", className: "font-normal cursor-pointer text-sm", children: "Send invite email to owner" })
21276
- ] }),
21277
- activationMode === "password" && /* @__PURE__ */ jsxs63("div", { className: "space-y-3 pt-1", children: [
21278
- /* @__PURE__ */ jsxs63("div", { children: [
21279
- /* @__PURE__ */ jsx76(Label3, { htmlFor: "ownerPassword", children: "Password" }),
21280
- /* @__PURE__ */ jsx76(
21281
- Input,
21282
- {
21283
- id: "ownerPassword",
21284
- type: "password",
21285
- required: true,
21286
- autoComplete: "new-password",
21287
- value: ownerPassword,
21288
- onChange: (e) => setOwnerPassword(e.target.value),
21289
- className: "mt-1"
21290
- }
21291
- )
21361
+ ] })
21292
21362
  ] }),
21293
- /* @__PURE__ */ jsxs63("div", { children: [
21294
- /* @__PURE__ */ jsx76(Label3, { htmlFor: "ownerPasswordConfirm", children: "Confirm password" }),
21295
- /* @__PURE__ */ jsx76(
21296
- 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,
21297
21401
  {
21298
- id: "ownerPasswordConfirm",
21299
- type: "password",
21300
- required: true,
21301
- autoComplete: "new-password",
21302
- value: ownerPasswordConfirm,
21303
- onChange: (e) => setOwnerPasswordConfirm(e.target.value),
21304
- 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
+ ]
21305
21421
  }
21306
- )
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 })
21307
21467
  ] })
21308
21468
  ] })
21309
- ] }),
21310
- error && /* @__PURE__ */ jsx76("p", { className: "text-sm text-red-600", children: error }),
21311
- message && /* @__PURE__ */ jsx76("p", { className: "text-sm text-green-700", children: message }),
21312
- inviteLink && /* @__PURE__ */ jsxs63("p", { className: "text-xs text-gray-600 break-all", children: [
21313
- "Invite link: ",
21314
- /* @__PURE__ */ jsx76("a", { href: inviteLink, className: "text-blue-600 underline", children: inviteLink })
21315
- ] }),
21316
- /* @__PURE__ */ jsx76(Button, { type: "submit", disabled: loading, children: loading ? "Creating\u2026" : submitLabel })
21317
- ] })
21469
+ }
21470
+ )
21318
21471
  ] });
21319
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
+ }
21320
21496
 
21321
21497
  // src/admin/pages/VendorTeamPage.tsx
21322
21498
  init_button();
@@ -21834,9 +22010,9 @@ init_DetailPageLayout();
21834
22010
  init_DetailPageHeader();
21835
22011
  import { useEffect as useEffect42, useState as useState45 } from "react";
21836
22012
  import Link14 from "next/link";
21837
- import { useRouter as useRouter18, useSearchParams as useSearchParams17 } from "next/navigation";
22013
+ import { useRouter as useRouter19, useSearchParams as useSearchParams17 } from "next/navigation";
21838
22014
  import { X as X21, Pencil as Pencil3, ChevronDown as ChevronDown7, ChevronRight as ChevronRight6, Zap as Zap2 } from "lucide-react";
21839
- 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";
21840
22016
  function statusBadge2(status) {
21841
22017
  const map = {
21842
22018
  ACTIVE: "bg-green-100 text-green-800",
@@ -21913,7 +22089,7 @@ function RuleTreeNode({ node, depth = 0 }) {
21913
22089
  const borderColor = depth % 2 === 0 ? "border-blue-200" : "border-purple-200";
21914
22090
  const bgColor = depth % 2 === 0 ? "bg-blue-50/30" : "bg-purple-50/30";
21915
22091
  return /* @__PURE__ */ jsxs65("div", { className: `border rounded-lg p-3 ${borderColor} ${bgColor}`, children: [
21916
- /* @__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: [
21917
22093
  /* @__PURE__ */ jsx78(
21918
22094
  "button",
21919
22095
  {
@@ -21925,7 +22101,7 @@ function RuleTreeNode({ node, depth = 0 }) {
21925
22101
  ),
21926
22102
  /* @__PURE__ */ jsx78("span", { className: "font-semibold text-xs uppercase text-gray-500", children: "Group" }),
21927
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() })
21928
- ] }) : /* @__PURE__ */ jsxs65(Fragment21, { children: [
22104
+ ] }) : /* @__PURE__ */ jsxs65(Fragment22, { children: [
21929
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 }),
21930
22106
  node.subType && /* @__PURE__ */ jsx78("span", { className: "text-gray-400 text-xs", children: node.subType }),
21931
22107
  node.comparisonOperator && /* @__PURE__ */ jsx78("span", { className: "font-mono text-xs font-semibold text-gray-700", children: node.comparisonOperator }),
@@ -21935,7 +22111,7 @@ function RuleTreeNode({ node, depth = 0 }) {
21935
22111
  ] });
21936
22112
  }
21937
22113
  function DiscountDetailPage({ discountId }) {
21938
- const router = useRouter18();
22114
+ const router = useRouter19();
21939
22115
  const searchParams = useSearchParams17();
21940
22116
  const listReturnUrl = safeAdminListReturnUrl(searchParams.get("from")) ?? "/admin/discounts";
21941
22117
  const [discount, setDiscount] = useState45(null);
@@ -22020,7 +22196,7 @@ function DiscountDetailPage({ discountId }) {
22020
22196
  /* @__PURE__ */ jsx78(
22021
22197
  DetailPageLayout,
22022
22198
  {
22023
- main: /* @__PURE__ */ jsxs65(Fragment21, { children: [
22199
+ main: /* @__PURE__ */ jsxs65(Fragment22, { children: [
22024
22200
  /* @__PURE__ */ jsxs65("section", { children: [
22025
22201
  /* @__PURE__ */ jsx78("h2", { className: "text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2", children: "Discount details" }),
22026
22202
  /* @__PURE__ */ jsxs65("div", { className: "border border-gray-200 rounded-lg p-4 bg-gray-50/50", children: [
@@ -22095,7 +22271,7 @@ function DiscountDetailPage({ discountId }) {
22095
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)) })
22096
22272
  ] })
22097
22273
  ] }),
22098
- sidebar: /* @__PURE__ */ jsxs65(Fragment21, { children: [
22274
+ sidebar: /* @__PURE__ */ jsxs65(Fragment22, { children: [
22099
22275
  /* @__PURE__ */ jsxs65("section", { children: [
22100
22276
  /* @__PURE__ */ jsx78("h2", { className: "text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2", children: "Usage" }),
22101
22277
  /* @__PURE__ */ jsxs65("div", { className: "border border-gray-200 rounded-lg p-4 bg-gray-50/50 space-y-3 text-sm", children: [
@@ -22167,8 +22343,8 @@ init_admin_list_return_url();
22167
22343
  init_DetailPageLayout();
22168
22344
  init_DetailPageHeader();
22169
22345
  import { useState as useState47, useEffect as useEffect44 } from "react";
22170
- import { useRouter as useRouter19, useSearchParams as useSearchParams18 } from "next/navigation";
22171
- 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";
22172
22348
 
22173
22349
  // src/admin/pages/DiscountsConditionsBuilder.tsx
22174
22350
  init_button();
@@ -22958,7 +23134,7 @@ function DiscountConditionsBuilder({
22958
23134
  }
22959
23135
 
22960
23136
  // src/admin/pages/DiscountEditPage.tsx
22961
- 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";
22962
23138
  function uid2() {
22963
23139
  return Math.random().toString(36).slice(2, 10);
22964
23140
  }
@@ -23026,7 +23202,7 @@ function useConvertedValue2(value, fromCurrency, toCurrency, discountType) {
23026
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";
23027
23203
  var isCreate4 = (id) => id === "create";
23028
23204
  function DiscountEditPage({ discountId }) {
23029
- const router = useRouter19();
23205
+ const router = useRouter20();
23030
23206
  const searchParams = useSearchParams18();
23031
23207
  const listReturnUrl = safeAdminListReturnUrl(searchParams.get("from")) ?? "/admin/discounts";
23032
23208
  const create = isCreate4(discountId);
@@ -23188,12 +23364,12 @@ function DiscountEditPage({ discountId }) {
23188
23364
  subtitle: create ? "Create a new discount coupon" : `Editing: ${couponCode || discountId}`,
23189
23365
  closeHref: listReturnUrl,
23190
23366
  menuItems: [
23191
- { label: saving ? "Saving..." : "Save", icon: Save11, onClick: handleSave }
23367
+ { label: saving ? "Saving..." : "Save", icon: Save12, onClick: handleSave }
23192
23368
  ]
23193
23369
  }
23194
23370
  ),
23195
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: [
23196
- /* @__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" }),
23197
23373
  /* @__PURE__ */ jsxs67("div", { className: "ml-3", children: [
23198
23374
  /* @__PURE__ */ jsx80("h3", { className: "text-sm font-medium text-red-800", children: "Please fix the following errors:" }),
23199
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)) })
@@ -23202,7 +23378,7 @@ function DiscountEditPage({ discountId }) {
23202
23378
  /* @__PURE__ */ jsx80(
23203
23379
  DetailPageLayout,
23204
23380
  {
23205
- main: /* @__PURE__ */ jsxs67(Fragment22, { children: [
23381
+ main: /* @__PURE__ */ jsxs67(Fragment23, { children: [
23206
23382
  /* @__PURE__ */ jsxs67("section", { children: [
23207
23383
  /* @__PURE__ */ jsx80("h2", { className: "text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2", children: "Basic info" }),
23208
23384
  /* @__PURE__ */ jsxs67("div", { className: "border border-gray-200 rounded-lg p-4 bg-gray-50/50 space-y-4", children: [
@@ -23430,7 +23606,7 @@ function DiscountEditPage({ discountId }) {
23430
23606
  ) })
23431
23607
  ] })
23432
23608
  ] }),
23433
- sidebar: /* @__PURE__ */ jsxs67(Fragment22, { children: [
23609
+ sidebar: /* @__PURE__ */ jsxs67(Fragment23, { children: [
23434
23610
  /* @__PURE__ */ jsxs67("section", { children: [
23435
23611
  /* @__PURE__ */ jsx80("h2", { className: "text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2", children: "Status" }),
23436
23612
  /* @__PURE__ */ jsxs67("div", { className: "border border-gray-200 rounded-lg p-4 bg-gray-50/50 space-y-3", children: [
@@ -23467,7 +23643,7 @@ function DiscountEditPage({ discountId }) {
23467
23643
  value && !isNaN(Number(value)) && /* @__PURE__ */ jsxs67("section", { children: [
23468
23644
  /* @__PURE__ */ jsx80("h2", { className: "text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2", children: "Preview" }),
23469
23645
  /* @__PURE__ */ jsxs67("div", { className: "border border-gray-200 rounded-lg p-4 bg-gray-50/50 space-y-1 text-sm", children: [
23470
- !isAutomatic && /* @__PURE__ */ jsxs67(Fragment22, { children: [
23646
+ !isAutomatic && /* @__PURE__ */ jsxs67(Fragment23, { children: [
23471
23647
  /* @__PURE__ */ jsx80("p", { className: "text-gray-500", children: "Code" }),
23472
23648
  /* @__PURE__ */ jsx80("p", { className: "font-mono font-semibold text-gray-900", children: couponCode || "\u2014" })
23473
23649
  ] }),
@@ -23508,7 +23684,6 @@ var PAGE_MAP = {
23508
23684
  roles: RolesPage,
23509
23685
  "blog-generator": BlogGeneratorPage,
23510
23686
  schedules: SchedulesPage,
23511
- "vendor-onboard": VendorOnboardPage,
23512
23687
  "vendor-team": VendorTeamPage
23513
23688
  };
23514
23689
  var CRUD_CONFIGS = {
@@ -23664,7 +23839,7 @@ function BlogEditorWrapper({
23664
23839
  );
23665
23840
  }
23666
23841
  function AdminPageResolver({ slug }) {
23667
- const router = useRouter21();
23842
+ const router = useRouter22();
23668
23843
  const searchParams = useSearchParams20();
23669
23844
  const { customCrudConfigs, storeEnabled } = useContext9(AdminConfigContext);
23670
23845
  const key = slug?.[0] || "dashboard";
@@ -23708,6 +23883,10 @@ function AdminPageResolver({ slug }) {
23708
23883
  /* @__PURE__ */ jsx83("span", { className: "ml-2", children: "Opening Plugins\u2026" })
23709
23884
  ] });
23710
23885
  }
23886
+ if (key === "vendor-onboard") {
23887
+ const sub = slug?.[1];
23888
+ return /* @__PURE__ */ jsx83(VendorOnboardPage, { showCreateForm: sub === "create" });
23889
+ }
23711
23890
  const Page = PAGE_MAP[key];
23712
23891
  if (Page) {
23713
23892
  return /* @__PURE__ */ jsx83(Page, {});
@@ -23798,7 +23977,7 @@ function AdminPageResolver({ slug }) {
23798
23977
  // src/admin/pages/LayoutSettingsPage.tsx
23799
23978
  init_button();
23800
23979
  import { useState as useState51, useEffect as useEffect48, useContext as useContext10 } from "react";
23801
- import { Save as Save12 } from "lucide-react";
23980
+ import { Save as Save13 } from "lucide-react";
23802
23981
  import { jsx as jsx84, jsxs as jsxs71 } from "react/jsx-runtime";
23803
23982
  function LayoutSettingsPage() {
23804
23983
  const { theme } = useContext10(AdminConfigContext);
@@ -23870,7 +24049,7 @@ function LayoutSettingsPage() {
23870
24049
  disabled: saving,
23871
24050
  className: "bg-white text-gray-800 hover:bg-gray-100 border-0 text-xs",
23872
24051
  children: [
23873
- /* @__PURE__ */ jsx84(Save12, { className: "h-4 w-4 mr-2" }),
24052
+ /* @__PURE__ */ jsx84(Save13, { className: "h-4 w-4 mr-2" }),
23874
24053
  saving ? "Saving..." : "Save"
23875
24054
  ]
23876
24055
  }