@froze-labs/medusa-plugin-brands 0.0.1

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.
@@ -0,0 +1,481 @@
1
+ import { jsxs, jsx, Fragment } from "react/jsx-runtime";
2
+ import { defineRouteConfig } from "@medusajs/admin-sdk";
3
+ import { TagSolid } from "@medusajs/icons";
4
+ import { Container, Heading, Button, Text, Table, toast, Badge, Label, Input, Textarea } from "@medusajs/ui";
5
+ import { useQuery, useQueryClient, useMutation } from "@tanstack/react-query";
6
+ import { useState, useMemo, useEffect } from "react";
7
+ import { useNavigate, Link, useParams } from "react-router-dom";
8
+ import Medusa from "@medusajs/js-sdk";
9
+ const sdk = new Medusa({
10
+ baseUrl: "",
11
+ auth: {
12
+ type: "session"
13
+ }
14
+ });
15
+ const BrandsPage = () => {
16
+ var _a;
17
+ const navigate = useNavigate();
18
+ const [currentPage, setCurrentPage] = useState(0);
19
+ const pageSize = 20;
20
+ const offset = useMemo(() => currentPage * pageSize, [currentPage]);
21
+ const { data, isLoading } = useQuery({
22
+ queryKey: ["brands", pageSize, offset],
23
+ queryFn: () => sdk.client.fetch("/admin/brands", {
24
+ query: {
25
+ limit: pageSize,
26
+ offset
27
+ }
28
+ })
29
+ });
30
+ const pageCount = useMemo(
31
+ () => Math.ceil(((data == null ? void 0 : data.count) || 0) / pageSize),
32
+ [data == null ? void 0 : data.count]
33
+ );
34
+ return /* @__PURE__ */ jsxs(Container, { className: "divide-y p-0", children: [
35
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-6 py-4", children: [
36
+ /* @__PURE__ */ jsx(Heading, { level: "h1", children: "Brands" }),
37
+ /* @__PURE__ */ jsx(Button, { onClick: () => navigate("/brands/create"), children: "Create Brand" })
38
+ ] }),
39
+ /* @__PURE__ */ jsx("div", { className: "px-6 py-4", children: isLoading ? /* @__PURE__ */ jsx(Text, { children: "Loading..." }) : !((_a = data == null ? void 0 : data.brands) == null ? void 0 : _a.length) ? /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted", children: "No brands found" }) : /* @__PURE__ */ jsxs(Fragment, { children: [
40
+ /* @__PURE__ */ jsxs(Table, { children: [
41
+ /* @__PURE__ */ jsx(Table.Header, { children: /* @__PURE__ */ jsxs(Table.Row, { children: [
42
+ /* @__PURE__ */ jsx(Table.HeaderCell, { children: "Name" }),
43
+ /* @__PURE__ */ jsx(Table.HeaderCell, { children: "Slug" }),
44
+ /* @__PURE__ */ jsx(Table.HeaderCell, { children: "Products" }),
45
+ /* @__PURE__ */ jsx(Table.HeaderCell, { children: "Created" })
46
+ ] }) }),
47
+ /* @__PURE__ */ jsx(Table.Body, { children: data.brands.map((brand) => /* @__PURE__ */ jsxs(
48
+ Table.Row,
49
+ {
50
+ className: "cursor-pointer",
51
+ onClick: () => navigate(`/brands/${brand.id}`),
52
+ children: [
53
+ /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
54
+ brand.logo_image && /* @__PURE__ */ jsx(
55
+ "img",
56
+ {
57
+ src: brand.logo_image,
58
+ alt: brand.name,
59
+ className: "h-8 w-8 rounded object-cover"
60
+ }
61
+ ),
62
+ /* @__PURE__ */ jsx(
63
+ Link,
64
+ {
65
+ to: `/brands/${brand.id}`,
66
+ className: "text-ui-fg-interactive hover:underline",
67
+ onClick: (e) => e.stopPropagation(),
68
+ children: brand.name
69
+ }
70
+ )
71
+ ] }) }),
72
+ /* @__PURE__ */ jsx(Table.Cell, { children: brand.slug }),
73
+ /* @__PURE__ */ jsx(Table.Cell, { children: brand.product_count }),
74
+ /* @__PURE__ */ jsx(Table.Cell, { children: new Date(brand.created_at).toLocaleDateString() })
75
+ ]
76
+ },
77
+ brand.id
78
+ )) })
79
+ ] }),
80
+ pageCount > 1 && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mt-4", children: [
81
+ /* @__PURE__ */ jsxs(Text, { className: "text-ui-fg-muted", children: [
82
+ "Page ",
83
+ currentPage + 1,
84
+ " of ",
85
+ pageCount
86
+ ] }),
87
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
88
+ /* @__PURE__ */ jsx(
89
+ Button,
90
+ {
91
+ variant: "secondary",
92
+ size: "small",
93
+ disabled: currentPage === 0,
94
+ onClick: () => setCurrentPage((p) => p - 1),
95
+ children: "Previous"
96
+ }
97
+ ),
98
+ /* @__PURE__ */ jsx(
99
+ Button,
100
+ {
101
+ variant: "secondary",
102
+ size: "small",
103
+ disabled: currentPage >= pageCount - 1,
104
+ onClick: () => setCurrentPage((p) => p + 1),
105
+ children: "Next"
106
+ }
107
+ )
108
+ ] })
109
+ ] })
110
+ ] }) })
111
+ ] });
112
+ };
113
+ const config = defineRouteConfig({
114
+ label: "Brands",
115
+ icon: TagSolid
116
+ });
117
+ const BrandDetailPage = () => {
118
+ var _a, _b;
119
+ const { id } = useParams();
120
+ const navigate = useNavigate();
121
+ const queryClient = useQueryClient();
122
+ const { data, isLoading } = useQuery({
123
+ queryKey: ["brand", id],
124
+ queryFn: () => sdk.client.fetch(`/admin/brands/${id}`)
125
+ });
126
+ const deleteMutation = useMutation({
127
+ mutationFn: () => sdk.client.fetch(`/admin/brands/${id}`, { method: "DELETE" }),
128
+ onSuccess: () => {
129
+ queryClient.invalidateQueries({ queryKey: ["brands"] });
130
+ toast.success("Success", {
131
+ description: "Brand deleted successfully"
132
+ });
133
+ navigate("/brands");
134
+ },
135
+ onError: () => {
136
+ toast.error("Error", {
137
+ description: "Failed to delete brand"
138
+ });
139
+ }
140
+ });
141
+ if (isLoading) {
142
+ return /* @__PURE__ */ jsx(Container, { className: "p-6", children: /* @__PURE__ */ jsx(Text, { children: "Loading..." }) });
143
+ }
144
+ const brand = data == null ? void 0 : data.brand;
145
+ if (!brand) {
146
+ return /* @__PURE__ */ jsx(Container, { className: "p-6", children: /* @__PURE__ */ jsx(Text, { children: "Brand not found" }) });
147
+ }
148
+ return /* @__PURE__ */ jsxs(Container, { className: "divide-y p-0", children: [
149
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-6 py-4", children: [
150
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4", children: [
151
+ brand.logo_image && /* @__PURE__ */ jsx(
152
+ "img",
153
+ {
154
+ src: brand.logo_image,
155
+ alt: brand.name,
156
+ className: "h-12 w-12 rounded object-cover"
157
+ }
158
+ ),
159
+ /* @__PURE__ */ jsxs("div", { children: [
160
+ /* @__PURE__ */ jsx(Heading, { level: "h1", children: brand.name }),
161
+ /* @__PURE__ */ jsxs(Text, { className: "text-ui-fg-muted", children: [
162
+ "/",
163
+ brand.slug
164
+ ] })
165
+ ] })
166
+ ] }),
167
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
168
+ /* @__PURE__ */ jsx(Button, { onClick: () => navigate(`/brands/${id}/edit`), children: "Edit" }),
169
+ /* @__PURE__ */ jsx(
170
+ Button,
171
+ {
172
+ variant: "danger",
173
+ onClick: () => {
174
+ if (confirm("Are you sure you want to delete this brand?")) {
175
+ deleteMutation.mutate();
176
+ }
177
+ },
178
+ children: "Delete"
179
+ }
180
+ )
181
+ ] })
182
+ ] }),
183
+ brand.description && /* @__PURE__ */ jsxs("div", { className: "px-6 py-4", children: [
184
+ /* @__PURE__ */ jsx(Heading, { level: "h2", className: "mb-2", children: "Description" }),
185
+ /* @__PURE__ */ jsx(Text, { children: brand.description })
186
+ ] }),
187
+ brand.cover_image && /* @__PURE__ */ jsxs("div", { className: "px-6 py-4", children: [
188
+ /* @__PURE__ */ jsx(Heading, { level: "h2", className: "mb-2", children: "Cover Image" }),
189
+ /* @__PURE__ */ jsx(
190
+ "img",
191
+ {
192
+ src: brand.cover_image,
193
+ alt: `${brand.name} cover`,
194
+ className: "max-h-48 rounded object-cover"
195
+ }
196
+ )
197
+ ] }),
198
+ /* @__PURE__ */ jsxs("div", { className: "px-6 py-4", children: [
199
+ /* @__PURE__ */ jsxs(Heading, { level: "h2", className: "mb-2", children: [
200
+ "Products ",
201
+ /* @__PURE__ */ jsx(Badge, { children: ((_a = brand.products) == null ? void 0 : _a.length) || 0 })
202
+ ] }),
203
+ ((_b = brand.products) == null ? void 0 : _b.length) > 0 ? /* @__PURE__ */ jsx("ul", { className: "list-disc pl-4", children: brand.products.map((product) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
204
+ Link,
205
+ {
206
+ to: `/products/${product.id}`,
207
+ className: "text-ui-fg-interactive hover:underline",
208
+ children: product.title
209
+ }
210
+ ) }, product.id)) }) : /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted", children: "No products linked to this brand" })
211
+ ] })
212
+ ] });
213
+ };
214
+ const CreateBrandPage = () => {
215
+ const navigate = useNavigate();
216
+ const [loading, setLoading] = useState(false);
217
+ const [form, setForm] = useState({
218
+ name: "",
219
+ description: "",
220
+ cover_image: "",
221
+ logo_image: ""
222
+ });
223
+ const handleSubmit = async (e) => {
224
+ e.preventDefault();
225
+ setLoading(true);
226
+ try {
227
+ await sdk.client.fetch("/admin/brands", {
228
+ method: "POST",
229
+ body: {
230
+ name: form.name,
231
+ description: form.description || void 0,
232
+ cover_image: form.cover_image || void 0,
233
+ logo_image: form.logo_image || void 0
234
+ }
235
+ });
236
+ toast.success("Success", {
237
+ description: "Brand created successfully"
238
+ });
239
+ navigate("/brands");
240
+ } catch (error) {
241
+ toast.error("Error", {
242
+ description: "Failed to create brand"
243
+ });
244
+ } finally {
245
+ setLoading(false);
246
+ }
247
+ };
248
+ return /* @__PURE__ */ jsxs(Container, { className: "divide-y p-0", children: [
249
+ /* @__PURE__ */ jsx("div", { className: "flex items-center justify-between px-6 py-4", children: /* @__PURE__ */ jsx(Heading, { level: "h1", children: "Create Brand" }) }),
250
+ /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, className: "flex flex-col gap-4 px-6 py-4", children: [
251
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
252
+ /* @__PURE__ */ jsx(Label, { htmlFor: "name", children: "Name *" }),
253
+ /* @__PURE__ */ jsx(
254
+ Input,
255
+ {
256
+ id: "name",
257
+ value: form.name,
258
+ onChange: (e) => setForm({ ...form, name: e.target.value }),
259
+ required: true
260
+ }
261
+ )
262
+ ] }),
263
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
264
+ /* @__PURE__ */ jsx(Label, { htmlFor: "description", children: "Description" }),
265
+ /* @__PURE__ */ jsx(
266
+ Textarea,
267
+ {
268
+ id: "description",
269
+ value: form.description,
270
+ onChange: (e) => setForm({ ...form, description: e.target.value })
271
+ }
272
+ )
273
+ ] }),
274
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
275
+ /* @__PURE__ */ jsx(Label, { htmlFor: "logo_image", children: "Logo Image URL" }),
276
+ /* @__PURE__ */ jsx(
277
+ Input,
278
+ {
279
+ id: "logo_image",
280
+ type: "url",
281
+ value: form.logo_image,
282
+ onChange: (e) => setForm({ ...form, logo_image: e.target.value }),
283
+ placeholder: "https://example.com/logo.png"
284
+ }
285
+ )
286
+ ] }),
287
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
288
+ /* @__PURE__ */ jsx(Label, { htmlFor: "cover_image", children: "Cover Image URL" }),
289
+ /* @__PURE__ */ jsx(
290
+ Input,
291
+ {
292
+ id: "cover_image",
293
+ type: "url",
294
+ value: form.cover_image,
295
+ onChange: (e) => setForm({ ...form, cover_image: e.target.value }),
296
+ placeholder: "https://example.com/cover.jpg"
297
+ }
298
+ )
299
+ ] }),
300
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
301
+ /* @__PURE__ */ jsx(Button, { type: "submit", isLoading: loading, children: "Create Brand" }),
302
+ /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: () => navigate("/brands"), children: "Cancel" })
303
+ ] })
304
+ ] })
305
+ ] });
306
+ };
307
+ const EditBrandPage = () => {
308
+ const { id } = useParams();
309
+ const navigate = useNavigate();
310
+ const queryClient = useQueryClient();
311
+ const [form, setForm] = useState({
312
+ name: "",
313
+ slug: "",
314
+ description: "",
315
+ cover_image: "",
316
+ logo_image: ""
317
+ });
318
+ const { data, isLoading } = useQuery({
319
+ queryKey: ["brand", id],
320
+ queryFn: () => sdk.client.fetch(`/admin/brands/${id}`)
321
+ });
322
+ useEffect(() => {
323
+ if (data == null ? void 0 : data.brand) {
324
+ setForm({
325
+ name: data.brand.name,
326
+ slug: data.brand.slug,
327
+ description: data.brand.description || "",
328
+ cover_image: data.brand.cover_image || "",
329
+ logo_image: data.brand.logo_image || ""
330
+ });
331
+ }
332
+ }, [data]);
333
+ const updateMutation = useMutation({
334
+ mutationFn: (formData) => sdk.client.fetch(`/admin/brands/${id}`, {
335
+ method: "PUT",
336
+ body: {
337
+ name: formData.name,
338
+ slug: formData.slug || void 0,
339
+ description: formData.description || null,
340
+ cover_image: formData.cover_image || null,
341
+ logo_image: formData.logo_image || null
342
+ }
343
+ }),
344
+ onSuccess: () => {
345
+ queryClient.invalidateQueries({ queryKey: ["brand", id] });
346
+ queryClient.invalidateQueries({ queryKey: ["brands"] });
347
+ toast.success("Success", {
348
+ description: "Brand updated successfully"
349
+ });
350
+ navigate(`/brands/${id}`);
351
+ },
352
+ onError: () => {
353
+ toast.error("Error", {
354
+ description: "Failed to update brand"
355
+ });
356
+ }
357
+ });
358
+ const handleSubmit = (e) => {
359
+ e.preventDefault();
360
+ updateMutation.mutate(form);
361
+ };
362
+ if (isLoading) {
363
+ return /* @__PURE__ */ jsx(Container, { className: "p-6", children: "Loading..." });
364
+ }
365
+ return /* @__PURE__ */ jsxs(Container, { className: "divide-y p-0", children: [
366
+ /* @__PURE__ */ jsx("div", { className: "flex items-center justify-between px-6 py-4", children: /* @__PURE__ */ jsx(Heading, { level: "h1", children: "Edit Brand" }) }),
367
+ /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, className: "flex flex-col gap-4 px-6 py-4", children: [
368
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
369
+ /* @__PURE__ */ jsx(Label, { htmlFor: "name", children: "Name *" }),
370
+ /* @__PURE__ */ jsx(
371
+ Input,
372
+ {
373
+ id: "name",
374
+ value: form.name,
375
+ onChange: (e) => setForm({ ...form, name: e.target.value }),
376
+ required: true
377
+ }
378
+ )
379
+ ] }),
380
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
381
+ /* @__PURE__ */ jsx(Label, { htmlFor: "slug", children: "Slug" }),
382
+ /* @__PURE__ */ jsx(
383
+ Input,
384
+ {
385
+ id: "slug",
386
+ value: form.slug,
387
+ onChange: (e) => setForm({ ...form, slug: e.target.value })
388
+ }
389
+ )
390
+ ] }),
391
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
392
+ /* @__PURE__ */ jsx(Label, { htmlFor: "description", children: "Description" }),
393
+ /* @__PURE__ */ jsx(
394
+ Textarea,
395
+ {
396
+ id: "description",
397
+ value: form.description,
398
+ onChange: (e) => setForm({ ...form, description: e.target.value })
399
+ }
400
+ )
401
+ ] }),
402
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
403
+ /* @__PURE__ */ jsx(Label, { htmlFor: "logo_image", children: "Logo Image URL" }),
404
+ /* @__PURE__ */ jsx(
405
+ Input,
406
+ {
407
+ id: "logo_image",
408
+ type: "url",
409
+ value: form.logo_image,
410
+ onChange: (e) => setForm({ ...form, logo_image: e.target.value })
411
+ }
412
+ )
413
+ ] }),
414
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
415
+ /* @__PURE__ */ jsx(Label, { htmlFor: "cover_image", children: "Cover Image URL" }),
416
+ /* @__PURE__ */ jsx(
417
+ Input,
418
+ {
419
+ id: "cover_image",
420
+ type: "url",
421
+ value: form.cover_image,
422
+ onChange: (e) => setForm({ ...form, cover_image: e.target.value })
423
+ }
424
+ )
425
+ ] }),
426
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
427
+ /* @__PURE__ */ jsx(Button, { type: "submit", isLoading: updateMutation.isPending, children: "Save Changes" }),
428
+ /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: () => navigate(`/brands/${id}`), children: "Cancel" })
429
+ ] })
430
+ ] })
431
+ ] });
432
+ };
433
+ const widgetModule = { widgets: [] };
434
+ const routeModule = {
435
+ routes: [
436
+ {
437
+ Component: BrandsPage,
438
+ path: "/brands"
439
+ },
440
+ {
441
+ Component: BrandDetailPage,
442
+ path: "/brands/:id"
443
+ },
444
+ {
445
+ Component: CreateBrandPage,
446
+ path: "/brands/create"
447
+ },
448
+ {
449
+ Component: EditBrandPage,
450
+ path: "/brands/:id/edit"
451
+ }
452
+ ]
453
+ };
454
+ const menuItemModule = {
455
+ menuItems: [
456
+ {
457
+ label: config.label,
458
+ icon: config.icon,
459
+ path: "/brands",
460
+ nested: void 0,
461
+ rank: void 0,
462
+ translationNs: void 0
463
+ }
464
+ ]
465
+ };
466
+ const formModule = { customFields: {} };
467
+ const displayModule = {
468
+ displays: {}
469
+ };
470
+ const i18nModule = { resources: {} };
471
+ const plugin = {
472
+ widgetModule,
473
+ routeModule,
474
+ menuItemModule,
475
+ formModule,
476
+ displayModule,
477
+ i18nModule
478
+ };
479
+ export {
480
+ plugin as default
481
+ };
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DELETE = exports.PUT = exports.GET = void 0;
4
+ const utils_1 = require("@medusajs/framework/utils");
5
+ const update_brand_1 = require("../../../../workflows/update-brand");
6
+ const delete_brand_1 = require("../../../../workflows/delete-brand");
7
+ const GET = async (req, res) => {
8
+ const { id } = req.params;
9
+ const query = req.scope.resolve(utils_1.ContainerRegistrationKeys.QUERY);
10
+ const { data } = await query.graph({
11
+ entity: "brand",
12
+ fields: ["*", "products.*"],
13
+ filters: { id },
14
+ });
15
+ if (!data.length) {
16
+ return res.status(404).json({ message: "Brand not found" });
17
+ }
18
+ res.json({ brand: data[0] });
19
+ };
20
+ exports.GET = GET;
21
+ const PUT = async (req, res) => {
22
+ const { id } = req.params;
23
+ const { result } = await (0, update_brand_1.updateBrandWorkflow)(req.scope).run({
24
+ input: {
25
+ id,
26
+ ...req.validatedBody,
27
+ },
28
+ });
29
+ res.json({ brand: result });
30
+ };
31
+ exports.PUT = PUT;
32
+ const DELETE = async (req, res) => {
33
+ const { id } = req.params;
34
+ await (0, delete_brand_1.deleteBrandWorkflow)(req.scope).run({
35
+ input: { id },
36
+ });
37
+ res.status(200).json({ id, deleted: true });
38
+ };
39
+ exports.DELETE = DELETE;
40
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2FkbWluL2JyYW5kcy9baWRdL3JvdXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUNBLHFEQUFxRTtBQUNyRSxxRUFBd0U7QUFDeEUscUVBQXdFO0FBR2pFLE1BQU0sR0FBRyxHQUFHLEtBQUssRUFBRSxHQUFrQixFQUFFLEdBQW1CLEVBQUUsRUFBRTtJQUNuRSxNQUFNLEVBQUUsRUFBRSxFQUFFLEdBQUcsR0FBRyxDQUFDLE1BQU0sQ0FBQTtJQUN6QixNQUFNLEtBQUssR0FBRyxHQUFHLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxpQ0FBeUIsQ0FBQyxLQUFLLENBQUMsQ0FBQTtJQUVoRSxNQUFNLEVBQUUsSUFBSSxFQUFFLEdBQUcsTUFBTSxLQUFLLENBQUMsS0FBSyxDQUFDO1FBQ2pDLE1BQU0sRUFBRSxPQUFPO1FBQ2YsTUFBTSxFQUFFLENBQUMsR0FBRyxFQUFFLFlBQVksQ0FBQztRQUMzQixPQUFPLEVBQUUsRUFBRSxFQUFFLEVBQUU7S0FDaEIsQ0FBQyxDQUFBO0lBRUYsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQztRQUNqQixPQUFPLEdBQUcsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxDQUFDLEVBQUUsT0FBTyxFQUFFLGlCQUFpQixFQUFFLENBQUMsQ0FBQTtJQUM3RCxDQUFDO0lBRUQsR0FBRyxDQUFDLElBQUksQ0FBQyxFQUFFLEtBQUssRUFBRSxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFBO0FBQzlCLENBQUMsQ0FBQTtBQWZZLFFBQUEsR0FBRyxPQWVmO0FBRU0sTUFBTSxHQUFHLEdBQUcsS0FBSyxFQUN0QixHQUEyQyxFQUMzQyxHQUFtQixFQUNuQixFQUFFO0lBQ0YsTUFBTSxFQUFFLEVBQUUsRUFBRSxHQUFHLEdBQUcsQ0FBQyxNQUFNLENBQUE7SUFFekIsTUFBTSxFQUFFLE1BQU0sRUFBRSxHQUFHLE1BQU0sSUFBQSxrQ0FBbUIsRUFBQyxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUMsR0FBRyxDQUFDO1FBQzFELEtBQUssRUFBRTtZQUNMLEVBQUU7WUFDRixHQUFHLEdBQUcsQ0FBQyxhQUFhO1NBQ3JCO0tBQ0YsQ0FBQyxDQUFBO0lBRUYsR0FBRyxDQUFDLElBQUksQ0FBQyxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsQ0FBQyxDQUFBO0FBQzdCLENBQUMsQ0FBQTtBQWRZLFFBQUEsR0FBRyxPQWNmO0FBRU0sTUFBTSxNQUFNLEdBQUcsS0FBSyxFQUFFLEdBQWtCLEVBQUUsR0FBbUIsRUFBRSxFQUFFO0lBQ3RFLE1BQU0sRUFBRSxFQUFFLEVBQUUsR0FBRyxHQUFHLENBQUMsTUFBTSxDQUFBO0lBRXpCLE1BQU0sSUFBQSxrQ0FBbUIsRUFBQyxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUMsR0FBRyxDQUFDO1FBQ3ZDLEtBQUssRUFBRSxFQUFFLEVBQUUsRUFBRTtLQUNkLENBQUMsQ0FBQTtJQUVGLEdBQUcsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxDQUFDLEVBQUUsRUFBRSxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFBO0FBQzdDLENBQUMsQ0FBQTtBQVJZLFFBQUEsTUFBTSxVQVFsQiJ9
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.POST = exports.GET = void 0;
4
+ const utils_1 = require("@medusajs/framework/utils");
5
+ const create_brand_1 = require("../../../workflows/create-brand");
6
+ const brand_1 = require("../../../modules/brand");
7
+ const GET = async (req, res) => {
8
+ const brandModuleService = req.scope.resolve(brand_1.BRAND_MODULE);
9
+ const query = req.scope.resolve(utils_1.ContainerRegistrationKeys.QUERY);
10
+ const { limit = 20, offset = 0, q } = req.validatedQuery;
11
+ const filters = {};
12
+ if (q) {
13
+ filters.$or = [
14
+ { name: { $like: `%${q}%` } },
15
+ { slug: { $like: `%${q}%` } },
16
+ ];
17
+ }
18
+ const [brands, count] = await brandModuleService.listAndCountBrands(filters, {
19
+ skip: offset,
20
+ take: limit,
21
+ order: { created_at: "DESC" },
22
+ });
23
+ const brandsWithCounts = await Promise.all(brands.map(async (brand) => {
24
+ const { data } = await query.graph({
25
+ entity: "brand",
26
+ fields: ["products.*"],
27
+ filters: { id: brand.id },
28
+ });
29
+ return {
30
+ ...brand,
31
+ product_count: data[0]?.products?.length || 0,
32
+ };
33
+ }));
34
+ res.json({
35
+ brands: brandsWithCounts,
36
+ count,
37
+ limit,
38
+ offset,
39
+ });
40
+ };
41
+ exports.GET = GET;
42
+ const POST = async (req, res) => {
43
+ const { result } = await (0, create_brand_1.createBrandWorkflow)(req.scope).run({
44
+ input: req.validatedBody,
45
+ });
46
+ res.status(201).json({ brand: result });
47
+ };
48
+ exports.POST = POST;
49
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2FkbWluL2JyYW5kcy9yb3V0ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFDQSxxREFBcUU7QUFDckUsa0VBQXFFO0FBQ3JFLGtEQUFxRDtBQU85QyxNQUFNLEdBQUcsR0FBRyxLQUFLLEVBQUUsR0FBa0IsRUFBRSxHQUFtQixFQUFFLEVBQUU7SUFDbkUsTUFBTSxrQkFBa0IsR0FDdEIsR0FBRyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsb0JBQVksQ0FBQyxDQUFBO0lBQ2pDLE1BQU0sS0FBSyxHQUFHLEdBQUcsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLGlDQUF5QixDQUFDLEtBQUssQ0FBQyxDQUFBO0lBRWhFLE1BQU0sRUFBRSxLQUFLLEdBQUcsRUFBRSxFQUFFLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEdBQUcsR0FBRyxDQUFDLGNBQTBDLENBQUE7SUFFcEYsTUFBTSxPQUFPLEdBQTRCLEVBQUUsQ0FBQTtJQUMzQyxJQUFJLENBQUMsRUFBRSxDQUFDO1FBQ04sT0FBTyxDQUFDLEdBQUcsR0FBRztZQUNaLEVBQUUsSUFBSSxFQUFFLEVBQUUsS0FBSyxFQUFFLElBQUksQ0FBQyxHQUFHLEVBQUUsRUFBRTtZQUM3QixFQUFFLElBQUksRUFBRSxFQUFFLEtBQUssRUFBRSxJQUFJLENBQUMsR0FBRyxFQUFFLEVBQUU7U0FDOUIsQ0FBQTtJQUNILENBQUM7SUFFRCxNQUFNLENBQUMsTUFBTSxFQUFFLEtBQUssQ0FBQyxHQUFHLE1BQU0sa0JBQWtCLENBQUMsa0JBQWtCLENBQUMsT0FBTyxFQUFFO1FBQzNFLElBQUksRUFBRSxNQUFNO1FBQ1osSUFBSSxFQUFFLEtBQUs7UUFDWCxLQUFLLEVBQUUsRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFO0tBQzlCLENBQUMsQ0FBQTtJQUVGLE1BQU0sZ0JBQWdCLEdBQUcsTUFBTSxPQUFPLENBQUMsR0FBRyxDQUN4QyxNQUFNLENBQUMsR0FBRyxDQUFDLEtBQUssRUFBRSxLQUFLLEVBQUUsRUFBRTtRQUN6QixNQUFNLEVBQUUsSUFBSSxFQUFFLEdBQUcsTUFBTSxLQUFLLENBQUMsS0FBSyxDQUFDO1lBQ2pDLE1BQU0sRUFBRSxPQUFPO1lBQ2YsTUFBTSxFQUFFLENBQUMsWUFBWSxDQUFDO1lBQ3RCLE9BQU8sRUFBRSxFQUFFLEVBQUUsRUFBRSxLQUFLLENBQUMsRUFBRSxFQUFFO1NBQzFCLENBQUMsQ0FBQTtRQUVGLE9BQU87WUFDTCxHQUFHLEtBQUs7WUFDUixhQUFhLEVBQUUsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLFFBQVEsRUFBRSxNQUFNLElBQUksQ0FBQztTQUM5QyxDQUFBO0lBQ0gsQ0FBQyxDQUFDLENBQ0gsQ0FBQTtJQUVELEdBQUcsQ0FBQyxJQUFJLENBQUM7UUFDUCxNQUFNLEVBQUUsZ0JBQWdCO1FBQ3hCLEtBQUs7UUFDTCxLQUFLO1FBQ0wsTUFBTTtLQUNQLENBQUMsQ0FBQTtBQUNKLENBQUMsQ0FBQTtBQTFDWSxRQUFBLEdBQUcsT0EwQ2Y7QUFFTSxNQUFNLElBQUksR0FBRyxLQUFLLEVBQ3ZCLEdBQTRDLEVBQzVDLEdBQW1CLEVBQ25CLEVBQUU7SUFDRixNQUFNLEVBQUUsTUFBTSxFQUFFLEdBQUcsTUFBTSxJQUFBLGtDQUFtQixFQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQyxHQUFHLENBQUM7UUFDMUQsS0FBSyxFQUFFLEdBQUcsQ0FBQyxhQUFhO0tBQ3pCLENBQUMsQ0FBQTtJQUVGLEdBQUcsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxDQUFDLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxDQUFDLENBQUE7QUFDekMsQ0FBQyxDQUFBO0FBVFksUUFBQSxJQUFJLFFBU2hCIn0=
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GetAdminBrandsParams = exports.PutAdminUpdateBrand = exports.PostAdminCreateBrand = void 0;
4
+ const zod_1 = require("zod");
5
+ exports.PostAdminCreateBrand = zod_1.z.object({
6
+ name: zod_1.z.string().min(1, "Name is required"),
7
+ slug: zod_1.z.string().optional(),
8
+ description: zod_1.z.string().optional(),
9
+ cover_image: zod_1.z.string().url().optional().or(zod_1.z.literal("")),
10
+ logo_image: zod_1.z.string().url().optional().or(zod_1.z.literal("")),
11
+ });
12
+ exports.PutAdminUpdateBrand = zod_1.z.object({
13
+ name: zod_1.z.string().min(1).optional(),
14
+ slug: zod_1.z.string().optional(),
15
+ description: zod_1.z.string().optional().nullable(),
16
+ cover_image: zod_1.z.string().url().optional().or(zod_1.z.literal("")).nullable(),
17
+ logo_image: zod_1.z.string().url().optional().or(zod_1.z.literal("")).nullable(),
18
+ });
19
+ exports.GetAdminBrandsParams = zod_1.z.object({
20
+ limit: zod_1.z.preprocess((val) => (val ? parseInt(val) : 20), zod_1.z.number().optional()),
21
+ offset: zod_1.z.preprocess((val) => (val ? parseInt(val) : 0), zod_1.z.number().optional()),
22
+ q: zod_1.z.string().optional(),
23
+ });
24
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmFsaWRhdG9ycy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9hcGkvYWRtaW4vYnJhbmRzL3ZhbGlkYXRvcnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsNkJBQXVCO0FBRVYsUUFBQSxvQkFBb0IsR0FBRyxPQUFDLENBQUMsTUFBTSxDQUFDO0lBQzNDLElBQUksRUFBRSxPQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxrQkFBa0IsQ0FBQztJQUMzQyxJQUFJLEVBQUUsT0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsRUFBRTtJQUMzQixXQUFXLEVBQUUsT0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsRUFBRTtJQUNsQyxXQUFXLEVBQUUsT0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLEdBQUcsRUFBRSxDQUFDLFFBQVEsRUFBRSxDQUFDLEVBQUUsQ0FBQyxPQUFDLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQzFELFVBQVUsRUFBRSxPQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsR0FBRyxFQUFFLENBQUMsUUFBUSxFQUFFLENBQUMsRUFBRSxDQUFDLE9BQUMsQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLENBQUM7Q0FDMUQsQ0FBQyxDQUFBO0FBRVcsUUFBQSxtQkFBbUIsR0FBRyxPQUFDLENBQUMsTUFBTSxDQUFDO0lBQzFDLElBQUksRUFBRSxPQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLFFBQVEsRUFBRTtJQUNsQyxJQUFJLEVBQUUsT0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsRUFBRTtJQUMzQixXQUFXLEVBQUUsT0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsRUFBRSxDQUFDLFFBQVEsRUFBRTtJQUM3QyxXQUFXLEVBQUUsT0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLEdBQUcsRUFBRSxDQUFDLFFBQVEsRUFBRSxDQUFDLEVBQUUsQ0FBQyxPQUFDLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsUUFBUSxFQUFFO0lBQ3JFLFVBQVUsRUFBRSxPQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsR0FBRyxFQUFFLENBQUMsUUFBUSxFQUFFLENBQUMsRUFBRSxDQUFDLE9BQUMsQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxRQUFRLEVBQUU7Q0FDckUsQ0FBQyxDQUFBO0FBRVcsUUFBQSxvQkFBb0IsR0FBRyxPQUFDLENBQUMsTUFBTSxDQUFDO0lBQzNDLEtBQUssRUFBRSxPQUFDLENBQUMsVUFBVSxDQUNqQixDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxHQUFhLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQzdDLE9BQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxRQUFRLEVBQUUsQ0FDdEI7SUFDRCxNQUFNLEVBQUUsT0FBQyxDQUFDLFVBQVUsQ0FDbEIsQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsR0FBYSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUM1QyxPQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsUUFBUSxFQUFFLENBQ3RCO0lBQ0QsQ0FBQyxFQUFFLE9BQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxRQUFRLEVBQUU7Q0FDekIsQ0FBQyxDQUFBIn0=
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const http_1 = require("@medusajs/framework/http");
4
+ const validators_1 = require("./admin/brands/validators");
5
+ exports.default = (0, http_1.defineMiddlewares)({
6
+ routes: [
7
+ {
8
+ matcher: "/admin/brands",
9
+ method: "GET",
10
+ middlewares: [(0, http_1.validateAndTransformQuery)(validators_1.GetAdminBrandsParams, {})],
11
+ },
12
+ {
13
+ matcher: "/admin/brands",
14
+ method: "POST",
15
+ middlewares: [(0, http_1.validateAndTransformBody)(validators_1.PostAdminCreateBrand)],
16
+ },
17
+ {
18
+ matcher: "/admin/brands/:id",
19
+ method: "PUT",
20
+ middlewares: [(0, http_1.validateAndTransformBody)(validators_1.PutAdminUpdateBrand)],
21
+ },
22
+ ],
23
+ });
24
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWlkZGxld2FyZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvYXBpL21pZGRsZXdhcmVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsbURBSWlDO0FBQ2pDLDBEQUlrQztBQUVsQyxrQkFBZSxJQUFBLHdCQUFpQixFQUFDO0lBQy9CLE1BQU0sRUFBRTtRQUNOO1lBQ0UsT0FBTyxFQUFFLGVBQWU7WUFDeEIsTUFBTSxFQUFFLEtBQUs7WUFDYixXQUFXLEVBQUUsQ0FBQyxJQUFBLGdDQUF5QixFQUFDLGlDQUFvQixFQUFFLEVBQUUsQ0FBQyxDQUFDO1NBQ25FO1FBQ0Q7WUFDRSxPQUFPLEVBQUUsZUFBZTtZQUN4QixNQUFNLEVBQUUsTUFBTTtZQUNkLFdBQVcsRUFBRSxDQUFDLElBQUEsK0JBQXdCLEVBQUMsaUNBQW9CLENBQUMsQ0FBQztTQUM5RDtRQUNEO1lBQ0UsT0FBTyxFQUFFLG1CQUFtQjtZQUM1QixNQUFNLEVBQUUsS0FBSztZQUNiLFdBQVcsRUFBRSxDQUFDLElBQUEsK0JBQXdCLEVBQUMsZ0NBQW1CLENBQUMsQ0FBQztTQUM3RDtLQUNGO0NBQ0YsQ0FBQyxDQUFBIn0=
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GET = void 0;
4
+ const utils_1 = require("@medusajs/framework/utils");
5
+ const brand_1 = require("../../../../modules/brand");
6
+ const GET = async (req, res) => {
7
+ const { id } = req.params;
8
+ const brandModuleService = req.scope.resolve(brand_1.BRAND_MODULE);
9
+ const query = req.scope.resolve(utils_1.ContainerRegistrationKeys.QUERY);
10
+ const isUUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(id);
11
+ if (isUUID) {
12
+ const { data } = await query.graph({
13
+ entity: "brand",
14
+ fields: ["*", "products.*"],
15
+ filters: { id },
16
+ });
17
+ if (!data.length) {
18
+ return res.status(404).json({ message: "Brand not found" });
19
+ }
20
+ return res.json({ brand: data[0] });
21
+ }
22
+ const brands = await brandModuleService.listBrands({ slug: id });
23
+ if (!brands.length) {
24
+ return res.status(404).json({ message: "Brand not found" });
25
+ }
26
+ const { data } = await query.graph({
27
+ entity: "brand",
28
+ fields: ["*", "products.*"],
29
+ filters: { id: brands[0].id },
30
+ });
31
+ res.json({ brand: data[0] });
32
+ };
33
+ exports.GET = GET;
34
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL3N0b3JlL2JyYW5kcy9baWRdL3JvdXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUNBLHFEQUFxRTtBQUNyRSxxREFBd0Q7QUFHakQsTUFBTSxHQUFHLEdBQUcsS0FBSyxFQUFFLEdBQWtCLEVBQUUsR0FBbUIsRUFBRSxFQUFFO0lBQ25FLE1BQU0sRUFBRSxFQUFFLEVBQUUsR0FBRyxHQUFHLENBQUMsTUFBTSxDQUFBO0lBQ3pCLE1BQU0sa0JBQWtCLEdBQ3RCLEdBQUcsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLG9CQUFZLENBQUMsQ0FBQTtJQUNqQyxNQUFNLEtBQUssR0FBRyxHQUFHLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxpQ0FBeUIsQ0FBQyxLQUFLLENBQUMsQ0FBQTtJQUVoRSxNQUFNLE1BQU0sR0FDVixpRUFBaUUsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUE7SUFFNUUsSUFBSSxNQUFNLEVBQUUsQ0FBQztRQUNYLE1BQU0sRUFBRSxJQUFJLEVBQUUsR0FBRyxNQUFNLEtBQUssQ0FBQyxLQUFLLENBQUM7WUFDakMsTUFBTSxFQUFFLE9BQU87WUFDZixNQUFNLEVBQUUsQ0FBQyxHQUFHLEVBQUUsWUFBWSxDQUFDO1lBQzNCLE9BQU8sRUFBRSxFQUFFLEVBQUUsRUFBRTtTQUNoQixDQUFDLENBQUE7UUFFRixJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDO1lBQ2pCLE9BQU8sR0FBRyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLENBQUMsRUFBRSxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsQ0FBQyxDQUFBO1FBQzdELENBQUM7UUFFRCxPQUFPLEdBQUcsQ0FBQyxJQUFJLENBQUMsRUFBRSxLQUFLLEVBQUUsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQTtJQUNyQyxDQUFDO0lBRUQsTUFBTSxNQUFNLEdBQUcsTUFBTSxrQkFBa0IsQ0FBQyxVQUFVLENBQUMsRUFBRSxJQUFJLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQTtJQUVoRSxJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sRUFBRSxDQUFDO1FBQ25CLE9BQU8sR0FBRyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLENBQUMsRUFBRSxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsQ0FBQyxDQUFBO0lBQzdELENBQUM7SUFFRCxNQUFNLEVBQUUsSUFBSSxFQUFFLEdBQUcsTUFBTSxLQUFLLENBQUMsS0FBSyxDQUFDO1FBQ2pDLE1BQU0sRUFBRSxPQUFPO1FBQ2YsTUFBTSxFQUFFLENBQUMsR0FBRyxFQUFFLFlBQVksQ0FBQztRQUMzQixPQUFPLEVBQUUsRUFBRSxFQUFFLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRTtLQUM5QixDQUFDLENBQUE7SUFFRixHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsS0FBSyxFQUFFLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUE7QUFDOUIsQ0FBQyxDQUFBO0FBcENZLFFBQUEsR0FBRyxPQW9DZiJ9