@zaamx/netme-bundle 0.0.5 → 0.0.8
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 +185 -244
- package/.medusa/server/src/admin/index.mjs +185 -244
- package/.medusa/server/src/api/admin/bundled-products/route.js +3 -2
- package/.medusa/server/src/api/admin/products/[id]/bundle/route.js +1 -1
- package/.medusa/server/src/api/store/special-packs/constants.js +8 -0
- package/.medusa/server/src/api/store/special-packs/route.js +40 -0
- package/.medusa/server/src/modules/bundles/service.js +188 -2
- package/.medusa/server/src/subscribers/redeem-special-pack.js +46 -0
- package/.medusa/server/src/workflows/hooks/validate-special-pack.js +42 -0
- package/.medusa/server/src/workflows/update-product-bundle.js +3 -1
- package/package.json +15 -15
|
@@ -102,9 +102,50 @@ const ProductSearchSelect = ({
|
|
|
102
102
|
] })
|
|
103
103
|
] });
|
|
104
104
|
};
|
|
105
|
+
const VariantPicker = ({
|
|
106
|
+
productId,
|
|
107
|
+
selectedIds,
|
|
108
|
+
onChange
|
|
109
|
+
}) => {
|
|
110
|
+
const [variants, setVariants] = useState([]);
|
|
111
|
+
const [loading, setLoading] = useState(false);
|
|
112
|
+
useEffect(() => {
|
|
113
|
+
if (!productId) {
|
|
114
|
+
setVariants([]);
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
setLoading(true);
|
|
118
|
+
sdk.admin.product.retrieve(productId).then(
|
|
119
|
+
({ product }) => setVariants(
|
|
120
|
+
(product.variants || []).map((v) => ({ id: v.id, title: v.title ?? v.id, sku: v.sku ?? void 0 }))
|
|
121
|
+
)
|
|
122
|
+
).catch(() => setVariants([])).finally(() => setLoading(false));
|
|
123
|
+
}, [productId]);
|
|
124
|
+
const toggle = (id) => onChange(
|
|
125
|
+
selectedIds.includes(id) ? selectedIds.filter((s) => s !== id) : [...selectedIds, id]
|
|
126
|
+
);
|
|
127
|
+
if (loading) return /* @__PURE__ */ jsx(Text, { className: "text-sm text-gray-400", children: "Loading variants…" });
|
|
128
|
+
if (!loading && variants.length === 0)
|
|
129
|
+
return /* @__PURE__ */ jsx(Text, { className: "text-sm text-gray-400", children: "No variants found." });
|
|
130
|
+
return /* @__PURE__ */ jsx("div", { className: "space-y-2 max-h-52 overflow-y-auto pr-1", children: variants.map((v) => /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2 cursor-pointer select-none", children: [
|
|
131
|
+
/* @__PURE__ */ jsx(
|
|
132
|
+
"input",
|
|
133
|
+
{
|
|
134
|
+
type: "checkbox",
|
|
135
|
+
checked: selectedIds.includes(v.id),
|
|
136
|
+
onChange: () => toggle(v.id),
|
|
137
|
+
className: "h-4 w-4 rounded border-gray-300"
|
|
138
|
+
}
|
|
139
|
+
),
|
|
140
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm", children: v.title }),
|
|
141
|
+
v.sku && /* @__PURE__ */ jsx("span", { className: "text-xs text-gray-400 font-mono", children: v.sku })
|
|
142
|
+
] }, v.id)) });
|
|
143
|
+
};
|
|
105
144
|
const emptyBundleItem = () => ({
|
|
106
145
|
product_id: void 0,
|
|
107
146
|
product_title: "",
|
|
147
|
+
variant_mode: "all",
|
|
148
|
+
variant_ids: [],
|
|
108
149
|
min_quantity: 1,
|
|
109
150
|
max_quantity: 1,
|
|
110
151
|
default_quantity: 1,
|
|
@@ -112,47 +153,42 @@ const emptyBundleItem = () => ({
|
|
|
112
153
|
separate_shipping: false,
|
|
113
154
|
individual_price: false
|
|
114
155
|
});
|
|
115
|
-
const
|
|
116
|
-
isEditing: false,
|
|
117
|
-
selectedProductId: void 0,
|
|
118
|
-
selectedProductTitle: "",
|
|
119
|
-
bundleItems: [],
|
|
120
|
-
bundleMeta: []
|
|
121
|
-
};
|
|
122
|
-
const limit = 15;
|
|
156
|
+
const LIMIT = 15;
|
|
123
157
|
const BundledProductsPage = () => {
|
|
124
158
|
const [page, setPage] = useState(0);
|
|
125
|
-
const [
|
|
159
|
+
const [openModal, setOpenModal] = useState(false);
|
|
126
160
|
const [isEditing, setIsEditing] = useState(false);
|
|
127
161
|
const [selectedProductId, setSelectedProductId] = useState();
|
|
128
162
|
const [selectedProductTitle, setSelectedProductTitle] = useState("");
|
|
129
163
|
const [bundleItems, setBundleItems] = useState([]);
|
|
130
164
|
const [bundleMeta, setBundleMeta] = useState([]);
|
|
131
165
|
const queryClient = useQueryClient();
|
|
132
|
-
const offset = page *
|
|
166
|
+
const offset = page * LIMIT;
|
|
133
167
|
const closeModal = () => {
|
|
134
|
-
|
|
135
|
-
setIsEditing(
|
|
136
|
-
setSelectedProductId(
|
|
137
|
-
setSelectedProductTitle(
|
|
138
|
-
setBundleItems(
|
|
139
|
-
setBundleMeta(
|
|
168
|
+
setOpenModal(false);
|
|
169
|
+
setIsEditing(false);
|
|
170
|
+
setSelectedProductId(void 0);
|
|
171
|
+
setSelectedProductTitle("");
|
|
172
|
+
setBundleItems([]);
|
|
173
|
+
setBundleMeta([]);
|
|
140
174
|
};
|
|
141
175
|
const { data, isLoading } = useQuery({
|
|
142
|
-
queryKey: ["bundled-products", offset,
|
|
176
|
+
queryKey: ["bundled-products", offset, LIMIT],
|
|
143
177
|
queryFn: () => sdk.client.fetch("/admin/bundled-products", {
|
|
144
178
|
method: "GET",
|
|
145
|
-
query: { limit, offset }
|
|
179
|
+
query: { limit: LIMIT, offset }
|
|
146
180
|
})
|
|
147
181
|
});
|
|
148
182
|
const { mutateAsync: saveBundle, isPending: isSaving } = useMutation({
|
|
149
|
-
mutationFn: async (
|
|
183
|
+
mutationFn: async () => {
|
|
150
184
|
if (!selectedProductId) throw new Error("No product selected");
|
|
185
|
+
const validItems = bundleItems.filter((i) => i.product_id);
|
|
151
186
|
await sdk.client.fetch(`/admin/products/${selectedProductId}/bundle`, {
|
|
152
187
|
method: "POST",
|
|
153
188
|
body: {
|
|
154
|
-
child_product_ids:
|
|
189
|
+
child_product_ids: validItems.map((item) => ({
|
|
155
190
|
id: item.product_id,
|
|
191
|
+
variant_ids: item.variant_mode === "specific" ? item.variant_ids : [],
|
|
156
192
|
min_quantity: item.min_quantity,
|
|
157
193
|
max_quantity: item.max_quantity,
|
|
158
194
|
default_quantity: item.default_quantity,
|
|
@@ -160,72 +196,70 @@ const BundledProductsPage = () => {
|
|
|
160
196
|
separate_shipping: item.separate_shipping,
|
|
161
197
|
individual_price: item.individual_price
|
|
162
198
|
})),
|
|
163
|
-
bundle_meta:
|
|
164
|
-
is_bundle:
|
|
199
|
+
bundle_meta: bundleMeta,
|
|
200
|
+
is_bundle: true
|
|
165
201
|
}
|
|
166
202
|
});
|
|
167
203
|
}
|
|
168
204
|
});
|
|
169
205
|
const { mutateAsync: deleteBundle } = useMutation({
|
|
170
|
-
mutationFn:
|
|
171
|
-
await sdk.client.fetch(`/admin/products/${productId}/bundle`, { method: "DELETE" });
|
|
172
|
-
}
|
|
206
|
+
mutationFn: (productId) => sdk.client.fetch(`/admin/products/${productId}/bundle`, { method: "DELETE" })
|
|
173
207
|
});
|
|
174
|
-
const handleDeleteBundle = async (productId) => {
|
|
175
|
-
try {
|
|
176
|
-
await deleteBundle(productId);
|
|
177
|
-
toast.success("Bundle deleted successfully");
|
|
178
|
-
queryClient.invalidateQueries({ queryKey: ["bundled-products"] });
|
|
179
|
-
} catch {
|
|
180
|
-
toast.error("Failed to delete bundle");
|
|
181
|
-
}
|
|
182
|
-
};
|
|
183
208
|
const handleEditBundle = (bundle) => {
|
|
184
209
|
setIsEditing(true);
|
|
185
210
|
setSelectedProductId(bundle.product.id);
|
|
186
211
|
setSelectedProductTitle(bundle.title);
|
|
187
212
|
setBundleItems(
|
|
188
|
-
bundle.items.map((item) =>
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
213
|
+
bundle.items.map((item) => {
|
|
214
|
+
var _a;
|
|
215
|
+
return {
|
|
216
|
+
product_id: item.product.id,
|
|
217
|
+
product_title: item.product.title,
|
|
218
|
+
variant_mode: ((_a = item.variant_ids) == null ? void 0 : _a.length) ? "specific" : "all",
|
|
219
|
+
variant_ids: item.variant_ids ?? [],
|
|
220
|
+
min_quantity: item.min_quantity,
|
|
221
|
+
max_quantity: item.max_quantity,
|
|
222
|
+
default_quantity: item.default_quantity,
|
|
223
|
+
optional: item.optional,
|
|
224
|
+
separate_shipping: item.separate_shipping,
|
|
225
|
+
individual_price: item.individual_price
|
|
226
|
+
};
|
|
227
|
+
})
|
|
198
228
|
);
|
|
199
229
|
setBundleMeta(bundle.bundle_meta || []);
|
|
200
|
-
|
|
230
|
+
setOpenModal(true);
|
|
201
231
|
};
|
|
202
|
-
const
|
|
232
|
+
const handleDeleteBundle = async (productId) => {
|
|
233
|
+
try {
|
|
234
|
+
await deleteBundle(productId);
|
|
235
|
+
toast.success("Bundle deleted");
|
|
236
|
+
queryClient.invalidateQueries({ queryKey: ["bundled-products"] });
|
|
237
|
+
} catch {
|
|
238
|
+
toast.error("Failed to delete bundle");
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
const handleSave = async () => {
|
|
203
242
|
if (!selectedProductId) {
|
|
204
243
|
toast.error("Please select a product");
|
|
205
244
|
return;
|
|
206
245
|
}
|
|
207
|
-
|
|
208
|
-
if (validItems.length === 0) {
|
|
246
|
+
if (!bundleItems.some((i) => i.product_id)) {
|
|
209
247
|
toast.error("Please add at least one product to the bundle");
|
|
210
248
|
return;
|
|
211
249
|
}
|
|
212
250
|
try {
|
|
213
|
-
await saveBundle(
|
|
214
|
-
toast.success(isEditing ? "Bundle updated
|
|
251
|
+
await saveBundle();
|
|
252
|
+
toast.success(isEditing ? "Bundle updated" : "Bundle created");
|
|
215
253
|
queryClient.invalidateQueries({ queryKey: ["bundled-products"] });
|
|
216
254
|
closeModal();
|
|
217
255
|
} catch {
|
|
218
256
|
toast.error(isEditing ? "Failed to update bundle" : "Failed to create bundle");
|
|
219
257
|
}
|
|
220
258
|
};
|
|
221
|
-
const
|
|
222
|
-
|
|
223
|
-
(prev) => prev.map((item, i) => i === index ? { ...item, [field]: value } : item)
|
|
224
|
-
);
|
|
225
|
-
};
|
|
226
|
-
const totalPages = Math.ceil(((data == null ? void 0 : data.count) || 0) / limit);
|
|
259
|
+
const updateItem = (index, field, value) => setBundleItems((prev) => prev.map((item, i) => i === index ? { ...item, [field]: value } : item));
|
|
260
|
+
const totalPages = Math.ceil(((data == null ? void 0 : data.count) || 0) / LIMIT);
|
|
227
261
|
return /* @__PURE__ */ jsxs(Container, { className: "divide-y p-0", children: [
|
|
228
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-
|
|
262
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between p-6", children: [
|
|
229
263
|
/* @__PURE__ */ jsx(Heading, { children: "Bundled Products" }),
|
|
230
264
|
/* @__PURE__ */ jsx(
|
|
231
265
|
Button,
|
|
@@ -233,7 +267,7 @@ const BundledProductsPage = () => {
|
|
|
233
267
|
variant: "primary",
|
|
234
268
|
onClick: () => {
|
|
235
269
|
closeModal();
|
|
236
|
-
|
|
270
|
+
setOpenModal(true);
|
|
237
271
|
},
|
|
238
272
|
children: "Create Bundle"
|
|
239
273
|
}
|
|
@@ -248,110 +282,60 @@ const BundledProductsPage = () => {
|
|
|
248
282
|
/* @__PURE__ */ jsx("th", { className: "border border-gray-200 px-4 py-2 text-left", children: "Actions" })
|
|
249
283
|
] }) }),
|
|
250
284
|
/* @__PURE__ */ jsxs("tbody", { children: [
|
|
251
|
-
((data == null ? void 0 : data.bundled_products.length) ?? 0) === 0 && /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx(
|
|
252
|
-
"td",
|
|
253
|
-
{
|
|
254
|
-
colSpan: 4,
|
|
255
|
-
className: "border border-gray-200 px-4 py-6 text-center text-gray-500",
|
|
256
|
-
children: "No bundled products found."
|
|
257
|
-
}
|
|
258
|
-
) }),
|
|
285
|
+
((data == null ? void 0 : data.bundled_products.length) ?? 0) === 0 && /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx("td", { colSpan: 4, className: "border border-gray-200 px-4 py-6 text-center text-gray-400", children: "No bundled products found." }) }),
|
|
259
286
|
data == null ? void 0 : data.bundled_products.map((bundle) => /* @__PURE__ */ jsxs("tr", { className: "hover:bg-gray-50", children: [
|
|
260
287
|
/* @__PURE__ */ jsxs("td", { className: "border border-gray-200 px-4 py-3", children: [
|
|
261
|
-
/* @__PURE__ */ jsx(
|
|
262
|
-
Link,
|
|
263
|
-
{
|
|
264
|
-
to: `/products/${bundle.product.id}`,
|
|
265
|
-
className: "font-medium text-blue-600 hover:underline",
|
|
266
|
-
children: bundle.title
|
|
267
|
-
}
|
|
268
|
-
),
|
|
288
|
+
/* @__PURE__ */ jsx(Link, { to: `/products/${bundle.product.id}`, className: "font-medium text-blue-600 hover:underline", children: bundle.title }),
|
|
269
289
|
/* @__PURE__ */ jsx("div", { className: "text-xs text-gray-400 mt-0.5", children: bundle.id })
|
|
270
290
|
] }),
|
|
271
|
-
/* @__PURE__ */ jsx("td", { className: "border border-gray-200 px-4 py-3", children: /* @__PURE__ */ jsx(
|
|
272
|
-
|
|
273
|
-
{
|
|
274
|
-
className: bundle.status === "published" ? "bg-green-100 text-green-700" : "bg-gray-100 text-gray-600",
|
|
275
|
-
children: bundle.status ?? "—"
|
|
276
|
-
}
|
|
277
|
-
) }),
|
|
278
|
-
/* @__PURE__ */ jsx("td", { className: "border border-gray-200 px-4 py-3", children: /* @__PURE__ */ jsxs("div", { className: "space-y-0.5", children: [
|
|
291
|
+
/* @__PURE__ */ jsx("td", { className: "border border-gray-200 px-4 py-3", children: /* @__PURE__ */ jsx(Badge, { className: bundle.status === "published" ? "bg-green-100 text-green-700" : "bg-gray-100 text-gray-600", children: bundle.status ?? "—" }) }),
|
|
292
|
+
/* @__PURE__ */ jsx("td", { className: "border border-gray-200 px-4 py-3", children: /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
279
293
|
bundle.items.length === 0 && /* @__PURE__ */ jsx("span", { className: "text-sm text-gray-400", children: "No items" }),
|
|
280
|
-
bundle.items.map((item) =>
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
{
|
|
284
|
-
to: `/products/${item.product.id}`,
|
|
285
|
-
className: "text-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
item.
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
294
|
+
bundle.items.map((item) => {
|
|
295
|
+
var _a;
|
|
296
|
+
return /* @__PURE__ */ jsxs("div", { className: "text-sm", children: [
|
|
297
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
298
|
+
/* @__PURE__ */ jsx(Link, { to: `/products/${item.product.id}`, className: "text-blue-600 hover:underline", children: item.product.title }),
|
|
299
|
+
/* @__PURE__ */ jsxs("span", { className: "text-gray-400", children: [
|
|
300
|
+
"× ",
|
|
301
|
+
item.default_quantity
|
|
302
|
+
] }),
|
|
303
|
+
item.optional && /* @__PURE__ */ jsx(Badge, { className: "bg-gray-100 text-gray-500 text-xs", children: "Optional" })
|
|
304
|
+
] }),
|
|
305
|
+
((_a = item.variant_ids) == null ? void 0 : _a.length) > 0 && /* @__PURE__ */ jsxs("div", { className: "text-xs text-gray-400 ml-1", children: [
|
|
306
|
+
item.variant_ids.length,
|
|
307
|
+
" specific variant",
|
|
308
|
+
item.variant_ids.length > 1 ? "s" : ""
|
|
309
|
+
] })
|
|
310
|
+
] }, item.id);
|
|
311
|
+
})
|
|
295
312
|
] }) }),
|
|
296
313
|
/* @__PURE__ */ jsx("td", { className: "border border-gray-200 px-4 py-3", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
297
|
-
/* @__PURE__ */ jsx(
|
|
298
|
-
|
|
299
|
-
{
|
|
300
|
-
variant: "secondary",
|
|
301
|
-
size: "small",
|
|
302
|
-
onClick: () => handleEditBundle(bundle),
|
|
303
|
-
children: "Edit"
|
|
304
|
-
}
|
|
305
|
-
),
|
|
306
|
-
/* @__PURE__ */ jsx(
|
|
307
|
-
Button,
|
|
308
|
-
{
|
|
309
|
-
variant: "secondary",
|
|
310
|
-
size: "small",
|
|
311
|
-
onClick: () => handleDeleteBundle(bundle.id),
|
|
312
|
-
className: "text-red-600 hover:text-red-700",
|
|
313
|
-
children: "Delete"
|
|
314
|
-
}
|
|
315
|
-
)
|
|
314
|
+
/* @__PURE__ */ jsx(Button, { variant: "secondary", size: "small", onClick: () => handleEditBundle(bundle), children: "Edit" }),
|
|
315
|
+
/* @__PURE__ */ jsx(Button, { variant: "secondary", size: "small", onClick: () => handleDeleteBundle(bundle.id), className: "text-red-600 hover:text-red-700", children: "Delete" })
|
|
316
316
|
] }) })
|
|
317
317
|
] }, bundle.id))
|
|
318
318
|
] })
|
|
319
319
|
] }) }),
|
|
320
320
|
totalPages > 1 && /* @__PURE__ */ jsxs("div", { className: "flex justify-center gap-2 mt-6", children: [
|
|
321
|
-
/* @__PURE__ */ jsx(
|
|
322
|
-
Button,
|
|
323
|
-
{
|
|
324
|
-
variant: "secondary",
|
|
325
|
-
onClick: () => setPage(Math.max(0, page - 1)),
|
|
326
|
-
disabled: page === 0,
|
|
327
|
-
children: "Previous"
|
|
328
|
-
}
|
|
329
|
-
),
|
|
321
|
+
/* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: () => setPage(Math.max(0, page - 1)), disabled: page === 0, children: "Previous" }),
|
|
330
322
|
/* @__PURE__ */ jsxs("span", { className: "flex items-center px-4", children: [
|
|
331
323
|
"Page ",
|
|
332
324
|
page + 1,
|
|
333
325
|
" of ",
|
|
334
326
|
totalPages
|
|
335
327
|
] }),
|
|
336
|
-
/* @__PURE__ */ jsx(
|
|
337
|
-
Button,
|
|
338
|
-
{
|
|
339
|
-
variant: "secondary",
|
|
340
|
-
onClick: () => setPage(Math.min(totalPages - 1, page + 1)),
|
|
341
|
-
disabled: page === totalPages - 1,
|
|
342
|
-
children: "Next"
|
|
343
|
-
}
|
|
344
|
-
)
|
|
328
|
+
/* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: () => setPage(Math.min(totalPages - 1, page + 1)), disabled: page === totalPages - 1, children: "Next" })
|
|
345
329
|
] })
|
|
346
330
|
] }),
|
|
347
|
-
/* @__PURE__ */ jsx(FocusModal, { open:
|
|
331
|
+
/* @__PURE__ */ jsx(FocusModal, { open: openModal, onOpenChange: (open) => {
|
|
348
332
|
if (!open) closeModal();
|
|
349
333
|
}, children: /* @__PURE__ */ jsxs(FocusModal.Content, { children: [
|
|
350
334
|
/* @__PURE__ */ jsx(FocusModal.Header, { children: /* @__PURE__ */ jsx(Heading, { level: "h1", children: isEditing ? "Edit Bundle" : "Create Bundle" }) }),
|
|
351
335
|
/* @__PURE__ */ jsx(FocusModal.Body, { children: /* @__PURE__ */ jsx("div", { className: "flex flex-1 flex-col items-center h-[80vh] overflow-y-auto px-2 py-8", children: /* @__PURE__ */ jsxs("div", { className: "w-full max-w-3xl flex flex-col gap-y-8", children: [
|
|
352
336
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
353
337
|
/* @__PURE__ */ jsx(Label, { children: "Bundle Product" }),
|
|
354
|
-
/* @__PURE__ */ jsx(Text, { className: "text-sm text-gray-500 mb-2", children: isEditing ? "The product this bundle is attached to" : "Choose the product that
|
|
338
|
+
/* @__PURE__ */ jsx(Text, { className: "text-sm text-gray-500 mb-2", children: isEditing ? "The product this bundle is attached to" : "Choose the product that becomes the bundle" }),
|
|
355
339
|
/* @__PURE__ */ jsx(
|
|
356
340
|
ProductSearchSelect,
|
|
357
341
|
{
|
|
@@ -375,80 +359,28 @@ const BundledProductsPage = () => {
|
|
|
375
359
|
{
|
|
376
360
|
item,
|
|
377
361
|
index,
|
|
378
|
-
onUpdate: (field, value) =>
|
|
362
|
+
onUpdate: (field, value) => updateItem(index, field, value),
|
|
379
363
|
onRemove: () => setBundleItems((prev) => prev.filter((_, i) => i !== index))
|
|
380
364
|
},
|
|
381
365
|
index
|
|
382
366
|
)),
|
|
383
|
-
/* @__PURE__ */ jsx(
|
|
384
|
-
Button,
|
|
385
|
-
{
|
|
386
|
-
variant: "secondary",
|
|
387
|
-
onClick: () => setBundleItems((prev) => [...prev, emptyBundleItem()]),
|
|
388
|
-
className: "mt-4",
|
|
389
|
-
children: "Add Item"
|
|
390
|
-
}
|
|
391
|
-
)
|
|
367
|
+
/* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: () => setBundleItems((prev) => [...prev, emptyBundleItem()]), className: "mt-2", children: "Add Item" })
|
|
392
368
|
] }),
|
|
393
369
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
394
370
|
/* @__PURE__ */ jsx(Heading, { level: "h2", children: "Bundle Metadata" }),
|
|
395
|
-
/* @__PURE__ */ jsx(Text, { className: "text-sm text-gray-500 mb-4", children: "Custom key-value pairs
|
|
371
|
+
/* @__PURE__ */ jsx(Text, { className: "text-sm text-gray-500 mb-4", children: "Custom key-value pairs" }),
|
|
396
372
|
bundleMeta.map((meta, index) => /* @__PURE__ */ jsxs("div", { className: "flex gap-2 mb-2", children: [
|
|
397
|
-
/* @__PURE__ */ jsx(
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
placeholder: "Key",
|
|
401
|
-
value: meta.key,
|
|
402
|
-
onChange: (e) => setBundleMeta(
|
|
403
|
-
(prev) => prev.map((m, i) => i === index ? { ...m, key: e.target.value } : m)
|
|
404
|
-
)
|
|
405
|
-
}
|
|
406
|
-
),
|
|
407
|
-
/* @__PURE__ */ jsx(
|
|
408
|
-
Input,
|
|
409
|
-
{
|
|
410
|
-
placeholder: "Value",
|
|
411
|
-
value: meta.value,
|
|
412
|
-
onChange: (e) => setBundleMeta(
|
|
413
|
-
(prev) => prev.map(
|
|
414
|
-
(m, i) => i === index ? { ...m, value: e.target.value } : m
|
|
415
|
-
)
|
|
416
|
-
)
|
|
417
|
-
}
|
|
418
|
-
),
|
|
419
|
-
/* @__PURE__ */ jsx(
|
|
420
|
-
Button,
|
|
421
|
-
{
|
|
422
|
-
variant: "secondary",
|
|
423
|
-
onClick: () => setBundleMeta((prev) => prev.filter((_, i) => i !== index)),
|
|
424
|
-
children: "Remove"
|
|
425
|
-
}
|
|
426
|
-
)
|
|
373
|
+
/* @__PURE__ */ jsx(Input, { placeholder: "Key", value: meta.key, onChange: (e) => setBundleMeta((prev) => prev.map((m, i) => i === index ? { ...m, key: e.target.value } : m)) }),
|
|
374
|
+
/* @__PURE__ */ jsx(Input, { placeholder: "Value", value: meta.value, onChange: (e) => setBundleMeta((prev) => prev.map((m, i) => i === index ? { ...m, value: e.target.value } : m)) }),
|
|
375
|
+
/* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: () => setBundleMeta((prev) => prev.filter((_, i) => i !== index)), children: "Remove" })
|
|
427
376
|
] }, index)),
|
|
428
|
-
/* @__PURE__ */ jsx(
|
|
429
|
-
Button,
|
|
430
|
-
{
|
|
431
|
-
variant: "secondary",
|
|
432
|
-
onClick: () => setBundleMeta((prev) => [...prev, { key: "", value: "" }]),
|
|
433
|
-
className: "mt-4",
|
|
434
|
-
children: "Add Metadata"
|
|
435
|
-
}
|
|
436
|
-
)
|
|
377
|
+
/* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: () => setBundleMeta((prev) => [...prev, { key: "", value: "" }]), className: "mt-2", children: "Add Metadata" })
|
|
437
378
|
] })
|
|
438
379
|
] })
|
|
439
380
|
] }) }) }),
|
|
440
381
|
/* @__PURE__ */ jsx(FocusModal.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
|
|
441
382
|
/* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: closeModal, children: "Cancel" }),
|
|
442
|
-
/* @__PURE__ */ jsx(
|
|
443
|
-
Button,
|
|
444
|
-
{
|
|
445
|
-
variant: "primary",
|
|
446
|
-
onClick: handleSaveBundle,
|
|
447
|
-
isLoading: isSaving,
|
|
448
|
-
disabled: !selectedProductId,
|
|
449
|
-
children: isEditing ? "Update Bundle" : "Create Bundle"
|
|
450
|
-
}
|
|
451
|
-
)
|
|
383
|
+
/* @__PURE__ */ jsx(Button, { variant: "primary", onClick: handleSave, isLoading: isSaving, disabled: !selectedProductId, children: isEditing ? "Update Bundle" : "Create Bundle" })
|
|
452
384
|
] }) })
|
|
453
385
|
] }) })
|
|
454
386
|
] });
|
|
@@ -471,78 +403,87 @@ const BundleItemForm = ({ item, index, onUpdate, onRemove }) => /* @__PURE__ */
|
|
|
471
403
|
onChange: (id, title) => {
|
|
472
404
|
onUpdate("product_id", id || void 0);
|
|
473
405
|
onUpdate("product_title", title);
|
|
406
|
+
onUpdate("variant_mode", "all");
|
|
407
|
+
onUpdate("variant_ids", []);
|
|
474
408
|
},
|
|
475
409
|
placeholder: "Search for a product…"
|
|
476
410
|
}
|
|
477
411
|
)
|
|
478
412
|
] }),
|
|
479
|
-
/* @__PURE__ */ jsxs("div", { className: "
|
|
480
|
-
/* @__PURE__ */
|
|
481
|
-
|
|
413
|
+
item.product_id && /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
|
|
414
|
+
/* @__PURE__ */ jsx(Label, { children: "Applies to" }),
|
|
415
|
+
/* @__PURE__ */ jsxs("div", { className: "flex gap-6", children: [
|
|
416
|
+
/* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2 text-sm cursor-pointer select-none", children: [
|
|
417
|
+
/* @__PURE__ */ jsx(
|
|
418
|
+
"input",
|
|
419
|
+
{
|
|
420
|
+
type: "radio",
|
|
421
|
+
name: `variant-mode-${index}`,
|
|
422
|
+
checked: item.variant_mode === "all",
|
|
423
|
+
onChange: () => {
|
|
424
|
+
onUpdate("variant_mode", "all");
|
|
425
|
+
onUpdate("variant_ids", []);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
),
|
|
429
|
+
"All variations"
|
|
430
|
+
] }),
|
|
431
|
+
/* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2 text-sm cursor-pointer select-none", children: [
|
|
432
|
+
/* @__PURE__ */ jsx(
|
|
433
|
+
"input",
|
|
434
|
+
{
|
|
435
|
+
type: "radio",
|
|
436
|
+
name: `variant-mode-${index}`,
|
|
437
|
+
checked: item.variant_mode === "specific",
|
|
438
|
+
onChange: () => onUpdate("variant_mode", "specific")
|
|
439
|
+
}
|
|
440
|
+
),
|
|
441
|
+
"Specific variations"
|
|
442
|
+
] })
|
|
443
|
+
] }),
|
|
444
|
+
item.variant_mode === "specific" && /* @__PURE__ */ jsxs("div", { className: "border border-gray-200 rounded-md p-3 bg-gray-50", children: [
|
|
445
|
+
/* @__PURE__ */ jsx(Text, { className: "text-xs text-gray-500 mb-3", children: 'Check each variation that qualifies for this bundle item. Switching back to "All variations" will clear this selection.' }),
|
|
482
446
|
/* @__PURE__ */ jsx(
|
|
483
|
-
|
|
447
|
+
VariantPicker,
|
|
484
448
|
{
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
onChange: (e) => onUpdate("min_quantity", parseInt(e.target.value) || 0)
|
|
449
|
+
productId: item.product_id,
|
|
450
|
+
selectedIds: item.variant_ids,
|
|
451
|
+
onChange: (ids) => onUpdate("variant_ids", ids)
|
|
489
452
|
}
|
|
490
|
-
)
|
|
453
|
+
),
|
|
454
|
+
item.variant_ids.length > 0 && /* @__PURE__ */ jsxs(Text, { className: "text-xs text-gray-400 mt-2", children: [
|
|
455
|
+
item.variant_ids.length,
|
|
456
|
+
" variation",
|
|
457
|
+
item.variant_ids.length > 1 ? "s" : "",
|
|
458
|
+
" selected"
|
|
459
|
+
] })
|
|
460
|
+
] })
|
|
461
|
+
] }),
|
|
462
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-3 gap-4", children: [
|
|
463
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
464
|
+
/* @__PURE__ */ jsx(Label, { children: "Min Quantity" }),
|
|
465
|
+
/* @__PURE__ */ jsx(Input, { type: "number", min: 0, value: item.min_quantity, onChange: (e) => onUpdate("min_quantity", parseInt(e.target.value) || 0) })
|
|
491
466
|
] }),
|
|
492
467
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
493
468
|
/* @__PURE__ */ jsx(Label, { children: "Max Quantity" }),
|
|
494
|
-
/* @__PURE__ */ jsx(
|
|
495
|
-
Input,
|
|
496
|
-
{
|
|
497
|
-
type: "number",
|
|
498
|
-
min: 0,
|
|
499
|
-
value: item.max_quantity,
|
|
500
|
-
onChange: (e) => onUpdate("max_quantity", parseInt(e.target.value) || 0)
|
|
501
|
-
}
|
|
502
|
-
)
|
|
469
|
+
/* @__PURE__ */ jsx(Input, { type: "number", min: 0, value: item.max_quantity, onChange: (e) => onUpdate("max_quantity", parseInt(e.target.value) || 0) })
|
|
503
470
|
] }),
|
|
504
471
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
505
472
|
/* @__PURE__ */ jsx(Label, { children: "Default Quantity" }),
|
|
506
|
-
/* @__PURE__ */ jsx(
|
|
507
|
-
Input,
|
|
508
|
-
{
|
|
509
|
-
type: "number",
|
|
510
|
-
min: 0,
|
|
511
|
-
value: item.default_quantity,
|
|
512
|
-
onChange: (e) => onUpdate("default_quantity", parseInt(e.target.value) || 0)
|
|
513
|
-
}
|
|
514
|
-
)
|
|
473
|
+
/* @__PURE__ */ jsx(Input, { type: "number", min: 0, value: item.default_quantity, onChange: (e) => onUpdate("default_quantity", parseInt(e.target.value) || 0) })
|
|
515
474
|
] })
|
|
516
475
|
] }),
|
|
517
476
|
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
518
477
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
519
|
-
/* @__PURE__ */ jsx(
|
|
520
|
-
Switch,
|
|
521
|
-
{
|
|
522
|
-
checked: item.optional,
|
|
523
|
-
onCheckedChange: (checked) => onUpdate("optional", checked)
|
|
524
|
-
}
|
|
525
|
-
),
|
|
478
|
+
/* @__PURE__ */ jsx(Switch, { checked: item.optional, onCheckedChange: (v) => onUpdate("optional", v) }),
|
|
526
479
|
/* @__PURE__ */ jsx(Label, { children: "Optional" })
|
|
527
480
|
] }),
|
|
528
481
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
529
|
-
/* @__PURE__ */ jsx(
|
|
530
|
-
Switch,
|
|
531
|
-
{
|
|
532
|
-
checked: item.separate_shipping,
|
|
533
|
-
onCheckedChange: (checked) => onUpdate("separate_shipping", checked)
|
|
534
|
-
}
|
|
535
|
-
),
|
|
482
|
+
/* @__PURE__ */ jsx(Switch, { checked: item.separate_shipping, onCheckedChange: (v) => onUpdate("separate_shipping", v) }),
|
|
536
483
|
/* @__PURE__ */ jsx(Label, { children: "Separate Shipping" })
|
|
537
484
|
] }),
|
|
538
485
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
539
|
-
/* @__PURE__ */ jsx(
|
|
540
|
-
Switch,
|
|
541
|
-
{
|
|
542
|
-
checked: item.individual_price,
|
|
543
|
-
onCheckedChange: (checked) => onUpdate("individual_price", checked)
|
|
544
|
-
}
|
|
545
|
-
),
|
|
486
|
+
/* @__PURE__ */ jsx(Switch, { checked: item.individual_price, onCheckedChange: (v) => onUpdate("individual_price", v) }),
|
|
546
487
|
/* @__PURE__ */ jsx(Label, { children: "Individual Price" })
|
|
547
488
|
] })
|
|
548
489
|
] })
|
|
@@ -52,6 +52,7 @@ async function GET(req, res) {
|
|
|
52
52
|
return {
|
|
53
53
|
id: childConfig.id,
|
|
54
54
|
product: { id: childConfig.id, title: childTitle },
|
|
55
|
+
variant_ids: childConfig.variant_ids ?? [],
|
|
55
56
|
quantity: childConfig.default_quantity || 1,
|
|
56
57
|
default_quantity: childConfig.default_quantity || 1,
|
|
57
58
|
min_quantity: childConfig.min_quantity ?? 1,
|
|
@@ -89,7 +90,7 @@ async function GET(req, res) {
|
|
|
89
90
|
}
|
|
90
91
|
async function POST(req, res) {
|
|
91
92
|
try {
|
|
92
|
-
const {
|
|
93
|
+
const { product, items } = req.body;
|
|
93
94
|
// Create the product first
|
|
94
95
|
const productService = req.scope.resolve(utils_1.Modules.PRODUCT);
|
|
95
96
|
const createdProducts = await productService.createProducts([product]);
|
|
@@ -141,4 +142,4 @@ async function POST(req, res) {
|
|
|
141
142
|
});
|
|
142
143
|
}
|
|
143
144
|
}
|
|
144
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
145
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2FkbWluL2J1bmRsZWQtcHJvZHVjdHMvcm91dGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFjQSxrQkFrRkM7QUFFRCxvQkE2REM7QUE5SkQsc0RBQXdEO0FBRXhELHFEQUFtRDtBQUduRCxTQUFTLGNBQWMsQ0FBQyxLQUFVO0lBQ2hDLElBQUksQ0FBQyxLQUFLO1FBQUUsT0FBTyxFQUFFLENBQUE7SUFDckIsSUFBSSxPQUFPLEtBQUssS0FBSyxRQUFRLEVBQUUsQ0FBQztRQUM5QixJQUFJLENBQUM7WUFBQyxPQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUE7UUFBQyxDQUFDO1FBQUMsTUFBTSxDQUFDO1lBQUMsT0FBTyxFQUFFLENBQUE7UUFBQyxDQUFDO0lBQ3RELENBQUM7SUFDRCxPQUFPLEtBQUssQ0FBQTtBQUNkLENBQUM7QUFFTSxLQUFLLFVBQVUsR0FBRyxDQUN2QixHQUFrQixFQUNsQixHQUFtQjtJQUVuQixJQUFJLENBQUM7UUFDSCxNQUFNLEtBQUssR0FBRyxRQUFRLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxLQUFlLENBQUMsSUFBSSxFQUFFLENBQUE7UUFDdkQsTUFBTSxNQUFNLEdBQUcsUUFBUSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsTUFBZ0IsQ0FBQyxJQUFJLENBQUMsQ0FBQTtRQUV4RCxNQUFNLGFBQWEsR0FBa0IsR0FBRyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsdUJBQWEsQ0FBQyxDQUFBO1FBQ3JFLE1BQU0sY0FBYyxHQUEwQixHQUFHLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxlQUFPLENBQUMsT0FBTyxDQUFDLENBQUE7UUFFaEYsOEVBQThFO1FBQzlFLE1BQU0sVUFBVSxHQUFHLE1BQU0sYUFBYSxDQUFDLFdBQVcsQ0FBQyxFQUFFLFNBQVMsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFBO1FBQ3ZFLE1BQU0sS0FBSyxHQUFHLFVBQVUsQ0FBQyxNQUFNLENBQUE7UUFDL0IsTUFBTSxPQUFPLEdBQUcsVUFBVSxDQUFDLEtBQUssQ0FBQyxNQUFNLEVBQUUsTUFBTSxHQUFHLEtBQUssQ0FBQyxDQUFBO1FBRXhELE1BQU0sZUFBZSxHQUFHLE1BQU0sT0FBTyxDQUFDLEdBQUcsQ0FDdkMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxLQUFLLEVBQUUsTUFBTSxFQUFFLEVBQUU7WUFDM0IsTUFBTSxpQkFBaUIsR0FBVSxjQUFjLENBQUMsTUFBTSxDQUFDLGNBQWMsQ0FBQyxFQUFFLElBQUksSUFBSSxFQUFFLENBQUE7WUFDbEYsTUFBTSxjQUFjLEdBQVUsY0FBYyxDQUFDLE1BQU0sQ0FBQyxXQUFXLENBQUMsRUFBRSxJQUFJLElBQUksRUFBRSxDQUFBO1lBRTVFLElBQUksWUFBWSxHQUFHLG1CQUFtQixDQUFBO1lBQ3RDLElBQUksYUFBYSxHQUFHLFNBQVMsQ0FBQTtZQUU3QixJQUFJLENBQUM7Z0JBQ0gsTUFBTSxPQUFPLEdBQUcsTUFBTSxjQUFjLENBQUMsZUFBZSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsQ0FBQTtnQkFDL0QsWUFBWSxHQUFHLE9BQU8sQ0FBQyxLQUFLLENBQUE7Z0JBQzVCLGFBQWEsR0FBRyxPQUFPLENBQUMsTUFBTSxDQUFBO1lBQ2hDLENBQUM7WUFBQyxNQUFNLENBQUM7Z0JBQ1AscURBQXFEO1lBQ3ZELENBQUM7WUFFRCxNQUFNLGFBQWEsR0FBRyxNQUFNLE9BQU8sQ0FBQyxHQUFHLENBQ3JDLGlCQUFpQixDQUFDLEdBQUcsQ0FBQyxLQUFLLEVBQUUsV0FBZ0IsRUFBRSxFQUFFO2dCQUMvQyxJQUFJLFVBQVUsR0FBRyxtQkFBbUIsQ0FBQTtnQkFDcEMsSUFBSSxDQUFDO29CQUNILE1BQU0sWUFBWSxHQUFHLE1BQU0sY0FBYyxDQUFDLGVBQWUsQ0FBQyxXQUFXLENBQUMsRUFBRSxDQUFDLENBQUE7b0JBQ3pFLFVBQVUsR0FBRyxZQUFZLENBQUMsS0FBSyxDQUFBO2dCQUNqQyxDQUFDO2dCQUFDLE1BQU0sQ0FBQztvQkFDUCx3QkFBd0I7Z0JBQzFCLENBQUM7Z0JBQ0QsT0FBTztvQkFDTCxFQUFFLEVBQUUsV0FBVyxDQUFDLEVBQUU7b0JBQ2xCLE9BQU8sRUFBRSxFQUFFLEVBQUUsRUFBRSxXQUFXLENBQUMsRUFBRSxFQUFFLEtBQUssRUFBRSxVQUFVLEVBQUU7b0JBQ2xELFdBQVcsRUFBRSxXQUFXLENBQUMsV0FBVyxJQUFJLEVBQUU7b0JBQzFDLFFBQVEsRUFBRSxXQUFXLENBQUMsZ0JBQWdCLElBQUksQ0FBQztvQkFDM0MsZ0JBQWdCLEVBQUUsV0FBVyxDQUFDLGdCQUFnQixJQUFJLENBQUM7b0JBQ25ELFlBQVksRUFBRSxXQUFXLENBQUMsWUFBWSxJQUFJLENBQUM7b0JBQzNDLFlBQVksRUFBRSxXQUFXLENBQUMsWUFBWSxJQUFJLENBQUM7b0JBQzNDLFFBQVEsRUFBRSxXQUFXLENBQUMsUUFBUSxJQUFJLEtBQUs7b0JBQ3ZDLGlCQUFpQixFQUFFLFdBQVcsQ0FBQyxpQkFBaUIsSUFBSSxLQUFLO29CQUN6RCxnQkFBZ0IsRUFBRSxXQUFXLENBQUMsZ0JBQWdCLElBQUksS0FBSztpQkFDeEQsQ0FBQTtZQUNILENBQUMsQ0FBQyxDQUNILENBQUE7WUFFRCxPQUFPO2dCQUNMLEVBQUUsRUFBRSxNQUFNLENBQUMsRUFBRTtnQkFDYixLQUFLLEVBQUUsWUFBWTtnQkFDbkIsTUFBTSxFQUFFLGFBQWE7Z0JBQ3JCLE9BQU8sRUFBRSxFQUFFLEVBQUUsRUFBRSxNQUFNLENBQUMsRUFBRSxFQUFFO2dCQUMxQixLQUFLLEVBQUUsYUFBYTtnQkFDcEIsV0FBVyxFQUFFLGNBQWM7Z0JBQzNCLFNBQVMsRUFBRSxNQUFNLENBQUMsU0FBUztnQkFDM0IsVUFBVSxFQUFFLE1BQU0sQ0FBQyxVQUFVO2dCQUM3QixVQUFVLEVBQUUsTUFBTSxDQUFDLFVBQVU7YUFDOUIsQ0FBQTtRQUNILENBQUMsQ0FBQyxDQUNILENBQUE7UUFFRCxHQUFHLENBQUMsSUFBSSxDQUFDO1lBQ1AsZ0JBQWdCLEVBQUUsZUFBZTtZQUNqQyxLQUFLO1lBQ0wsS0FBSztZQUNMLE1BQU07U0FDUCxDQUFDLENBQUE7SUFDSixDQUFDO0lBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztRQUNmLEdBQUcsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxDQUFDO1lBQ25CLE9BQU8sRUFBRSxxQ0FBcUM7WUFDOUMsS0FBSyxFQUFFLEtBQUssWUFBWSxLQUFLLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLGVBQWU7U0FDaEUsQ0FBQyxDQUFBO0lBQ0osQ0FBQztBQUNILENBQUM7QUFFTSxLQUFLLFVBQVUsSUFBSSxDQUN4QixHQUFrQixFQUNsQixHQUFtQjtJQUVuQixJQUFJLENBQUM7UUFDSCxNQUFNLEVBQUUsT0FBTyxFQUFFLEtBQUssRUFBRSxHQUFHLEdBQUcsQ0FBQyxJQUc5QixDQUFBO1FBRUQsMkJBQTJCO1FBQzNCLE1BQU0sY0FBYyxHQUEwQixHQUFHLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxlQUFPLENBQUMsT0FBTyxDQUFDLENBQUE7UUFDaEYsTUFBTSxlQUFlLEdBQUcsTUFBTSxjQUFjLENBQUMsY0FBYyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQTtRQUN0RSxNQUFNLGNBQWMsR0FBRyxlQUFlLENBQUMsQ0FBQyxDQUFDLENBQUE7UUFFekMsOEJBQThCO1FBQzlCLE1BQU0sYUFBYSxHQUFrQixHQUFHLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyx1QkFBYSxDQUFDLENBQUE7UUFDckUsTUFBTSxNQUFNLEdBQUcsTUFBTSxhQUFhLENBQUMsYUFBYSxDQUFDLENBQUM7Z0JBQ2hELEVBQUUsRUFBRSxjQUFjLENBQUMsRUFBRTtnQkFDckIsY0FBYyxFQUFFO29CQUNkLElBQUksRUFBRSxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxDQUFDO3dCQUN6QixFQUFFLEVBQUUsSUFBSSxDQUFDLFVBQVU7d0JBQ25CLFlBQVksRUFBRSxDQUFDO3dCQUNmLFlBQVksRUFBRSxDQUFDO3dCQUNmLGdCQUFnQixFQUFFLElBQUksQ0FBQyxRQUFRO3dCQUMvQixRQUFRLEVBQUUsS0FBSzt3QkFDZixpQkFBaUIsRUFBRSxLQUFLO3dCQUN4QixnQkFBZ0IsRUFBRSxLQUFLO3FCQUN4QixDQUFDLENBQUM7aUJBQ0o7Z0JBQ0QsV0FBVyxFQUFFO29CQUNYLElBQUksRUFBRSxFQUFFO2lCQUNUO2dCQUNELFNBQVMsRUFBRSxJQUFJO2FBQ2hCLENBQUMsQ0FBQyxDQUFBO1FBRUgsR0FBRyxDQUFDLElBQUksQ0FBQztZQUNQLGVBQWUsRUFBRTtnQkFDZixFQUFFLEVBQUUsY0FBYyxDQUFDLEVBQUU7Z0JBQ3JCLEtBQUssRUFBRSxjQUFjLENBQUMsS0FBSztnQkFDM0IsT0FBTyxFQUFFO29CQUNQLEVBQUUsRUFBRSxjQUFjLENBQUMsRUFBRTtpQkFDdEI7Z0JBQ0QsS0FBSyxFQUFFLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLENBQUM7b0JBQzFCLEVBQUUsRUFBRSxJQUFJLENBQUMsVUFBVTtvQkFDbkIsT0FBTyxFQUFFO3dCQUNQLEVBQUUsRUFBRSxJQUFJLENBQUMsVUFBVTt3QkFDbkIsS0FBSyxFQUFFLFNBQVMsRUFBRSxtREFBbUQ7cUJBQ3RFO29CQUNELFFBQVEsRUFBRSxJQUFJLENBQUMsUUFBUTtpQkFDeEIsQ0FBQyxDQUFDO2dCQUNILFVBQVUsRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsVUFBVTtnQkFDaEMsVUFBVSxFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxVQUFVO2FBQ2pDO1NBQ0YsQ0FBQyxDQUFBO0lBQ0osQ0FBQztJQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7UUFDZixHQUFHLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQztZQUNuQixPQUFPLEVBQUUsa0NBQWtDO1lBQzNDLEtBQUssRUFBRSxLQUFLLFlBQVksS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxlQUFlO1NBQ2hFLENBQUMsQ0FBQTtJQUNKLENBQUM7QUFDSCxDQUFDIn0=
|