medusa-product-helper 0.0.27 → 0.0.29

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.
@@ -149,7 +149,8 @@ const useMetadataConfig = (entity) => {
149
149
  const useProductMetadataConfig = () => useMetadataConfig("product");
150
150
  const useCategoryMetadataConfig = () => useMetadataConfig("category");
151
151
  const useOrderMetadataConfig = () => useMetadataConfig("order");
152
- const CONFIG_DOCS_URL$2 = "https://docs.medusajs.com/admin/extension-points/widgets#product-category-details";
152
+ const useCollectionMetadataConfig = () => useMetadataConfig("collection");
153
+ const CONFIG_DOCS_URL$3 = "https://docs.medusajs.com/admin/extension-points/widgets#product-category-details";
153
154
  const CategoryMetadataTableWidget = ({ data }) => {
154
155
  const { data: descriptors = [], isPending, isError } = useCategoryMetadataConfig();
155
156
  const categoryId = (data == null ? void 0 : data.id) ?? void 0;
@@ -287,6 +288,390 @@ const CategoryMetadataTableWidget = ({ data }) => {
287
288
  setIsSaving(false);
288
289
  }
289
290
  };
291
+ return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "flex flex-col gap-y-4", children: [
292
+ /* @__PURE__ */ jsxRuntime.jsxs("header", { className: "flex flex-col gap-y-1", children: [
293
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-x-3", children: [
294
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", children: "Metadata" }),
295
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { size: "2xsmall", rounded: "full", children: descriptors.length })
296
+ ] }),
297
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-subtle", children: "Structured metadata mapped to the keys you configured in the plugin options." })
298
+ ] }),
299
+ isPending || !isInitializedRef.current || Object.keys(values).length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: "h-[160px] w-full" }) : isError ? /* @__PURE__ */ jsxRuntime.jsxs(ui.InlineTip, { variant: "error", label: "Configuration unavailable", children: [
300
+ "Unable to load metadata configuration for this plugin. Confirm that the plugin is registered with options in ",
301
+ /* @__PURE__ */ jsxRuntime.jsx("code", { children: "medusa-config.ts" }),
302
+ "."
303
+ ] }) : !descriptors.length ? /* @__PURE__ */ jsxRuntime.jsxs(ui.InlineTip, { variant: "info", label: "No configured metadata keys", children: [
304
+ "Provide a ",
305
+ /* @__PURE__ */ jsxRuntime.jsx("code", { children: "metadataDescriptors" }),
306
+ " array in the plugin options to control which keys show up here.",
307
+ " ",
308
+ /* @__PURE__ */ jsxRuntime.jsx(
309
+ "a",
310
+ {
311
+ className: "text-ui-fg-interactive underline",
312
+ href: CONFIG_DOCS_URL$3,
313
+ target: "_blank",
314
+ rel: "noreferrer",
315
+ children: "Learn how to configure it."
316
+ }
317
+ )
318
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
319
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-hidden rounded-lg border border-ui-border-base", children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "min-w-full divide-y divide-ui-border-base", children: [
320
+ /* @__PURE__ */ jsxRuntime.jsx("thead", { className: "bg-ui-bg-subtle", children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
321
+ /* @__PURE__ */ jsxRuntime.jsx(
322
+ "th",
323
+ {
324
+ scope: "col",
325
+ className: "txt-compact-xsmall-plus text-left uppercase tracking-wide text-ui-fg-muted px-4 py-3",
326
+ children: "Label"
327
+ }
328
+ ),
329
+ /* @__PURE__ */ jsxRuntime.jsx(
330
+ "th",
331
+ {
332
+ scope: "col",
333
+ className: "txt-compact-xsmall-plus text-left uppercase tracking-wide text-ui-fg-muted px-4 py-3",
334
+ children: "Value"
335
+ }
336
+ )
337
+ ] }) }),
338
+ /* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "divide-y divide-ui-border-subtle bg-ui-bg-base", children: descriptors.map((descriptor) => {
339
+ const value = values[descriptor.key];
340
+ const error = errors[descriptor.key];
341
+ return /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
342
+ /* @__PURE__ */ jsxRuntime.jsx(
343
+ "th",
344
+ {
345
+ scope: "row",
346
+ className: "txt-compact-medium text-ui-fg-base align-top px-4 py-4",
347
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-1", children: [
348
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: descriptor.label ?? descriptor.key }),
349
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "txt-compact-xsmall-plus text-ui-fg-muted uppercase tracking-wide", children: descriptor.type })
350
+ ] })
351
+ }
352
+ ),
353
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "align-top px-4 py-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-2", children: [
354
+ /* @__PURE__ */ jsxRuntime.jsx(
355
+ ValueField$3,
356
+ {
357
+ descriptor,
358
+ value,
359
+ onStringChange: handleStringChange,
360
+ onBooleanChange: handleBooleanChange
361
+ }
362
+ ),
363
+ error && /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "txt-compact-small text-ui-fg-error", children: error })
364
+ ] }) })
365
+ ] }, descriptor.key);
366
+ }) })
367
+ ] }) }),
368
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-3 border-t border-ui-border-subtle pt-3 md:flex-row md:items-center md:justify-between", children: [
369
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted", children: "Changes are stored on the category metadata object. Clearing a field removes the corresponding key on save." }),
370
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-x-2", children: [
371
+ /* @__PURE__ */ jsxRuntime.jsx(
372
+ ui.Button,
373
+ {
374
+ variant: "secondary",
375
+ size: "small",
376
+ disabled: !isDirty || isSaving,
377
+ onClick: handleReset,
378
+ children: "Reset"
379
+ }
380
+ ),
381
+ /* @__PURE__ */ jsxRuntime.jsx(
382
+ ui.Button,
383
+ {
384
+ size: "small",
385
+ onClick: handleSubmit,
386
+ disabled: !isDirty || hasErrors || isSaving,
387
+ isLoading: isSaving,
388
+ children: "Save metadata"
389
+ }
390
+ )
391
+ ] })
392
+ ] })
393
+ ] })
394
+ ] });
395
+ };
396
+ const ValueField$3 = ({
397
+ descriptor,
398
+ value,
399
+ onStringChange,
400
+ onBooleanChange
401
+ }) => {
402
+ const fileInputRef = react.useRef(null);
403
+ const [isUploading, setIsUploading] = react.useState(false);
404
+ const handleFileUpload = async (event) => {
405
+ var _a;
406
+ const file = (_a = event.target.files) == null ? void 0 : _a[0];
407
+ if (!file) {
408
+ return;
409
+ }
410
+ setIsUploading(true);
411
+ try {
412
+ const formData = new FormData();
413
+ formData.append("files", file);
414
+ const response = await fetch("/admin/uploads", {
415
+ method: "POST",
416
+ credentials: "include",
417
+ body: formData
418
+ });
419
+ if (!response.ok) {
420
+ const payload = await response.json().catch(() => null);
421
+ throw new Error((payload == null ? void 0 : payload.message) ?? "File upload failed");
422
+ }
423
+ const result = await response.json();
424
+ if (result.files && result.files.length > 0) {
425
+ const uploadedFile = result.files[0];
426
+ const fileUrl = uploadedFile.url || uploadedFile.key;
427
+ if (fileUrl) {
428
+ onStringChange(descriptor.key, fileUrl);
429
+ ui.toast.success("File uploaded successfully");
430
+ } else {
431
+ throw new Error("File upload succeeded but no URL returned");
432
+ }
433
+ } else {
434
+ throw new Error("File upload failed - no files returned");
435
+ }
436
+ } catch (error) {
437
+ ui.toast.error(
438
+ error instanceof Error ? error.message : "Failed to upload file"
439
+ );
440
+ } finally {
441
+ setIsUploading(false);
442
+ if (fileInputRef.current) {
443
+ fileInputRef.current.value = "";
444
+ }
445
+ }
446
+ };
447
+ if (descriptor.type === "bool") {
448
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-x-2", children: [
449
+ /* @__PURE__ */ jsxRuntime.jsx(
450
+ ui.Switch,
451
+ {
452
+ checked: Boolean(value),
453
+ onCheckedChange: (checked) => onBooleanChange(descriptor.key, Boolean(checked)),
454
+ "aria-label": `Toggle ${descriptor.label ?? descriptor.key}`
455
+ }
456
+ ),
457
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "txt-compact-small text-ui-fg-muted", children: Boolean(value) ? "True" : "False" })
458
+ ] });
459
+ }
460
+ if (descriptor.type === "text") {
461
+ return /* @__PURE__ */ jsxRuntime.jsx(
462
+ ui.Textarea,
463
+ {
464
+ value: value ?? "",
465
+ placeholder: "Enter text",
466
+ rows: 3,
467
+ onChange: (event) => onStringChange(descriptor.key, event.target.value)
468
+ }
469
+ );
470
+ }
471
+ if (descriptor.type === "number") {
472
+ return /* @__PURE__ */ jsxRuntime.jsx(
473
+ ui.Input,
474
+ {
475
+ type: "text",
476
+ inputMode: "decimal",
477
+ placeholder: "0.00",
478
+ value: value ?? "",
479
+ onChange: (event) => onStringChange(descriptor.key, event.target.value)
480
+ }
481
+ );
482
+ }
483
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-2", children: [
484
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-x-2", children: [
485
+ /* @__PURE__ */ jsxRuntime.jsx(
486
+ ui.Input,
487
+ {
488
+ type: "url",
489
+ placeholder: "https://example.com/file",
490
+ value: value ?? "",
491
+ onChange: (event) => onStringChange(descriptor.key, event.target.value),
492
+ className: "flex-1"
493
+ }
494
+ ),
495
+ /* @__PURE__ */ jsxRuntime.jsx(
496
+ "input",
497
+ {
498
+ ref: fileInputRef,
499
+ type: "file",
500
+ className: "hidden",
501
+ onChange: handleFileUpload,
502
+ disabled: isUploading,
503
+ "aria-label": `Upload file for ${descriptor.label ?? descriptor.key}`
504
+ }
505
+ ),
506
+ /* @__PURE__ */ jsxRuntime.jsx(
507
+ ui.Button,
508
+ {
509
+ type: "button",
510
+ variant: "secondary",
511
+ size: "small",
512
+ onClick: () => {
513
+ var _a;
514
+ return (_a = fileInputRef.current) == null ? void 0 : _a.click();
515
+ },
516
+ disabled: isUploading,
517
+ isLoading: isUploading,
518
+ children: isUploading ? "Uploading..." : "Upload"
519
+ }
520
+ )
521
+ ] }),
522
+ typeof value === "string" && value && /* @__PURE__ */ jsxRuntime.jsx(
523
+ "a",
524
+ {
525
+ className: "txt-compact-small-plus text-ui-fg-interactive underline",
526
+ href: value,
527
+ target: "_blank",
528
+ rel: "noreferrer",
529
+ children: "View file"
530
+ }
531
+ )
532
+ ] });
533
+ };
534
+ adminSdk.defineWidgetConfig({
535
+ zone: "product_category.details.after"
536
+ });
537
+ const CONFIG_DOCS_URL$2 = "https://docs.medusajs.com/admin/extension-points/widgets#product-collection-details";
538
+ const CollectionMetadataTableWidget = ({ data }) => {
539
+ const { data: descriptors = [], isPending, isError } = useCollectionMetadataConfig();
540
+ const collectionId = (data == null ? void 0 : data.id) ?? void 0;
541
+ const [baselineMetadata, setBaselineMetadata] = react.useState(
542
+ (data == null ? void 0 : data.metadata) ?? {}
543
+ );
544
+ const queryClient = reactQuery.useQueryClient();
545
+ const previousCollectionIdRef = react.useRef(collectionId);
546
+ const isInitializedRef = react.useRef(false);
547
+ const dataRef = react.useRef(data);
548
+ const descriptorsRef = react.useRef(descriptors);
549
+ react.useEffect(() => {
550
+ dataRef.current = data;
551
+ descriptorsRef.current = descriptors;
552
+ }, [data, descriptors]);
553
+ react.useEffect(() => {
554
+ var _a;
555
+ if (previousCollectionIdRef.current === collectionId && isInitializedRef.current) {
556
+ return;
557
+ }
558
+ const collectionIdChanged = previousCollectionIdRef.current !== collectionId;
559
+ if (collectionIdChanged || !isInitializedRef.current) {
560
+ const currentMetadata = (data == null ? void 0 : data.metadata) ?? ((_a = dataRef.current) == null ? void 0 : _a.metadata) ?? {};
561
+ const currentDescriptors = descriptorsRef.current.length > 0 ? descriptorsRef.current : descriptors;
562
+ if (currentDescriptors.length === 0) {
563
+ return;
564
+ }
565
+ previousCollectionIdRef.current = collectionId;
566
+ setBaselineMetadata(currentMetadata);
567
+ const newInitialState = buildInitialFormState(currentDescriptors, currentMetadata);
568
+ setValues(newInitialState);
569
+ isInitializedRef.current = true;
570
+ }
571
+ }, [collectionId]);
572
+ const metadataStringRef = react.useRef("");
573
+ react.useEffect(() => {
574
+ const hasCollectionData = !!data;
575
+ const descriptorsLoaded = descriptors.length > 0;
576
+ const sameCollection = previousCollectionIdRef.current === collectionId;
577
+ const notInitialized = !isInitializedRef.current;
578
+ const currentMetadata = (data == null ? void 0 : data.metadata) ?? {};
579
+ const currentMetadataString = JSON.stringify(currentMetadata);
580
+ const metadataChanged = currentMetadataString !== metadataStringRef.current;
581
+ if (hasCollectionData && descriptorsLoaded && sameCollection && (notInitialized || metadataChanged)) {
582
+ const newInitialState = buildInitialFormState(descriptors, currentMetadata);
583
+ setBaselineMetadata(currentMetadata);
584
+ setValues(newInitialState);
585
+ metadataStringRef.current = currentMetadataString;
586
+ isInitializedRef.current = true;
587
+ }
588
+ }, [data, descriptors.length, collectionId]);
589
+ const initialState = react.useMemo(
590
+ () => buildInitialFormState(descriptors, baselineMetadata),
591
+ [descriptors, baselineMetadata]
592
+ );
593
+ const [values, setValues] = react.useState({});
594
+ const [isSaving, setIsSaving] = react.useState(false);
595
+ const errors = react.useMemo(() => {
596
+ return descriptors.reduce((acc, descriptor) => {
597
+ const error = validateValueForDescriptor(descriptor, values[descriptor.key]);
598
+ if (error) {
599
+ acc[descriptor.key] = error;
600
+ }
601
+ return acc;
602
+ }, {});
603
+ }, [descriptors, values]);
604
+ const hasErrors = Object.keys(errors).length > 0;
605
+ const isDirty = react.useMemo(() => {
606
+ return hasMetadataChanges({
607
+ descriptors,
608
+ values,
609
+ originalMetadata: baselineMetadata
610
+ });
611
+ }, [descriptors, values, baselineMetadata]);
612
+ const handleStringChange = (key, nextValue) => {
613
+ setValues((prev) => ({
614
+ ...prev,
615
+ [key]: nextValue
616
+ }));
617
+ };
618
+ const handleBooleanChange = (key, nextValue) => {
619
+ setValues((prev) => ({
620
+ ...prev,
621
+ [key]: nextValue
622
+ }));
623
+ };
624
+ const handleReset = () => {
625
+ setValues(initialState);
626
+ };
627
+ const handleSubmit = async () => {
628
+ if (!(data == null ? void 0 : data.id) || !descriptors.length) {
629
+ return;
630
+ }
631
+ setIsSaving(true);
632
+ try {
633
+ const metadataPayload = buildMetadataPayload({
634
+ descriptors,
635
+ values,
636
+ originalMetadata: baselineMetadata
637
+ });
638
+ const response = await fetch(`/admin/collections/${data.id}`, {
639
+ method: "POST",
640
+ credentials: "include",
641
+ headers: {
642
+ "Content-Type": "application/json"
643
+ },
644
+ body: JSON.stringify({
645
+ metadata: metadataPayload
646
+ })
647
+ });
648
+ if (!response.ok) {
649
+ const payload = await response.json().catch(() => null);
650
+ throw new Error((payload == null ? void 0 : payload.message) ?? "Unable to save metadata");
651
+ }
652
+ const updated = await response.json();
653
+ const nextMetadata = updated.collection.metadata;
654
+ setBaselineMetadata(nextMetadata);
655
+ setValues(buildInitialFormState(descriptors, nextMetadata));
656
+ ui.toast.success("Metadata saved");
657
+ await queryClient.invalidateQueries({
658
+ queryKey: ["collections"]
659
+ });
660
+ await queryClient.invalidateQueries({
661
+ queryKey: ["collection", data.id]
662
+ });
663
+ if (data.id) {
664
+ queryClient.refetchQueries({
665
+ queryKey: ["collection", data.id]
666
+ }).catch(() => {
667
+ });
668
+ }
669
+ } catch (error) {
670
+ ui.toast.error(error instanceof Error ? error.message : "Save failed");
671
+ } finally {
672
+ setIsSaving(false);
673
+ }
674
+ };
290
675
  return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "flex flex-col gap-y-4", children: [
291
676
  /* @__PURE__ */ jsxRuntime.jsxs("header", { className: "flex flex-col gap-y-1", children: [
292
677
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-x-3", children: [
@@ -365,7 +750,7 @@ const CategoryMetadataTableWidget = ({ data }) => {
365
750
  }) })
366
751
  ] }) }),
367
752
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-3 border-t border-ui-border-subtle pt-3 md:flex-row md:items-center md:justify-between", children: [
368
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted", children: "Changes are stored on the category metadata object. Clearing a field removes the corresponding key on save." }),
753
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-muted", children: "Changes are stored on the collection metadata object. Clearing a field removes the corresponding key on save." }),
369
754
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-x-2", children: [
370
755
  /* @__PURE__ */ jsxRuntime.jsx(
371
756
  ui.Button,
@@ -531,7 +916,7 @@ const ValueField$2 = ({
531
916
  ] });
532
917
  };
533
918
  adminSdk.defineWidgetConfig({
534
- zone: "product_category.details.after"
919
+ zone: "product_collection.details.after"
535
920
  });
536
921
  const HideCategoryDefaultMetadataWidget = () => {
537
922
  react.useEffect(() => {
@@ -590,6 +975,63 @@ const HideCategoryDefaultMetadataWidget = () => {
590
975
  adminSdk.defineWidgetConfig({
591
976
  zone: "product_category.details.side.before"
592
977
  });
978
+ const HideCollectionDefaultMetadataWidget = () => {
979
+ react.useEffect(() => {
980
+ const hideMetadataSection = () => {
981
+ const headings = document.querySelectorAll("h2");
982
+ headings.forEach((heading) => {
983
+ var _a;
984
+ if (((_a = heading.textContent) == null ? void 0 : _a.trim()) === "Metadata") {
985
+ let container = heading.parentElement;
986
+ while (container && container !== document.body) {
987
+ const hasContainerClass = container.classList.toString().includes("Container");
988
+ const isInSidebar = container.closest('[class*="Sidebar"]') || container.closest('[class*="sidebar"]');
989
+ if (hasContainerClass || isInSidebar) {
990
+ const editLink = container.querySelector('a[href*="metadata/edit"]');
991
+ const badge = container.querySelector('div[class*="Badge"]');
992
+ if (editLink && badge) {
993
+ container.style.display = "none";
994
+ container.setAttribute("data-collection-metadata-hidden", "true");
995
+ return;
996
+ }
997
+ }
998
+ container = container.parentElement;
999
+ }
1000
+ }
1001
+ });
1002
+ };
1003
+ const runHide = () => {
1004
+ setTimeout(hideMetadataSection, 100);
1005
+ };
1006
+ runHide();
1007
+ const observer = new MutationObserver(() => {
1008
+ const alreadyHidden = document.querySelector(
1009
+ '[data-collection-metadata-hidden="true"]'
1010
+ );
1011
+ if (!alreadyHidden) {
1012
+ runHide();
1013
+ }
1014
+ });
1015
+ observer.observe(document.body, {
1016
+ childList: true,
1017
+ subtree: true
1018
+ });
1019
+ return () => {
1020
+ observer.disconnect();
1021
+ const hidden = document.querySelector(
1022
+ '[data-collection-metadata-hidden="true"]'
1023
+ );
1024
+ if (hidden) {
1025
+ hidden.style.display = "";
1026
+ hidden.removeAttribute("data-collection-metadata-hidden");
1027
+ }
1028
+ };
1029
+ }, []);
1030
+ return null;
1031
+ };
1032
+ adminSdk.defineWidgetConfig({
1033
+ zone: "product_collection.details.after"
1034
+ });
593
1035
  const HideDefaultMetadataWidget = () => {
594
1036
  react.useEffect(() => {
595
1037
  const hideMetadataSection = () => {
@@ -1540,10 +1982,18 @@ const widgetModule = { widgets: [
1540
1982
  Component: CategoryMetadataTableWidget,
1541
1983
  zone: ["product_category.details.after"]
1542
1984
  },
1985
+ {
1986
+ Component: CollectionMetadataTableWidget,
1987
+ zone: ["product_collection.details.after"]
1988
+ },
1543
1989
  {
1544
1990
  Component: HideCategoryDefaultMetadataWidget,
1545
1991
  zone: ["product_category.details.side.before"]
1546
1992
  },
1993
+ {
1994
+ Component: HideCollectionDefaultMetadataWidget,
1995
+ zone: ["product_collection.details.after"]
1996
+ },
1547
1997
  {
1548
1998
  Component: HideDefaultMetadataWidget,
1549
1999
  zone: ["product.details.side.before"]
@@ -148,7 +148,8 @@ const useMetadataConfig = (entity) => {
148
148
  const useProductMetadataConfig = () => useMetadataConfig("product");
149
149
  const useCategoryMetadataConfig = () => useMetadataConfig("category");
150
150
  const useOrderMetadataConfig = () => useMetadataConfig("order");
151
- const CONFIG_DOCS_URL$2 = "https://docs.medusajs.com/admin/extension-points/widgets#product-category-details";
151
+ const useCollectionMetadataConfig = () => useMetadataConfig("collection");
152
+ const CONFIG_DOCS_URL$3 = "https://docs.medusajs.com/admin/extension-points/widgets#product-category-details";
152
153
  const CategoryMetadataTableWidget = ({ data }) => {
153
154
  const { data: descriptors = [], isPending, isError } = useCategoryMetadataConfig();
154
155
  const categoryId = (data == null ? void 0 : data.id) ?? void 0;
@@ -286,6 +287,390 @@ const CategoryMetadataTableWidget = ({ data }) => {
286
287
  setIsSaving(false);
287
288
  }
288
289
  };
290
+ return /* @__PURE__ */ jsxs(Container, { className: "flex flex-col gap-y-4", children: [
291
+ /* @__PURE__ */ jsxs("header", { className: "flex flex-col gap-y-1", children: [
292
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-3", children: [
293
+ /* @__PURE__ */ jsx(Heading, { level: "h2", children: "Metadata" }),
294
+ /* @__PURE__ */ jsx(Badge, { size: "2xsmall", rounded: "full", children: descriptors.length })
295
+ ] }),
296
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: "Structured metadata mapped to the keys you configured in the plugin options." })
297
+ ] }),
298
+ isPending || !isInitializedRef.current || Object.keys(values).length === 0 ? /* @__PURE__ */ jsx(Skeleton, { className: "h-[160px] w-full" }) : isError ? /* @__PURE__ */ jsxs(InlineTip, { variant: "error", label: "Configuration unavailable", children: [
299
+ "Unable to load metadata configuration for this plugin. Confirm that the plugin is registered with options in ",
300
+ /* @__PURE__ */ jsx("code", { children: "medusa-config.ts" }),
301
+ "."
302
+ ] }) : !descriptors.length ? /* @__PURE__ */ jsxs(InlineTip, { variant: "info", label: "No configured metadata keys", children: [
303
+ "Provide a ",
304
+ /* @__PURE__ */ jsx("code", { children: "metadataDescriptors" }),
305
+ " array in the plugin options to control which keys show up here.",
306
+ " ",
307
+ /* @__PURE__ */ jsx(
308
+ "a",
309
+ {
310
+ className: "text-ui-fg-interactive underline",
311
+ href: CONFIG_DOCS_URL$3,
312
+ target: "_blank",
313
+ rel: "noreferrer",
314
+ children: "Learn how to configure it."
315
+ }
316
+ )
317
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
318
+ /* @__PURE__ */ jsx("div", { className: "overflow-hidden rounded-lg border border-ui-border-base", children: /* @__PURE__ */ jsxs("table", { className: "min-w-full divide-y divide-ui-border-base", children: [
319
+ /* @__PURE__ */ jsx("thead", { className: "bg-ui-bg-subtle", children: /* @__PURE__ */ jsxs("tr", { children: [
320
+ /* @__PURE__ */ jsx(
321
+ "th",
322
+ {
323
+ scope: "col",
324
+ className: "txt-compact-xsmall-plus text-left uppercase tracking-wide text-ui-fg-muted px-4 py-3",
325
+ children: "Label"
326
+ }
327
+ ),
328
+ /* @__PURE__ */ jsx(
329
+ "th",
330
+ {
331
+ scope: "col",
332
+ className: "txt-compact-xsmall-plus text-left uppercase tracking-wide text-ui-fg-muted px-4 py-3",
333
+ children: "Value"
334
+ }
335
+ )
336
+ ] }) }),
337
+ /* @__PURE__ */ jsx("tbody", { className: "divide-y divide-ui-border-subtle bg-ui-bg-base", children: descriptors.map((descriptor) => {
338
+ const value = values[descriptor.key];
339
+ const error = errors[descriptor.key];
340
+ return /* @__PURE__ */ jsxs("tr", { children: [
341
+ /* @__PURE__ */ jsx(
342
+ "th",
343
+ {
344
+ scope: "row",
345
+ className: "txt-compact-medium text-ui-fg-base align-top px-4 py-4",
346
+ children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-y-1", children: [
347
+ /* @__PURE__ */ jsx("span", { children: descriptor.label ?? descriptor.key }),
348
+ /* @__PURE__ */ jsx("span", { className: "txt-compact-xsmall-plus text-ui-fg-muted uppercase tracking-wide", children: descriptor.type })
349
+ ] })
350
+ }
351
+ ),
352
+ /* @__PURE__ */ jsx("td", { className: "align-top px-4 py-4", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-y-2", children: [
353
+ /* @__PURE__ */ jsx(
354
+ ValueField$3,
355
+ {
356
+ descriptor,
357
+ value,
358
+ onStringChange: handleStringChange,
359
+ onBooleanChange: handleBooleanChange
360
+ }
361
+ ),
362
+ error && /* @__PURE__ */ jsx(Text, { className: "txt-compact-small text-ui-fg-error", children: error })
363
+ ] }) })
364
+ ] }, descriptor.key);
365
+ }) })
366
+ ] }) }),
367
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-y-3 border-t border-ui-border-subtle pt-3 md:flex-row md:items-center md:justify-between", children: [
368
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted", children: "Changes are stored on the category metadata object. Clearing a field removes the corresponding key on save." }),
369
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-2", children: [
370
+ /* @__PURE__ */ jsx(
371
+ Button,
372
+ {
373
+ variant: "secondary",
374
+ size: "small",
375
+ disabled: !isDirty || isSaving,
376
+ onClick: handleReset,
377
+ children: "Reset"
378
+ }
379
+ ),
380
+ /* @__PURE__ */ jsx(
381
+ Button,
382
+ {
383
+ size: "small",
384
+ onClick: handleSubmit,
385
+ disabled: !isDirty || hasErrors || isSaving,
386
+ isLoading: isSaving,
387
+ children: "Save metadata"
388
+ }
389
+ )
390
+ ] })
391
+ ] })
392
+ ] })
393
+ ] });
394
+ };
395
+ const ValueField$3 = ({
396
+ descriptor,
397
+ value,
398
+ onStringChange,
399
+ onBooleanChange
400
+ }) => {
401
+ const fileInputRef = useRef(null);
402
+ const [isUploading, setIsUploading] = useState(false);
403
+ const handleFileUpload = async (event) => {
404
+ var _a;
405
+ const file = (_a = event.target.files) == null ? void 0 : _a[0];
406
+ if (!file) {
407
+ return;
408
+ }
409
+ setIsUploading(true);
410
+ try {
411
+ const formData = new FormData();
412
+ formData.append("files", file);
413
+ const response = await fetch("/admin/uploads", {
414
+ method: "POST",
415
+ credentials: "include",
416
+ body: formData
417
+ });
418
+ if (!response.ok) {
419
+ const payload = await response.json().catch(() => null);
420
+ throw new Error((payload == null ? void 0 : payload.message) ?? "File upload failed");
421
+ }
422
+ const result = await response.json();
423
+ if (result.files && result.files.length > 0) {
424
+ const uploadedFile = result.files[0];
425
+ const fileUrl = uploadedFile.url || uploadedFile.key;
426
+ if (fileUrl) {
427
+ onStringChange(descriptor.key, fileUrl);
428
+ toast.success("File uploaded successfully");
429
+ } else {
430
+ throw new Error("File upload succeeded but no URL returned");
431
+ }
432
+ } else {
433
+ throw new Error("File upload failed - no files returned");
434
+ }
435
+ } catch (error) {
436
+ toast.error(
437
+ error instanceof Error ? error.message : "Failed to upload file"
438
+ );
439
+ } finally {
440
+ setIsUploading(false);
441
+ if (fileInputRef.current) {
442
+ fileInputRef.current.value = "";
443
+ }
444
+ }
445
+ };
446
+ if (descriptor.type === "bool") {
447
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-2", children: [
448
+ /* @__PURE__ */ jsx(
449
+ Switch,
450
+ {
451
+ checked: Boolean(value),
452
+ onCheckedChange: (checked) => onBooleanChange(descriptor.key, Boolean(checked)),
453
+ "aria-label": `Toggle ${descriptor.label ?? descriptor.key}`
454
+ }
455
+ ),
456
+ /* @__PURE__ */ jsx(Text, { className: "txt-compact-small text-ui-fg-muted", children: Boolean(value) ? "True" : "False" })
457
+ ] });
458
+ }
459
+ if (descriptor.type === "text") {
460
+ return /* @__PURE__ */ jsx(
461
+ Textarea,
462
+ {
463
+ value: value ?? "",
464
+ placeholder: "Enter text",
465
+ rows: 3,
466
+ onChange: (event) => onStringChange(descriptor.key, event.target.value)
467
+ }
468
+ );
469
+ }
470
+ if (descriptor.type === "number") {
471
+ return /* @__PURE__ */ jsx(
472
+ Input,
473
+ {
474
+ type: "text",
475
+ inputMode: "decimal",
476
+ placeholder: "0.00",
477
+ value: value ?? "",
478
+ onChange: (event) => onStringChange(descriptor.key, event.target.value)
479
+ }
480
+ );
481
+ }
482
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-y-2", children: [
483
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-2", children: [
484
+ /* @__PURE__ */ jsx(
485
+ Input,
486
+ {
487
+ type: "url",
488
+ placeholder: "https://example.com/file",
489
+ value: value ?? "",
490
+ onChange: (event) => onStringChange(descriptor.key, event.target.value),
491
+ className: "flex-1"
492
+ }
493
+ ),
494
+ /* @__PURE__ */ jsx(
495
+ "input",
496
+ {
497
+ ref: fileInputRef,
498
+ type: "file",
499
+ className: "hidden",
500
+ onChange: handleFileUpload,
501
+ disabled: isUploading,
502
+ "aria-label": `Upload file for ${descriptor.label ?? descriptor.key}`
503
+ }
504
+ ),
505
+ /* @__PURE__ */ jsx(
506
+ Button,
507
+ {
508
+ type: "button",
509
+ variant: "secondary",
510
+ size: "small",
511
+ onClick: () => {
512
+ var _a;
513
+ return (_a = fileInputRef.current) == null ? void 0 : _a.click();
514
+ },
515
+ disabled: isUploading,
516
+ isLoading: isUploading,
517
+ children: isUploading ? "Uploading..." : "Upload"
518
+ }
519
+ )
520
+ ] }),
521
+ typeof value === "string" && value && /* @__PURE__ */ jsx(
522
+ "a",
523
+ {
524
+ className: "txt-compact-small-plus text-ui-fg-interactive underline",
525
+ href: value,
526
+ target: "_blank",
527
+ rel: "noreferrer",
528
+ children: "View file"
529
+ }
530
+ )
531
+ ] });
532
+ };
533
+ defineWidgetConfig({
534
+ zone: "product_category.details.after"
535
+ });
536
+ const CONFIG_DOCS_URL$2 = "https://docs.medusajs.com/admin/extension-points/widgets#product-collection-details";
537
+ const CollectionMetadataTableWidget = ({ data }) => {
538
+ const { data: descriptors = [], isPending, isError } = useCollectionMetadataConfig();
539
+ const collectionId = (data == null ? void 0 : data.id) ?? void 0;
540
+ const [baselineMetadata, setBaselineMetadata] = useState(
541
+ (data == null ? void 0 : data.metadata) ?? {}
542
+ );
543
+ const queryClient = useQueryClient();
544
+ const previousCollectionIdRef = useRef(collectionId);
545
+ const isInitializedRef = useRef(false);
546
+ const dataRef = useRef(data);
547
+ const descriptorsRef = useRef(descriptors);
548
+ useEffect(() => {
549
+ dataRef.current = data;
550
+ descriptorsRef.current = descriptors;
551
+ }, [data, descriptors]);
552
+ useEffect(() => {
553
+ var _a;
554
+ if (previousCollectionIdRef.current === collectionId && isInitializedRef.current) {
555
+ return;
556
+ }
557
+ const collectionIdChanged = previousCollectionIdRef.current !== collectionId;
558
+ if (collectionIdChanged || !isInitializedRef.current) {
559
+ const currentMetadata = (data == null ? void 0 : data.metadata) ?? ((_a = dataRef.current) == null ? void 0 : _a.metadata) ?? {};
560
+ const currentDescriptors = descriptorsRef.current.length > 0 ? descriptorsRef.current : descriptors;
561
+ if (currentDescriptors.length === 0) {
562
+ return;
563
+ }
564
+ previousCollectionIdRef.current = collectionId;
565
+ setBaselineMetadata(currentMetadata);
566
+ const newInitialState = buildInitialFormState(currentDescriptors, currentMetadata);
567
+ setValues(newInitialState);
568
+ isInitializedRef.current = true;
569
+ }
570
+ }, [collectionId]);
571
+ const metadataStringRef = useRef("");
572
+ useEffect(() => {
573
+ const hasCollectionData = !!data;
574
+ const descriptorsLoaded = descriptors.length > 0;
575
+ const sameCollection = previousCollectionIdRef.current === collectionId;
576
+ const notInitialized = !isInitializedRef.current;
577
+ const currentMetadata = (data == null ? void 0 : data.metadata) ?? {};
578
+ const currentMetadataString = JSON.stringify(currentMetadata);
579
+ const metadataChanged = currentMetadataString !== metadataStringRef.current;
580
+ if (hasCollectionData && descriptorsLoaded && sameCollection && (notInitialized || metadataChanged)) {
581
+ const newInitialState = buildInitialFormState(descriptors, currentMetadata);
582
+ setBaselineMetadata(currentMetadata);
583
+ setValues(newInitialState);
584
+ metadataStringRef.current = currentMetadataString;
585
+ isInitializedRef.current = true;
586
+ }
587
+ }, [data, descriptors.length, collectionId]);
588
+ const initialState = useMemo(
589
+ () => buildInitialFormState(descriptors, baselineMetadata),
590
+ [descriptors, baselineMetadata]
591
+ );
592
+ const [values, setValues] = useState({});
593
+ const [isSaving, setIsSaving] = useState(false);
594
+ const errors = useMemo(() => {
595
+ return descriptors.reduce((acc, descriptor) => {
596
+ const error = validateValueForDescriptor(descriptor, values[descriptor.key]);
597
+ if (error) {
598
+ acc[descriptor.key] = error;
599
+ }
600
+ return acc;
601
+ }, {});
602
+ }, [descriptors, values]);
603
+ const hasErrors = Object.keys(errors).length > 0;
604
+ const isDirty = useMemo(() => {
605
+ return hasMetadataChanges({
606
+ descriptors,
607
+ values,
608
+ originalMetadata: baselineMetadata
609
+ });
610
+ }, [descriptors, values, baselineMetadata]);
611
+ const handleStringChange = (key, nextValue) => {
612
+ setValues((prev) => ({
613
+ ...prev,
614
+ [key]: nextValue
615
+ }));
616
+ };
617
+ const handleBooleanChange = (key, nextValue) => {
618
+ setValues((prev) => ({
619
+ ...prev,
620
+ [key]: nextValue
621
+ }));
622
+ };
623
+ const handleReset = () => {
624
+ setValues(initialState);
625
+ };
626
+ const handleSubmit = async () => {
627
+ if (!(data == null ? void 0 : data.id) || !descriptors.length) {
628
+ return;
629
+ }
630
+ setIsSaving(true);
631
+ try {
632
+ const metadataPayload = buildMetadataPayload({
633
+ descriptors,
634
+ values,
635
+ originalMetadata: baselineMetadata
636
+ });
637
+ const response = await fetch(`/admin/collections/${data.id}`, {
638
+ method: "POST",
639
+ credentials: "include",
640
+ headers: {
641
+ "Content-Type": "application/json"
642
+ },
643
+ body: JSON.stringify({
644
+ metadata: metadataPayload
645
+ })
646
+ });
647
+ if (!response.ok) {
648
+ const payload = await response.json().catch(() => null);
649
+ throw new Error((payload == null ? void 0 : payload.message) ?? "Unable to save metadata");
650
+ }
651
+ const updated = await response.json();
652
+ const nextMetadata = updated.collection.metadata;
653
+ setBaselineMetadata(nextMetadata);
654
+ setValues(buildInitialFormState(descriptors, nextMetadata));
655
+ toast.success("Metadata saved");
656
+ await queryClient.invalidateQueries({
657
+ queryKey: ["collections"]
658
+ });
659
+ await queryClient.invalidateQueries({
660
+ queryKey: ["collection", data.id]
661
+ });
662
+ if (data.id) {
663
+ queryClient.refetchQueries({
664
+ queryKey: ["collection", data.id]
665
+ }).catch(() => {
666
+ });
667
+ }
668
+ } catch (error) {
669
+ toast.error(error instanceof Error ? error.message : "Save failed");
670
+ } finally {
671
+ setIsSaving(false);
672
+ }
673
+ };
289
674
  return /* @__PURE__ */ jsxs(Container, { className: "flex flex-col gap-y-4", children: [
290
675
  /* @__PURE__ */ jsxs("header", { className: "flex flex-col gap-y-1", children: [
291
676
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-3", children: [
@@ -364,7 +749,7 @@ const CategoryMetadataTableWidget = ({ data }) => {
364
749
  }) })
365
750
  ] }) }),
366
751
  /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-y-3 border-t border-ui-border-subtle pt-3 md:flex-row md:items-center md:justify-between", children: [
367
- /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted", children: "Changes are stored on the category metadata object. Clearing a field removes the corresponding key on save." }),
752
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted", children: "Changes are stored on the collection metadata object. Clearing a field removes the corresponding key on save." }),
368
753
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-2", children: [
369
754
  /* @__PURE__ */ jsx(
370
755
  Button,
@@ -530,7 +915,7 @@ const ValueField$2 = ({
530
915
  ] });
531
916
  };
532
917
  defineWidgetConfig({
533
- zone: "product_category.details.after"
918
+ zone: "product_collection.details.after"
534
919
  });
535
920
  const HideCategoryDefaultMetadataWidget = () => {
536
921
  useEffect(() => {
@@ -589,6 +974,63 @@ const HideCategoryDefaultMetadataWidget = () => {
589
974
  defineWidgetConfig({
590
975
  zone: "product_category.details.side.before"
591
976
  });
977
+ const HideCollectionDefaultMetadataWidget = () => {
978
+ useEffect(() => {
979
+ const hideMetadataSection = () => {
980
+ const headings = document.querySelectorAll("h2");
981
+ headings.forEach((heading) => {
982
+ var _a;
983
+ if (((_a = heading.textContent) == null ? void 0 : _a.trim()) === "Metadata") {
984
+ let container = heading.parentElement;
985
+ while (container && container !== document.body) {
986
+ const hasContainerClass = container.classList.toString().includes("Container");
987
+ const isInSidebar = container.closest('[class*="Sidebar"]') || container.closest('[class*="sidebar"]');
988
+ if (hasContainerClass || isInSidebar) {
989
+ const editLink = container.querySelector('a[href*="metadata/edit"]');
990
+ const badge = container.querySelector('div[class*="Badge"]');
991
+ if (editLink && badge) {
992
+ container.style.display = "none";
993
+ container.setAttribute("data-collection-metadata-hidden", "true");
994
+ return;
995
+ }
996
+ }
997
+ container = container.parentElement;
998
+ }
999
+ }
1000
+ });
1001
+ };
1002
+ const runHide = () => {
1003
+ setTimeout(hideMetadataSection, 100);
1004
+ };
1005
+ runHide();
1006
+ const observer = new MutationObserver(() => {
1007
+ const alreadyHidden = document.querySelector(
1008
+ '[data-collection-metadata-hidden="true"]'
1009
+ );
1010
+ if (!alreadyHidden) {
1011
+ runHide();
1012
+ }
1013
+ });
1014
+ observer.observe(document.body, {
1015
+ childList: true,
1016
+ subtree: true
1017
+ });
1018
+ return () => {
1019
+ observer.disconnect();
1020
+ const hidden = document.querySelector(
1021
+ '[data-collection-metadata-hidden="true"]'
1022
+ );
1023
+ if (hidden) {
1024
+ hidden.style.display = "";
1025
+ hidden.removeAttribute("data-collection-metadata-hidden");
1026
+ }
1027
+ };
1028
+ }, []);
1029
+ return null;
1030
+ };
1031
+ defineWidgetConfig({
1032
+ zone: "product_collection.details.after"
1033
+ });
592
1034
  const HideDefaultMetadataWidget = () => {
593
1035
  useEffect(() => {
594
1036
  const hideMetadataSection = () => {
@@ -1539,10 +1981,18 @@ const widgetModule = { widgets: [
1539
1981
  Component: CategoryMetadataTableWidget,
1540
1982
  zone: ["product_category.details.after"]
1541
1983
  },
1984
+ {
1985
+ Component: CollectionMetadataTableWidget,
1986
+ zone: ["product_collection.details.after"]
1987
+ },
1542
1988
  {
1543
1989
  Component: HideCategoryDefaultMetadataWidget,
1544
1990
  zone: ["product_category.details.side.before"]
1545
1991
  },
1992
+ {
1993
+ Component: HideCollectionDefaultMetadataWidget,
1994
+ zone: ["product_collection.details.after"]
1995
+ },
1546
1996
  {
1547
1997
  Component: HideDefaultMetadataWidget,
1548
1998
  zone: ["product.details.side.before"]
@@ -7,6 +7,7 @@ const ENTITY_PARAM = {
7
7
  PRODUCT: "product",
8
8
  CATEGORY: "category",
9
9
  ORDER: "order",
10
+ COLLECTION: "collection",
10
11
  };
11
12
  async function GET(req, res) {
12
13
  const configModule = req.scope.resolve(utils_1.ContainerRegistrationKeys.CONFIG_MODULE);
@@ -16,9 +17,11 @@ async function GET(req, res) {
16
17
  ? options.metadata.categories.descriptors
17
18
  : entity === ENTITY_PARAM.ORDER
18
19
  ? options.metadata.orders.descriptors
19
- : options.metadata.products.descriptors;
20
+ : entity === ENTITY_PARAM.COLLECTION
21
+ ? options.metadata.collections.descriptors
22
+ : options.metadata.products.descriptors;
20
23
  res.json({
21
24
  metadataDescriptors,
22
25
  });
23
26
  }
24
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2FkbWluL3Byb2R1Y3QtbWV0YWRhdGEtY29uZmlnL3JvdXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBYUEsa0JBa0JDO0FBOUJELHFEQUFxRTtBQUVyRSxtRkFBb0Y7QUFFcEYsTUFBTSxZQUFZLEdBQUc7SUFDbkIsT0FBTyxFQUFFLFNBQVM7SUFDbEIsUUFBUSxFQUFFLFVBQVU7SUFDcEIsS0FBSyxFQUFFLE9BQU87Q0FDTixDQUFBO0FBSUgsS0FBSyxVQUFVLEdBQUcsQ0FBQyxHQUFrQixFQUFFLEdBQW1CO0lBQy9ELE1BQU0sWUFBWSxHQUFHLEdBQUcsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUNwQyxpQ0FBeUIsQ0FBQyxhQUFhLENBQ3hDLENBQUE7SUFFRCxNQUFNLE9BQU8sR0FBRyxJQUFBLG9EQUEyQixFQUFDLFlBQVksQ0FBQyxDQUFBO0lBQ3pELE1BQU0sTUFBTSxHQUFJLEdBQUcsQ0FBQyxLQUFLLEVBQUUsTUFBeUIsSUFBSSxZQUFZLENBQUMsT0FBTyxDQUFBO0lBRTVFLE1BQU0sbUJBQW1CLEdBQ3ZCLE1BQU0sS0FBSyxZQUFZLENBQUMsUUFBUTtRQUM5QixDQUFDLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsV0FBVztRQUN6QyxDQUFDLENBQUMsTUFBTSxLQUFLLFlBQVksQ0FBQyxLQUFLO1lBQy9CLENBQUMsQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxXQUFXO1lBQ3JDLENBQUMsQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxXQUFXLENBQUE7SUFFM0MsR0FBRyxDQUFDLElBQUksQ0FBQztRQUNQLG1CQUFtQjtLQUNwQixDQUFDLENBQUE7QUFDSixDQUFDIn0=
27
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2FkbWluL3Byb2R1Y3QtbWV0YWRhdGEtY29uZmlnL3JvdXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBY0Esa0JBb0JDO0FBakNELHFEQUFxRTtBQUVyRSxtRkFBb0Y7QUFFcEYsTUFBTSxZQUFZLEdBQUc7SUFDbkIsT0FBTyxFQUFFLFNBQVM7SUFDbEIsUUFBUSxFQUFFLFVBQVU7SUFDcEIsS0FBSyxFQUFFLE9BQU87SUFDZCxVQUFVLEVBQUUsWUFBWTtDQUNoQixDQUFBO0FBSUgsS0FBSyxVQUFVLEdBQUcsQ0FBQyxHQUFrQixFQUFFLEdBQW1CO0lBQy9ELE1BQU0sWUFBWSxHQUFHLEdBQUcsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUNwQyxpQ0FBeUIsQ0FBQyxhQUFhLENBQ3hDLENBQUE7SUFFRCxNQUFNLE9BQU8sR0FBRyxJQUFBLG9EQUEyQixFQUFDLFlBQVksQ0FBQyxDQUFBO0lBQ3pELE1BQU0sTUFBTSxHQUFJLEdBQUcsQ0FBQyxLQUFLLEVBQUUsTUFBeUIsSUFBSSxZQUFZLENBQUMsT0FBTyxDQUFBO0lBRTVFLE1BQU0sbUJBQW1CLEdBQ3ZCLE1BQU0sS0FBSyxZQUFZLENBQUMsUUFBUTtRQUM5QixDQUFDLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsV0FBVztRQUN6QyxDQUFDLENBQUMsTUFBTSxLQUFLLFlBQVksQ0FBQyxLQUFLO1lBQy9CLENBQUMsQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxXQUFXO1lBQ3JDLENBQUMsQ0FBQyxNQUFNLEtBQUssWUFBWSxDQUFDLFVBQVU7Z0JBQ3BDLENBQUMsQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLFdBQVcsQ0FBQyxXQUFXO2dCQUMxQyxDQUFDLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsV0FBVyxDQUFBO0lBRTNDLEdBQUcsQ0FBQyxJQUFJLENBQUM7UUFDUCxtQkFBbUI7S0FDcEIsQ0FBQyxDQUFBO0FBQ0osQ0FBQyJ9
@@ -66,6 +66,9 @@ const MetadataSchema = zod_1.z.object({
66
66
  orders: MetadataCollectionSchema.default({
67
67
  descriptors: [],
68
68
  }),
69
+ collections: MetadataCollectionSchema.default({
70
+ descriptors: [],
71
+ }),
69
72
  });
70
73
  const PromotionWindowSchema = zod_1.z.object({
71
74
  start_metadata_key: zod_1.z.string().min(1).default("promotion_start"),
@@ -109,6 +112,9 @@ const ProductHelperOptionsSchema = zod_1.z.object({
109
112
  orders: {
110
113
  descriptors: [],
111
114
  },
115
+ collections: {
116
+ descriptors: [],
117
+ },
112
118
  }),
113
119
  default_price_range: PriceRangeSchema.default({
114
120
  label: "custom",
@@ -162,6 +168,10 @@ function normalizeProductHelperOptions(input) {
162
168
  ...parsed.metadata.orders,
163
169
  descriptors: (0, utils_2.normalizeMetadataDescriptors)(parsed.metadata.orders.descriptors),
164
170
  },
171
+ collections: {
172
+ ...parsed.metadata.collections,
173
+ descriptors: (0, utils_2.normalizeMetadataDescriptors)(parsed.metadata.collections.descriptors),
174
+ },
165
175
  },
166
176
  filterProviders: parsed.filterProviders ?? [],
167
177
  disableBuiltInProviders: parsed.disableBuiltInProviders ?? [],
@@ -182,4 +192,4 @@ function resolveProductHelperOptions(configModule) {
182
192
  }
183
193
  return exports.DEFAULT_PRODUCT_HELPER_OPTIONS;
184
194
  }
185
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvZHVjdC1oZWxwZXItb3B0aW9ucy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9jb25maWcvcHJvZHVjdC1oZWxwZXItb3B0aW9ucy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUEwTUEsc0VBOEJDO0FBRUQsa0VBbUJDO0FBN1BELHFEQUFvRDtBQUNwRCw2QkFBdUI7QUFFdkIsNERBR3lDO0FBQ3pDLDREQUErRTtBQUUvRSxNQUFNLGdCQUFnQixHQUFHLE9BQUM7S0FDdkIsTUFBTSxDQUFDO0lBQ04sS0FBSyxFQUFFLE9BQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUM7SUFDbEQsYUFBYSxFQUFFLE9BQUM7U0FDYixNQUFNLEVBQUU7U0FDUixJQUFJLEVBQUU7U0FDTixNQUFNLENBQUMsQ0FBQyxFQUFFLG1DQUFtQyxDQUFDO1NBQzlDLFNBQVMsQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLFdBQVcsRUFBRSxDQUFDO1NBQ3pDLFFBQVEsRUFBRTtJQUNiLEdBQUcsRUFBRSxPQUFDO1NBQ0gsTUFBTSxDQUFDO1FBQ04sTUFBTSxFQUFFLElBQUk7UUFDWixrQkFBa0IsRUFBRSw0QkFBNEI7S0FDakQsQ0FBQztTQUNELFdBQVcsRUFBRTtTQUNiLFFBQVEsRUFBRTtTQUNWLE9BQU8sQ0FBQyxJQUFJLENBQUM7SUFDaEIsR0FBRyxFQUFFLE9BQUM7U0FDSCxNQUFNLENBQUM7UUFDTixNQUFNLEVBQUUsSUFBSTtRQUNaLGtCQUFrQixFQUFFLDRCQUE0QjtLQUNqRCxDQUFDO1NBQ0QsV0FBVyxFQUFFO1NBQ2IsUUFBUSxFQUFFO1NBQ1YsT0FBTyxDQUFDLElBQUksQ0FBQztDQUNqQixDQUFDO0tBQ0QsTUFBTSxDQUNMLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FDUixLQUFL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
195
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvZHVjdC1oZWxwZXItb3B0aW9ucy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9jb25maWcvcHJvZHVjdC1oZWxwZXItb3B0aW9ucy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFtTkEsc0VBb0NDO0FBRUQsa0VBbUJDO0FBNVFELHFEQUFvRDtBQUNwRCw2QkFBdUI7QUFFdkIsNERBR3lDO0FBQ3pDLDREQUErRTtBQUUvRSxNQUFNLGdCQUFnQixHQUFHLE9BQUM7S0FDdkIsTUFBTSxDQUFDO0lBQ04sS0FBSyxFQUFFLE9BQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUM7SUFDbEQsYUFBYSxFQUFFLE9BQUM7U0FDYixNQUFNLEVBQUU7U0FDUixJQUFJLEVBQUU7U0FDTixNQUFNLENBQUMsQ0FBQyxFQUFFLG1DQUFtQyxDQUFDO1NBQzlDLFNBQVMsQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLFdBQVcsRUFBRSxDQUFDO1NBQ3pDLFFBQVEsRUFBRTtJQUNiLEdBQUcsRUFBRSxPQUFDO1NBQ0gsTUFBTSxDQUFDO1FBQ04sTUFBTSxFQUFFLElBQUk7UUFDWixrQkFBa0IsRUFBRSw0QkFBNEI7S0FDakQsQ0FBQztTQUNELFdBQVcsRUFBRTtTQUNiLFFBQVEsRUFBRTtTQUNWLE9BQU8sQ0FBQyxJQUFJLENBQUM7SUFDaEIsR0FBRyxFQUFFLE9BQUM7U0FDSCxNQUFNLENBQUM7UUFDTixNQUFNLEVBQUUsSUFBSTtRQUNaLGtCQUFrQixFQUFFLDRCQUE0QjtLQUNqRCxDQUFDO1NBQ0QsV0FBVyxFQUFFO1NBQ2IsUUFBUSxFQUFFO1NBQ1YsT0FBTyxDQUFDLElBQUksQ0FBQztDQUNqQixDQUFDO0tBQ0QsTUFBTSxDQUNMLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FDUixLQUFL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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "medusa-product-helper",
3
- "version": "0.0.27",
3
+ "version": "0.0.29",
4
4
  "description": "A starter for Medusa plugins.",
5
5
  "author": "Medusa (https://medusajs.com)",
6
6
  "license": "MIT",