@zaamx/netme-bundle 0.0.2 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.medusa/server/src/admin/index.js +359 -333
- package/.medusa/server/src/admin/index.mjs +361 -335
- package/.medusa/server/src/api/admin/bundled-products/route.js +64 -72
- package/.medusa/server/src/api/admin/products/[id]/bundle/route.js +2 -11
- package/README.md +443 -48
- package/package.json +10 -5
|
@@ -16,231 +16,309 @@ const sdk = new Medusa__default.default({
|
|
|
16
16
|
type: "session"
|
|
17
17
|
}
|
|
18
18
|
});
|
|
19
|
+
const ProductSearchSelect = ({
|
|
20
|
+
value,
|
|
21
|
+
valueLabel,
|
|
22
|
+
onChange,
|
|
23
|
+
disabled,
|
|
24
|
+
placeholder = "Search products…"
|
|
25
|
+
}) => {
|
|
26
|
+
const [search, setSearch] = react.useState("");
|
|
27
|
+
const [open, setOpen] = react.useState(false);
|
|
28
|
+
const [results, setResults] = react.useState([]);
|
|
29
|
+
const [loading, setLoading] = react.useState(false);
|
|
30
|
+
const containerRef = react.useRef(null);
|
|
31
|
+
react.useEffect(() => {
|
|
32
|
+
const handler = (e) => {
|
|
33
|
+
if (containerRef.current && !containerRef.current.contains(e.target)) {
|
|
34
|
+
setOpen(false);
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
document.addEventListener("mousedown", handler);
|
|
38
|
+
return () => document.removeEventListener("mousedown", handler);
|
|
39
|
+
}, []);
|
|
40
|
+
react.useEffect(() => {
|
|
41
|
+
if (!open) return;
|
|
42
|
+
const delay = search.trim() ? 300 : 0;
|
|
43
|
+
const timer = setTimeout(async () => {
|
|
44
|
+
setLoading(true);
|
|
45
|
+
try {
|
|
46
|
+
const { products } = await sdk.admin.product.list({
|
|
47
|
+
q: search.trim() || void 0,
|
|
48
|
+
limit: 15
|
|
49
|
+
});
|
|
50
|
+
setResults(products.map((p) => ({ id: p.id, title: p.title ?? "" })));
|
|
51
|
+
} catch {
|
|
52
|
+
setResults([]);
|
|
53
|
+
} finally {
|
|
54
|
+
setLoading(false);
|
|
55
|
+
}
|
|
56
|
+
}, delay);
|
|
57
|
+
return () => clearTimeout(timer);
|
|
58
|
+
}, [search, open]);
|
|
59
|
+
if (disabled) {
|
|
60
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border border-gray-200 rounded-md px-3 py-2 bg-gray-50 text-sm text-gray-700 min-h-[38px]", children: valueLabel || value || /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-gray-400", children: "—" }) });
|
|
61
|
+
}
|
|
62
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: containerRef, className: "relative", children: [
|
|
63
|
+
value && valueLabel && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-1 flex items-center gap-2", children: [
|
|
64
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { className: "bg-blue-50 text-blue-700 text-xs", children: valueLabel }),
|
|
65
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
66
|
+
"button",
|
|
67
|
+
{
|
|
68
|
+
type: "button",
|
|
69
|
+
className: "text-xs text-gray-400 hover:text-gray-600",
|
|
70
|
+
onClick: () => onChange("", ""),
|
|
71
|
+
children: "✕ clear"
|
|
72
|
+
}
|
|
73
|
+
)
|
|
74
|
+
] }),
|
|
75
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
76
|
+
ui.Input,
|
|
77
|
+
{
|
|
78
|
+
placeholder: value ? "Search to change…" : placeholder,
|
|
79
|
+
value: search,
|
|
80
|
+
onChange: (e) => {
|
|
81
|
+
setSearch(e.target.value);
|
|
82
|
+
setOpen(true);
|
|
83
|
+
},
|
|
84
|
+
onFocus: () => setOpen(true)
|
|
85
|
+
}
|
|
86
|
+
),
|
|
87
|
+
open && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute z-50 w-full mt-1 bg-white border border-gray-200 rounded-md shadow-lg max-h-60 overflow-y-auto", children: [
|
|
88
|
+
loading && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3 py-2 text-sm text-gray-400", children: "Searching…" }),
|
|
89
|
+
!loading && results.length === 0 && search.trim() && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3 py-2 text-sm text-gray-400", children: "No products found." }),
|
|
90
|
+
results.map((product) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
91
|
+
"button",
|
|
92
|
+
{
|
|
93
|
+
type: "button",
|
|
94
|
+
className: "w-full text-left px-3 py-2 hover:bg-gray-50 text-sm border-b border-gray-100 last:border-0",
|
|
95
|
+
onMouseDown: (e) => {
|
|
96
|
+
e.preventDefault();
|
|
97
|
+
onChange(product.id, product.title);
|
|
98
|
+
setSearch("");
|
|
99
|
+
setOpen(false);
|
|
100
|
+
},
|
|
101
|
+
children: product.title
|
|
102
|
+
},
|
|
103
|
+
product.id
|
|
104
|
+
))
|
|
105
|
+
] })
|
|
106
|
+
] });
|
|
107
|
+
};
|
|
108
|
+
const emptyBundleItem = () => ({
|
|
109
|
+
product_id: void 0,
|
|
110
|
+
product_title: "",
|
|
111
|
+
min_quantity: 1,
|
|
112
|
+
max_quantity: 1,
|
|
113
|
+
default_quantity: 1,
|
|
114
|
+
optional: false,
|
|
115
|
+
separate_shipping: false,
|
|
116
|
+
individual_price: false
|
|
117
|
+
});
|
|
118
|
+
const resetModal = {
|
|
119
|
+
isEditing: false,
|
|
120
|
+
selectedProductId: void 0,
|
|
121
|
+
selectedProductTitle: "",
|
|
122
|
+
bundleItems: [],
|
|
123
|
+
bundleMeta: []
|
|
124
|
+
};
|
|
19
125
|
const limit = 15;
|
|
20
126
|
const BundledProductsPage = () => {
|
|
21
127
|
const [page, setPage] = react.useState(0);
|
|
22
128
|
const [openCreateModal, setOpenCreateModal] = react.useState(false);
|
|
23
129
|
const [isEditing, setIsEditing] = react.useState(false);
|
|
24
130
|
const [selectedProductId, setSelectedProductId] = react.useState();
|
|
131
|
+
const [selectedProductTitle, setSelectedProductTitle] = react.useState("");
|
|
25
132
|
const [bundleItems, setBundleItems] = react.useState([]);
|
|
26
133
|
const [bundleMeta, setBundleMeta] = react.useState([]);
|
|
27
|
-
const [products, setProducts] = react.useState([]);
|
|
28
|
-
const productsLimit = 15;
|
|
29
|
-
const [currentProductPage, setCurrentProductPage] = react.useState(0);
|
|
30
|
-
const [productsCount, setProductsCount] = react.useState(0);
|
|
31
|
-
const hasNextPage = react.useMemo(
|
|
32
|
-
() => productsCount ? productsCount > productsLimit : true,
|
|
33
|
-
[productsCount, productsLimit]
|
|
34
|
-
);
|
|
35
134
|
const queryClient = reactQuery.useQueryClient();
|
|
36
135
|
const offset = page * limit;
|
|
136
|
+
const closeModal = () => {
|
|
137
|
+
setOpenCreateModal(false);
|
|
138
|
+
setIsEditing(resetModal.isEditing);
|
|
139
|
+
setSelectedProductId(resetModal.selectedProductId);
|
|
140
|
+
setSelectedProductTitle(resetModal.selectedProductTitle);
|
|
141
|
+
setBundleItems(resetModal.bundleItems);
|
|
142
|
+
setBundleMeta(resetModal.bundleMeta);
|
|
143
|
+
};
|
|
37
144
|
const { data, isLoading } = reactQuery.useQuery({
|
|
38
145
|
queryKey: ["bundled-products", offset, limit],
|
|
39
146
|
queryFn: () => sdk.client.fetch("/admin/bundled-products", {
|
|
40
147
|
method: "GET",
|
|
41
|
-
query: {
|
|
42
|
-
limit,
|
|
43
|
-
offset
|
|
44
|
-
}
|
|
148
|
+
query: { limit, offset }
|
|
45
149
|
})
|
|
46
150
|
});
|
|
47
|
-
reactQuery.
|
|
48
|
-
|
|
49
|
-
queryFn: async () => {
|
|
50
|
-
const { products: products2, count } = await sdk.admin.product.list({
|
|
51
|
-
limit: productsLimit,
|
|
52
|
-
offset: currentProductPage * productsLimit
|
|
53
|
-
});
|
|
54
|
-
setProductsCount(count);
|
|
55
|
-
setProducts((prev) => [...prev, ...products2]);
|
|
56
|
-
return products2;
|
|
57
|
-
},
|
|
58
|
-
enabled: hasNextPage
|
|
59
|
-
});
|
|
60
|
-
const fetchMoreProducts = () => {
|
|
61
|
-
if (!hasNextPage) {
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
setCurrentProductPage(currentProductPage + 1);
|
|
65
|
-
};
|
|
66
|
-
const { mutateAsync: createBundle, isPending: isCreating } = reactQuery.useMutation({
|
|
67
|
-
mutationFn: async (data2) => {
|
|
151
|
+
const { mutateAsync: saveBundle, isPending: isSaving } = reactQuery.useMutation({
|
|
152
|
+
mutationFn: async (payload) => {
|
|
68
153
|
if (!selectedProductId) throw new Error("No product selected");
|
|
69
154
|
await sdk.client.fetch(`/admin/products/${selectedProductId}/bundle`, {
|
|
70
155
|
method: "POST",
|
|
71
|
-
body:
|
|
156
|
+
body: {
|
|
157
|
+
child_product_ids: payload.child_product_ids.map((item) => ({
|
|
158
|
+
id: item.product_id,
|
|
159
|
+
min_quantity: item.min_quantity,
|
|
160
|
+
max_quantity: item.max_quantity,
|
|
161
|
+
default_quantity: item.default_quantity,
|
|
162
|
+
optional: item.optional,
|
|
163
|
+
separate_shipping: item.separate_shipping,
|
|
164
|
+
individual_price: item.individual_price
|
|
165
|
+
})),
|
|
166
|
+
bundle_meta: payload.bundle_meta,
|
|
167
|
+
is_bundle: payload.is_bundle
|
|
168
|
+
}
|
|
72
169
|
});
|
|
73
170
|
}
|
|
74
171
|
});
|
|
75
|
-
const { mutateAsync: deleteBundle
|
|
172
|
+
const { mutateAsync: deleteBundle } = reactQuery.useMutation({
|
|
76
173
|
mutationFn: async (productId) => {
|
|
77
|
-
await sdk.client.fetch(`/admin/products/${productId}/bundle`, {
|
|
78
|
-
method: "DELETE"
|
|
79
|
-
});
|
|
174
|
+
await sdk.client.fetch(`/admin/products/${productId}/bundle`, { method: "DELETE" });
|
|
80
175
|
}
|
|
81
176
|
});
|
|
82
177
|
const handleDeleteBundle = async (productId) => {
|
|
83
178
|
try {
|
|
84
179
|
await deleteBundle(productId);
|
|
85
180
|
ui.toast.success("Bundle deleted successfully");
|
|
86
|
-
queryClient.invalidateQueries({
|
|
87
|
-
|
|
88
|
-
});
|
|
89
|
-
} catch (error) {
|
|
90
|
-
console.error("Error deleting bundle:", error);
|
|
181
|
+
queryClient.invalidateQueries({ queryKey: ["bundled-products"] });
|
|
182
|
+
} catch {
|
|
91
183
|
ui.toast.error("Failed to delete bundle");
|
|
92
184
|
}
|
|
93
185
|
};
|
|
94
186
|
const handleEditBundle = (bundle) => {
|
|
95
187
|
setIsEditing(true);
|
|
96
188
|
setSelectedProductId(bundle.product.id);
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
189
|
+
setSelectedProductTitle(bundle.title);
|
|
190
|
+
setBundleItems(
|
|
191
|
+
bundle.items.map((item) => ({
|
|
192
|
+
product_id: item.product.id,
|
|
193
|
+
product_title: item.product.title,
|
|
194
|
+
min_quantity: item.min_quantity,
|
|
195
|
+
max_quantity: item.max_quantity,
|
|
196
|
+
default_quantity: item.default_quantity,
|
|
197
|
+
optional: item.optional,
|
|
198
|
+
separate_shipping: item.separate_shipping,
|
|
199
|
+
individual_price: item.individual_price
|
|
200
|
+
}))
|
|
201
|
+
);
|
|
106
202
|
setBundleMeta(bundle.bundle_meta || []);
|
|
107
203
|
setOpenCreateModal(true);
|
|
108
204
|
};
|
|
109
|
-
const
|
|
205
|
+
const handleSaveBundle = async () => {
|
|
206
|
+
if (!selectedProductId) {
|
|
207
|
+
ui.toast.error("Please select a product");
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
const validItems = bundleItems.filter((item) => item.product_id);
|
|
211
|
+
if (validItems.length === 0) {
|
|
212
|
+
ui.toast.error("Please add at least one product to the bundle");
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
110
215
|
try {
|
|
111
|
-
|
|
112
|
-
ui.toast.error("Please select a product");
|
|
113
|
-
return;
|
|
114
|
-
}
|
|
115
|
-
const validItems = bundleItems.filter((item) => item.product_id);
|
|
116
|
-
if (validItems.length === 0) {
|
|
117
|
-
ui.toast.error("Please add at least one product to the bundle");
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
120
|
-
await createBundle({
|
|
121
|
-
child_product_ids: validItems.map((item) => ({
|
|
122
|
-
id: item.product_id,
|
|
123
|
-
min_quantity: item.min_quantity,
|
|
124
|
-
max_quantity: item.max_quantity,
|
|
125
|
-
default_quantity: item.default_quantity,
|
|
126
|
-
optional: item.optional,
|
|
127
|
-
separate_shipping: item.separate_shipping,
|
|
128
|
-
individual_price: item.individual_price
|
|
129
|
-
})),
|
|
130
|
-
bundle_meta: bundleMeta,
|
|
131
|
-
is_bundle: true
|
|
132
|
-
});
|
|
133
|
-
setOpenCreateModal(false);
|
|
216
|
+
await saveBundle({ child_product_ids: validItems, bundle_meta: bundleMeta, is_bundle: true });
|
|
134
217
|
ui.toast.success(isEditing ? "Bundle updated successfully" : "Bundle created successfully");
|
|
135
|
-
queryClient.invalidateQueries({
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
setSelectedProductId(void 0);
|
|
140
|
-
setBundleItems([]);
|
|
141
|
-
setBundleMeta([]);
|
|
142
|
-
} catch (error) {
|
|
143
|
-
console.error("Error creating bundle:", error);
|
|
144
|
-
ui.toast.error("Failed to create bundle");
|
|
218
|
+
queryClient.invalidateQueries({ queryKey: ["bundled-products"] });
|
|
219
|
+
closeModal();
|
|
220
|
+
} catch {
|
|
221
|
+
ui.toast.error(isEditing ? "Failed to update bundle" : "Failed to create bundle");
|
|
145
222
|
}
|
|
146
223
|
};
|
|
147
|
-
const addBundleItem = () => {
|
|
148
|
-
setBundleItems([
|
|
149
|
-
...bundleItems,
|
|
150
|
-
{
|
|
151
|
-
product_id: void 0,
|
|
152
|
-
min_quantity: 1,
|
|
153
|
-
max_quantity: 1,
|
|
154
|
-
default_quantity: 1,
|
|
155
|
-
optional: false,
|
|
156
|
-
separate_shipping: false,
|
|
157
|
-
individual_price: false
|
|
158
|
-
}
|
|
159
|
-
]);
|
|
160
|
-
};
|
|
161
|
-
const removeBundleItem = (index) => {
|
|
162
|
-
setBundleItems(bundleItems.filter((_, i) => i !== index));
|
|
163
|
-
};
|
|
164
224
|
const updateBundleItem = (index, field, value) => {
|
|
165
|
-
setBundleItems(
|
|
166
|
-
(item, i) => i === index ? { ...item, [field]: value } : item
|
|
167
|
-
)
|
|
168
|
-
};
|
|
169
|
-
const addBundleMeta = () => {
|
|
170
|
-
setBundleMeta([...bundleMeta, { key: "", value: "" }]);
|
|
171
|
-
};
|
|
172
|
-
const removeBundleMeta = (index) => {
|
|
173
|
-
setBundleMeta(bundleMeta.filter((_, i) => i !== index));
|
|
174
|
-
};
|
|
175
|
-
const updateBundleMeta = (index, field, value) => {
|
|
176
|
-
setBundleMeta(bundleMeta.map(
|
|
177
|
-
(item, i) => i === index ? { ...item, [field]: value } : item
|
|
178
|
-
));
|
|
225
|
+
setBundleItems(
|
|
226
|
+
(prev) => prev.map((item, i) => i === index ? { ...item, [field]: value } : item)
|
|
227
|
+
);
|
|
179
228
|
};
|
|
180
229
|
const totalPages = Math.ceil(((data == null ? void 0 : data.count) || 0) / limit);
|
|
181
230
|
return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "divide-y p-0", children: [
|
|
182
231
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-2 md:flex-row md:items-center p-6", children: [
|
|
183
232
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Bundled Products" }),
|
|
184
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
233
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
234
|
+
ui.Button,
|
|
235
|
+
{
|
|
236
|
+
variant: "primary",
|
|
237
|
+
onClick: () => {
|
|
238
|
+
closeModal();
|
|
239
|
+
setOpenCreateModal(true);
|
|
240
|
+
},
|
|
241
|
+
children: "Create Bundle"
|
|
242
|
+
}
|
|
243
|
+
)
|
|
185
244
|
] }),
|
|
186
|
-
isLoading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-6", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: "Loading
|
|
245
|
+
isLoading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-6", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: "Loading…" }) }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-6", children: [
|
|
187
246
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "w-full border-collapse border border-gray-200", children: [
|
|
188
247
|
/* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "bg-gray-50", children: [
|
|
189
|
-
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "border border-gray-200 px-4 py-2 text-left", children: "ID" }),
|
|
190
|
-
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "border border-gray-200 px-4 py-2 text-left", children: "Title" }),
|
|
191
|
-
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "border border-gray-200 px-4 py-2 text-left", children: "Items" }),
|
|
192
248
|
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "border border-gray-200 px-4 py-2 text-left", children: "Product" }),
|
|
193
|
-
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "border border-gray-200 px-4 py-2 text-left", children: "Status" })
|
|
249
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "border border-gray-200 px-4 py-2 text-left", children: "Status" }),
|
|
250
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "border border-gray-200 px-4 py-2 text-left", children: "Items" }),
|
|
251
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { className: "border border-gray-200 px-4 py-2 text-left", children: "Actions" })
|
|
194
252
|
] }) }),
|
|
195
|
-
/* @__PURE__ */ jsxRuntime.
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "border border-gray-200 px-4 py-2", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1", children: bundle.items.map((item) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-sm", children: [
|
|
199
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
200
|
-
reactRouterDom.Link,
|
|
201
|
-
{
|
|
202
|
-
to: `/products/${item.product.id}`,
|
|
203
|
-
className: "text-blue-600 hover:underline",
|
|
204
|
-
children: item.product.title
|
|
205
|
-
}
|
|
206
|
-
),
|
|
207
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-gray-500", children: [
|
|
208
|
-
" x ",
|
|
209
|
-
item.quantity
|
|
210
|
-
] }),
|
|
211
|
-
item.optional && /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { className: "ml-2 bg-gray-100 text-gray-700", children: "Optional" })
|
|
212
|
-
] }, item.id)) }) }),
|
|
213
|
-
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "border border-gray-200 px-4 py-2", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
214
|
-
reactRouterDom.Link,
|
|
253
|
+
/* @__PURE__ */ jsxRuntime.jsxs("tbody", { children: [
|
|
254
|
+
((data == null ? void 0 : data.bundled_products.length) ?? 0) === 0 && /* @__PURE__ */ jsxRuntime.jsx("tr", { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
255
|
+
"td",
|
|
215
256
|
{
|
|
216
|
-
|
|
217
|
-
className: "text-
|
|
218
|
-
children: "
|
|
257
|
+
colSpan: 4,
|
|
258
|
+
className: "border border-gray-200 px-4 py-6 text-center text-gray-500",
|
|
259
|
+
children: "No bundled products found."
|
|
219
260
|
}
|
|
220
261
|
) }),
|
|
221
|
-
|
|
222
|
-
/* @__PURE__ */ jsxRuntime.
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
262
|
+
data == null ? void 0 : data.bundled_products.map((bundle) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "hover:bg-gray-50", children: [
|
|
263
|
+
/* @__PURE__ */ jsxRuntime.jsxs("td", { className: "border border-gray-200 px-4 py-3", children: [
|
|
264
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
265
|
+
reactRouterDom.Link,
|
|
266
|
+
{
|
|
267
|
+
to: `/products/${bundle.product.id}`,
|
|
268
|
+
className: "font-medium text-blue-600 hover:underline",
|
|
269
|
+
children: bundle.title
|
|
270
|
+
}
|
|
271
|
+
),
|
|
272
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-gray-400 mt-0.5", children: bundle.id })
|
|
273
|
+
] }),
|
|
274
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "border border-gray-200 px-4 py-3", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
275
|
+
ui.Badge,
|
|
234
276
|
{
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
onClick: () => handleDeleteBundle(bundle.id),
|
|
238
|
-
className: "text-red-600 hover:text-red-700",
|
|
239
|
-
children: "Delete"
|
|
277
|
+
className: bundle.status === "published" ? "bg-green-100 text-green-700" : "bg-gray-100 text-gray-600",
|
|
278
|
+
children: bundle.status ?? "—"
|
|
240
279
|
}
|
|
241
|
-
)
|
|
242
|
-
|
|
243
|
-
|
|
280
|
+
) }),
|
|
281
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "border border-gray-200 px-4 py-3", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-0.5", children: [
|
|
282
|
+
bundle.items.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-gray-400", children: "No items" }),
|
|
283
|
+
bundle.items.map((item) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-sm flex items-center gap-1", children: [
|
|
284
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
285
|
+
reactRouterDom.Link,
|
|
286
|
+
{
|
|
287
|
+
to: `/products/${item.product.id}`,
|
|
288
|
+
className: "text-blue-600 hover:underline",
|
|
289
|
+
children: item.product.title
|
|
290
|
+
}
|
|
291
|
+
),
|
|
292
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-gray-400", children: [
|
|
293
|
+
"× ",
|
|
294
|
+
item.default_quantity
|
|
295
|
+
] }),
|
|
296
|
+
item.optional && /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { className: "bg-gray-100 text-gray-500 text-xs", children: "Optional" })
|
|
297
|
+
] }, item.id))
|
|
298
|
+
] }) }),
|
|
299
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "border border-gray-200 px-4 py-3", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
300
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
301
|
+
ui.Button,
|
|
302
|
+
{
|
|
303
|
+
variant: "secondary",
|
|
304
|
+
size: "small",
|
|
305
|
+
onClick: () => handleEditBundle(bundle),
|
|
306
|
+
children: "Edit"
|
|
307
|
+
}
|
|
308
|
+
),
|
|
309
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
310
|
+
ui.Button,
|
|
311
|
+
{
|
|
312
|
+
variant: "secondary",
|
|
313
|
+
size: "small",
|
|
314
|
+
onClick: () => handleDeleteBundle(bundle.id),
|
|
315
|
+
className: "text-red-600 hover:text-red-700",
|
|
316
|
+
children: "Delete"
|
|
317
|
+
}
|
|
318
|
+
)
|
|
319
|
+
] }) })
|
|
320
|
+
] }, bundle.id))
|
|
321
|
+
] })
|
|
244
322
|
] }) }),
|
|
245
323
|
totalPages > 1 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-center gap-2 mt-6", children: [
|
|
246
324
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -269,46 +347,39 @@ const BundledProductsPage = () => {
|
|
|
269
347
|
)
|
|
270
348
|
] })
|
|
271
349
|
] }),
|
|
272
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.FocusModal, { open: openCreateModal, onOpenChange:
|
|
350
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.FocusModal, { open: openCreateModal, onOpenChange: (open) => {
|
|
351
|
+
if (!open) closeModal();
|
|
352
|
+
}, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.FocusModal.Content, { children: [
|
|
273
353
|
/* @__PURE__ */ jsxRuntime.jsx(ui.FocusModal.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h1", children: isEditing ? "Edit Bundle" : "Create Bundle" }) }),
|
|
274
354
|
/* @__PURE__ */ jsxRuntime.jsx(ui.FocusModal.Body, { children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-1 flex-col items-center h-[80vh] overflow-y-auto px-2 py-8", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full max-w-3xl flex flex-col gap-y-8", children: [
|
|
275
355
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
276
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { children: "
|
|
277
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-sm text-gray-
|
|
278
|
-
/* @__PURE__ */ jsxRuntime.
|
|
279
|
-
|
|
356
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { children: "Bundle Product" }),
|
|
357
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-sm text-gray-500 mb-2", children: isEditing ? "The product this bundle is attached to" : "Choose the product that will become a bundle" }),
|
|
358
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
359
|
+
ProductSearchSelect,
|
|
280
360
|
{
|
|
281
361
|
value: selectedProductId,
|
|
282
|
-
|
|
362
|
+
valueLabel: selectedProductTitle,
|
|
363
|
+
onChange: (id, title) => {
|
|
364
|
+
setSelectedProductId(id || void 0);
|
|
365
|
+
setSelectedProductTitle(title);
|
|
366
|
+
},
|
|
283
367
|
disabled: isEditing,
|
|
284
|
-
|
|
285
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Select.Trigger, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Value, { placeholder: "Select a product to bundle" }) }),
|
|
286
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Select.Content, { children: products == null ? void 0 : products.map((product) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
287
|
-
ui.Select.Item,
|
|
288
|
-
{
|
|
289
|
-
value: product.id,
|
|
290
|
-
children: product.title
|
|
291
|
-
},
|
|
292
|
-
product.id
|
|
293
|
-
)) })
|
|
294
|
-
]
|
|
368
|
+
placeholder: "Search for a product to bundle…"
|
|
295
369
|
}
|
|
296
370
|
)
|
|
297
371
|
] }),
|
|
298
372
|
selectedProductId && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
299
373
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
300
374
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", children: "Bundle Items" }),
|
|
301
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-sm text-gray-
|
|
375
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-sm text-gray-500 mb-4", children: "Products included in this bundle" }),
|
|
302
376
|
bundleItems.map((item, index) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
303
377
|
BundleItemForm,
|
|
304
378
|
{
|
|
305
379
|
item,
|
|
306
380
|
index,
|
|
307
|
-
products,
|
|
308
381
|
onUpdate: (field, value) => updateBundleItem(index, field, value),
|
|
309
|
-
onRemove: () =>
|
|
310
|
-
fetchMoreProducts,
|
|
311
|
-
hasNextPage
|
|
382
|
+
onRemove: () => setBundleItems((prev) => prev.filter((_, i) => i !== index))
|
|
312
383
|
},
|
|
313
384
|
index
|
|
314
385
|
)),
|
|
@@ -316,7 +387,7 @@ const BundledProductsPage = () => {
|
|
|
316
387
|
ui.Button,
|
|
317
388
|
{
|
|
318
389
|
variant: "secondary",
|
|
319
|
-
onClick:
|
|
390
|
+
onClick: () => setBundleItems((prev) => [...prev, emptyBundleItem()]),
|
|
320
391
|
className: "mt-4",
|
|
321
392
|
children: "Add Item"
|
|
322
393
|
}
|
|
@@ -324,14 +395,16 @@ const BundledProductsPage = () => {
|
|
|
324
395
|
] }),
|
|
325
396
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
326
397
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", children: "Bundle Metadata" }),
|
|
327
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-sm text-gray-
|
|
398
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-sm text-gray-500 mb-4", children: "Custom key-value pairs for this bundle" }),
|
|
328
399
|
bundleMeta.map((meta, index) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-2 mb-2", children: [
|
|
329
400
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
330
401
|
ui.Input,
|
|
331
402
|
{
|
|
332
403
|
placeholder: "Key",
|
|
333
404
|
value: meta.key,
|
|
334
|
-
onChange: (e) =>
|
|
405
|
+
onChange: (e) => setBundleMeta(
|
|
406
|
+
(prev) => prev.map((m, i) => i === index ? { ...m, key: e.target.value } : m)
|
|
407
|
+
)
|
|
335
408
|
}
|
|
336
409
|
),
|
|
337
410
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -339,14 +412,18 @@ const BundledProductsPage = () => {
|
|
|
339
412
|
{
|
|
340
413
|
placeholder: "Value",
|
|
341
414
|
value: meta.value,
|
|
342
|
-
onChange: (e) =>
|
|
415
|
+
onChange: (e) => setBundleMeta(
|
|
416
|
+
(prev) => prev.map(
|
|
417
|
+
(m, i) => i === index ? { ...m, value: e.target.value } : m
|
|
418
|
+
)
|
|
419
|
+
)
|
|
343
420
|
}
|
|
344
421
|
),
|
|
345
422
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
346
423
|
ui.Button,
|
|
347
424
|
{
|
|
348
425
|
variant: "secondary",
|
|
349
|
-
onClick: () =>
|
|
426
|
+
onClick: () => setBundleMeta((prev) => prev.filter((_, i) => i !== index)),
|
|
350
427
|
children: "Remove"
|
|
351
428
|
}
|
|
352
429
|
)
|
|
@@ -355,7 +432,7 @@ const BundledProductsPage = () => {
|
|
|
355
432
|
ui.Button,
|
|
356
433
|
{
|
|
357
434
|
variant: "secondary",
|
|
358
|
-
onClick:
|
|
435
|
+
onClick: () => setBundleMeta((prev) => [...prev, { key: "", value: "" }]),
|
|
359
436
|
className: "mt-4",
|
|
360
437
|
children: "Add Metadata"
|
|
361
438
|
}
|
|
@@ -364,19 +441,13 @@ const BundledProductsPage = () => {
|
|
|
364
441
|
] })
|
|
365
442
|
] }) }) }),
|
|
366
443
|
/* @__PURE__ */ jsxRuntime.jsx(ui.FocusModal.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
|
|
367
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "secondary", onClick:
|
|
368
|
-
setOpenCreateModal(false);
|
|
369
|
-
setIsEditing(false);
|
|
370
|
-
setSelectedProductId(void 0);
|
|
371
|
-
setBundleItems([]);
|
|
372
|
-
setBundleMeta([]);
|
|
373
|
-
}, children: "Cancel" }),
|
|
444
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "secondary", onClick: closeModal, children: "Cancel" }),
|
|
374
445
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
375
446
|
ui.Button,
|
|
376
447
|
{
|
|
377
448
|
variant: "primary",
|
|
378
|
-
onClick:
|
|
379
|
-
isLoading:
|
|
449
|
+
onClick: handleSaveBundle,
|
|
450
|
+
isLoading: isSaving,
|
|
380
451
|
disabled: !selectedProductId,
|
|
381
452
|
children: isEditing ? "Update Bundle" : "Create Bundle"
|
|
382
453
|
}
|
|
@@ -385,145 +456,100 @@ const BundledProductsPage = () => {
|
|
|
385
456
|
] }) })
|
|
386
457
|
] });
|
|
387
458
|
};
|
|
388
|
-
const BundleItemForm = ({
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
459
|
+
const BundleItemForm = ({ item, index, onUpdate, onRemove }) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border rounded-lg p-4 space-y-4 mb-4", children: [
|
|
460
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
461
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Heading, { level: "h3", children: [
|
|
462
|
+
"Item ",
|
|
463
|
+
index + 1
|
|
464
|
+
] }),
|
|
465
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "secondary", onClick: onRemove, children: "Remove" })
|
|
466
|
+
] }),
|
|
467
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
468
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { children: "Product" }),
|
|
469
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
470
|
+
ProductSearchSelect,
|
|
471
|
+
{
|
|
472
|
+
value: item.product_id,
|
|
473
|
+
valueLabel: item.product_title,
|
|
474
|
+
onChange: (id, title) => {
|
|
475
|
+
onUpdate("product_id", id || void 0);
|
|
476
|
+
onUpdate("product_title", title);
|
|
477
|
+
},
|
|
478
|
+
placeholder: "Search for a product…"
|
|
479
|
+
}
|
|
480
|
+
)
|
|
481
|
+
] }),
|
|
482
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-3 gap-4", children: [
|
|
483
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
484
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { children: "Min Quantity" }),
|
|
485
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
486
|
+
ui.Input,
|
|
487
|
+
{
|
|
488
|
+
type: "number",
|
|
489
|
+
min: 0,
|
|
490
|
+
value: item.min_quantity,
|
|
491
|
+
onChange: (e) => onUpdate("min_quantity", parseInt(e.target.value) || 0)
|
|
402
492
|
}
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
493
|
+
)
|
|
494
|
+
] }),
|
|
495
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
496
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { children: "Max Quantity" }),
|
|
497
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
498
|
+
ui.Input,
|
|
499
|
+
{
|
|
500
|
+
type: "number",
|
|
501
|
+
min: 0,
|
|
502
|
+
value: item.max_quantity,
|
|
503
|
+
onChange: (e) => onUpdate("max_quantity", parseInt(e.target.value) || 0)
|
|
406
504
|
}
|
|
407
|
-
|
|
408
|
-
{ threshold: 1 }
|
|
409
|
-
)
|
|
410
|
-
);
|
|
411
|
-
const lastOptionRef = react.useCallback(
|
|
412
|
-
(node) => {
|
|
413
|
-
if (!hasNextPage) {
|
|
414
|
-
return;
|
|
415
|
-
}
|
|
416
|
-
if (observer.current) {
|
|
417
|
-
observer.current.disconnect();
|
|
418
|
-
}
|
|
419
|
-
if (node) {
|
|
420
|
-
observer.current.observe(node);
|
|
421
|
-
}
|
|
422
|
-
},
|
|
423
|
-
[hasNextPage]
|
|
424
|
-
);
|
|
425
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border rounded-lg p-4 space-y-4", children: [
|
|
426
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
427
|
-
/* @__PURE__ */ jsxRuntime.jsxs(ui.Heading, { level: "h3", children: [
|
|
428
|
-
"Item ",
|
|
429
|
-
index + 1
|
|
430
|
-
] }),
|
|
431
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "secondary", onClick: onRemove, children: "Remove" })
|
|
505
|
+
)
|
|
432
506
|
] }),
|
|
433
507
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
434
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { children: "
|
|
435
|
-
/* @__PURE__ */ jsxRuntime.
|
|
436
|
-
ui.
|
|
508
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { children: "Default Quantity" }),
|
|
509
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
510
|
+
ui.Input,
|
|
437
511
|
{
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Select.Content, { children: products == null ? void 0 : products.map((product, productIndex) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
443
|
-
ui.Select.Item,
|
|
444
|
-
{
|
|
445
|
-
value: product.id,
|
|
446
|
-
ref: productIndex === products.length - 1 ? lastOptionRef : null,
|
|
447
|
-
children: product.title
|
|
448
|
-
},
|
|
449
|
-
product.id
|
|
450
|
-
)) })
|
|
451
|
-
]
|
|
512
|
+
type: "number",
|
|
513
|
+
min: 0,
|
|
514
|
+
value: item.default_quantity,
|
|
515
|
+
onChange: (e) => onUpdate("default_quantity", parseInt(e.target.value) || 0)
|
|
452
516
|
}
|
|
453
517
|
)
|
|
518
|
+
] })
|
|
519
|
+
] }),
|
|
520
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
521
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
522
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
523
|
+
ui.Switch,
|
|
524
|
+
{
|
|
525
|
+
checked: item.optional,
|
|
526
|
+
onCheckedChange: (checked) => onUpdate("optional", checked)
|
|
527
|
+
}
|
|
528
|
+
),
|
|
529
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { children: "Optional" })
|
|
454
530
|
] }),
|
|
455
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "
|
|
456
|
-
/* @__PURE__ */ jsxRuntime.
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
onChange: (e) => onUpdate("min_quantity", parseInt(e.target.value) || 0)
|
|
465
|
-
}
|
|
466
|
-
)
|
|
467
|
-
] }),
|
|
468
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
469
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { children: "Max Quantity" }),
|
|
470
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
471
|
-
ui.Input,
|
|
472
|
-
{
|
|
473
|
-
type: "number",
|
|
474
|
-
min: 0,
|
|
475
|
-
value: item.max_quantity,
|
|
476
|
-
onChange: (e) => onUpdate("max_quantity", parseInt(e.target.value) || 0)
|
|
477
|
-
}
|
|
478
|
-
)
|
|
479
|
-
] }),
|
|
480
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
481
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { children: "Default Quantity" }),
|
|
482
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
483
|
-
ui.Input,
|
|
484
|
-
{
|
|
485
|
-
type: "number",
|
|
486
|
-
min: 0,
|
|
487
|
-
value: item.default_quantity,
|
|
488
|
-
onChange: (e) => onUpdate("default_quantity", parseInt(e.target.value) || 0)
|
|
489
|
-
}
|
|
490
|
-
)
|
|
491
|
-
] })
|
|
531
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
532
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
533
|
+
ui.Switch,
|
|
534
|
+
{
|
|
535
|
+
checked: item.separate_shipping,
|
|
536
|
+
onCheckedChange: (checked) => onUpdate("separate_shipping", checked)
|
|
537
|
+
}
|
|
538
|
+
),
|
|
539
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { children: "Separate Shipping" })
|
|
492
540
|
] }),
|
|
493
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "
|
|
494
|
-
/* @__PURE__ */ jsxRuntime.
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { children: "Optional" })
|
|
503
|
-
] }),
|
|
504
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
505
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
506
|
-
ui.Switch,
|
|
507
|
-
{
|
|
508
|
-
checked: item.separate_shipping,
|
|
509
|
-
onCheckedChange: (checked) => onUpdate("separate_shipping", checked)
|
|
510
|
-
}
|
|
511
|
-
),
|
|
512
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { children: "Separate Shipping" })
|
|
513
|
-
] }),
|
|
514
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
515
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
516
|
-
ui.Switch,
|
|
517
|
-
{
|
|
518
|
-
checked: item.individual_price,
|
|
519
|
-
onCheckedChange: (checked) => onUpdate("individual_price", checked)
|
|
520
|
-
}
|
|
521
|
-
),
|
|
522
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { children: "Individual Price" })
|
|
523
|
-
] })
|
|
541
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
542
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
543
|
+
ui.Switch,
|
|
544
|
+
{
|
|
545
|
+
checked: item.individual_price,
|
|
546
|
+
onCheckedChange: (checked) => onUpdate("individual_price", checked)
|
|
547
|
+
}
|
|
548
|
+
),
|
|
549
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { children: "Individual Price" })
|
|
524
550
|
] })
|
|
525
|
-
] })
|
|
526
|
-
};
|
|
551
|
+
] })
|
|
552
|
+
] });
|
|
527
553
|
const config = adminSdk.defineRouteConfig({
|
|
528
554
|
label: "Bundled Products",
|
|
529
555
|
icon: icons.CubeSolid
|