@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.cjs CHANGED
@@ -122,6 +122,30 @@ var init_permission_entities = __esm({
122
122
  }
123
123
  });
124
124
 
125
+ // src/auth/role-helpers.ts
126
+ function isSuperAdmin(user) {
127
+ if (!user) return false;
128
+ if (user.groupId === SUPER_ADMIN_GROUP_ID) return true;
129
+ if (user.isRBACAdmin === true) return true;
130
+ return isSuperAdminGroupName(user.groupName);
131
+ }
132
+ function isVendorAdmin(user) {
133
+ if (!user?.email || isSuperAdmin(user)) return false;
134
+ if (user.groupId === VENDOR_ADMIN_GROUP_ID) return true;
135
+ if ((user.vendorIds?.length ?? 0) > 0) return true;
136
+ return isVendorGroupName(user.groupName);
137
+ }
138
+ var SUPER_ADMIN_GROUP_ID, VENDOR_ADMIN_GROUP_ID;
139
+ var init_role_helpers = __esm({
140
+ "src/auth/role-helpers.ts"() {
141
+ "use strict";
142
+ init_permission_entities();
143
+ init_vendor_scope();
144
+ SUPER_ADMIN_GROUP_ID = 1;
145
+ VENDOR_ADMIN_GROUP_ID = 5;
146
+ }
147
+ });
148
+
125
149
  // src/auth/vendor-scope.ts
126
150
  function isVendorGroupName(name) {
127
151
  if (!name?.trim()) return false;
@@ -130,12 +154,12 @@ function isVendorGroupName(name) {
130
154
  }
131
155
  function isPlatformAdministrator(user) {
132
156
  if (!user?.email) return false;
133
- return !!(user.isRBACAdmin || isSuperAdminGroupName(user.groupName));
157
+ return isSuperAdmin(user);
134
158
  }
135
159
  function isVendorPortalUser(user) {
136
160
  if (user?.isVendorPortal === true) return true;
137
161
  if (!user?.email || isPlatformAdministrator(user)) return false;
138
- if ((user.vendorIds?.length ?? 0) > 0) return true;
162
+ if (isVendorAdmin(user)) return true;
139
163
  return isVendorGroupName(user.groupName);
140
164
  }
141
165
  function isVendorOwner(user) {
@@ -159,7 +183,7 @@ var VENDOR_SCOPED_STORE_ENTITIES, VENDOR_STORE_RBAC_ENTITIES, VENDOR_OWNER_GROUP
159
183
  var init_vendor_scope = __esm({
160
184
  "src/auth/vendor-scope.ts"() {
161
185
  "use strict";
162
- init_permission_entities();
186
+ init_role_helpers();
163
187
  VENDOR_SCOPED_STORE_ENTITIES = /* @__PURE__ */ new Set([
164
188
  "products",
165
189
  "collections",
@@ -821,8 +845,8 @@ function RequiredMark() {
821
845
  ] });
822
846
  }
823
847
  function ContactDetailPage({ contactId }) {
824
- const router = (0, import_navigation29.useRouter)();
825
- const searchParams = (0, import_navigation29.useSearchParams)();
848
+ const router = (0, import_navigation30.useRouter)();
849
+ const searchParams = (0, import_navigation30.useSearchParams)();
826
850
  const listReturnUrl = safeAdminListReturnUrl(searchParams.get("from")) ?? "/admin/contacts";
827
851
  const [contact, setContact] = (0, import_react67.useState)(null);
828
852
  const [loading, setLoading] = (0, import_react67.useState)(true);
@@ -940,7 +964,7 @@ function ContactDetailPage({ contactId }) {
940
964
  return /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)("div", { className: "rounded-lg bg-white p-6 shadow-md", children: [
941
965
  /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("p", { className: "text-red-600", children: error ?? "Not found" }),
942
966
  /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(import_link15.default, { href: listReturnUrl, children: /* @__PURE__ */ (0, import_jsx_runtime82.jsxs)(Button, { variant: "outline", className: "mt-4", children: [
943
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(import_lucide_react49.X, { className: "h-4 w-4 mr-2" }),
967
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(import_lucide_react50.X, { className: "h-4 w-4 mr-2" }),
944
968
  "Close"
945
969
  ] }) })
946
970
  ] });
@@ -1017,7 +1041,7 @@ function ContactDetailPage({ contactId }) {
1017
1041
  },
1018
1042
  className: "inline-flex items-center gap-1",
1019
1043
  children: [
1020
- /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(import_lucide_react49.Plus, { className: "h-3.5 w-3.5" }),
1044
+ /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(import_lucide_react50.Plus, { className: "h-3.5 w-3.5" }),
1021
1045
  " Add address"
1022
1046
  ]
1023
1047
  }
@@ -1042,7 +1066,7 @@ function ContactDetailPage({ contactId }) {
1042
1066
  title: "Delete address",
1043
1067
  "aria-label": `Delete address ${a.id}`,
1044
1068
  onClick: () => setAddressPendingDelete(a),
1045
- children: /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(import_lucide_react49.Trash2, { className: "h-4 w-4" })
1069
+ children: /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(import_lucide_react50.Trash2, { className: "h-4 w-4" })
1046
1070
  }
1047
1071
  ) })
1048
1072
  ] }, a.id)) })
@@ -1245,16 +1269,16 @@ function ContactDetailPage({ contactId }) {
1245
1269
  )
1246
1270
  ] });
1247
1271
  }
1248
- var import_react67, import_link15, import_navigation29, import_lucide_react49, import_sonner13, import_country_state_city3, import_jsx_runtime82, ADDRESS_TAGS, CONTACT_TYPE_LABELS;
1272
+ var import_react67, import_link15, import_navigation30, import_lucide_react50, import_sonner13, import_country_state_city3, import_jsx_runtime82, ADDRESS_TAGS, CONTACT_TYPE_LABELS;
1249
1273
  var init_ContactDetailPage = __esm({
1250
1274
  "src/admin/pages/ContactDetailPage.tsx"() {
1251
1275
  "use strict";
1252
1276
  "use client";
1253
1277
  import_react67 = require("react");
1254
1278
  import_link15 = __toESM(require("next/link"), 1);
1255
- import_navigation29 = require("next/navigation");
1279
+ import_navigation30 = require("next/navigation");
1256
1280
  init_admin_list_return_url();
1257
- import_lucide_react49 = require("lucide-react");
1281
+ import_lucide_react50 = require("lucide-react");
1258
1282
  import_sonner13 = require("sonner");
1259
1283
  init_button();
1260
1284
  init_input();
@@ -1594,7 +1618,7 @@ var defaultValue = {
1594
1618
  var AdminConfigContext = (0, import_react4.createContext)(defaultValue);
1595
1619
 
1596
1620
  // src/lib/cms-version.ts
1597
- var CMS_VERSION = true ? "1.0.33" : "0.0.0";
1621
+ var CMS_VERSION = true ? "1.0.34" : "0.0.0";
1598
1622
 
1599
1623
  // src/components/Admin/Sidebar.tsx
1600
1624
  var import_jsx_runtime4 = require("react/jsx-runtime");
@@ -1802,7 +1826,7 @@ function AdminSidebar({ variant = "sidebar" }) {
1802
1826
  className: `${linkCls} ${isActive("/admin/vendor-onboard") ? linkActive : linkInactive}`,
1803
1827
  children: [
1804
1828
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react3.Store, { className: `h-4 w-4 mr-2 ${isActive("/admin/vendor-onboard") ? iconActive : iconInactive}` }),
1805
- "Onboard vendor"
1829
+ "Vendors"
1806
1830
  ]
1807
1831
  }
1808
1832
  ) }),
@@ -2787,7 +2811,8 @@ function CreateEditForm({
2787
2811
  apiEndpoint,
2788
2812
  columns,
2789
2813
  existingData,
2790
- duplicateSeed
2814
+ duplicateSeed,
2815
+ resource
2791
2816
  }) {
2792
2817
  const isMobile = useIsMobile();
2793
2818
  const { currency } = (0, import_react13.useContext)(AdminConfigContext);
@@ -2795,6 +2820,9 @@ function CreateEditForm({
2795
2820
  currency: currency || "INR"
2796
2821
  });
2797
2822
  const [errors, setErrors] = (0, import_react13.useState)({});
2823
+ const [password, setPassword] = (0, import_react13.useState)("");
2824
+ const [confirmPassword, setConfirmPassword] = (0, import_react13.useState)("");
2825
+ const isCustomerCreate = resource === "vendor_customers" && !existingData;
2798
2826
  (0, import_react13.useEffect)(() => {
2799
2827
  fetch("/api/settings/store").then((res) => res.json()).then((data) => {
2800
2828
  setFormData((prev) => ({
@@ -2824,14 +2852,10 @@ function CreateEditForm({
2824
2852
  };
2825
2853
  }).filter(Boolean)
2826
2854
  );
2827
- }).catch(
2828
- (err) => console.error("Failed to load customers", err)
2829
- );
2855
+ }).catch((err) => console.error("Failed to load customers", err));
2830
2856
  }, [columns]);
2831
2857
  const handleCustomerSelect = (customerId) => {
2832
- const customer = customers.find(
2833
- (c) => String(c.id) === customerId
2834
- );
2858
+ const customer = customers.find((c) => String(c.id) === customerId);
2835
2859
  if (!customer) return;
2836
2860
  setFormData((prev) => ({
2837
2861
  ...prev,
@@ -2845,23 +2869,14 @@ function CreateEditForm({
2845
2869
  const [totalLoading, setTotalLoading] = (0, import_react13.useState)(false);
2846
2870
  (0, import_react13.useEffect)(() => {
2847
2871
  return () => {
2848
- if (debounceRef.current) {
2849
- clearTimeout(debounceRef.current);
2850
- }
2872
+ if (debounceRef.current) clearTimeout(debounceRef.current);
2851
2873
  };
2852
2874
  }, []);
2853
2875
  const recalculateTotal = (itemsSummaryValue) => {
2854
- if (debounceRef.current) {
2855
- clearTimeout(debounceRef.current);
2856
- }
2876
+ if (debounceRef.current) clearTimeout(debounceRef.current);
2857
2877
  const names = itemsSummaryValue.split(",").map((s) => s.trim()).filter(Boolean);
2858
2878
  if (names.length === 0) {
2859
- setFormData((prev) => ({
2860
- ...prev,
2861
- subtotal: "",
2862
- tax: "",
2863
- total: ""
2864
- }));
2879
+ setFormData((prev) => ({ ...prev, subtotal: "", tax: "", total: "" }));
2865
2880
  return;
2866
2881
  }
2867
2882
  debounceRef.current = setTimeout(async () => {
@@ -2869,12 +2884,8 @@ function CreateEditForm({
2869
2884
  try {
2870
2885
  const res = await fetch("/api/orders/calculate", {
2871
2886
  method: "POST",
2872
- headers: {
2873
- "Content-Type": "application/json"
2874
- },
2875
- body: JSON.stringify({
2876
- itemsSummary: itemsSummaryValue
2877
- })
2887
+ headers: { "Content-Type": "application/json" },
2888
+ body: JSON.stringify({ itemsSummary: itemsSummaryValue })
2878
2889
  });
2879
2890
  if (!res.ok) return;
2880
2891
  const data = await res.json();
@@ -2899,13 +2910,9 @@ function CreateEditForm({
2899
2910
  const path = col.field || col.key;
2900
2911
  if (!path) return;
2901
2912
  const v = getNestedValue(ex, path);
2902
- if (v !== void 0) {
2903
- merged[path] = v === null ? "" : v;
2904
- }
2913
+ if (v !== void 0) merged[path] = v === null ? "" : v;
2905
2914
  });
2906
- columns.filter(
2907
- (col) => !col.hideInForm && isDateFormColumn(col.type)
2908
- ).forEach((col) => {
2915
+ columns.filter((col) => !col.hideInForm && isDateFormColumn(col.type)).forEach((col) => {
2909
2916
  const path = col.field || col.key;
2910
2917
  if (!path) return;
2911
2918
  const raw = merged[path];
@@ -2921,9 +2928,7 @@ function CreateEditForm({
2921
2928
  ).forEach((col) => {
2922
2929
  const path = col.field || col.key;
2923
2930
  if (!path) return;
2924
- const allowed = new Set(
2925
- col.options.map((o) => String(o.value))
2926
- );
2931
+ const allowed = new Set(col.options.map((o) => String(o.value)));
2927
2932
  const raw = merged[path];
2928
2933
  if (raw != null && raw !== "" && !allowed.has(String(raw))) {
2929
2934
  merged[path] = "";
@@ -2931,6 +2936,8 @@ function CreateEditForm({
2931
2936
  });
2932
2937
  setFormData(merged);
2933
2938
  } else {
2939
+ setPassword("");
2940
+ setConfirmPassword("");
2934
2941
  setFormData(
2935
2942
  columns.filter((col) => !col.hideInForm).reduce((acc, col) => {
2936
2943
  const path = col.field || col.key;
@@ -2939,29 +2946,18 @@ function CreateEditForm({
2939
2946
  if (isDateFormColumn(col.type) && (initial === "" || initial == null)) {
2940
2947
  initial = todayLocalDateString();
2941
2948
  }
2942
- return {
2943
- ...acc,
2944
- [path]: initial
2945
- };
2949
+ return { ...acc, [path]: initial };
2946
2950
  }, {})
2947
2951
  );
2948
2952
  }
2949
2953
  }, [existingData, duplicateSeed, columns]);
2950
2954
  const handleChange = (e, field) => {
2951
2955
  const value = e.target.value;
2952
- setFormData((prev) => ({
2953
- ...prev,
2954
- [field]: value
2955
- }));
2956
- if (field === "itemsSummary") {
2957
- recalculateTotal(value);
2958
- }
2956
+ setFormData((prev) => ({ ...prev, [field]: value }));
2957
+ if (field === "itemsSummary") recalculateTotal(value);
2959
2958
  };
2960
2959
  const handleFileUpload = (field, url) => {
2961
- setFormData({
2962
- ...formData,
2963
- [field]: url
2964
- });
2960
+ setFormData({ ...formData, [field]: url });
2965
2961
  };
2966
2962
  const isValidPhoneFieldValue = (value) => {
2967
2963
  const v = String(value ?? "").trim();
@@ -2985,6 +2981,18 @@ function CreateEditForm({
2985
2981
  }
2986
2982
  }
2987
2983
  });
2984
+ if (isCustomerCreate) {
2985
+ if (!password) {
2986
+ newErrors["_password"] = "Password is required";
2987
+ } else if (password.length < 6) {
2988
+ newErrors["_password"] = "Password must be at least 6 characters";
2989
+ }
2990
+ if (!confirmPassword) {
2991
+ newErrors["_confirmPassword"] = "Please confirm your password";
2992
+ } else if (password && confirmPassword !== password) {
2993
+ newErrors["_confirmPassword"] = "Passwords do not match";
2994
+ }
2995
+ }
2988
2996
  setErrors(newErrors);
2989
2997
  return Object.keys(newErrors).length === 0;
2990
2998
  };
@@ -3002,16 +3010,19 @@ function CreateEditForm({
3002
3010
  if (!existingData) {
3003
3011
  delete payload.id;
3004
3012
  }
3013
+ if (isCustomerCreate) {
3014
+ payload._password = password;
3015
+ }
3005
3016
  try {
3006
3017
  const res = await fetch(url, {
3007
3018
  method,
3008
- headers: {
3009
- "Content-Type": "application/json"
3010
- },
3019
+ headers: { "Content-Type": "application/json" },
3011
3020
  body: JSON.stringify(payload)
3012
3021
  });
3013
3022
  if (!res.ok) {
3014
- throw new Error("Failed to save data");
3023
+ const errData = await res.json().catch(() => ({}));
3024
+ import_sonner3.toast.error(errData.error ?? "Failed to save data");
3025
+ return;
3015
3026
  }
3016
3027
  const result = await res.json();
3017
3028
  if (result.inviteLink) {
@@ -3025,13 +3036,12 @@ Note: ${result.note}`
3025
3036
  onClose();
3026
3037
  } catch (error) {
3027
3038
  console.error("Error saving data:", error);
3039
+ import_sonner3.toast.error("An unexpected error occurred. Please try again.");
3028
3040
  }
3029
3041
  };
3030
3042
  const visibleColumns = columns.filter((col) => {
3031
3043
  if (col.hideInForm) return false;
3032
- if (!existingData && col.hideInCreate) {
3033
- return false;
3034
- }
3044
+ if (!existingData && col.hideInCreate) return false;
3035
3045
  return true;
3036
3046
  });
3037
3047
  const isFieldDisabled = (path) => {
@@ -3061,228 +3071,193 @@ Note: ${result.note}`
3061
3071
  }
3062
3072
  )
3063
3073
  ] }),
3064
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
3065
- "form",
3066
- {
3067
- onSubmit: handleSubmit,
3068
- className: "flex flex-col flex-1 min-h-0",
3069
- children: [
3070
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "flex-1 min-h-0 overflow-y-auto p-6 space-y-4", children: visibleColumns.map((col) => {
3071
- const path = col.field || col.key;
3072
- if (!path) return null;
3073
- const disabled = isFieldDisabled(path);
3074
- const optionSet = col.type === "select" && Array.isArray(col.options) ? new Set(
3075
- col.options.map(
3076
- (o) => String(o.value)
3077
- )
3078
- ) : null;
3079
- const rawStr = formData[path] != null && formData[path] !== "" ? String(formData[path]) : "";
3080
- const selectValue = optionSet ? rawStr !== "" && optionSet.has(rawStr) ? rawStr : col.defaultValue : void 0;
3081
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_react13.default.Fragment, { children: [
3082
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { children: [
3083
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(Label3, { className: "block text-sm font-medium mb-1", children: [
3084
- col.displayName,
3085
- ["subtotal", "tax", "total"].includes(path) && totalLoading && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "ml-2 text-xs text-gray-400 font-normal", children: "Calculating\u2026" })
3086
- ] }),
3087
- col.type === "customerDropdown" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
3088
- Select,
3089
- {
3090
- value: (() => {
3091
- const match = customers.find(
3092
- (c) => String(c.id) === String(
3093
- formData["contactId"]
3094
- ) || c.name === formData["contact.name"]
3095
- );
3096
- return match ? String(match.id) : void 0;
3097
- })(),
3098
- onValueChange: handleCustomerSelect,
3099
- children: [
3100
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(SelectTrigger, { children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(SelectValue, { placeholder: "Select a customer" }) }),
3101
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(SelectContent, { children: customers.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3102
- SelectItem,
3103
- {
3104
- value: "__loading__",
3105
- disabled: true,
3106
- children: "Loading\u2026"
3107
- }
3108
- ) : customers.map((c) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3109
- SelectItem,
3110
- {
3111
- value: String(
3112
- c.id
3113
- ),
3114
- children: c.name
3115
- },
3116
- c.id
3117
- )) })
3118
- ]
3119
- }
3120
- ) : col.relationApi ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3121
- RelationAutocomplete,
3122
- {
3123
- apiEndpoint: col.relationApi,
3124
- value: formData[path] ?? "",
3125
- onChange: (v) => setFormData({
3126
- ...formData,
3127
- [path]: v
3128
- }),
3129
- labelField: col.relationLabelField ?? "name",
3130
- valueField: col.relationValueField ?? "id",
3131
- queryParams: col.relationQueryParams,
3132
- placeholder: `Select ${col.displayName}`
3133
- }
3134
- ) : col.type === "textarea" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3135
- Textarea,
3136
- {
3137
- rows: typeof col.textareaRows === "number" ? col.textareaRows : 4,
3138
- className: "min-h-[80px] font-mono text-sm",
3139
- value: formData[path] ?? "",
3140
- onChange: (e) => handleChange(e, path),
3141
- placeholder: col.placeholder,
3142
- disabled
3143
- }
3144
- ) : col.type === "select" && Array.isArray(
3145
- col.options
3146
- ) && col.options.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
3147
- Select,
3148
- {
3149
- value: selectValue,
3150
- onValueChange: (value) => setFormData({
3151
- ...formData,
3152
- [path]: value
3153
- }),
3154
- disabled,
3155
- children: [
3156
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(SelectTrigger, { children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3157
- SelectValue,
3158
- {
3159
- placeholder: selectValue ? void 0 : "Select an option"
3160
- }
3161
- ) }),
3162
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(SelectContent, { children: col.options.map(
3163
- (option) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3164
- SelectItem,
3165
- {
3166
- value: option.value,
3167
- children: option.label
3168
- },
3169
- option.value
3170
- )
3171
- ) })
3172
- ]
3173
- }
3174
- ) : col.type === "boolean" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3175
- Switch,
3176
- {
3177
- checked: Boolean(
3178
- formData[path]
3179
- ),
3180
- onCheckedChange: (checked) => setFormData({
3181
- ...formData,
3182
- [path]: checked
3183
- }),
3184
- disabled
3185
- }
3186
- ) : isDateFormColumn(
3187
- col.type
3188
- ) ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3189
- Input,
3190
- {
3191
- type: "date",
3192
- value: formData[path] ?? "",
3193
- onChange: (e) => handleChange(e, path),
3194
- disabled
3195
- }
3196
- ) : col.type === "password" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3197
- Input,
3198
- {
3199
- type: "password",
3200
- value: formData[path] || "",
3201
- onChange: (e) => handleChange(e, path),
3202
- disabled
3203
- }
3204
- ) : col.type === "number" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3205
- Input,
3206
- {
3207
- type: "number",
3208
- placeholder: col.placeholder,
3209
- value: formData[path] ?? "",
3210
- onChange: (e) => handleChange(e, path),
3211
- disabled
3212
- }
3213
- ) : col.type === "phone" || col.type === "tel" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3214
- Input,
3215
- {
3216
- type: "tel",
3217
- inputMode: "tel",
3218
- autoComplete: "tel",
3219
- placeholder: col.placeholder ?? "e.g. +1 555 123 4567",
3220
- value: formData[path] ?? "",
3221
- onChange: (e) => handleChange(e, path),
3222
- disabled
3223
- }
3224
- ) : col.type === "file" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3225
- FileUpload,
3226
- {
3227
- onUploadSuccess: (url) => handleFileUpload(
3228
- path,
3229
- url
3230
- )
3231
- }
3232
- ) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3233
- Input,
3234
- {
3235
- type: col.type || "text",
3236
- placeholder: ["subtotal", "tax", "total"].includes(path) ? "Auto-calculated from items" : col.placeholder,
3237
- value: formData[path] ?? "",
3238
- onChange: (e) => handleChange(e, path),
3239
- disabled
3240
- }
3241
- ),
3242
- errors[path] && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { className: "text-red-500 text-sm mt-1", children: errors[path] })
3074
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("form", { onSubmit: handleSubmit, className: "flex flex-col flex-1 min-h-0", children: [
3075
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex-1 min-h-0 overflow-y-auto p-6 space-y-4", children: [
3076
+ visibleColumns.map((col) => {
3077
+ const path = col.field || col.key;
3078
+ if (!path) return null;
3079
+ const disabled = isFieldDisabled(path);
3080
+ const optionSet = col.type === "select" && Array.isArray(col.options) ? new Set(col.options.map((o) => String(o.value))) : null;
3081
+ const rawStr = formData[path] != null && formData[path] !== "" ? String(formData[path]) : "";
3082
+ const selectValue = optionSet ? rawStr !== "" && optionSet.has(rawStr) ? rawStr : col.defaultValue : void 0;
3083
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_react13.default.Fragment, { children: [
3084
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { children: [
3085
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(Label3, { className: "block text-sm font-medium mb-1", children: [
3086
+ col.displayName,
3087
+ ["subtotal", "tax", "total"].includes(path) && totalLoading && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "ml-2 text-xs text-gray-400 font-normal", children: "Calculating\u2026" })
3243
3088
  ] }),
3244
- col.type === "customerDropdown" && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { children: [
3245
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Label3, { className: "block text-sm font-medium mb-1", children: "Name" }),
3246
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3247
- Input,
3248
- {
3249
- type: "text",
3250
- placeholder: "Customer name",
3251
- value: formData["contact.name"] ?? "",
3252
- onChange: (e) => setFormData(
3253
- (prev) => ({
3254
- ...prev,
3255
- "contact.name": e.target.value
3256
- })
3257
- )
3258
- }
3259
- )
3260
- ] })
3261
- ] }, path);
3262
- }) }),
3263
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex gap-2 p-4 border-t border-gray-200 shrink-0 bg-white", children: [
3089
+ col.type === "customerDropdown" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
3090
+ Select,
3091
+ {
3092
+ value: (() => {
3093
+ const match = customers.find(
3094
+ (c) => String(c.id) === String(formData["contactId"]) || c.name === formData["contact.name"]
3095
+ );
3096
+ return match ? String(match.id) : void 0;
3097
+ })(),
3098
+ onValueChange: handleCustomerSelect,
3099
+ children: [
3100
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(SelectTrigger, { children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(SelectValue, { placeholder: "Select a customer" }) }),
3101
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(SelectContent, { children: customers.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(SelectItem, { value: "__loading__", disabled: true, children: "Loading\u2026" }) : customers.map((c) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(SelectItem, { value: String(c.id), children: c.name }, c.id)) })
3102
+ ]
3103
+ }
3104
+ ) : col.relationApi ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3105
+ RelationAutocomplete,
3106
+ {
3107
+ apiEndpoint: col.relationApi,
3108
+ value: formData[path] ?? "",
3109
+ onChange: (v) => setFormData({ ...formData, [path]: v }),
3110
+ labelField: col.relationLabelField ?? "name",
3111
+ valueField: col.relationValueField ?? "id",
3112
+ queryParams: col.relationQueryParams,
3113
+ placeholder: `Select ${col.displayName}`
3114
+ }
3115
+ ) : col.type === "textarea" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3116
+ Textarea,
3117
+ {
3118
+ rows: typeof col.textareaRows === "number" ? col.textareaRows : 4,
3119
+ className: "min-h-[80px] font-mono text-sm",
3120
+ value: formData[path] ?? "",
3121
+ onChange: (e) => handleChange(e, path),
3122
+ placeholder: col.placeholder,
3123
+ disabled
3124
+ }
3125
+ ) : col.type === "select" && Array.isArray(col.options) && col.options.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
3126
+ Select,
3127
+ {
3128
+ value: selectValue,
3129
+ onValueChange: (value) => setFormData({ ...formData, [path]: value }),
3130
+ disabled,
3131
+ children: [
3132
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(SelectTrigger, { children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3133
+ SelectValue,
3134
+ {
3135
+ placeholder: selectValue ? void 0 : "Select an option"
3136
+ }
3137
+ ) }),
3138
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(SelectContent, { children: col.options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(SelectItem, { value: option.value, children: option.label }, option.value)) })
3139
+ ]
3140
+ }
3141
+ ) : col.type === "boolean" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3142
+ Switch,
3143
+ {
3144
+ checked: Boolean(formData[path]),
3145
+ onCheckedChange: (checked) => setFormData({ ...formData, [path]: checked }),
3146
+ disabled
3147
+ }
3148
+ ) : isDateFormColumn(col.type) ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3149
+ Input,
3150
+ {
3151
+ type: "date",
3152
+ value: formData[path] ?? "",
3153
+ onChange: (e) => handleChange(e, path),
3154
+ disabled
3155
+ }
3156
+ ) : col.type === "password" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3157
+ Input,
3158
+ {
3159
+ type: "password",
3160
+ value: formData[path] || "",
3161
+ onChange: (e) => handleChange(e, path),
3162
+ disabled
3163
+ }
3164
+ ) : col.type === "number" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3165
+ Input,
3166
+ {
3167
+ type: "number",
3168
+ placeholder: col.placeholder,
3169
+ value: formData[path] ?? "",
3170
+ onChange: (e) => handleChange(e, path),
3171
+ disabled
3172
+ }
3173
+ ) : col.type === "phone" || col.type === "tel" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3174
+ Input,
3175
+ {
3176
+ type: "tel",
3177
+ inputMode: "tel",
3178
+ autoComplete: "tel",
3179
+ placeholder: col.placeholder ?? "e.g. +1 555 123 4567",
3180
+ value: formData[path] ?? "",
3181
+ onChange: (e) => handleChange(e, path),
3182
+ disabled
3183
+ }
3184
+ ) : col.type === "file" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3185
+ FileUpload,
3186
+ {
3187
+ onUploadSuccess: (url) => handleFileUpload(path, url)
3188
+ }
3189
+ ) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3190
+ Input,
3191
+ {
3192
+ type: col.type || "text",
3193
+ placeholder: ["subtotal", "tax", "total"].includes(path) ? "Auto-calculated from items" : col.placeholder,
3194
+ value: formData[path] ?? "",
3195
+ onChange: (e) => handleChange(e, path),
3196
+ disabled
3197
+ }
3198
+ ),
3199
+ errors[path] && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { className: "text-red-500 text-sm mt-1", children: errors[path] })
3200
+ ] }),
3201
+ col.type === "customerDropdown" && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { children: [
3202
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Label3, { className: "block text-sm font-medium mb-1", children: "Name" }),
3203
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3204
+ Input,
3205
+ {
3206
+ type: "text",
3207
+ placeholder: "Customer name",
3208
+ value: formData["contact.name"] ?? "",
3209
+ onChange: (e) => setFormData((prev) => ({
3210
+ ...prev,
3211
+ "contact.name": e.target.value
3212
+ }))
3213
+ }
3214
+ )
3215
+ ] })
3216
+ ] }, path);
3217
+ }),
3218
+ isCustomerCreate && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
3219
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { children: [
3220
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Label3, { className: "block text-sm font-medium mb-1", children: "Password" }),
3264
3221
  /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3265
- Button,
3222
+ Input,
3266
3223
  {
3267
- type: "submit",
3268
- className: "flex-1",
3269
- children: "Save"
3224
+ type: "password",
3225
+ value: password,
3226
+ onChange: (e) => setPassword(e.target.value),
3227
+ placeholder: "Min. 6 characters"
3270
3228
  }
3271
3229
  ),
3230
+ errors["_password"] && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { className: "text-red-500 text-sm mt-1", children: errors["_password"] })
3231
+ ] }),
3232
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { children: [
3233
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Label3, { className: "block text-sm font-medium mb-1", children: "Confirm Password" }),
3272
3234
  /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3273
- Button,
3235
+ Input,
3274
3236
  {
3275
- type: "button",
3276
- variant: "outline",
3277
- onClick: onClose,
3278
- className: "flex-1",
3279
- children: "Cancel"
3237
+ type: "password",
3238
+ value: confirmPassword,
3239
+ onChange: (e) => setConfirmPassword(e.target.value),
3240
+ placeholder: "Re-enter password"
3280
3241
  }
3281
- )
3242
+ ),
3243
+ errors["_confirmPassword"] && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { className: "text-red-500 text-sm mt-1", children: errors["_confirmPassword"] })
3282
3244
  ] })
3283
- ]
3284
- }
3285
- )
3245
+ ] })
3246
+ ] }),
3247
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex gap-2 p-4 border-t border-gray-200 shrink-0 bg-white", children: [
3248
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Button, { type: "submit", className: "flex-1", children: "Save" }),
3249
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3250
+ Button,
3251
+ {
3252
+ type: "button",
3253
+ variant: "outline",
3254
+ onClick: onClose,
3255
+ className: "flex-1",
3256
+ children: "Cancel"
3257
+ }
3258
+ )
3259
+ ] })
3260
+ ] })
3286
3261
  ]
3287
3262
  }
3288
3263
  ) }) : null;
@@ -5528,7 +5503,8 @@ function AdminCRUD({
5528
5503
  apiEndpoint,
5529
5504
  columns,
5530
5505
  existingData: editingItem,
5531
- duplicateSeed
5506
+ duplicateSeed,
5507
+ resource: resourceName
5532
5508
  }
5533
5509
  ),
5534
5510
  /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
@@ -10121,7 +10097,7 @@ function DashboardPage() {
10121
10097
  // src/admin/pages/AdminPageResolver.tsx
10122
10098
  var import_react68 = require("react");
10123
10099
  var import_dynamic2 = __toESM(require("next/dynamic"), 1);
10124
- var import_navigation30 = require("next/navigation");
10100
+ var import_navigation31 = require("next/navigation");
10125
10101
 
10126
10102
  // src/admin/pages/SubmissionDetailPage.tsx
10127
10103
  var import_react37 = require("react");
@@ -11085,6 +11061,7 @@ function formatMoney3(amount, currency) {
11085
11061
  }).format(Number(amount));
11086
11062
  }
11087
11063
  var MANUAL_CUSTOMER = "__manual__";
11064
+ var MANUAL_CONTACT = "__manual__";
11088
11065
  function OrderPlacementPage({ editOrderId }) {
11089
11066
  const router = (0, import_navigation15.useRouter)();
11090
11067
  const searchParams = (0, import_navigation15.useSearchParams)();
@@ -11092,25 +11069,23 @@ function OrderPlacementPage({ editOrderId }) {
11092
11069
  const [customers, setCustomers] = (0, import_react40.useState)([]);
11093
11070
  const [customersLoading, setCustomersLoading] = (0, import_react40.useState)(true);
11094
11071
  const [contactId, setContactId] = (0, import_react40.useState)(null);
11072
+ const [selectedCustomerId, setSelectedCustomerId] = (0, import_react40.useState)(null);
11095
11073
  const [contactName, setContactName] = (0, import_react40.useState)("");
11096
11074
  const [contactEmail, setContactEmail] = (0, import_react40.useState)("");
11097
11075
  const [contactPhone, setContactPhone] = (0, import_react40.useState)("");
11076
+ const [placeForSomeoneElse, setPlaceForSomeoneElse] = (0, import_react40.useState)(false);
11077
+ const [customerContacts, setCustomerContacts] = (0, import_react40.useState)([]);
11078
+ const [customerContactsLoading, setCustomerContactsLoading] = (0, import_react40.useState)(false);
11079
+ const [subContactId, setSubContactId] = (0, import_react40.useState)(null);
11080
+ const [subContactName, setSubContactName] = (0, import_react40.useState)("");
11081
+ const [subContactEmail, setSubContactEmail] = (0, import_react40.useState)("");
11082
+ const [subContactPhone, setSubContactPhone] = (0, import_react40.useState)("");
11098
11083
  const [status, setStatus] = (0, import_react40.useState)("pending");
11099
11084
  const [currency, setCurrency] = (0, import_react40.useState)("INR");
11100
11085
  const [loadingOrder, setLoadingOrder] = (0, import_react40.useState)(Boolean(editOrderId));
11101
11086
  const [orderLoadError, setOrderLoadError] = (0, import_react40.useState)(null);
11102
- const [couponError, setCouponError] = (0, import_react40.useState)(null);
11103
- const [couponLoading, setCouponLoading] = (0, import_react40.useState)(false);
11104
11087
  const [coupons, setCoupons] = (0, import_react40.useState)([]);
11105
- const [couponInput, setCouponInput] = (0, import_react40.useState)("");
11106
- const emptyAddress = {
11107
- line1: "",
11108
- line2: "",
11109
- city: "",
11110
- state: "",
11111
- country: "",
11112
- postalCode: ""
11113
- };
11088
+ const emptyAddress = { line1: "", line2: "", city: "", state: "", country: "", postalCode: "" };
11114
11089
  const [billingAddress, setBillingAddress] = (0, import_react40.useState)(emptyAddress);
11115
11090
  const [shippingAddress, setShippingAddress] = (0, import_react40.useState)(emptyAddress);
11116
11091
  const [sameAsBilling, setSameAsBilling] = (0, import_react40.useState)(true);
@@ -11173,9 +11148,7 @@ function OrderPlacementPage({ editOrderId }) {
11173
11148
  setSameAsBilling(true);
11174
11149
  }
11175
11150
  const loadedCid = typeof cid === "number" && Number.isFinite(cid) ? cid : null;
11176
- if (loadedCid && !o.billingAddress && !o.shippingAddress) {
11177
- void loadCustomerAddresses(loadedCid);
11178
- }
11151
+ if (loadedCid && !o.billingAddress && !o.shippingAddress) void loadContactAddresses(loadedCid);
11179
11152
  setStatus(String(o.status ?? "pending"));
11180
11153
  const cur = String(o.currency ?? "INR").trim().toUpperCase().slice(0, 8);
11181
11154
  if (cur) setCurrency(cur);
@@ -11185,13 +11158,7 @@ function OrderPlacementPage({ editOrderId }) {
11185
11158
  const coll = p?.collection?.name;
11186
11159
  const nm = p?.name;
11187
11160
  const label = [coll, nm].filter(Boolean).join(" \u2014 ") || nm || `Product #${pid}`;
11188
- return {
11189
- key: `line-${it.id}`,
11190
- productId: pid,
11191
- label,
11192
- sku: p?.sku ?? null,
11193
- quantity: Math.max(1, Math.floor(Number(it.quantity) || 1))
11194
- };
11161
+ return { key: `line-${it.id}`, productId: pid, label, sku: p?.sku ?? null, quantity: Math.max(1, Math.floor(Number(it.quantity) || 1)) };
11195
11162
  });
11196
11163
  setLines(draft);
11197
11164
  try {
@@ -11204,18 +11171,7 @@ function OrderPlacementPage({ editOrderId }) {
11204
11171
  if (dr.ok) {
11205
11172
  const d = await dr.json();
11206
11173
  if (d?.id) {
11207
- setCoupons([{
11208
- couponCode: d.couponCode ?? "",
11209
- discountId: d.id,
11210
- name: d.name,
11211
- value: d.value,
11212
- type: d.discountType,
11213
- canCombine: !!d.canCombineWithOtherDiscounts,
11214
- calculatedDiscount: 0,
11215
- rewardProductIds: [],
11216
- rewardLines: [],
11217
- isAutomatic: d.isAutomatic ?? false
11218
- }]);
11174
+ 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 }]);
11219
11175
  }
11220
11176
  }
11221
11177
  }
@@ -11226,12 +11182,7 @@ function OrderPlacementPage({ editOrderId }) {
11226
11182
  const pid = Number(it.productId);
11227
11183
  const p = it.product;
11228
11184
  const unit = Number(it.unitPrice ?? 0);
11229
- productCache.current.set(pid, {
11230
- id: pid,
11231
- name: p?.name ?? null,
11232
- sku: p?.sku ?? null,
11233
- price: Number.isFinite(unit) ? unit : 0
11234
- });
11185
+ productCache.current.set(pid, { id: pid, name: p?.name ?? null, sku: p?.sku ?? null, price: Number.isFinite(unit) ? unit : 0 });
11235
11186
  }
11236
11187
  } catch {
11237
11188
  if (!cancelled) setOrderLoadError("Failed to load order");
@@ -11248,23 +11199,17 @@ function OrderPlacementPage({ editOrderId }) {
11248
11199
  (async () => {
11249
11200
  setCustomersLoading(true);
11250
11201
  try {
11251
- const res = await fetch(
11252
- "/api/vendor_customers?limit=500&sortField=createdAt&sortOrder=asc"
11253
- );
11202
+ const res = await fetch("/api/vendor_customers?limit=500&sortField=createdAt&sortOrder=asc");
11254
11203
  if (!res.ok) {
11255
11204
  if (!cancelled) setCustomers([]);
11256
11205
  return;
11257
11206
  }
11258
11207
  const data = await res.json();
11259
11208
  const rows = (Array.isArray(data?.data) ? data.data : []).map((row) => {
11260
- const id = Number(row.contactId ?? row.contact?.id);
11209
+ const id = Number(row.id);
11261
11210
  if (!Number.isFinite(id)) return null;
11262
- return {
11263
- id,
11264
- name: row.name ?? row.contact?.name ?? null,
11265
- email: row.email ?? row.contact?.email ?? null,
11266
- phone: row.phone ?? row.contact?.phone ?? null
11267
- };
11211
+ const rawCustomerId = Number(row.customerId);
11212
+ return { id, customerId: Number.isFinite(rawCustomerId) && rawCustomerId > 0 ? rawCustomerId : null, name: row.name ?? null, email: row.email ?? null, phone: row.phone ?? null };
11268
11213
  }).filter((r) => r != null);
11269
11214
  if (!cancelled) setCustomers(rows);
11270
11215
  } catch {
@@ -11277,6 +11222,140 @@ function OrderPlacementPage({ editOrderId }) {
11277
11222
  cancelled = true;
11278
11223
  };
11279
11224
  }, []);
11225
+ async function loadCustomerContacts(customerId) {
11226
+ setCustomerContactsLoading(true);
11227
+ setCustomerContacts([]);
11228
+ setSubContactId(null);
11229
+ setSubContactName("");
11230
+ setSubContactEmail("");
11231
+ setSubContactPhone("");
11232
+ try {
11233
+ const res = await fetch(`/api/customer_contacts?customerId=${customerId}&limit=200&sortField=id&sortOrder=asc`);
11234
+ if (!res.ok) return;
11235
+ const data = await res.json();
11236
+ const rows = (Array.isArray(data?.data) ? data.data : Array.isArray(data) ? data : []).filter((r) => r.contact && Number.isFinite(Number(r.contactId)));
11237
+ setCustomerContacts(rows);
11238
+ } catch {
11239
+ setCustomerContacts([]);
11240
+ } finally {
11241
+ setCustomerContactsLoading(false);
11242
+ }
11243
+ }
11244
+ async function loadContactAddressesByEmail(email) {
11245
+ try {
11246
+ const res = await fetch(`/api/contacts?search=${encodeURIComponent(email)}&limit=5`);
11247
+ if (!res.ok) {
11248
+ setBillingAddress({ ...emptyAddress });
11249
+ setShippingAddress({ ...emptyAddress });
11250
+ return;
11251
+ }
11252
+ const data = await res.json();
11253
+ const match = data.data?.find((c) => c.email?.toLowerCase() === email.toLowerCase());
11254
+ if (!match) {
11255
+ setBillingAddress({ ...emptyAddress });
11256
+ setShippingAddress({ ...emptyAddress });
11257
+ return;
11258
+ }
11259
+ await loadContactAddresses(match.id);
11260
+ } catch {
11261
+ setBillingAddress({ ...emptyAddress });
11262
+ setShippingAddress({ ...emptyAddress });
11263
+ }
11264
+ }
11265
+ async function loadContactAddresses(cid) {
11266
+ try {
11267
+ const res = await fetch(`/api/order_addresses?contactId=${cid}&limit=100&sortField=createdAt&sortOrder=desc`);
11268
+ if (!res.ok) return;
11269
+ const body = await res.json();
11270
+ const rows = Array.isArray(body) ? body : Array.isArray(body?.data) ? body.data : [];
11271
+ const billing = rows.find((a) => a.addressType === "billing_address");
11272
+ const shipping = rows.find((a) => a.addressType === "shipping_address");
11273
+ if (billing) setBillingAddress(mapAddressToForm(billing));
11274
+ else setBillingAddress({ ...emptyAddress });
11275
+ if (sameAsBilling) setShippingAddress(billing ? mapAddressToForm(billing) : { ...emptyAddress });
11276
+ else setShippingAddress(shipping ? mapAddressToForm(shipping) : { ...emptyAddress });
11277
+ } catch {
11278
+ setBillingAddress(emptyAddress);
11279
+ setShippingAddress(emptyAddress);
11280
+ }
11281
+ }
11282
+ function handleCustomerSelect(value) {
11283
+ if (value === MANUAL_CUSTOMER) {
11284
+ setContactId(null);
11285
+ setSelectedCustomerId(null);
11286
+ setCustomerContacts([]);
11287
+ setSubContactId(null);
11288
+ setSubContactName("");
11289
+ setSubContactEmail("");
11290
+ setSubContactPhone("");
11291
+ setBillingAddress({ ...emptyAddress });
11292
+ setShippingAddress({ ...emptyAddress });
11293
+ return;
11294
+ }
11295
+ const id = Number(value);
11296
+ if (!Number.isFinite(id)) return;
11297
+ const customer = customers.find((c) => c.id === id);
11298
+ if (!customer) return;
11299
+ setContactId(id);
11300
+ setSelectedCustomerId(customer.customerId ?? null);
11301
+ setContactName(customer.name ?? "");
11302
+ setContactEmail(customer.email ?? "");
11303
+ setContactPhone(customer.phone ?? "");
11304
+ setSubContactId(null);
11305
+ setSubContactName("");
11306
+ setSubContactEmail("");
11307
+ setSubContactPhone("");
11308
+ setPlaceForSomeoneElse(false);
11309
+ if (customer.customerId != null) loadCustomerContacts(customer.customerId);
11310
+ if (customer.email) {
11311
+ loadContactAddressesByEmail(customer.email);
11312
+ } else {
11313
+ setBillingAddress({ ...emptyAddress });
11314
+ setShippingAddress({ ...emptyAddress });
11315
+ }
11316
+ }
11317
+ function handleSubContactSelect(value) {
11318
+ if (value === MANUAL_CONTACT) {
11319
+ setSubContactId(null);
11320
+ setSubContactName("");
11321
+ setSubContactEmail("");
11322
+ setSubContactPhone("");
11323
+ setBillingAddress({ ...emptyAddress });
11324
+ setShippingAddress({ ...emptyAddress });
11325
+ return;
11326
+ }
11327
+ const cid = Number(value);
11328
+ if (!Number.isFinite(cid)) return;
11329
+ const row = customerContacts.find((r) => r.contactId === cid);
11330
+ if (!row) return;
11331
+ setSubContactId(cid);
11332
+ setSubContactName(row.contact.name ?? "");
11333
+ setSubContactEmail(row.contact.email ?? "");
11334
+ setSubContactPhone(row.contact.phone ?? "");
11335
+ loadContactAddresses(cid);
11336
+ }
11337
+ function handlePlaceForSomeoneElseToggle(checked) {
11338
+ setPlaceForSomeoneElse(checked);
11339
+ if (checked) {
11340
+ setBillingAddress({ ...emptyAddress });
11341
+ setShippingAddress({ ...emptyAddress });
11342
+ setSubContactId(null);
11343
+ setSubContactName("");
11344
+ setSubContactEmail("");
11345
+ setSubContactPhone("");
11346
+ return;
11347
+ }
11348
+ setSubContactId(null);
11349
+ setSubContactName("");
11350
+ setSubContactEmail("");
11351
+ setSubContactPhone("");
11352
+ if (contactEmail) {
11353
+ loadContactAddressesByEmail(contactEmail);
11354
+ } else {
11355
+ setBillingAddress({ ...emptyAddress });
11356
+ setShippingAddress({ ...emptyAddress });
11357
+ }
11358
+ }
11280
11359
  const cartProductIds = (0, import_react40.useMemo)(() => new Set(lines.map((l) => l.productId)), [lines]);
11281
11360
  (0, import_react40.useEffect)(() => {
11282
11361
  const q = productQuery.trim();
@@ -11285,13 +11364,7 @@ function OrderPlacementPage({ editOrderId }) {
11285
11364
  (async () => {
11286
11365
  setHitsLoading(true);
11287
11366
  try {
11288
- const params = new URLSearchParams({
11289
- limit: "50",
11290
- page: "1",
11291
- sortField: "name",
11292
- sortOrder: "asc",
11293
- status: "available"
11294
- });
11367
+ const params = new URLSearchParams({ limit: "50", page: "1", sortField: "name", sortOrder: "asc", status: "available" });
11295
11368
  if (q.length >= 2) params.set("search", q);
11296
11369
  const res = await fetch(`/api/products?${params}`);
11297
11370
  if (!res.ok) {
@@ -11372,53 +11445,34 @@ function OrderPlacementPage({ editOrderId }) {
11372
11445
  const res = await fetch("/api/discounts/validate-coupon", {
11373
11446
  method: "POST",
11374
11447
  headers: { "Content-Type": "application/json" },
11375
- body: JSON.stringify({
11376
- discountId: coupon.discountId,
11377
- isAutomatic: true,
11378
- orderLines: nonRewardLines.map((l) => ({ productId: l.productId, quantity: l.quantity })),
11379
- currency,
11380
- contactId
11381
- })
11448
+ body: JSON.stringify({ discountId: coupon.discountId, isAutomatic: true, orderLines: nonRewardLines.map((l) => ({ productId: l.productId, quantity: l.quantity })), currency, contactId })
11382
11449
  });
11383
11450
  if (cancelled) return;
11384
11451
  const data = await res.json();
11385
11452
  if (!data.valid) {
11386
11453
  const rewardPids = new Set(coupon.rewardLines.map((r) => r.productId));
11387
11454
  setCoupons((prev) => prev.filter((c) => c.discountId !== coupon.discountId));
11388
- setLines(
11389
- (prev) => prev.map((l) => {
11390
- if (!rewardPids.has(l.productId)) return l;
11391
- const rewardLine = coupon.rewardLines.find((r) => r.productId === l.productId);
11392
- if (!rewardLine) return l;
11393
- const newQty = l.quantity - rewardLine.quantity;
11394
- return newQty > 0 ? { ...l, quantity: newQty } : null;
11395
- }).filter((l) => l !== null)
11396
- );
11455
+ setLines((prev) => prev.map((l) => {
11456
+ if (!rewardPids.has(l.productId)) return l;
11457
+ const rewardLine = coupon.rewardLines.find((r) => r.productId === l.productId);
11458
+ if (!rewardLine) return l;
11459
+ const newQty = l.quantity - rewardLine.quantity;
11460
+ return newQty > 0 ? { ...l, quantity: newQty } : null;
11461
+ }).filter((l) => l !== null));
11397
11462
  rewardPids.forEach((pid) => rewardProductIds.current.delete(pid));
11398
11463
  rewardInjectedForDiscount.current.delete(coupon.discountId);
11399
11464
  } else {
11400
11465
  const newRewardLines = data.discount.rewardLines ?? [];
11401
- setCoupons((prev) => prev.map(
11402
- (c) => c.discountId !== coupon.discountId ? c : {
11403
- ...c,
11404
- calculatedDiscount: data.discount.calculatedDiscount,
11405
- rewardProductIds: data.discount.rewardProductIds ?? [],
11406
- rewardLines: newRewardLines
11407
- }
11408
- ));
11466
+ setCoupons((prev) => prev.map((c) => c.discountId !== coupon.discountId ? c : { ...c, calculatedDiscount: data.discount.calculatedDiscount, rewardProductIds: data.discount.rewardProductIds ?? [], rewardLines: newRewardLines }));
11409
11467
  setLines((prev) => {
11410
11468
  let next = [...prev];
11411
11469
  for (const rewardLine of newRewardLines) {
11412
11470
  const idx = next.findIndex((l) => l.productId === rewardLine.productId);
11413
- if (idx >= 0 && rewardProductIds.current.has(rewardLine.productId)) {
11414
- next[idx] = { ...next[idx], quantity: rewardLine.quantity };
11415
- }
11471
+ if (idx >= 0 && rewardProductIds.current.has(rewardLine.productId)) next[idx] = { ...next[idx], quantity: rewardLine.quantity };
11416
11472
  }
11417
11473
  const newRewardPids = new Set(newRewardLines.map((r) => r.productId));
11418
11474
  const oldRewardPids = new Set(coupon.rewardLines.map((r) => r.productId));
11419
- next = next.filter(
11420
- (l) => !oldRewardPids.has(l.productId) || newRewardPids.has(l.productId)
11421
- );
11475
+ next = next.filter((l) => !oldRewardPids.has(l.productId) || newRewardPids.has(l.productId));
11422
11476
  return next;
11423
11477
  });
11424
11478
  }
@@ -11433,126 +11487,28 @@ function OrderPlacementPage({ editOrderId }) {
11433
11487
  lines.filter((l) => !rewardProductIds.current.has(l.productId)).map((l) => `${l.productId}:${l.quantity}`).join(","),
11434
11488
  coupons.filter((c) => c.isAutomatic).map((c) => c.discountId).join(",")
11435
11489
  ]);
11436
- async function handleApplyCoupon() {
11437
- const code = couponInput.trim().toUpperCase();
11438
- if (!code) return;
11439
- if (coupons.some((c) => c.couponCode === code)) {
11440
- setCouponError("Coupon already applied");
11441
- return;
11442
- }
11443
- if (coupons.length > 0 && !coupons[0].canCombine) {
11444
- setCouponError("Applied coupon cannot be combined with other discounts");
11445
- return;
11446
- }
11447
- setCouponError(null);
11448
- setCouponLoading(true);
11449
- try {
11450
- const orderLines = lines.map((l) => ({ productId: l.productId, quantity: l.quantity }));
11451
- const res = await fetch("/api/discounts/validate-coupon", {
11452
- method: "POST",
11453
- headers: { "Content-Type": "application/json" },
11454
- body: JSON.stringify({ couponCode: code, orderLines, currency, contactId })
11455
- });
11456
- const data = await res.json();
11457
- if (!res.ok || !data.valid) {
11458
- setCouponError(data.error ?? "Invalid coupon");
11459
- return;
11460
- }
11461
- const d = data.discount;
11462
- if (!d.canCombineWithOtherDiscounts && coupons.length > 0) {
11463
- setCouponError("This coupon cannot be combined with other discounts");
11464
- return;
11465
- }
11466
- setCoupons((prev) => [...prev, {
11467
- couponCode: code,
11468
- discountId: d.id,
11469
- name: d.name,
11470
- value: d.value,
11471
- type: d.discountType,
11472
- canCombine: d.canCombineWithOtherDiscounts,
11473
- calculatedDiscount: d.calculatedDiscount,
11474
- rewardProductIds: d.rewardProductIds ?? [],
11475
- rewardLines: d.rewardLines ?? [],
11476
- isAutomatic: false
11477
- }]);
11478
- setCouponInput("");
11479
- import_sonner7.toast.success(`Coupon "${code}" applied`);
11480
- } catch {
11481
- setCouponError("Failed to validate coupon");
11482
- } finally {
11483
- setCouponLoading(false);
11484
- }
11485
- }
11486
11490
  function handleRemoveCoupon(couponCode) {
11487
11491
  const coupon = coupons.find((c) => c.couponCode === couponCode);
11488
11492
  if (coupon) {
11489
- const rewardKeyPrefix = `reward-`;
11490
- const rewardKeyForDiscount = new Set(
11491
- (coupon.rewardLines ?? []).map((r) => `reward-${r.productId}-${coupon.discountId}`)
11492
- );
11493
+ const rewardKeyForDiscount = new Set((coupon.rewardLines ?? []).map((r) => `reward-${r.productId}-${coupon.discountId}`));
11493
11494
  if (rewardKeyForDiscount.size > 0) {
11494
- setLines(
11495
- (prev) => prev.filter((l) => !rewardKeyForDiscount.has(l.key))
11496
- );
11495
+ setLines((prev) => prev.filter((l) => !rewardKeyForDiscount.has(l.key)));
11497
11496
  coupon.rewardLines.forEach((r) => {
11498
- const stillRewardByOther = coupons.some(
11499
- (c) => c.couponCode !== couponCode && c.rewardLines.some((rl) => rl.productId === r.productId)
11500
- );
11497
+ const stillRewardByOther = coupons.some((c) => c.couponCode !== couponCode && c.rewardLines.some((rl) => rl.productId === r.productId));
11501
11498
  if (!stillRewardByOther) rewardProductIds.current.delete(r.productId);
11502
11499
  });
11503
11500
  }
11504
11501
  rewardInjectedForDiscount.current.delete(coupon.discountId);
11505
11502
  }
11506
11503
  setCoupons((prev) => prev.filter((c) => c.couponCode !== couponCode));
11507
- setCouponError(null);
11508
11504
  }
11509
11505
  function mapAddressToForm(addr) {
11510
- return {
11511
- line1: addr.line1 ?? "",
11512
- line2: addr.line2 ?? "",
11513
- city: addr.city ?? "",
11514
- state: addr.state ?? "",
11515
- country: addr.country ?? "",
11516
- postalCode: addr.postalCode ?? ""
11517
- };
11506
+ return { line1: addr.line1 ?? "", line2: addr.line2 ?? "", city: addr.city ?? "", state: addr.state ?? "", country: addr.country ?? "", postalCode: addr.postalCode ?? "" };
11518
11507
  }
11519
11508
  function updateAddress(type, field, value) {
11520
11509
  if (type === "billing") setBillingAddress((prev) => ({ ...prev, [field]: value }));
11521
11510
  else setShippingAddress((prev) => ({ ...prev, [field]: value }));
11522
11511
  }
11523
- function handleCustomerSelect(value) {
11524
- if (value === MANUAL_CUSTOMER) {
11525
- setContactId(null);
11526
- return;
11527
- }
11528
- const id = Number(value);
11529
- if (!Number.isFinite(id)) return;
11530
- const customer = customers.find((c) => c.id === id);
11531
- if (!customer) return;
11532
- setContactId(id);
11533
- setContactName(customer.name ?? "");
11534
- setContactEmail(customer.email ?? "");
11535
- setContactPhone(customer.phone ?? "");
11536
- loadCustomerAddresses(id);
11537
- }
11538
- async function loadCustomerAddresses(customerId) {
11539
- try {
11540
- const res = await fetch(`/api/order_addresses?contactId=${customerId}&limit=100&sortField=createdAt&sortOrder=desc`);
11541
- if (!res.ok) return;
11542
- const body = await res.json();
11543
- const rows = Array.isArray(body) ? body : Array.isArray(body?.data) ? body.data : [];
11544
- const billing = rows.find((a) => a.addressType === "billing_address");
11545
- const shipping = rows.find((a) => a.addressType === "shipping_address");
11546
- if (billing) setBillingAddress(mapAddressToForm(billing));
11547
- else setBillingAddress({ ...emptyAddress });
11548
- if (sameAsBilling) setShippingAddress(billing ? mapAddressToForm(billing) : { ...emptyAddress });
11549
- else setShippingAddress(shipping ? mapAddressToForm(shipping) : { ...emptyAddress });
11550
- } catch {
11551
- setBillingAddress(emptyAddress);
11552
- setShippingAddress(emptyAddress);
11553
- }
11554
- }
11555
- const customerSelectValue = contactId != null ? String(contactId) : MANUAL_CUSTOMER;
11556
11512
  function toggleStaged(id) {
11557
11513
  setStagedIds((prev) => {
11558
11514
  const next = new Set(prev);
@@ -11589,9 +11545,7 @@ function OrderPlacementPage({ editOrderId }) {
11589
11545
  if (idx >= 0) {
11590
11546
  const row = next[idx];
11591
11547
  next[idx] = { ...row, quantity: row.quantity + 1 };
11592
- } else {
11593
- next.push({ key: String(id), productId: id, label: hit.name ?? `Product #${id}`, sku: hit.sku, quantity: 1 });
11594
- }
11548
+ } else next.push({ key: String(id), productId: id, label: hit.name ?? `Product #${id}`, sku: hit.sku, quantity: 1 });
11595
11549
  }
11596
11550
  return next;
11597
11551
  });
@@ -11620,9 +11574,12 @@ function OrderPlacementPage({ editOrderId }) {
11620
11574
  }, [preview]);
11621
11575
  async function handleSubmit(e) {
11622
11576
  e.preventDefault();
11623
- const email = contactEmail.trim();
11624
- if (contactId == null && !email) {
11625
- import_sonner7.toast.error("Select a customer or enter an email address");
11577
+ const effectiveEmail = placeForSomeoneElse ? subContactEmail.trim() : contactEmail.trim();
11578
+ const effectiveName = placeForSomeoneElse ? subContactName.trim() : contactName.trim();
11579
+ const effectivePhone = placeForSomeoneElse ? subContactPhone.trim() : contactPhone.trim();
11580
+ const effectiveContactId = placeForSomeoneElse ? subContactId : contactId;
11581
+ if (effectiveContactId == null && !effectiveEmail) {
11582
+ import_sonner7.toast.error(placeForSomeoneElse ? "Enter the contact's email address" : "Select a customer or enter an email address");
11626
11583
  return;
11627
11584
  }
11628
11585
  if (lines.length === 0) {
@@ -11636,46 +11593,67 @@ function OrderPlacementPage({ editOrderId }) {
11636
11593
  }
11637
11594
  setSubmitting(true);
11638
11595
  try {
11596
+ let resolvedContactId = placeForSomeoneElse ? subContactId : null;
11597
+ if (!resolvedContactId && effectiveEmail) {
11598
+ try {
11599
+ const res2 = await fetch(`/api/contacts?search=${encodeURIComponent(effectiveEmail)}&limit=1`);
11600
+ if (res2.ok) {
11601
+ const data = await res2.json();
11602
+ const match = data.data?.find((c) => c.email?.toLowerCase() === effectiveEmail.toLowerCase());
11603
+ if (match) resolvedContactId = match.id;
11604
+ }
11605
+ } catch {
11606
+ }
11607
+ }
11608
+ let orderContactId = resolvedContactId;
11609
+ if (placeForSomeoneElse) {
11610
+ if (contactEmail) {
11611
+ try {
11612
+ const res2 = await fetch(`/api/contacts?search=${encodeURIComponent(contactEmail)}&limit=5`);
11613
+ if (res2.ok) {
11614
+ const data = await res2.json();
11615
+ const match = data.data?.find((c) => c.email?.toLowerCase() === contactEmail.toLowerCase());
11616
+ if (match) orderContactId = match.id;
11617
+ }
11618
+ } catch {
11619
+ }
11620
+ }
11621
+ }
11639
11622
  const payload = {
11640
11623
  status,
11641
11624
  currency,
11642
- "contact.name": contactName.trim() || email.split("@")[0] || "Customer",
11643
- "contact.email": email || (contactId != null ? customers.find((c) => c.id === contactId)?.email : "") || "",
11644
- "contact.phone": contactPhone.trim() || null,
11625
+ "contact.name": effectiveName || effectiveEmail.split("@")[0] || "Customer",
11626
+ "contact.email": effectiveEmail || "",
11627
+ "contact.phone": effectivePhone || null,
11645
11628
  billingAddress,
11646
11629
  shippingAddress: sameAsBilling ? billingAddress : shippingAddress,
11647
11630
  orderLines: lines.map((l) => {
11648
11631
  const calc = preview?.lines.find((pl) => pl.productId === l.productId);
11649
- return {
11650
- productId: l.productId,
11651
- quantity: l.quantity,
11652
- unitPrice: calc?.unitPrice ?? productCache.current.get(l.productId)?.price ?? 0
11653
- };
11632
+ return { productId: l.productId, quantity: l.quantity, unitPrice: calc?.unitPrice ?? productCache.current.get(l.productId)?.price ?? 0 };
11654
11633
  })
11655
11634
  };
11656
- if (contactId != null) payload.contactId = contactId;
11635
+ if (orderContactId != null) payload.contactId = orderContactId;
11636
+ if (!placeForSomeoneElse && contactId != null) payload.customerId = contactId;
11657
11637
  if (coupons.length > 0) payload.discountId = coupons[0].discountId;
11658
11638
  const url = editOrderId ? `/api/orders/${editOrderId}` : "/api/orders";
11659
11639
  const method = editOrderId ? "PUT" : "POST";
11660
- const res = await fetch(url, {
11661
- method,
11662
- headers: { "Content-Type": "application/json" },
11663
- body: JSON.stringify(payload)
11664
- });
11640
+ const res = await fetch(url, { method, headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload) });
11665
11641
  const body = await res.json().catch(() => ({}));
11666
11642
  if (!res.ok) {
11667
11643
  import_sonner7.toast.error(body.error ?? (editOrderId ? "Failed to update order" : "Failed to create order"));
11668
11644
  return;
11669
11645
  }
11670
- if (editOrderId && contactId != null) {
11671
- const cr = await fetch(`/api/contacts/${contactId}`, {
11646
+ if (resolvedContactId == null) {
11647
+ const serverContactId = body.contactId;
11648
+ if (serverContactId != null && Number.isFinite(serverContactId)) {
11649
+ resolvedContactId = serverContactId;
11650
+ }
11651
+ }
11652
+ if (editOrderId && effectiveContactId != null) {
11653
+ const cr = await fetch(`/api/contacts/${effectiveContactId}`, {
11672
11654
  method: "PUT",
11673
11655
  headers: { "Content-Type": "application/json" },
11674
- body: JSON.stringify({
11675
- name: contactName.trim() || email.split("@")[0] || "Customer",
11676
- email: email || void 0,
11677
- phone: contactPhone.trim() || null
11678
- })
11656
+ body: JSON.stringify({ name: effectiveName || effectiveEmail.split("@")[0] || "Customer", email: effectiveEmail || void 0, phone: effectivePhone || null })
11679
11657
  });
11680
11658
  if (!cr.ok) {
11681
11659
  const cb = await cr.json().catch(() => ({}));
@@ -11687,6 +11665,25 @@ function OrderPlacementPage({ editOrderId }) {
11687
11665
  router.push(withAdminListFromParam(listReturnUrl, `/admin/orders/${editOrderId}/view`));
11688
11666
  return;
11689
11667
  }
11668
+ if (selectedCustomerId != null && resolvedContactId != null) {
11669
+ try {
11670
+ const linkCheck = await fetch(`/api/customer_contacts?customerId=${selectedCustomerId}&limit=200`);
11671
+ if (linkCheck.ok) {
11672
+ const linkData = await linkCheck.json();
11673
+ const existingRows = Array.isArray(linkData?.data) ? linkData.data : Array.isArray(linkData) ? linkData : [];
11674
+ const alreadyLinked = existingRows.some((r) => Number(r.contactId) === resolvedContactId);
11675
+ if (!alreadyLinked) {
11676
+ await fetch("/api/customer_contacts", {
11677
+ method: "POST",
11678
+ headers: { "Content-Type": "application/json" },
11679
+ body: JSON.stringify({ customerId: selectedCustomerId, contactId: resolvedContactId })
11680
+ });
11681
+ }
11682
+ }
11683
+ } catch {
11684
+ console.warn("[OrderPlacement] Could not link contact to customer");
11685
+ }
11686
+ }
11690
11687
  const id = body.id;
11691
11688
  import_sonner7.toast.success("Order created");
11692
11689
  if (id != null) router.push(withAdminListFromParam(listReturnUrl, `/admin/orders/${id}/view`));
@@ -11698,6 +11695,8 @@ function OrderPlacementPage({ editOrderId }) {
11698
11695
  }
11699
11696
  }
11700
11697
  const allVisibleStaged = productHits.length > 0 && productHits.every((p) => stagedIds.has(p.id));
11698
+ const customerSelectValue = contactId != null ? String(contactId) : MANUAL_CUSTOMER;
11699
+ const subContactSelectValue = subContactId != null ? String(subContactId) : MANUAL_CONTACT;
11701
11700
  if (editOrderId && loadingOrder) {
11702
11701
  return /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("div", { className: "rounded-lg bg-white shadow-md min-w-0", children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("div", { className: "flex justify-center items-center py-16 text-gray-500 text-sm", children: "Loading order\u2026" }) });
11703
11702
  }
@@ -11742,74 +11741,168 @@ function OrderPlacementPage({ editOrderId }) {
11742
11741
  ] }),
11743
11742
  /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "space-y-2 sm:col-span-2", children: [
11744
11743
  /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Label3, { htmlFor: "c-email", children: "Email" }),
11745
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Input, { id: "c-email", type: "email", value: contactEmail, onChange: (e) => setContactEmail(e.target.value), placeholder: "name@example.com", required: contactId == null })
11744
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Input, { id: "c-email", type: "email", value: contactEmail, onChange: (e) => setContactEmail(e.target.value), placeholder: "name@example.com", required: contactId == null && !placeForSomeoneElse })
11746
11745
  ] }),
11747
11746
  /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "space-y-2 sm:col-span-2", children: [
11748
11747
  /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Label3, { htmlFor: "c-phone", children: "Phone" }),
11749
11748
  /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Input, { id: "c-phone", value: contactPhone, onChange: (e) => setContactPhone(e.target.value), placeholder: "phone number" })
11749
+ ] })
11750
+ ] }),
11751
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("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: [
11752
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
11753
+ Checkbox,
11754
+ {
11755
+ id: "place-for-someone-else",
11756
+ checked: placeForSomeoneElse,
11757
+ onCheckedChange: (checked) => handlePlaceForSomeoneElseToggle(Boolean(checked)),
11758
+ disabled: contactId == null
11759
+ }
11760
+ ),
11761
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "space-y-0.5", children: [
11762
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
11763
+ "label",
11764
+ {
11765
+ htmlFor: "place-for-someone-else",
11766
+ className: `text-sm font-medium leading-none cursor-pointer ${contactId == null ? "text-gray-400" : "text-gray-700"}`,
11767
+ children: "Place this order for someone else"
11768
+ }
11769
+ ),
11770
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("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." })
11771
+ ] })
11772
+ ] }),
11773
+ placeForSomeoneElse && contactId != null && /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "rounded-lg border border-blue-200 bg-blue-50/40 p-4 space-y-3", children: [
11774
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "flex items-center gap-2", children: [
11775
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(import_lucide_react30.Users, { className: "h-4 w-4 text-blue-600" }),
11776
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("h3", { className: "text-sm font-semibold text-blue-800", children: "Order recipient" })
11750
11777
  ] }),
11751
- /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "space-y-4 sm:col-span-2 border rounded-lg p-4", children: [
11752
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("h3", { className: "text-sm font-semibold", children: "Billing Address" }),
11753
- /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-3", children: [
11754
- /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "space-y-2 md:col-span-2", children: [
11755
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Label3, { children: "Address Line 1" }),
11756
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Input, { value: billingAddress.line1, onChange: (e) => updateAddress("billing", "line1", e.target.value), placeholder: "Street Address" })
11757
- ] }),
11758
- /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "space-y-2 md:col-span-2", children: [
11759
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Label3, { children: "Address Line 2" }),
11760
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Input, { value: billingAddress.line2, onChange: (e) => updateAddress("billing", "line2", e.target.value), placeholder: "Apartment, Suite, floor, etc." })
11761
- ] }),
11762
- /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "space-y-2", children: [
11763
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Label3, { children: "City" }),
11764
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Input, { value: billingAddress.city, onChange: (e) => updateAddress("billing", "city", e.target.value), placeholder: "City" })
11765
- ] }),
11766
- /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "space-y-2", children: [
11767
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Label3, { children: "State" }),
11768
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Input, { value: billingAddress.state, onChange: (e) => updateAddress("billing", "state", e.target.value), placeholder: "State" })
11769
- ] }),
11770
- /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "space-y-2", children: [
11771
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Label3, { children: "Country" }),
11772
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Input, { value: billingAddress.country, onChange: (e) => updateAddress("billing", "country", e.target.value), placeholder: "Country" })
11773
- ] }),
11774
- /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "space-y-2", children: [
11775
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Label3, { children: "Postal Code" }),
11776
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Input, { value: billingAddress.postalCode, onChange: (e) => updateAddress("billing", "postalCode", e.target.value), placeholder: "Postal Code" })
11777
- ] })
11778
+ customerContactsLoading ? /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("p", { className: "text-xs text-gray-500", children: "Loading contacts\u2026" }) : /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "space-y-2", children: [
11779
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Label3, { htmlFor: "sc-select", children: "Select contact" }),
11780
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)(
11781
+ "select",
11782
+ {
11783
+ id: "sc-select",
11784
+ value: subContactSelectValue,
11785
+ onChange: (e) => handleSubContactSelect(e.target.value),
11786
+ 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",
11787
+ children: [
11788
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("option", { value: MANUAL_CONTACT, children: "Enter manually (new contact)" }),
11789
+ customerContacts.map((r) => /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("option", { value: String(r.contactId), children: [
11790
+ r.contact.name,
11791
+ r.contact.email ? ` \u2014 ${r.contact.email}` : ""
11792
+ ] }, r.contactId))
11793
+ ]
11794
+ }
11795
+ ),
11796
+ customerContacts.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("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." })
11797
+ ] }),
11798
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-3", children: [
11799
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "space-y-2 sm:col-span-2", children: [
11800
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Label3, { htmlFor: "sc-name", children: "Recipient name" }),
11801
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
11802
+ Input,
11803
+ {
11804
+ id: "sc-name",
11805
+ value: subContactName,
11806
+ onChange: (e) => setSubContactName(e.target.value),
11807
+ placeholder: "Full name",
11808
+ readOnly: subContactId != null,
11809
+ className: subContactId != null ? "bg-gray-100 cursor-not-allowed" : ""
11810
+ }
11811
+ )
11812
+ ] }),
11813
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "space-y-2 sm:col-span-2", children: [
11814
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Label3, { htmlFor: "sc-email", children: "Recipient email" }),
11815
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
11816
+ Input,
11817
+ {
11818
+ id: "sc-email",
11819
+ type: "email",
11820
+ value: subContactEmail,
11821
+ onChange: (e) => setSubContactEmail(e.target.value),
11822
+ placeholder: "email@example.com",
11823
+ required: placeForSomeoneElse && subContactId == null,
11824
+ readOnly: subContactId != null,
11825
+ className: subContactId != null ? "bg-gray-100 cursor-not-allowed" : ""
11826
+ }
11827
+ )
11828
+ ] }),
11829
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "space-y-2 sm:col-span-2", children: [
11830
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Label3, { htmlFor: "sc-phone", children: "Recipient phone" }),
11831
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
11832
+ Input,
11833
+ {
11834
+ id: "sc-phone",
11835
+ value: subContactPhone,
11836
+ onChange: (e) => setSubContactPhone(e.target.value),
11837
+ placeholder: "phone number",
11838
+ readOnly: subContactId != null,
11839
+ className: subContactId != null ? "bg-gray-100 cursor-not-allowed" : ""
11840
+ }
11841
+ )
11842
+ ] })
11843
+ ] })
11844
+ ] }),
11845
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "space-y-4 border rounded-lg p-4", children: [
11846
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("h3", { className: "text-sm font-semibold", children: "Billing Address" }),
11847
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-3", children: [
11848
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "space-y-2 md:col-span-2", children: [
11849
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Label3, { children: "Address Line 1" }),
11850
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Input, { value: billingAddress.line1, onChange: (e) => updateAddress("billing", "line1", e.target.value), placeholder: "Street Address" })
11851
+ ] }),
11852
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "space-y-2 md:col-span-2", children: [
11853
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Label3, { children: "Address Line 2" }),
11854
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Input, { value: billingAddress.line2, onChange: (e) => updateAddress("billing", "line2", e.target.value), placeholder: "Apartment, Suite, Floor, etc." })
11855
+ ] }),
11856
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "space-y-2", children: [
11857
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Label3, { children: "City" }),
11858
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Input, { value: billingAddress.city, onChange: (e) => updateAddress("billing", "city", e.target.value), placeholder: "City" })
11859
+ ] }),
11860
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "space-y-2", children: [
11861
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Label3, { children: "State" }),
11862
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Input, { value: billingAddress.state, onChange: (e) => updateAddress("billing", "state", e.target.value), placeholder: "State" })
11863
+ ] }),
11864
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "space-y-2", children: [
11865
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Label3, { children: "Country" }),
11866
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Input, { value: billingAddress.country, onChange: (e) => updateAddress("billing", "country", e.target.value), placeholder: "Country" })
11867
+ ] }),
11868
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "space-y-2", children: [
11869
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Label3, { children: "Postal Code" }),
11870
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Input, { value: billingAddress.postalCode, onChange: (e) => updateAddress("billing", "postalCode", e.target.value), placeholder: "Postal Code" })
11871
+ ] })
11872
+ ] })
11873
+ ] }),
11874
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "space-y-4 border rounded-lg p-4", children: [
11875
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "flex items-center justify-between", children: [
11876
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("h3", { className: "text-sm font-semibold", children: "Shipping Address" }),
11877
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "flex items-center gap-2", children: [
11878
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Checkbox, { checked: sameAsBilling, onCheckedChange: (checked) => setSameAsBilling(Boolean(checked)) }),
11879
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("span", { className: "text-sm text-gray-600", children: "Same as Billing" })
11778
11880
  ] })
11779
11881
  ] }),
11780
- /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "space-y-4 sm:col-span-2 border rounded-lg p-4", children: [
11781
- /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "flex items-center justify-between", children: [
11782
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("h3", { className: "text-sm font-semibold", children: "Shipping Address" }),
11783
- /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "flex items-center gap-2", children: [
11784
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Checkbox, { checked: sameAsBilling, onCheckedChange: (checked) => setSameAsBilling(Boolean(checked)) }),
11785
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("span", { className: "text-sm text-gray-600", children: "Same as Billing" })
11786
- ] })
11882
+ !sameAsBilling && /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-3", children: [
11883
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "space-y-2 md:col-span-2", children: [
11884
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Label3, { children: "Address Line 1" }),
11885
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Input, { value: shippingAddress.line1, onChange: (e) => updateAddress("shipping", "line1", e.target.value), placeholder: "Street Address" })
11787
11886
  ] }),
11788
- !sameAsBilling && /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-3", children: [
11789
- /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "space-y-2 md:col-span-2", children: [
11790
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Label3, { children: "Address Line 1" }),
11791
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Input, { value: shippingAddress.line1, onChange: (e) => updateAddress("shipping", "line1", e.target.value), placeholder: "Street Address" })
11792
- ] }),
11793
- /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "space-y-2 md:col-span-2", children: [
11794
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Label3, { children: "Address Line 2" }),
11795
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Input, { value: shippingAddress.line2, onChange: (e) => updateAddress("shipping", "line2", e.target.value), placeholder: "Apartment, Suite, Floor, etc." })
11796
- ] }),
11797
- /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "space-y-2 md:col-span-2", children: [
11798
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Label3, { children: "City" }),
11799
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Input, { value: shippingAddress.city, onChange: (e) => updateAddress("shipping", "city", e.target.value), placeholder: "City" })
11800
- ] }),
11801
- /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "space-y-2 md:col-span-2", children: [
11802
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Label3, { children: "State" }),
11803
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Input, { value: shippingAddress.state, onChange: (e) => updateAddress("shipping", "state", e.target.value), placeholder: "State" })
11804
- ] }),
11805
- /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "space-y-2 md:col-span-2", children: [
11806
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Label3, { children: "Country" }),
11807
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Input, { value: shippingAddress.country, onChange: (e) => updateAddress("shipping", "country", e.target.value), placeholder: "Country" })
11808
- ] }),
11809
- /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "space-y-2 md:col-span-2", children: [
11810
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Label3, { children: "Postal Code" }),
11811
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Input, { value: shippingAddress.postalCode, onChange: (e) => updateAddress("shipping", "postalCode", e.target.value), placeholder: "Postal Code" })
11812
- ] })
11887
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "space-y-2 md:col-span-2", children: [
11888
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Label3, { children: "Address Line 2" }),
11889
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Input, { value: shippingAddress.line2, onChange: (e) => updateAddress("shipping", "line2", e.target.value), placeholder: "Apartment, Suite, Floor, etc." })
11890
+ ] }),
11891
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "space-y-2 md:col-span-2", children: [
11892
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Label3, { children: "City" }),
11893
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Input, { value: shippingAddress.city, onChange: (e) => updateAddress("shipping", "city", e.target.value), placeholder: "City" })
11894
+ ] }),
11895
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "space-y-2 md:col-span-2", children: [
11896
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Label3, { children: "State" }),
11897
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Input, { value: shippingAddress.state, onChange: (e) => updateAddress("shipping", "state", e.target.value), placeholder: "State" })
11898
+ ] }),
11899
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "space-y-2 md:col-span-2", children: [
11900
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Label3, { children: "Country" }),
11901
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Input, { value: shippingAddress.country, onChange: (e) => updateAddress("shipping", "country", e.target.value), placeholder: "Country" })
11902
+ ] }),
11903
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "space-y-2 md:col-span-2", children: [
11904
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Label3, { children: "Postal Code" }),
11905
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Input, { value: shippingAddress.postalCode, onChange: (e) => updateAddress("shipping", "postalCode", e.target.value), placeholder: "Postal Code" })
11813
11906
  ] })
11814
11907
  ] })
11815
11908
  ] })
@@ -11907,51 +12000,21 @@ function OrderPlacementPage({ editOrderId }) {
11907
12000
  const active = selectedKey === line.key;
11908
12001
  const calc = calcByProductId.get(line.productId);
11909
12002
  const isReward = line.key.startsWith("reward-");
11910
- return /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)(
11911
- TableRow,
11912
- {
11913
- className: active ? "bg-blue-50/80 cursor-pointer" : "cursor-pointer",
11914
- onClick: () => setSelectedKey(line.key),
11915
- children: [
11916
- /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)(TableCell, { className: "align-top min-w-0", children: [
11917
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("p", { className: "font-medium text-gray-900 break-words", children: line.label }),
11918
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("p", { className: "text-xs text-gray-500 font-mono", children: line.sku ?? "\u2014" }),
11919
- isReward && /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("span", { className: "text-[10px] text-purple-600 font-medium", children: "\u{1F381} Reward" })
11920
- ] }),
11921
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(TableCell, { className: "align-top text-right", children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
11922
- Input,
11923
- {
11924
- type: "number",
11925
- min: 1,
11926
- className: "h-8 w-14 ml-auto text-right",
11927
- value: line.quantity,
11928
- onChange: (e) => updateQty(line.key, Number(e.target.value)),
11929
- onClick: (e) => e.stopPropagation(),
11930
- readOnly: isReward,
11931
- disabled: isReward
11932
- }
11933
- ) }),
11934
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(TableCell, { className: "align-top text-right text-sm hidden sm:table-cell whitespace-nowrap", children: calc ? formatMoney3(calc.unitPrice, currency) : previewLoading ? "\u2026" : "\u2014" }),
11935
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(TableCell, { className: "align-top text-right text-sm hidden md:table-cell whitespace-nowrap", children: calc ? formatMoney3(calc.tax, currency) : previewLoading ? "\u2026" : "\u2014" }),
11936
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(TableCell, { className: "align-top text-right font-medium text-sm whitespace-nowrap", children: calc ? formatMoney3(calc.total, currency) : previewLoading ? "\u2026" : "\u2014" }),
11937
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(TableCell, { className: "align-top", children: !isReward && /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
11938
- Button,
11939
- {
11940
- type: "button",
11941
- variant: "ghost",
11942
- size: "icon",
11943
- className: "h-8 w-8 text-red-600",
11944
- onClick: (e) => {
11945
- e.stopPropagation();
11946
- removeLine(line.key);
11947
- },
11948
- children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(import_lucide_react30.Trash2, { className: "h-4 w-4" })
11949
- }
11950
- ) })
11951
- ]
11952
- },
11953
- line.key
11954
- );
12003
+ return /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)(TableRow, { className: active ? "bg-blue-50/80 cursor-pointer" : "cursor-pointer", onClick: () => setSelectedKey(line.key), children: [
12004
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)(TableCell, { className: "align-top min-w-0", children: [
12005
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("p", { className: "font-medium text-gray-900 break-words", children: line.label }),
12006
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("p", { className: "text-xs text-gray-500 font-mono", children: line.sku ?? "\u2014" }),
12007
+ isReward && /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("span", { className: "text-[10px] text-purple-600 font-medium", children: "\u{1F381} Reward" })
12008
+ ] }),
12009
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(TableCell, { className: "align-top text-right", children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(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 }) }),
12010
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(TableCell, { className: "align-top text-right text-sm hidden sm:table-cell whitespace-nowrap", children: calc ? formatMoney3(calc.unitPrice, currency) : previewLoading ? "\u2026" : "\u2014" }),
12011
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(TableCell, { className: "align-top text-right text-sm hidden md:table-cell whitespace-nowrap", children: calc ? formatMoney3(calc.tax, currency) : previewLoading ? "\u2026" : "\u2014" }),
12012
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(TableCell, { className: "align-top text-right font-medium text-sm whitespace-nowrap", children: calc ? formatMoney3(calc.total, currency) : previewLoading ? "\u2026" : "\u2014" }),
12013
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(TableCell, { className: "align-top", children: !isReward && /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Button, { type: "button", variant: "ghost", size: "icon", className: "h-8 w-8 text-red-600", onClick: (e) => {
12014
+ e.stopPropagation();
12015
+ removeLine(line.key);
12016
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(import_lucide_react30.Trash2, { className: "h-4 w-4" }) }) })
12017
+ ] }, line.key);
11955
12018
  }) })
11956
12019
  ] }) }),
11957
12020
  /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("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: [
@@ -12018,21 +12081,13 @@ function OrderPlacementPage({ editOrderId }) {
12018
12081
  if (!hit) return;
12019
12082
  const productHit = hit;
12020
12083
  setLines((prev) => {
12021
- const existingRewardIdx = prev.findIndex(
12022
- (l) => l.productId === pid && rewardProductIds.current.has(pid)
12023
- );
12084
+ const existingRewardIdx = prev.findIndex((l) => l.productId === pid && rewardProductIds.current.has(pid));
12024
12085
  if (existingRewardIdx >= 0) {
12025
12086
  const next = [...prev];
12026
12087
  next[existingRewardIdx] = { ...next[existingRewardIdx], quantity: qty };
12027
12088
  return next;
12028
12089
  }
12029
- return [...prev, {
12030
- key: `reward-${pid}-${coupon.discountId}`,
12031
- productId: pid,
12032
- label: productHit.name ?? `Product #${pid}`,
12033
- sku: productHit.sku,
12034
- quantity: qty
12035
- }];
12090
+ return [...prev, { key: `reward-${pid}-${coupon.discountId}`, productId: pid, label: productHit.name ?? `Product #${pid}`, sku: productHit.sku, quantity: qty }];
12036
12091
  });
12037
12092
  });
12038
12093
  }
@@ -21050,8 +21105,12 @@ function SchedulesPage() {
21050
21105
 
21051
21106
  // src/admin/pages/VendorOnboardPage.tsx
21052
21107
  var import_react59 = require("react");
21108
+ var import_navigation27 = require("next/navigation");
21053
21109
  var import_react60 = require("next-auth/react");
21110
+ var import_lucide_react46 = require("lucide-react");
21054
21111
  init_vendor_scope();
21112
+ init_DetailPageHeader();
21113
+ init_DetailPageLayout();
21055
21114
  init_button();
21056
21115
  init_input();
21057
21116
 
@@ -21090,10 +21149,39 @@ RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName;
21090
21149
 
21091
21150
  // src/admin/pages/VendorOnboardPage.tsx
21092
21151
  var import_jsx_runtime76 = require("react/jsx-runtime");
21093
- function VendorOnboardPage() {
21094
- const { data: session } = (0, import_react60.useSession)();
21095
- const sessionUser = session?.user;
21096
- const isAdmin = canOnboardVendors(session?.user);
21152
+ var VENDOR_LIST_COLUMNS = [
21153
+ { field: "name", displayName: "Name" },
21154
+ { field: "slug", displayName: "Slug" },
21155
+ { field: "email", displayName: "Email" },
21156
+ { field: "phone", displayName: "Phone" },
21157
+ { field: "active", displayName: "Active", type: "boolean" },
21158
+ {
21159
+ field: "inviteStatus",
21160
+ displayName: "Invite",
21161
+ type: "select",
21162
+ options: [
21163
+ { value: "none", label: "None" },
21164
+ { value: "pending", label: "Pending" },
21165
+ { value: "expired", label: "Expired" },
21166
+ { value: "accepted", label: "Accepted" }
21167
+ ]
21168
+ },
21169
+ { field: "createdAt", displayName: "Created", type: "date" }
21170
+ ];
21171
+ function AccessDenied({ groupName }) {
21172
+ return /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("div", { className: "rounded-lg bg-white p-6 shadow-md max-w-lg", children: /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("p", { className: "text-sm text-red-600", children: [
21173
+ "Only users in the ",
21174
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("strong", { children: "Administrator" }),
21175
+ " group can manage vendors.",
21176
+ groupName ? /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)(import_jsx_runtime76.Fragment, { children: [
21177
+ " ",
21178
+ "Your group is ",
21179
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("strong", { children: groupName }),
21180
+ ". Assign Administrator under System \u2192 Users, then sign out and sign in again."
21181
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(import_jsx_runtime76.Fragment, { children: " Assign the Administrator group under System \u2192 Users, then sign out and sign in again." })
21182
+ ] }) });
21183
+ }
21184
+ function VendorOnboardForm({ onSuccess }) {
21097
21185
  const [vendorName, setVendorName] = (0, import_react59.useState)("");
21098
21186
  const [vendorSlug, setVendorSlug] = (0, import_react59.useState)("");
21099
21187
  const [vendorEmail, setVendorEmail] = (0, import_react59.useState)("");
@@ -21101,44 +21189,31 @@ function VendorOnboardPage() {
21101
21189
  const [ownerName, setOwnerName] = (0, import_react59.useState)("");
21102
21190
  const [ownerEmail, setOwnerEmail] = (0, import_react59.useState)("");
21103
21191
  const [activationMode, setActivationMode] = (0, import_react59.useState)("invite");
21104
- const [sendInviteEmail, setSendInviteEmail] = (0, import_react59.useState)(true);
21192
+ const [sendOwnerEmail, setSendOwnerEmail] = (0, import_react59.useState)(true);
21105
21193
  const [ownerPassword, setOwnerPassword] = (0, import_react59.useState)("");
21106
21194
  const [ownerPasswordConfirm, setOwnerPasswordConfirm] = (0, import_react59.useState)("");
21107
21195
  const [loading, setLoading] = (0, import_react59.useState)(false);
21108
21196
  const [message, setMessage] = (0, import_react59.useState)(null);
21109
21197
  const [inviteLink, setInviteLink] = (0, import_react59.useState)(null);
21110
- const [error, setError] = (0, import_react59.useState)(null);
21111
- if (!isAdmin) {
21112
- return /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("div", { className: "p-6 max-w-lg", children: /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("p", { className: "text-sm text-red-600", children: [
21113
- "Only users in the ",
21114
- /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("strong", { children: "Administrator" }),
21115
- " group can onboard vendors.",
21116
- sessionUser?.groupName ? /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)(import_jsx_runtime76.Fragment, { children: [
21117
- " Your group is ",
21118
- /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("strong", { children: sessionUser.groupName }),
21119
- ". Assign Administrator under System \u2192 Users, then sign out and sign in again."
21120
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(import_jsx_runtime76.Fragment, { children: " Assign the Administrator group under System \u2192 Users, then sign out and sign in again." })
21121
- ] }) });
21122
- }
21123
- const handleSubmit = async (e) => {
21124
- e.preventDefault();
21198
+ const [errors, setErrors] = (0, import_react59.useState)([]);
21199
+ const handleSubmit = async () => {
21125
21200
  setLoading(true);
21126
21201
  setMessage(null);
21127
- setError(null);
21202
+ setErrors([]);
21128
21203
  setInviteLink(null);
21129
21204
  if (activationMode === "password") {
21130
21205
  if (!ownerPassword) {
21131
- setError("Enter a password for the owner account");
21206
+ setErrors(["Enter a password for the owner account"]);
21132
21207
  setLoading(false);
21133
21208
  return;
21134
21209
  }
21135
21210
  if (ownerPassword !== ownerPasswordConfirm) {
21136
- setError("Passwords do not match");
21211
+ setErrors(["Passwords do not match"]);
21137
21212
  setLoading(false);
21138
21213
  return;
21139
21214
  }
21140
21215
  if (ownerPassword.length < 6) {
21141
- setError("Password must be at least 6 characters");
21216
+ setErrors(["Password must be at least 6 characters"]);
21142
21217
  setLoading(false);
21143
21218
  return;
21144
21219
  }
@@ -21149,7 +21224,7 @@ function VendorOnboardPage() {
21149
21224
  headers: { "Content-Type": "application/json" },
21150
21225
  body: JSON.stringify({
21151
21226
  activation: activationMode,
21152
- sendInviteEmail: activationMode === "invite" ? sendInviteEmail : false,
21227
+ sendOwnerEmail,
21153
21228
  vendor: {
21154
21229
  name: vendorName,
21155
21230
  slug: vendorSlug || void 0,
@@ -21166,140 +21241,241 @@ function VendorOnboardPage() {
21166
21241
  });
21167
21242
  const data = await res.json();
21168
21243
  if (!res.ok) {
21169
- setError(data.error || "Onboarding failed");
21244
+ setErrors([data.error || "Onboarding failed"]);
21170
21245
  return;
21171
21246
  }
21172
21247
  setMessage(data.message || "Vendor created");
21173
21248
  setInviteLink(data.inviteLink ?? null);
21174
- setVendorName("");
21175
- setVendorSlug("");
21176
- setVendorEmail("");
21177
- setVendorPhone("");
21178
- setOwnerName("");
21179
- setOwnerEmail("");
21180
- setOwnerPassword("");
21181
- setOwnerPasswordConfirm("");
21249
+ if (!data.inviteLink) {
21250
+ onSuccess();
21251
+ }
21182
21252
  } catch {
21183
- setError("Request failed");
21253
+ setErrors(["Request failed"]);
21184
21254
  } finally {
21185
21255
  setLoading(false);
21186
21256
  }
21187
21257
  };
21188
- const submitLabel = activationMode === "password" ? "Create vendor & set password" : sendInviteEmail ? "Create vendor & send invite" : "Create vendor & copy invite link";
21189
- return /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { className: "p-6 max-w-xl", children: [
21190
- /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("h1", { className: "text-xl font-semibold text-gray-900 dark:text-white", children: "Onboard vendor" }),
21191
- /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("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." }),
21192
- /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("form", { onSubmit: handleSubmit, className: "mt-6 space-y-6", children: [
21193
- /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { className: "space-y-3", children: [
21194
- /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("h2", { className: "text-sm font-medium text-gray-900 dark:text-white", children: "Store" }),
21195
- /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { children: [
21196
- /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(Label3, { htmlFor: "vendorName", children: "Store name" }),
21197
- /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(Input, { id: "vendorName", required: true, value: vendorName, onChange: (e) => setVendorName(e.target.value), className: "mt-1" })
21198
- ] }),
21199
- /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { children: [
21200
- /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(Label3, { htmlFor: "vendorSlug", children: "Slug (optional)" }),
21201
- /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(Input, { id: "vendorSlug", value: vendorSlug, onChange: (e) => setVendorSlug(e.target.value), placeholder: "auto from name", className: "mt-1" })
21202
- ] }),
21203
- /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { children: [
21204
- /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(Label3, { htmlFor: "vendorEmail", children: "Store email" }),
21205
- /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(Input, { id: "vendorEmail", type: "email", value: vendorEmail, onChange: (e) => setVendorEmail(e.target.value), className: "mt-1" })
21206
- ] }),
21207
- /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { children: [
21208
- /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(Label3, { htmlFor: "vendorPhone", children: "Phone" }),
21209
- /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(Input, { id: "vendorPhone", value: vendorPhone, onChange: (e) => setVendorPhone(e.target.value), className: "mt-1" })
21210
- ] })
21211
- ] }),
21212
- /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { className: "space-y-3", children: [
21213
- /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("h2", { className: "text-sm font-medium text-gray-900 dark:text-white", children: "Owner account" }),
21214
- /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { children: [
21215
- /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(Label3, { htmlFor: "ownerName", children: "Name" }),
21216
- /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(Input, { id: "ownerName", required: true, value: ownerName, onChange: (e) => setOwnerName(e.target.value), className: "mt-1" })
21217
- ] }),
21218
- /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { children: [
21219
- /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(Label3, { htmlFor: "ownerEmail", children: "Email" }),
21220
- /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(Input, { id: "ownerEmail", type: "email", required: true, value: ownerEmail, onChange: (e) => setOwnerEmail(e.target.value), className: "mt-1" })
21221
- ] })
21258
+ const submitLabel = activationMode === "password" ? sendOwnerEmail ? "Create vendor & send welcome email" : "Create vendor & set password" : sendOwnerEmail ? "Create vendor & send invite" : "Create vendor & copy invite link";
21259
+ const fieldClass = "w-full rounded-md border border-gray-300 px-3 py-2 text-sm";
21260
+ return /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { className: "rounded-lg bg-white shadow-md", children: [
21261
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(
21262
+ DetailPageHeader,
21263
+ {
21264
+ title: "Create vendor",
21265
+ subtitle: "Creates a vendor store and a Vendor Owner account",
21266
+ closeHref: "/admin/vendor-onboard",
21267
+ menuItems: [{ label: loading ? "Creating\u2026" : submitLabel, icon: import_lucide_react46.Save, onClick: handleSubmit }]
21268
+ }
21269
+ ),
21270
+ errors.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("div", { className: "bg-red-50 border-l-4 border-red-400 p-4 mx-6 mt-4", children: /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { className: "flex", children: [
21271
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(import_lucide_react46.AlertCircle, { className: "h-5 w-5 text-red-400 flex-shrink-0" }),
21272
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { className: "ml-3", children: [
21273
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("h3", { className: "text-sm font-medium text-red-800", children: "Please fix the following errors:" }),
21274
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("ul", { className: "mt-2 text-sm text-red-700 list-disc pl-5 space-y-1", children: errors.map((e, i) => /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("li", { children: e }, i)) })
21275
+ ] })
21276
+ ] }) }),
21277
+ message && /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { className: "mx-6 mt-4 rounded-lg border border-green-200 bg-green-50 p-4 text-sm text-green-800", children: [
21278
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("p", { children: message }),
21279
+ inviteLink && /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("p", { className: "mt-2 text-xs break-all", children: [
21280
+ "Invite link:",
21281
+ " ",
21282
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("a", { href: inviteLink, className: "text-blue-600 underline", children: inviteLink })
21222
21283
  ] }),
21223
- /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { className: "space-y-3 rounded-lg border border-gray-200 p-4", children: [
21224
- /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("h2", { className: "text-sm font-medium text-gray-900 dark:text-white", children: "Owner access" }),
21225
- /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)(
21226
- RadioGroup2,
21227
- {
21228
- value: activationMode,
21229
- onValueChange: (v) => setActivationMode(v),
21230
- className: "gap-3",
21231
- children: [
21232
- /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { className: "flex items-start gap-2", children: [
21233
- /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(RadioGroupItem, { value: "invite", id: "activation-invite", className: "mt-0.5" }),
21234
- /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { children: [
21235
- /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(Label3, { htmlFor: "activation-invite", className: "font-normal cursor-pointer", children: "Send invite link" }),
21236
- /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("p", { className: "text-xs text-gray-500 mt-0.5", children: "Owner sets their own password via email or the link below." })
21237
- ] })
21284
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(Button, { type: "button", variant: "outline", size: "sm", className: "mt-3", onClick: onSuccess, children: "Back to vendors" })
21285
+ ] }),
21286
+ !message && /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(
21287
+ DetailPageLayout,
21288
+ {
21289
+ main: /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)(import_jsx_runtime76.Fragment, { children: [
21290
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("section", { children: [
21291
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("h2", { className: "text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2", children: "Store" }),
21292
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { className: "min-w-0 overflow-hidden border border-gray-200 rounded-lg p-4 bg-gray-50/50 space-y-4", children: [
21293
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { children: [
21294
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(Label3, { htmlFor: "vendorName", className: "text-xs font-medium text-gray-600", children: "Store name *" }),
21295
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(
21296
+ Input,
21297
+ {
21298
+ id: "vendorName",
21299
+ required: true,
21300
+ value: vendorName,
21301
+ onChange: (e) => setVendorName(e.target.value),
21302
+ className: `mt-1 ${fieldClass}`
21303
+ }
21304
+ )
21238
21305
  ] }),
21239
- /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { className: "flex items-start gap-2", children: [
21240
- /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(RadioGroupItem, { value: "password", id: "activation-password", className: "mt-0.5" }),
21241
- /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { children: [
21242
- /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(Label3, { htmlFor: "activation-password", className: "font-normal cursor-pointer", children: "Set password now" }),
21243
- /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("p", { className: "text-xs text-gray-500 mt-0.5", children: "Account is active immediately; share the password with the owner securely." })
21244
- ] })
21306
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { children: [
21307
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(Label3, { htmlFor: "vendorSlug", className: "text-xs font-medium text-gray-600", children: "Slug (optional)" }),
21308
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(
21309
+ Input,
21310
+ {
21311
+ id: "vendorSlug",
21312
+ value: vendorSlug,
21313
+ onChange: (e) => setVendorSlug(e.target.value),
21314
+ placeholder: "auto from name",
21315
+ className: `mt-1 ${fieldClass}`
21316
+ }
21317
+ )
21318
+ ] }),
21319
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { children: [
21320
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(Label3, { htmlFor: "vendorEmail", className: "text-xs font-medium text-gray-600", children: "Store email" }),
21321
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(
21322
+ Input,
21323
+ {
21324
+ id: "vendorEmail",
21325
+ type: "email",
21326
+ value: vendorEmail,
21327
+ onChange: (e) => setVendorEmail(e.target.value),
21328
+ className: `mt-1 ${fieldClass}`
21329
+ }
21330
+ )
21331
+ ] }),
21332
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { children: [
21333
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(Label3, { htmlFor: "vendorPhone", className: "text-xs font-medium text-gray-600", children: "Phone" }),
21334
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(
21335
+ Input,
21336
+ {
21337
+ id: "vendorPhone",
21338
+ value: vendorPhone,
21339
+ onChange: (e) => setVendorPhone(e.target.value),
21340
+ className: `mt-1 ${fieldClass}`
21341
+ }
21342
+ )
21245
21343
  ] })
21246
- ]
21247
- }
21248
- ),
21249
- activationMode === "invite" && /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { className: "flex items-center gap-2 pt-1", children: [
21250
- /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(
21251
- Checkbox,
21252
- {
21253
- id: "sendInviteEmail",
21254
- checked: sendInviteEmail,
21255
- onCheckedChange: (checked) => setSendInviteEmail(checked === true)
21256
- }
21257
- ),
21258
- /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(Label3, { htmlFor: "sendInviteEmail", className: "font-normal cursor-pointer text-sm", children: "Send invite email to owner" })
21259
- ] }),
21260
- activationMode === "password" && /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { className: "space-y-3 pt-1", children: [
21261
- /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { children: [
21262
- /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(Label3, { htmlFor: "ownerPassword", children: "Password" }),
21263
- /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(
21264
- Input,
21265
- {
21266
- id: "ownerPassword",
21267
- type: "password",
21268
- required: true,
21269
- autoComplete: "new-password",
21270
- value: ownerPassword,
21271
- onChange: (e) => setOwnerPassword(e.target.value),
21272
- className: "mt-1"
21273
- }
21274
- )
21344
+ ] })
21275
21345
  ] }),
21276
- /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { children: [
21277
- /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(Label3, { htmlFor: "ownerPasswordConfirm", children: "Confirm password" }),
21278
- /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(
21279
- Input,
21346
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("section", { children: [
21347
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("h2", { className: "text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2", children: "Owner account" }),
21348
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { className: "min-w-0 overflow-hidden border border-gray-200 rounded-lg p-4 bg-gray-50/50 space-y-4", children: [
21349
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { children: [
21350
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(Label3, { htmlFor: "ownerName", className: "text-xs font-medium text-gray-600", children: "Name *" }),
21351
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(
21352
+ Input,
21353
+ {
21354
+ id: "ownerName",
21355
+ required: true,
21356
+ value: ownerName,
21357
+ onChange: (e) => setOwnerName(e.target.value),
21358
+ className: `mt-1 ${fieldClass}`
21359
+ }
21360
+ )
21361
+ ] }),
21362
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { children: [
21363
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(Label3, { htmlFor: "ownerEmail", className: "text-xs font-medium text-gray-600", children: "Email *" }),
21364
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(
21365
+ Input,
21366
+ {
21367
+ id: "ownerEmail",
21368
+ type: "email",
21369
+ required: true,
21370
+ value: ownerEmail,
21371
+ onChange: (e) => setOwnerEmail(e.target.value),
21372
+ className: `mt-1 ${fieldClass}`
21373
+ }
21374
+ )
21375
+ ] })
21376
+ ] })
21377
+ ] })
21378
+ ] }),
21379
+ sidebar: /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("section", { children: [
21380
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("h2", { className: "text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2", children: "Owner access" }),
21381
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { className: "min-w-0 overflow-hidden border border-gray-200 rounded-lg p-4 bg-gray-50/50 space-y-4", children: [
21382
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)(
21383
+ RadioGroup2,
21280
21384
  {
21281
- id: "ownerPasswordConfirm",
21282
- type: "password",
21283
- required: true,
21284
- autoComplete: "new-password",
21285
- value: ownerPasswordConfirm,
21286
- onChange: (e) => setOwnerPasswordConfirm(e.target.value),
21287
- className: "mt-1"
21385
+ value: activationMode,
21386
+ onValueChange: (v) => setActivationMode(v),
21387
+ className: "gap-3",
21388
+ children: [
21389
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { className: "flex items-start gap-2", children: [
21390
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(RadioGroupItem, { value: "invite", id: "activation-invite", className: "mt-0.5" }),
21391
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { children: [
21392
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(Label3, { htmlFor: "activation-invite", className: "font-normal cursor-pointer text-sm", children: "Send invite link" }),
21393
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("p", { className: "text-xs text-gray-500 mt-0.5", children: "Owner sets their own password via email or the link below." })
21394
+ ] })
21395
+ ] }),
21396
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { className: "flex items-start gap-2", children: [
21397
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(RadioGroupItem, { value: "password", id: "activation-password", className: "mt-0.5" }),
21398
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { children: [
21399
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(Label3, { htmlFor: "activation-password", className: "font-normal cursor-pointer text-sm", children: "Set password now" }),
21400
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("p", { className: "text-xs text-gray-500 mt-0.5", children: "Account is active immediately; share the password with the owner securely." })
21401
+ ] })
21402
+ ] })
21403
+ ]
21288
21404
  }
21289
- )
21405
+ ),
21406
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { className: "flex items-center gap-2 pt-1", children: [
21407
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(
21408
+ Checkbox,
21409
+ {
21410
+ id: "sendOwnerEmail",
21411
+ checked: sendOwnerEmail,
21412
+ onCheckedChange: (checked) => setSendOwnerEmail(checked === true)
21413
+ }
21414
+ ),
21415
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(Label3, { htmlFor: "sendOwnerEmail", className: "font-normal cursor-pointer text-sm", children: activationMode === "invite" ? "Send invite email to owner" : "Send welcome email to owner" })
21416
+ ] }),
21417
+ activationMode === "password" && /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { className: "space-y-3 pt-1", children: [
21418
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { children: [
21419
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(Label3, { htmlFor: "ownerPassword", className: "text-xs font-medium text-gray-600", children: "Password *" }),
21420
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(
21421
+ Input,
21422
+ {
21423
+ id: "ownerPassword",
21424
+ type: "password",
21425
+ required: true,
21426
+ autoComplete: "new-password",
21427
+ value: ownerPassword,
21428
+ onChange: (e) => setOwnerPassword(e.target.value),
21429
+ className: `mt-1 ${fieldClass}`
21430
+ }
21431
+ )
21432
+ ] }),
21433
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { children: [
21434
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(Label3, { htmlFor: "ownerPasswordConfirm", className: "text-xs font-medium text-gray-600", children: "Confirm password *" }),
21435
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(
21436
+ Input,
21437
+ {
21438
+ id: "ownerPasswordConfirm",
21439
+ type: "password",
21440
+ required: true,
21441
+ autoComplete: "new-password",
21442
+ value: ownerPasswordConfirm,
21443
+ onChange: (e) => setOwnerPasswordConfirm(e.target.value),
21444
+ className: `mt-1 ${fieldClass}`
21445
+ }
21446
+ )
21447
+ ] })
21448
+ ] }),
21449
+ /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(Button, { type: "button", disabled: loading, onClick: handleSubmit, className: "w-full", children: loading ? "Creating\u2026" : submitLabel })
21290
21450
  ] })
21291
21451
  ] })
21292
- ] }),
21293
- error && /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("p", { className: "text-sm text-red-600", children: error }),
21294
- message && /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("p", { className: "text-sm text-green-700", children: message }),
21295
- inviteLink && /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("p", { className: "text-xs text-gray-600 break-all", children: [
21296
- "Invite link: ",
21297
- /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("a", { href: inviteLink, className: "text-blue-600 underline", children: inviteLink })
21298
- ] }),
21299
- /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(Button, { type: "submit", disabled: loading, children: loading ? "Creating\u2026" : submitLabel })
21300
- ] })
21452
+ }
21453
+ )
21301
21454
  ] });
21302
21455
  }
21456
+ function VendorOnboardPage({ showCreateForm }) {
21457
+ const router = (0, import_navigation27.useRouter)();
21458
+ const { data: session } = (0, import_react60.useSession)();
21459
+ const sessionUser = session?.user;
21460
+ const isAdmin = canOnboardVendors(session?.user);
21461
+ if (!isAdmin) {
21462
+ return /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(AccessDenied, { groupName: sessionUser?.groupName });
21463
+ }
21464
+ if (showCreateForm) {
21465
+ return /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(VendorOnboardForm, { onSuccess: () => router.push("/admin/vendor-onboard") });
21466
+ }
21467
+ return /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(
21468
+ AdminCRUD,
21469
+ {
21470
+ title: "Vendors",
21471
+ apiEndpoint: "/api/vendors",
21472
+ columns: [...VENDOR_LIST_COLUMNS],
21473
+ addEditPageUrl: "/admin/vendor-onboard",
21474
+ defaultSortField: "createdAt",
21475
+ defaultSortOrder: "desc"
21476
+ }
21477
+ );
21478
+ }
21303
21479
 
21304
21480
  // src/admin/pages/VendorTeamPage.tsx
21305
21481
  var import_react61 = require("react");
@@ -21812,9 +21988,9 @@ var STORE_CRUD_CONFIGS = {
21812
21988
  // src/admin/pages/DiscountDetailsPage.tsx
21813
21989
  var import_react63 = require("react");
21814
21990
  var import_link14 = __toESM(require("next/link"), 1);
21815
- var import_navigation27 = require("next/navigation");
21991
+ var import_navigation28 = require("next/navigation");
21816
21992
  init_admin_list_return_url();
21817
- var import_lucide_react46 = require("lucide-react");
21993
+ var import_lucide_react47 = require("lucide-react");
21818
21994
  init_button();
21819
21995
  init_utils();
21820
21996
  init_DetailPageLayout();
@@ -21903,7 +22079,7 @@ function RuleTreeNode({ node, depth = 0 }) {
21903
22079
  type: "button",
21904
22080
  onClick: () => setOpen(!open),
21905
22081
  className: "text-gray-400 hover:text-gray-600",
21906
- children: open ? /* @__PURE__ */ (0, import_jsx_runtime78.jsx)(import_lucide_react46.ChevronDown, { className: "h-4 w-4" }) : /* @__PURE__ */ (0, import_jsx_runtime78.jsx)(import_lucide_react46.ChevronRight, { className: "h-4 w-4" })
22082
+ children: open ? /* @__PURE__ */ (0, import_jsx_runtime78.jsx)(import_lucide_react47.ChevronDown, { className: "h-4 w-4" }) : /* @__PURE__ */ (0, import_jsx_runtime78.jsx)(import_lucide_react47.ChevronRight, { className: "h-4 w-4" })
21907
22083
  }
21908
22084
  ),
21909
22085
  /* @__PURE__ */ (0, import_jsx_runtime78.jsx)("span", { className: "font-semibold text-xs uppercase text-gray-500", children: "Group" }),
@@ -21918,8 +22094,8 @@ function RuleTreeNode({ node, depth = 0 }) {
21918
22094
  ] });
21919
22095
  }
21920
22096
  function DiscountDetailPage({ discountId }) {
21921
- const router = (0, import_navigation27.useRouter)();
21922
- const searchParams = (0, import_navigation27.useSearchParams)();
22097
+ const router = (0, import_navigation28.useRouter)();
22098
+ const searchParams = (0, import_navigation28.useSearchParams)();
21923
22099
  const listReturnUrl = safeAdminListReturnUrl(searchParams.get("from")) ?? "/admin/discounts";
21924
22100
  const [discount, setDiscount] = (0, import_react63.useState)(null);
21925
22101
  const [loading, setLoading] = (0, import_react63.useState)(true);
@@ -21967,7 +22143,7 @@ function DiscountDetailPage({ discountId }) {
21967
22143
  return /* @__PURE__ */ (0, import_jsx_runtime78.jsxs)("div", { className: "rounded-lg bg-white p-6 shadow-md", children: [
21968
22144
  /* @__PURE__ */ (0, import_jsx_runtime78.jsx)("p", { className: "text-red-600", children: error ?? "Not found" }),
21969
22145
  /* @__PURE__ */ (0, import_jsx_runtime78.jsx)(import_link14.default, { href: listReturnUrl, children: /* @__PURE__ */ (0, import_jsx_runtime78.jsxs)(Button, { variant: "outline", className: "mt-4", children: [
21970
- /* @__PURE__ */ (0, import_jsx_runtime78.jsx)(import_lucide_react46.X, { className: "h-4 w-4 mr-2" }),
22146
+ /* @__PURE__ */ (0, import_jsx_runtime78.jsx)(import_lucide_react47.X, { className: "h-4 w-4 mr-2" }),
21971
22147
  " Close"
21972
22148
  ] }) })
21973
22149
  ] });
@@ -21989,14 +22165,14 @@ function DiscountDetailPage({ discountId }) {
21989
22165
  title: /* @__PURE__ */ (0, import_jsx_runtime78.jsxs)("span", { className: "flex items-center gap-2", children: [
21990
22166
  discount.name,
21991
22167
  discount.isAutomatic && /* @__PURE__ */ (0, import_jsx_runtime78.jsxs)("span", { className: "inline-flex items-center gap-1 rounded-full bg-amber-100 px-2 py-0.5 text-xs font-medium text-amber-700", children: [
21992
- /* @__PURE__ */ (0, import_jsx_runtime78.jsx)(import_lucide_react46.Zap, { className: "h-3 w-3" }),
22168
+ /* @__PURE__ */ (0, import_jsx_runtime78.jsx)(import_lucide_react47.Zap, { className: "h-3 w-3" }),
21993
22169
  " Automatic"
21994
22170
  ] })
21995
22171
  ] }),
21996
22172
  subtitle: discount.isAutomatic ? /* @__PURE__ */ (0, import_jsx_runtime78.jsx)("span", { className: "text-sm text-gray-400 italic", children: "No coupon code \u2014 applied automatically" }) : /* @__PURE__ */ (0, import_jsx_runtime78.jsx)("span", { className: "font-mono text-sm text-gray-400", children: discount.couponCode }),
21997
22173
  closeHref: listReturnUrl,
21998
22174
  menuItems: [
21999
- { label: "Edit discount", icon: import_lucide_react46.Pencil, onClick: () => router.push(editHref) }
22175
+ { label: "Edit discount", icon: import_lucide_react47.Pencil, onClick: () => router.push(editHref) }
22000
22176
  ]
22001
22177
  }
22002
22178
  ),
@@ -22036,7 +22212,7 @@ function DiscountDetailPage({ discountId }) {
22036
22212
  /* @__PURE__ */ (0, import_jsx_runtime78.jsxs)("div", { children: [
22037
22213
  /* @__PURE__ */ (0, import_jsx_runtime78.jsx)("dt", { className: "text-gray-500", children: "Application" }),
22038
22214
  /* @__PURE__ */ (0, import_jsx_runtime78.jsx)("dd", { className: "font-medium text-gray-900", children: discount.isAutomatic ? /* @__PURE__ */ (0, import_jsx_runtime78.jsxs)("span", { className: "inline-flex items-center gap-1 text-amber-700", children: [
22039
- /* @__PURE__ */ (0, import_jsx_runtime78.jsx)(import_lucide_react46.Zap, { className: "h-3.5 w-3.5" }),
22215
+ /* @__PURE__ */ (0, import_jsx_runtime78.jsx)(import_lucide_react47.Zap, { className: "h-3.5 w-3.5" }),
22040
22216
  " Automatic"
22041
22217
  ] }) : "Coupon code" })
22042
22218
  ] }),
@@ -22131,7 +22307,7 @@ function DiscountDetailPage({ discountId }) {
22131
22307
  discount.isAutomatic && /* @__PURE__ */ (0, import_jsx_runtime78.jsxs)("section", { children: [
22132
22308
  /* @__PURE__ */ (0, import_jsx_runtime78.jsx)("h2", { className: "text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2", children: "Application" }),
22133
22309
  /* @__PURE__ */ (0, import_jsx_runtime78.jsxs)("div", { className: "border border-amber-200 rounded-lg p-4 bg-amber-50/50 flex items-start gap-2 text-sm text-amber-800", children: [
22134
- /* @__PURE__ */ (0, import_jsx_runtime78.jsx)(import_lucide_react46.Zap, { className: "h-4 w-4 mt-0.5 flex-shrink-0 text-amber-500" }),
22310
+ /* @__PURE__ */ (0, import_jsx_runtime78.jsx)(import_lucide_react47.Zap, { className: "h-4 w-4 mt-0.5 flex-shrink-0 text-amber-500" }),
22135
22311
  /* @__PURE__ */ (0, import_jsx_runtime78.jsxs)("span", { children: [
22136
22312
  "This discount is applied ",
22137
22313
  /* @__PURE__ */ (0, import_jsx_runtime78.jsx)("strong", { children: "automatically" }),
@@ -22147,15 +22323,15 @@ function DiscountDetailPage({ discountId }) {
22147
22323
 
22148
22324
  // src/admin/pages/DiscountEditPage.tsx
22149
22325
  var import_react65 = require("react");
22150
- var import_navigation28 = require("next/navigation");
22326
+ var import_navigation29 = require("next/navigation");
22151
22327
  init_admin_list_return_url();
22152
- var import_lucide_react48 = require("lucide-react");
22328
+ var import_lucide_react49 = require("lucide-react");
22153
22329
  init_DetailPageLayout();
22154
22330
  init_DetailPageHeader();
22155
22331
 
22156
22332
  // src/admin/pages/DiscountsConditionsBuilder.tsx
22157
22333
  var import_react64 = require("react");
22158
- var import_lucide_react47 = require("lucide-react");
22334
+ var import_lucide_react48 = require("lucide-react");
22159
22335
  init_button();
22160
22336
  var import_jsx_runtime79 = require("react/jsx-runtime");
22161
22337
  function uid() {
@@ -22358,14 +22534,14 @@ function ProductPicker({
22358
22534
  onClick: () => setOpen((o) => !o),
22359
22535
  className: "flex items-center gap-2 w-full rounded-md border border-gray-300 px-3 py-1.5 text-sm text-left hover:border-gray-400 focus:outline-none focus:ring-1 focus:ring-gray-400 bg-white",
22360
22536
  children: [
22361
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(import_lucide_react47.Package, { className: "h-3.5 w-3.5 text-gray-400 shrink-0" }),
22537
+ /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(import_lucide_react48.Package, { className: "h-3.5 w-3.5 text-gray-400 shrink-0" }),
22362
22538
  /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: label ? "text-gray-900" : "text-gray-400", children: label ?? "Select product\u2026" })
22363
22539
  ]
22364
22540
  }
22365
22541
  ),
22366
22542
  open && /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: "absolute z-50 top-full left-0 right-0 mt-1 rounded-lg border border-gray-200 bg-white shadow-lg", children: [
22367
22543
  /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("div", { className: "p-2 border-b border-gray-100", children: /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: "flex items-center gap-2 px-2 py-1 rounded border border-gray-200", children: [
22368
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(import_lucide_react47.Search, { className: "h-3.5 w-3.5 text-gray-400" }),
22544
+ /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(import_lucide_react48.Search, { className: "h-3.5 w-3.5 text-gray-400" }),
22369
22545
  /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("input", { autoFocus: true, value: query, onChange: (e) => setQuery(e.target.value), placeholder: "Search products\u2026", className: "flex-1 text-sm outline-none bg-transparent" })
22370
22546
  ] }) }),
22371
22547
  /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("div", { className: "max-h-48 overflow-y-auto", children: loading ? /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("p", { className: "text-xs text-gray-400 p-3", children: "Loading\u2026" }) : hits.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("p", { className: "text-xs text-gray-400 p-3", children: "No products found" }) : hits.map((p) => /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)(
@@ -22426,14 +22602,14 @@ function CategoryPicker({
22426
22602
  onClick: () => setOpen((o) => !o),
22427
22603
  className: "flex items-center gap-2 w-full rounded-md border border-gray-300 px-3 py-1.5 text-sm text-left hover:border-gray-400 focus:outline-none focus:ring-1 focus:ring-gray-400 bg-white",
22428
22604
  children: [
22429
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(import_lucide_react47.Package, { className: "h-3.5 w-3.5 text-gray-400 shrink-0" }),
22605
+ /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(import_lucide_react48.Package, { className: "h-3.5 w-3.5 text-gray-400 shrink-0" }),
22430
22606
  /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: label ? "text-gray-900" : "text-gray-400", children: label ?? "Select category\u2026" })
22431
22607
  ]
22432
22608
  }
22433
22609
  ),
22434
22610
  open && /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: "absolute z-50 top-full left-0 right-0 mt-1 rounded-lg border border-gray-200 bg-white shadow-lg", children: [
22435
22611
  /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("div", { className: "p-2 border-b border-gray-100", children: /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: "flex items-center gap-2 px-2 py-1 rounded border border-gray-200", children: [
22436
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(import_lucide_react47.Search, { className: "h-3.5 w-3.5 text-gray-400" }),
22612
+ /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(import_lucide_react48.Search, { className: "h-3.5 w-3.5 text-gray-400" }),
22437
22613
  /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("input", { autoFocus: true, value: query, onChange: (e) => setQuery(e.target.value), placeholder: "Search categories\u2026", className: "flex-1 text-sm outline-none bg-transparent" })
22438
22614
  ] }) }),
22439
22615
  /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("div", { className: "max-h-48 overflow-y-auto", children: loading ? /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("p", { className: "text-xs text-gray-400 p-3", children: "Loading\u2026" }) : hits.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("p", { className: "text-xs text-gray-400 p-3", children: "No categories found" }) : hits.map((c) => /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)(
@@ -22533,14 +22709,14 @@ function CustomerPicker({
22533
22709
  onClick: () => setOpen((o) => !o),
22534
22710
  className: "flex items-center gap-2 w-full rounded-md border border-gray-300 px-3 py-1.5 text-sm text-left hover:border-gray-400 focus:outline-none focus:ring-1 focus:ring-gray-400 bg-white",
22535
22711
  children: [
22536
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(import_lucide_react47.User, { className: "h-3.5 w-3.5 text-gray-400 shrink-0" }),
22712
+ /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(import_lucide_react48.User, { className: "h-3.5 w-3.5 text-gray-400 shrink-0" }),
22537
22713
  /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("span", { className: displayLabel ? "text-gray-900" : "text-gray-400", children: displayLabel || "Select customer\u2026" })
22538
22714
  ]
22539
22715
  }
22540
22716
  ),
22541
22717
  open && /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: "absolute z-50 top-full left-0 right-0 mt-1 rounded-lg border border-gray-200 bg-white shadow-lg", children: [
22542
22718
  /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("div", { className: "p-2 border-b border-gray-100", children: /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: "flex items-center gap-2 px-2 py-1 rounded border border-gray-200", children: [
22543
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(import_lucide_react47.Search, { className: "h-3.5 w-3.5 text-gray-400" }),
22719
+ /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(import_lucide_react48.Search, { className: "h-3.5 w-3.5 text-gray-400" }),
22544
22720
  /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("input", { autoFocus: true, value: query, onChange: (e) => setQuery(e.target.value), placeholder: "Search customers\u2026", className: "flex-1 text-sm outline-none bg-transparent" })
22545
22721
  ] }) }),
22546
22722
  /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("div", { className: "max-h-48 overflow-y-auto", children: loading ? /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("p", { className: "text-xs text-gray-400 p-3", children: "Loading\u2026" }) : hits.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("p", { className: "text-xs text-gray-400 p-3", children: "No customers found" }) : hits.map((c) => /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)(
@@ -22572,16 +22748,16 @@ function ConditionCard({
22572
22748
  onRemove
22573
22749
  }) {
22574
22750
  const iconMap = {
22575
- minAmount: /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(import_lucide_react47.DollarSign, { className: "h-3.5 w-3.5 text-blue-500" }),
22576
- minQuantity: /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(import_lucide_react47.Hash, { className: "h-3.5 w-3.5 text-purple-500" }),
22577
- productMinQuantity: /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(import_lucide_react47.Hash, { className: "h-3.5 w-3.5 text-green-600" }),
22578
- nthOrder: /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(import_lucide_react47.ShoppingCart, { className: "h-3.5 w-3.5 text-orange-500" }),
22579
- userType: /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(import_lucide_react47.User, { className: "h-3.5 w-3.5 text-pink-500" }),
22580
- paymentMethod: /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(import_lucide_react47.DollarSign, { className: "h-3.5 w-3.5 text-indigo-500" }),
22581
- category: /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(import_lucide_react47.Package, { className: "h-3.5 w-3.5 text-teal-500" }),
22582
- customers: /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(import_lucide_react47.User, { className: "h-3.5 w-3.5 text-blue-400" }),
22583
- shipping: /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(import_lucide_react47.DollarSign, { className: "h-3.5 w-3.5 text-gray-500" }),
22584
- referral: /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(import_lucide_react47.User, { className: "h-3.5 w-3.5 text-rose-500" })
22751
+ minAmount: /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(import_lucide_react48.DollarSign, { className: "h-3.5 w-3.5 text-blue-500" }),
22752
+ minQuantity: /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(import_lucide_react48.Hash, { className: "h-3.5 w-3.5 text-purple-500" }),
22753
+ productMinQuantity: /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(import_lucide_react48.Hash, { className: "h-3.5 w-3.5 text-green-600" }),
22754
+ nthOrder: /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(import_lucide_react48.ShoppingCart, { className: "h-3.5 w-3.5 text-orange-500" }),
22755
+ userType: /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(import_lucide_react48.User, { className: "h-3.5 w-3.5 text-pink-500" }),
22756
+ paymentMethod: /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(import_lucide_react48.DollarSign, { className: "h-3.5 w-3.5 text-indigo-500" }),
22757
+ category: /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(import_lucide_react48.Package, { className: "h-3.5 w-3.5 text-teal-500" }),
22758
+ customers: /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(import_lucide_react48.User, { className: "h-3.5 w-3.5 text-blue-400" }),
22759
+ shipping: /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(import_lucide_react48.DollarSign, { className: "h-3.5 w-3.5 text-gray-500" }),
22760
+ referral: /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(import_lucide_react48.User, { className: "h-3.5 w-3.5 text-rose-500" })
22585
22761
  };
22586
22762
  return /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: "flex items-start gap-3 rounded-lg border border-gray-200 bg-white p-3 shadow-sm", children: [
22587
22763
  /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("div", { className: "mt-0.5 shrink-0", children: iconMap[condition.kind] }),
@@ -22670,7 +22846,7 @@ function ConditionCard({
22670
22846
  condition.kind === "shipping" && /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("p", { className: "text-xs text-gray-400 italic", children: "Applied when any shipping method is selected." }),
22671
22847
  condition.kind === "referral" && /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("p", { className: "text-xs text-gray-400 italic", children: "Applied when order comes from a referral." })
22672
22848
  ] }),
22673
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("button", { type: "button", onClick: onRemove, className: "shrink-0 text-gray-300 hover:text-red-500 transition-colors mt-0.5", children: /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(import_lucide_react47.Trash2, { className: "h-4 w-4" }) })
22849
+ /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("button", { type: "button", onClick: onRemove, className: "shrink-0 text-gray-300 hover:text-red-500 transition-colors mt-0.5", children: /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(import_lucide_react48.Trash2, { className: "h-4 w-4" }) })
22674
22850
  ] });
22675
22851
  }
22676
22852
  function RewardCard({
@@ -22681,7 +22857,7 @@ function RewardCard({
22681
22857
  discountValue
22682
22858
  }) {
22683
22859
  return /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: "flex items-start gap-3 rounded-lg border border-purple-200 bg-purple-50/40 p-3 shadow-sm", children: [
22684
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(import_lucide_react47.Gift, { className: "h-3.5 w-3.5 text-purple-500 mt-0.5 shrink-0" }),
22860
+ /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(import_lucide_react48.Gift, { className: "h-3.5 w-3.5 text-purple-500 mt-0.5 shrink-0" }),
22685
22861
  /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { className: "flex-1 min-w-0 space-y-2", children: [
22686
22862
  /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("p", { className: "text-xs font-medium text-purple-700", children: [
22687
22863
  "Reward product \u2014 ",
@@ -22695,7 +22871,7 @@ function RewardCard({
22695
22871
  ] }),
22696
22872
  /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("p", { className: "text-[11px] text-purple-600", children: "This product will be automatically added to cart when the discount is applied." })
22697
22873
  ] }),
22698
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("button", { type: "button", onClick: onRemove, className: "shrink-0 text-gray-300 hover:text-red-500 transition-colors mt-0.5", children: /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(import_lucide_react47.Trash2, { className: "h-4 w-4" }) })
22874
+ /* @__PURE__ */ (0, import_jsx_runtime79.jsx)("button", { type: "button", onClick: onRemove, className: "shrink-0 text-gray-300 hover:text-red-500 transition-colors mt-0.5", children: /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(import_lucide_react48.Trash2, { className: "h-4 w-4" }) })
22699
22875
  ] });
22700
22876
  }
22701
22877
  function DiscountConditionsBuilder({
@@ -22852,7 +23028,7 @@ function DiscountConditionsBuilder({
22852
23028
  type: "button",
22853
23029
  onClick: () => removeGroup(group.id),
22854
23030
  className: "text-gray-300 hover:text-red-500 transition-colors",
22855
- children: /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(import_lucide_react47.Trash2, { className: "h-3.5 w-3.5" })
23031
+ children: /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(import_lucide_react48.Trash2, { className: "h-3.5 w-3.5" })
22856
23032
  }
22857
23033
  )
22858
23034
  ] }),
@@ -22880,7 +23056,7 @@ function DiscountConditionsBuilder({
22880
23056
  onClick: () => addCondition(group.id),
22881
23057
  className: "flex items-center gap-1.5 text-xs mt-1",
22882
23058
  children: [
22883
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(import_lucide_react47.Plus, { className: "h-3.5 w-3.5" }),
23059
+ /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(import_lucide_react48.Plus, { className: "h-3.5 w-3.5" }),
22884
23060
  "Add condition"
22885
23061
  ]
22886
23062
  }
@@ -22896,7 +23072,7 @@ function DiscountConditionsBuilder({
22896
23072
  onClick: addGroup,
22897
23073
  className: "flex items-center gap-1.5 text-xs border-dashed border-gray-300 text-gray-500",
22898
23074
  children: [
22899
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(import_lucide_react47.Plus, { className: "h-3.5 w-3.5" }),
23075
+ /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(import_lucide_react48.Plus, { className: "h-3.5 w-3.5" }),
22900
23076
  "Add condition group"
22901
23077
  ]
22902
23078
  }
@@ -22931,7 +23107,7 @@ function DiscountConditionsBuilder({
22931
23107
  onClick: addReward,
22932
23108
  className: "flex items-center gap-1.5 text-xs border-purple-200 text-purple-700 hover:bg-purple-50",
22933
23109
  children: [
22934
- /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(import_lucide_react47.Gift, { className: "h-3.5 w-3.5" }),
23110
+ /* @__PURE__ */ (0, import_jsx_runtime79.jsx)(import_lucide_react48.Gift, { className: "h-3.5 w-3.5" }),
22935
23111
  "Add reward product (BXGY / BOGO)"
22936
23112
  ]
22937
23113
  }
@@ -23009,8 +23185,8 @@ function useConvertedValue2(value, fromCurrency, toCurrency, discountType) {
23009
23185
  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";
23010
23186
  var isCreate4 = (id) => id === "create";
23011
23187
  function DiscountEditPage({ discountId }) {
23012
- const router = (0, import_navigation28.useRouter)();
23013
- const searchParams = (0, import_navigation28.useSearchParams)();
23188
+ const router = (0, import_navigation29.useRouter)();
23189
+ const searchParams = (0, import_navigation29.useSearchParams)();
23014
23190
  const listReturnUrl = safeAdminListReturnUrl(searchParams.get("from")) ?? "/admin/discounts";
23015
23191
  const create = isCreate4(discountId);
23016
23192
  const [loading, setLoading] = (0, import_react65.useState)(!create);
@@ -23171,12 +23347,12 @@ function DiscountEditPage({ discountId }) {
23171
23347
  subtitle: create ? "Create a new discount coupon" : `Editing: ${couponCode || discountId}`,
23172
23348
  closeHref: listReturnUrl,
23173
23349
  menuItems: [
23174
- { label: saving ? "Saving..." : "Save", icon: import_lucide_react48.Save, onClick: handleSave }
23350
+ { label: saving ? "Saving..." : "Save", icon: import_lucide_react49.Save, onClick: handleSave }
23175
23351
  ]
23176
23352
  }
23177
23353
  ),
23178
23354
  errors.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("div", { className: "bg-red-50 border-l-4 border-red-400 p-4 mx-6 mt-4", children: /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "flex", children: [
23179
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(import_lucide_react48.AlertCircle, { className: "h-5 w-5 text-red-400 flex-shrink-0" }),
23355
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(import_lucide_react49.AlertCircle, { className: "h-5 w-5 text-red-400 flex-shrink-0" }),
23180
23356
  /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "ml-3", children: [
23181
23357
  /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("h3", { className: "text-sm font-medium text-red-800", children: "Please fix the following errors:" }),
23182
23358
  /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("ul", { className: "mt-2 text-sm text-red-700 list-disc pl-5 space-y-1", children: errors.map((e, i) => /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("li", { children: e }, i)) })
@@ -23204,7 +23380,7 @@ function DiscountEditPage({ discountId }) {
23204
23380
  ) }),
23205
23381
  /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { children: [
23206
23382
  /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("span", { className: "flex items-center gap-1.5 text-sm font-medium text-gray-700", children: [
23207
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(import_lucide_react48.Zap, { className: "h-3.5 w-3.5 text-amber-500" }),
23383
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(import_lucide_react49.Zap, { className: "h-3.5 w-3.5 text-amber-500" }),
23208
23384
  "Automatic discount"
23209
23385
  ] }),
23210
23386
  /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("p", { className: "text-xs text-gray-400 mt-0.5", children: "Applied automatically at checkout \u2014 no coupon code needed. When enabled, the coupon code field is hidden." })
@@ -23455,7 +23631,7 @@ function DiscountEditPage({ discountId }) {
23455
23631
  /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("p", { className: "font-mono font-semibold text-gray-900", children: couponCode || "\u2014" })
23456
23632
  ] }),
23457
23633
  isAutomatic && /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("p", { className: "flex items-center gap-1 text-amber-600 text-xs font-medium mb-1", children: [
23458
- /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(import_lucide_react48.Zap, { className: "h-3 w-3" }),
23634
+ /* @__PURE__ */ (0, import_jsx_runtime80.jsx)(import_lucide_react49.Zap, { className: "h-3 w-3" }),
23459
23635
  " Automatic \u2014 no code needed"
23460
23636
  ] }),
23461
23637
  /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("p", { className: "text-gray-500 mt-2", children: "Discount" }),
@@ -23491,7 +23667,6 @@ var PAGE_MAP = {
23491
23667
  roles: RolesPage,
23492
23668
  "blog-generator": BlogGeneratorPage,
23493
23669
  schedules: SchedulesPage,
23494
- "vendor-onboard": VendorOnboardPage,
23495
23670
  "vendor-team": VendorTeamPage
23496
23671
  };
23497
23672
  var CRUD_CONFIGS = {
@@ -23647,8 +23822,8 @@ function BlogEditorWrapper({
23647
23822
  );
23648
23823
  }
23649
23824
  function AdminPageResolver({ slug }) {
23650
- const router = (0, import_navigation30.useRouter)();
23651
- const searchParams = (0, import_navigation30.useSearchParams)();
23825
+ const router = (0, import_navigation31.useRouter)();
23826
+ const searchParams = (0, import_navigation31.useSearchParams)();
23652
23827
  const { customCrudConfigs, storeEnabled } = (0, import_react68.useContext)(AdminConfigContext);
23653
23828
  const key = slug?.[0] || "dashboard";
23654
23829
  const crud = (0, import_react68.useMemo)(() => {
@@ -23691,6 +23866,10 @@ function AdminPageResolver({ slug }) {
23691
23866
  /* @__PURE__ */ (0, import_jsx_runtime83.jsx)("span", { className: "ml-2", children: "Opening Plugins\u2026" })
23692
23867
  ] });
23693
23868
  }
23869
+ if (key === "vendor-onboard") {
23870
+ const sub = slug?.[1];
23871
+ return /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(VendorOnboardPage, { showCreateForm: sub === "create" });
23872
+ }
23694
23873
  const Page = PAGE_MAP[key];
23695
23874
  if (Page) {
23696
23875
  return /* @__PURE__ */ (0, import_jsx_runtime83.jsx)(Page, {});
@@ -23781,7 +23960,7 @@ function AdminPageResolver({ slug }) {
23781
23960
  // src/admin/pages/LayoutSettingsPage.tsx
23782
23961
  var import_react69 = require("react");
23783
23962
  init_button();
23784
- var import_lucide_react50 = require("lucide-react");
23963
+ var import_lucide_react51 = require("lucide-react");
23785
23964
  var import_jsx_runtime84 = require("react/jsx-runtime");
23786
23965
  function LayoutSettingsPage() {
23787
23966
  const { theme } = (0, import_react69.useContext)(AdminConfigContext);
@@ -23853,7 +24032,7 @@ function LayoutSettingsPage() {
23853
24032
  disabled: saving,
23854
24033
  className: "bg-white text-gray-800 hover:bg-gray-100 border-0 text-xs",
23855
24034
  children: [
23856
- /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(import_lucide_react50.Save, { className: "h-4 w-4 mr-2" }),
24035
+ /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(import_lucide_react51.Save, { className: "h-4 w-4 mr-2" }),
23857
24036
  saving ? "Saving..." : "Save"
23858
24037
  ]
23859
24038
  }