@medusajs/draft-order 2.10.4-preview-20250922000330 → 2.10.4-preview-20250922031739

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.
@@ -9825,6 +9825,27 @@ const EmailForm = ({ order }) => {
9825
9825
  const schema$4 = objectType({
9826
9826
  email: stringType().email()
9827
9827
  });
9828
+ const CustomItems = () => {
9829
+ return /* @__PURE__ */ jsxs(RouteDrawer, { children: [
9830
+ /* @__PURE__ */ jsx(RouteDrawer.Header, { children: /* @__PURE__ */ jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Edit Custom Items" }) }) }),
9831
+ /* @__PURE__ */ jsx(CustomItemsForm, {})
9832
+ ] });
9833
+ };
9834
+ const CustomItemsForm = () => {
9835
+ const form = useForm({
9836
+ resolver: zodResolver(schema$3)
9837
+ });
9838
+ return /* @__PURE__ */ jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxs(KeyboundForm, { className: "flex flex-1 flex-col", children: [
9839
+ /* @__PURE__ */ jsx(RouteDrawer.Body, {}),
9840
+ /* @__PURE__ */ jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
9841
+ /* @__PURE__ */ jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
9842
+ /* @__PURE__ */ jsx(Button, { size: "small", type: "submit", children: "Save" })
9843
+ ] }) })
9844
+ ] }) });
9845
+ };
9846
+ const schema$3 = objectType({
9847
+ email: stringType().email()
9848
+ });
9828
9849
  const NumberInput = forwardRef(
9829
9850
  ({
9830
9851
  value,
@@ -10799,632 +10820,632 @@ const customItemSchema = objectType({
10799
10820
  quantity: numberType(),
10800
10821
  unit_price: unionType([numberType(), stringType()])
10801
10822
  });
10802
- const InlineTip = forwardRef(
10803
- ({ variant = "tip", label, className, children, ...props }, ref) => {
10804
- const labelValue = label || (variant === "warning" ? "Warning" : "Tip");
10805
- return /* @__PURE__ */ jsxs(
10806
- "div",
10807
- {
10808
- ref,
10809
- className: clx(
10810
- "bg-ui-bg-component txt-small text-ui-fg-subtle grid grid-cols-[4px_1fr] items-start gap-3 rounded-lg border p-3",
10811
- className
10812
- ),
10813
- ...props,
10814
- children: [
10815
- /* @__PURE__ */ jsx(
10816
- "div",
10817
- {
10818
- role: "presentation",
10819
- className: clx("w-4px bg-ui-tag-neutral-icon h-full rounded-full", {
10820
- "bg-ui-tag-orange-icon": variant === "warning"
10821
- })
10822
- }
10823
- ),
10824
- /* @__PURE__ */ jsxs("div", { className: "text-pretty", children: [
10825
- /* @__PURE__ */ jsxs("strong", { className: "txt-small-plus text-ui-fg-base", children: [
10826
- labelValue,
10827
- ":"
10828
- ] }),
10829
- " ",
10830
- children
10831
- ] })
10832
- ]
10833
- }
10834
- );
10835
- }
10836
- );
10837
- InlineTip.displayName = "InlineTip";
10838
- const MetadataFieldSchema = objectType({
10839
- key: stringType(),
10840
- disabled: booleanType().optional(),
10841
- value: anyType()
10842
- });
10843
- const MetadataSchema = objectType({
10844
- metadata: arrayType(MetadataFieldSchema)
10845
- });
10846
- const Metadata = () => {
10847
- const { id } = useParams();
10848
- const { order, isPending, isError, error } = useOrder(id, {
10849
- fields: "metadata"
10823
+ const PROMOTION_QUERY_KEY = "promotions";
10824
+ const promotionsQueryKeys = {
10825
+ list: (query2) => [
10826
+ PROMOTION_QUERY_KEY,
10827
+ query2 ? query2 : void 0
10828
+ ],
10829
+ detail: (id, query2) => [
10830
+ PROMOTION_QUERY_KEY,
10831
+ id,
10832
+ query2 ? query2 : void 0
10833
+ ]
10834
+ };
10835
+ const usePromotions = (query2, options) => {
10836
+ const { data, ...rest } = useQuery({
10837
+ queryKey: promotionsQueryKeys.list(query2),
10838
+ queryFn: async () => sdk.admin.promotion.list(query2),
10839
+ ...options
10850
10840
  });
10851
- if (isError) {
10852
- throw error;
10841
+ return { ...data, ...rest };
10842
+ };
10843
+ const Promotions = () => {
10844
+ const { id } = useParams();
10845
+ const {
10846
+ order: preview,
10847
+ isError: isPreviewError,
10848
+ error: previewError
10849
+ } = useOrderPreview(id, void 0);
10850
+ useInitiateOrderEdit({ preview });
10851
+ const { onCancel } = useCancelOrderEdit({ preview });
10852
+ if (isPreviewError) {
10853
+ throw previewError;
10853
10854
  }
10854
- const isReady = !isPending && !!order;
10855
- return /* @__PURE__ */ jsxs(RouteDrawer, { children: [
10856
- /* @__PURE__ */ jsxs(RouteDrawer.Header, { children: [
10857
- /* @__PURE__ */ jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Metadata" }) }),
10858
- /* @__PURE__ */ jsx(RouteDrawer.Description, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Add metadata to the draft order." }) })
10859
- ] }),
10860
- !isReady ? /* @__PURE__ */ jsx(PlaceholderInner, {}) : /* @__PURE__ */ jsx(MetadataForm, { orderId: id, metadata: order == null ? void 0 : order.metadata })
10855
+ const isReady = !!preview;
10856
+ return /* @__PURE__ */ jsxs(RouteDrawer, { onClose: onCancel, children: [
10857
+ /* @__PURE__ */ jsx(RouteDrawer.Header, { children: /* @__PURE__ */ jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Edit Promotions" }) }) }),
10858
+ isReady && /* @__PURE__ */ jsx(PromotionForm, { preview })
10861
10859
  ] });
10862
10860
  };
10863
- const METADATA_KEY_LABEL_ID = "metadata-form-key-label";
10864
- const METADATA_VALUE_LABEL_ID = "metadata-form-value-label";
10865
- const MetadataForm = ({ orderId, metadata }) => {
10861
+ const PromotionForm = ({ preview }) => {
10862
+ const { items, shipping_methods } = preview;
10863
+ const [isSubmitting, setIsSubmitting] = useState(false);
10864
+ const [comboboxValue, setComboboxValue] = useState("");
10866
10865
  const { handleSuccess } = useRouteModal();
10867
- const hasUneditableRows = getHasUneditableRows(metadata);
10868
- const { mutateAsync, isPending } = useUpdateDraftOrder(orderId);
10869
- const form = useForm({
10870
- defaultValues: {
10871
- metadata: getDefaultValues(metadata)
10866
+ const { mutateAsync: addPromotions, isPending: isAddingPromotions } = useDraftOrderAddPromotions(preview.id);
10867
+ const promoIds = getPromotionIds(items, shipping_methods);
10868
+ const { promotions, isPending, isError, error } = usePromotions(
10869
+ {
10870
+ id: promoIds
10872
10871
  },
10873
- resolver: zodResolver(MetadataSchema)
10872
+ {
10873
+ enabled: !!promoIds.length
10874
+ }
10875
+ );
10876
+ const comboboxData = useComboboxData({
10877
+ queryKey: ["promotions", "combobox", promoIds],
10878
+ queryFn: async (params) => {
10879
+ return await sdk.admin.promotion.list({
10880
+ ...params,
10881
+ id: {
10882
+ $nin: promoIds
10883
+ }
10884
+ });
10885
+ },
10886
+ getOptions: (data) => {
10887
+ return data.promotions.map((promotion) => ({
10888
+ label: promotion.code,
10889
+ value: promotion.code
10890
+ }));
10891
+ }
10874
10892
  });
10875
- const handleSubmit = form.handleSubmit(async (data) => {
10876
- const parsedData = parseValues(data);
10877
- await mutateAsync(
10893
+ const add = async (value) => {
10894
+ if (!value) {
10895
+ return;
10896
+ }
10897
+ addPromotions(
10878
10898
  {
10879
- metadata: parsedData
10899
+ promo_codes: [value]
10880
10900
  },
10881
10901
  {
10882
- onSuccess: () => {
10883
- toast.success("Metadata updated");
10884
- handleSuccess();
10902
+ onError: (e) => {
10903
+ toast.error(e.message);
10904
+ comboboxData.onSearchValueChange("");
10905
+ setComboboxValue("");
10885
10906
  },
10886
- onError: (error) => {
10887
- toast.error(error.message);
10907
+ onSuccess: () => {
10908
+ comboboxData.onSearchValueChange("");
10909
+ setComboboxValue("");
10888
10910
  }
10889
10911
  }
10890
10912
  );
10891
- });
10892
- const { fields, insert, remove } = useFieldArray({
10893
- control: form.control,
10894
- name: "metadata"
10895
- });
10896
- function deleteRow(index) {
10897
- remove(index);
10898
- if (fields.length === 1) {
10899
- insert(0, {
10900
- key: "",
10901
- value: "",
10902
- disabled: false
10903
- });
10913
+ };
10914
+ const { mutateAsync: confirmOrderEdit } = useDraftOrderConfirmEdit(preview.id);
10915
+ const { mutateAsync: requestOrderEdit } = useOrderEditRequest(preview.id);
10916
+ const onSubmit = async () => {
10917
+ setIsSubmitting(true);
10918
+ let requestSucceeded = false;
10919
+ await requestOrderEdit(void 0, {
10920
+ onError: (e) => {
10921
+ toast.error(e.message);
10922
+ },
10923
+ onSuccess: () => {
10924
+ requestSucceeded = true;
10925
+ }
10926
+ });
10927
+ if (!requestSucceeded) {
10928
+ setIsSubmitting(false);
10929
+ return;
10904
10930
  }
10905
- }
10906
- function insertRow(index, position) {
10907
- insert(index + (position === "above" ? 0 : 1), {
10908
- key: "",
10909
- value: "",
10910
- disabled: false
10931
+ await confirmOrderEdit(void 0, {
10932
+ onError: (e) => {
10933
+ toast.error(e.message);
10934
+ },
10935
+ onSuccess: () => {
10936
+ handleSuccess();
10937
+ },
10938
+ onSettled: () => {
10939
+ setIsSubmitting(false);
10940
+ }
10911
10941
  });
10942
+ };
10943
+ if (isError) {
10944
+ throw error;
10912
10945
  }
10913
- return /* @__PURE__ */ jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxs(
10914
- KeyboundForm,
10915
- {
10916
- onSubmit: handleSubmit,
10917
- className: "flex flex-1 flex-col overflow-hidden",
10918
- children: [
10919
- /* @__PURE__ */ jsxs(RouteDrawer.Body, { className: "flex flex-1 flex-col gap-y-8 overflow-y-auto", children: [
10920
- /* @__PURE__ */ jsxs("div", { className: "bg-ui-bg-base shadow-elevation-card-rest grid grid-cols-1 divide-y rounded-lg", children: [
10921
- /* @__PURE__ */ jsxs("div", { className: "bg-ui-bg-subtle grid grid-cols-2 divide-x rounded-t-lg", children: [
10922
- /* @__PURE__ */ jsx("div", { className: "txt-compact-small-plus text-ui-fg-subtle px-2 py-1.5", children: /* @__PURE__ */ jsx("label", { id: METADATA_KEY_LABEL_ID, children: "Key" }) }),
10923
- /* @__PURE__ */ jsx("div", { className: "txt-compact-small-plus text-ui-fg-subtle px-2 py-1.5", children: /* @__PURE__ */ jsx("label", { id: METADATA_VALUE_LABEL_ID, children: "Value" }) })
10924
- ] }),
10925
- fields.map((field, index) => {
10926
- const isDisabled = field.disabled || false;
10927
- let placeholder = "-";
10928
- if (typeof field.value === "object") {
10929
- placeholder = "{ ... }";
10930
- }
10931
- if (Array.isArray(field.value)) {
10932
- placeholder = "[ ... ]";
10933
- }
10934
- return /* @__PURE__ */ jsx(
10935
- ConditionalTooltip,
10936
- {
10937
- showTooltip: isDisabled,
10938
- content: "This row is disabled because it contains non-primitive data.",
10939
- children: /* @__PURE__ */ jsxs("div", { className: "group/table relative", children: [
10940
- /* @__PURE__ */ jsxs(
10941
- "div",
10942
- {
10943
- className: clx("grid grid-cols-2 divide-x", {
10944
- "overflow-hidden rounded-b-lg": index === fields.length - 1
10945
- }),
10946
- children: [
10947
- /* @__PURE__ */ jsx(
10948
- Form$2.Field,
10949
- {
10950
- control: form.control,
10951
- name: `metadata.${index}.key`,
10952
- render: ({ field: field2 }) => {
10953
- return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
10954
- GridInput,
10955
- {
10956
- "aria-labelledby": METADATA_KEY_LABEL_ID,
10957
- ...field2,
10958
- disabled: isDisabled,
10959
- placeholder: "Key"
10960
- }
10961
- ) }) });
10962
- }
10963
- }
10964
- ),
10965
- /* @__PURE__ */ jsx(
10966
- Form$2.Field,
10967
- {
10968
- control: form.control,
10969
- name: `metadata.${index}.value`,
10970
- render: ({ field: { value, ...field2 } }) => {
10971
- return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
10972
- GridInput,
10973
- {
10974
- "aria-labelledby": METADATA_VALUE_LABEL_ID,
10975
- ...field2,
10976
- value: isDisabled ? placeholder : value,
10977
- disabled: isDisabled,
10978
- placeholder: "Value"
10979
- }
10980
- ) }) });
10981
- }
10982
- }
10983
- )
10984
- ]
10985
- }
10986
- ),
10987
- /* @__PURE__ */ jsxs(DropdownMenu, { children: [
10988
- /* @__PURE__ */ jsx(
10989
- DropdownMenu.Trigger,
10990
- {
10991
- className: clx(
10992
- "invisible absolute inset-y-0 -right-2.5 my-auto group-hover/table:visible data-[state='open']:visible",
10993
- {
10994
- hidden: isDisabled
10995
- }
10996
- ),
10997
- disabled: isDisabled,
10998
- asChild: true,
10999
- children: /* @__PURE__ */ jsx(IconButton, { size: "2xsmall", children: /* @__PURE__ */ jsx(EllipsisVertical, {}) })
11000
- }
11001
- ),
11002
- /* @__PURE__ */ jsxs(DropdownMenu.Content, { children: [
11003
- /* @__PURE__ */ jsxs(
11004
- DropdownMenu.Item,
11005
- {
11006
- className: "gap-x-2",
11007
- onClick: () => insertRow(index, "above"),
11008
- children: [
11009
- /* @__PURE__ */ jsx(ArrowUpMini, { className: "text-ui-fg-subtle" }),
11010
- "Insert row above"
11011
- ]
11012
- }
11013
- ),
11014
- /* @__PURE__ */ jsxs(
11015
- DropdownMenu.Item,
11016
- {
11017
- className: "gap-x-2",
11018
- onClick: () => insertRow(index, "below"),
11019
- children: [
11020
- /* @__PURE__ */ jsx(ArrowDownMini, { className: "text-ui-fg-subtle" }),
11021
- "Insert row below"
11022
- ]
11023
- }
11024
- ),
11025
- /* @__PURE__ */ jsx(DropdownMenu.Separator, {}),
11026
- /* @__PURE__ */ jsxs(
11027
- DropdownMenu.Item,
11028
- {
11029
- className: "gap-x-2",
11030
- onClick: () => deleteRow(index),
11031
- children: [
11032
- /* @__PURE__ */ jsx(Trash, { className: "text-ui-fg-subtle" }),
11033
- "Delete row"
11034
- ]
11035
- }
11036
- )
11037
- ] })
11038
- ] })
11039
- ] })
11040
- },
11041
- field.id
11042
- );
11043
- })
11044
- ] }),
11045
- hasUneditableRows && /* @__PURE__ */ jsx(InlineTip, { variant: "warning", label: "Some rows are disabled", children: "This object contains non-primitive metadata, such as arrays or objects, that can't be edited here. To edit the disabled rows, use the API directly." })
10946
+ return /* @__PURE__ */ jsxs(KeyboundForm, { className: "flex flex-1 flex-col", onSubmit, children: [
10947
+ /* @__PURE__ */ jsx(RouteDrawer.Body, { children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
10948
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
10949
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
10950
+ /* @__PURE__ */ jsx(Label$1, { size: "small", weight: "plus", htmlFor: "promotion-combobox", children: "Apply promotions" }),
10951
+ /* @__PURE__ */ jsx(Hint$1, { id: "promotion-combobox-hint", children: "Manage promotions that should be applied to the order." })
11046
10952
  ] }),
11047
- /* @__PURE__ */ jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
11048
- /* @__PURE__ */ jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
11049
- /* @__PURE__ */ jsx(Button, { size: "small", type: "submit", isLoading: isPending, children: "Save" })
11050
- ] }) })
11051
- ]
11052
- }
11053
- ) });
11054
- };
11055
- const GridInput = forwardRef(({ className, ...props }, ref) => {
11056
- return /* @__PURE__ */ jsx(
11057
- "input",
11058
- {
11059
- ref,
11060
- ...props,
11061
- autoComplete: "off",
11062
- className: clx(
11063
- "txt-compact-small text-ui-fg-base placeholder:text-ui-fg-muted disabled:text-ui-fg-disabled disabled:bg-ui-bg-base bg-transparent px-2 py-1.5 outline-none",
11064
- className
10953
+ /* @__PURE__ */ jsx(
10954
+ Combobox,
10955
+ {
10956
+ id: "promotion-combobox",
10957
+ "aria-describedby": "promotion-combobox-hint",
10958
+ isFetchingNextPage: comboboxData.isFetchingNextPage,
10959
+ fetchNextPage: comboboxData.fetchNextPage,
10960
+ options: comboboxData.options,
10961
+ onSearchValueChange: comboboxData.onSearchValueChange,
10962
+ searchValue: comboboxData.searchValue,
10963
+ disabled: comboboxData.disabled || isAddingPromotions,
10964
+ onChange: add,
10965
+ value: comboboxValue
10966
+ }
10967
+ )
10968
+ ] }),
10969
+ /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
10970
+ /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-2", children: promotions == null ? void 0 : promotions.map((promotion) => /* @__PURE__ */ jsx(
10971
+ PromotionItem,
10972
+ {
10973
+ promotion,
10974
+ orderId: preview.id,
10975
+ isLoading: isPending
10976
+ },
10977
+ promotion.id
10978
+ )) })
10979
+ ] }) }),
10980
+ /* @__PURE__ */ jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
10981
+ /* @__PURE__ */ jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
10982
+ /* @__PURE__ */ jsx(
10983
+ Button,
10984
+ {
10985
+ size: "small",
10986
+ type: "submit",
10987
+ isLoading: isSubmitting || isAddingPromotions,
10988
+ children: "Save"
10989
+ }
11065
10990
  )
11066
- }
11067
- );
11068
- });
11069
- GridInput.displayName = "MetadataForm.GridInput";
11070
- const PlaceholderInner = () => {
11071
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col overflow-hidden", children: [
11072
- /* @__PURE__ */ jsx(RouteDrawer.Body, { children: /* @__PURE__ */ jsx(Skeleton, { className: "h-[148ox] w-full rounded-lg" }) }),
11073
- /* @__PURE__ */ jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
11074
- /* @__PURE__ */ jsx(Skeleton, { className: "h-7 w-12 rounded-md" }),
11075
- /* @__PURE__ */ jsx(Skeleton, { className: "h-7 w-12 rounded-md" })
11076
10991
  ] }) })
11077
10992
  ] });
11078
10993
  };
11079
- const EDITABLE_TYPES = ["string", "number", "boolean"];
11080
- function getDefaultValues(metadata) {
11081
- if (!metadata || !Object.keys(metadata).length) {
11082
- return [
10994
+ const PromotionItem = ({
10995
+ promotion,
10996
+ orderId,
10997
+ isLoading
10998
+ }) => {
10999
+ var _a;
11000
+ const { mutateAsync: removePromotions, isPending } = useDraftOrderRemovePromotions(orderId);
11001
+ const onRemove = async () => {
11002
+ removePromotions(
11083
11003
  {
11084
- key: "",
11085
- value: "",
11086
- disabled: false
11004
+ promo_codes: [promotion.code]
11005
+ },
11006
+ {
11007
+ onError: (e) => {
11008
+ toast.error(e.message);
11009
+ }
11087
11010
  }
11088
- ];
11011
+ );
11012
+ };
11013
+ const displayValue = getDisplayValue(promotion);
11014
+ return /* @__PURE__ */ jsxs(
11015
+ "div",
11016
+ {
11017
+ className: clx(
11018
+ "bg-ui-bg-component shadow-elevation-card-rest flex items-center justify-between rounded-lg px-3 py-2",
11019
+ {
11020
+ "animate-pulse": isLoading
11021
+ }
11022
+ ),
11023
+ children: [
11024
+ /* @__PURE__ */ jsxs("div", { children: [
11025
+ /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: promotion.code }),
11026
+ /* @__PURE__ */ jsxs("div", { className: "text-ui-fg-subtle flex items-center gap-1.5", children: [
11027
+ displayValue && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
11028
+ /* @__PURE__ */ jsx(Text, { size: "small", leading: "compact", children: displayValue }),
11029
+ /* @__PURE__ */ jsx(Text, { size: "small", leading: "compact", children: "·" })
11030
+ ] }),
11031
+ /* @__PURE__ */ jsx(Text, { size: "small", leading: "compact", className: "capitalize", children: (_a = promotion.application_method) == null ? void 0 : _a.allocation })
11032
+ ] })
11033
+ ] }),
11034
+ /* @__PURE__ */ jsx(
11035
+ IconButton,
11036
+ {
11037
+ size: "small",
11038
+ type: "button",
11039
+ variant: "transparent",
11040
+ onClick: onRemove,
11041
+ isLoading: isPending || isLoading,
11042
+ children: /* @__PURE__ */ jsx(XMark, {})
11043
+ }
11044
+ )
11045
+ ]
11046
+ },
11047
+ promotion.id
11048
+ );
11049
+ };
11050
+ function getDisplayValue(promotion) {
11051
+ var _a, _b, _c, _d;
11052
+ const value = (_a = promotion.application_method) == null ? void 0 : _a.value;
11053
+ if (!value) {
11054
+ return null;
11089
11055
  }
11090
- return Object.entries(metadata).map(([key, value]) => {
11091
- if (!EDITABLE_TYPES.includes(typeof value)) {
11092
- return {
11093
- key,
11094
- value,
11095
- disabled: true
11096
- };
11097
- }
11098
- let stringValue = value;
11099
- if (typeof value !== "string") {
11100
- stringValue = JSON.stringify(value);
11056
+ if (((_b = promotion.application_method) == null ? void 0 : _b.type) === "fixed") {
11057
+ const currency = (_c = promotion.application_method) == null ? void 0 : _c.currency_code;
11058
+ if (!currency) {
11059
+ return null;
11101
11060
  }
11102
- return {
11103
- key,
11104
- value: stringValue,
11105
- original_key: key
11106
- };
11107
- });
11061
+ return getLocaleAmount(value, currency);
11062
+ } else if (((_d = promotion.application_method) == null ? void 0 : _d.type) === "percentage") {
11063
+ return formatPercentage(value);
11064
+ }
11065
+ return null;
11108
11066
  }
11109
- function parseValues(values) {
11110
- const metadata = values.metadata;
11111
- const isEmpty = !metadata.length || metadata.length === 1 && !metadata[0].key && !metadata[0].value;
11112
- if (isEmpty) {
11113
- return null;
11067
+ const formatter = new Intl.NumberFormat([], {
11068
+ style: "percent",
11069
+ minimumFractionDigits: 2
11070
+ });
11071
+ const formatPercentage = (value, isPercentageValue = false) => {
11072
+ let val = value || 0;
11073
+ if (!isPercentageValue) {
11074
+ val = val / 100;
11114
11075
  }
11115
- const update = {};
11116
- metadata.forEach((field) => {
11117
- let key = field.key;
11118
- let value = field.value;
11119
- const disabled = field.disabled;
11120
- if (!key || !value) {
11121
- return;
11122
- }
11123
- if (disabled) {
11124
- update[key] = value;
11125
- return;
11076
+ return formatter.format(val);
11077
+ };
11078
+ function getPromotionIds(items, shippingMethods) {
11079
+ const promotionIds = /* @__PURE__ */ new Set();
11080
+ for (const item of items) {
11081
+ if (item.adjustments) {
11082
+ for (const adjustment of item.adjustments) {
11083
+ if (adjustment.promotion_id) {
11084
+ promotionIds.add(adjustment.promotion_id);
11085
+ }
11086
+ }
11126
11087
  }
11127
- key = key.trim();
11128
- value = value.trim();
11129
- if (value === "true") {
11130
- update[key] = true;
11131
- } else if (value === "false") {
11132
- update[key] = false;
11133
- } else {
11134
- const parsedNumber = parseFloat(value);
11135
- if (!isNaN(parsedNumber)) {
11136
- update[key] = parsedNumber;
11137
- } else {
11138
- update[key] = value;
11088
+ }
11089
+ for (const shippingMethod of shippingMethods) {
11090
+ if (shippingMethod.adjustments) {
11091
+ for (const adjustment of shippingMethod.adjustments) {
11092
+ if (adjustment.promotion_id) {
11093
+ promotionIds.add(adjustment.promotion_id);
11094
+ }
11139
11095
  }
11140
11096
  }
11141
- });
11142
- return update;
11143
- }
11144
- function getHasUneditableRows(metadata) {
11145
- if (!metadata) {
11146
- return false;
11147
11097
  }
11148
- return Object.values(metadata).some(
11149
- (value) => !EDITABLE_TYPES.includes(typeof value)
11150
- );
11098
+ return Array.from(promotionIds);
11151
11099
  }
11152
- const PROMOTION_QUERY_KEY = "promotions";
11153
- const promotionsQueryKeys = {
11154
- list: (query2) => [
11155
- PROMOTION_QUERY_KEY,
11156
- query2 ? query2 : void 0
11157
- ],
11158
- detail: (id, query2) => [
11159
- PROMOTION_QUERY_KEY,
11160
- id,
11161
- query2 ? query2 : void 0
11162
- ]
11163
- };
11164
- const usePromotions = (query2, options) => {
11165
- const { data, ...rest } = useQuery({
11166
- queryKey: promotionsQueryKeys.list(query2),
11167
- queryFn: async () => sdk.admin.promotion.list(query2),
11168
- ...options
11169
- });
11170
- return { ...data, ...rest };
11171
- };
11172
- const Promotions = () => {
11100
+ const InlineTip = forwardRef(
11101
+ ({ variant = "tip", label, className, children, ...props }, ref) => {
11102
+ const labelValue = label || (variant === "warning" ? "Warning" : "Tip");
11103
+ return /* @__PURE__ */ jsxs(
11104
+ "div",
11105
+ {
11106
+ ref,
11107
+ className: clx(
11108
+ "bg-ui-bg-component txt-small text-ui-fg-subtle grid grid-cols-[4px_1fr] items-start gap-3 rounded-lg border p-3",
11109
+ className
11110
+ ),
11111
+ ...props,
11112
+ children: [
11113
+ /* @__PURE__ */ jsx(
11114
+ "div",
11115
+ {
11116
+ role: "presentation",
11117
+ className: clx("w-4px bg-ui-tag-neutral-icon h-full rounded-full", {
11118
+ "bg-ui-tag-orange-icon": variant === "warning"
11119
+ })
11120
+ }
11121
+ ),
11122
+ /* @__PURE__ */ jsxs("div", { className: "text-pretty", children: [
11123
+ /* @__PURE__ */ jsxs("strong", { className: "txt-small-plus text-ui-fg-base", children: [
11124
+ labelValue,
11125
+ ":"
11126
+ ] }),
11127
+ " ",
11128
+ children
11129
+ ] })
11130
+ ]
11131
+ }
11132
+ );
11133
+ }
11134
+ );
11135
+ InlineTip.displayName = "InlineTip";
11136
+ const MetadataFieldSchema = objectType({
11137
+ key: stringType(),
11138
+ disabled: booleanType().optional(),
11139
+ value: anyType()
11140
+ });
11141
+ const MetadataSchema = objectType({
11142
+ metadata: arrayType(MetadataFieldSchema)
11143
+ });
11144
+ const Metadata = () => {
11173
11145
  const { id } = useParams();
11174
- const {
11175
- order: preview,
11176
- isError: isPreviewError,
11177
- error: previewError
11178
- } = useOrderPreview(id, void 0);
11179
- useInitiateOrderEdit({ preview });
11180
- const { onCancel } = useCancelOrderEdit({ preview });
11181
- if (isPreviewError) {
11182
- throw previewError;
11146
+ const { order, isPending, isError, error } = useOrder(id, {
11147
+ fields: "metadata"
11148
+ });
11149
+ if (isError) {
11150
+ throw error;
11183
11151
  }
11184
- const isReady = !!preview;
11185
- return /* @__PURE__ */ jsxs(RouteDrawer, { onClose: onCancel, children: [
11186
- /* @__PURE__ */ jsx(RouteDrawer.Header, { children: /* @__PURE__ */ jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Edit Promotions" }) }) }),
11187
- isReady && /* @__PURE__ */ jsx(PromotionForm, { preview })
11152
+ const isReady = !isPending && !!order;
11153
+ return /* @__PURE__ */ jsxs(RouteDrawer, { children: [
11154
+ /* @__PURE__ */ jsxs(RouteDrawer.Header, { children: [
11155
+ /* @__PURE__ */ jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Metadata" }) }),
11156
+ /* @__PURE__ */ jsx(RouteDrawer.Description, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Add metadata to the draft order." }) })
11157
+ ] }),
11158
+ !isReady ? /* @__PURE__ */ jsx(PlaceholderInner, {}) : /* @__PURE__ */ jsx(MetadataForm, { orderId: id, metadata: order == null ? void 0 : order.metadata })
11188
11159
  ] });
11189
11160
  };
11190
- const PromotionForm = ({ preview }) => {
11191
- const { items, shipping_methods } = preview;
11192
- const [isSubmitting, setIsSubmitting] = useState(false);
11193
- const [comboboxValue, setComboboxValue] = useState("");
11161
+ const METADATA_KEY_LABEL_ID = "metadata-form-key-label";
11162
+ const METADATA_VALUE_LABEL_ID = "metadata-form-value-label";
11163
+ const MetadataForm = ({ orderId, metadata }) => {
11194
11164
  const { handleSuccess } = useRouteModal();
11195
- const { mutateAsync: addPromotions, isPending: isAddingPromotions } = useDraftOrderAddPromotions(preview.id);
11196
- const promoIds = getPromotionIds(items, shipping_methods);
11197
- const { promotions, isPending, isError, error } = usePromotions(
11198
- {
11199
- id: promoIds
11200
- },
11201
- {
11202
- enabled: !!promoIds.length
11203
- }
11204
- );
11205
- const comboboxData = useComboboxData({
11206
- queryKey: ["promotions", "combobox", promoIds],
11207
- queryFn: async (params) => {
11208
- return await sdk.admin.promotion.list({
11209
- ...params,
11210
- id: {
11211
- $nin: promoIds
11212
- }
11213
- });
11165
+ const hasUneditableRows = getHasUneditableRows(metadata);
11166
+ const { mutateAsync, isPending } = useUpdateDraftOrder(orderId);
11167
+ const form = useForm({
11168
+ defaultValues: {
11169
+ metadata: getDefaultValues(metadata)
11214
11170
  },
11215
- getOptions: (data) => {
11216
- return data.promotions.map((promotion) => ({
11217
- label: promotion.code,
11218
- value: promotion.code
11219
- }));
11220
- }
11171
+ resolver: zodResolver(MetadataSchema)
11221
11172
  });
11222
- const add = async (value) => {
11223
- if (!value) {
11224
- return;
11225
- }
11226
- addPromotions(
11173
+ const handleSubmit = form.handleSubmit(async (data) => {
11174
+ const parsedData = parseValues(data);
11175
+ await mutateAsync(
11227
11176
  {
11228
- promo_codes: [value]
11177
+ metadata: parsedData
11229
11178
  },
11230
11179
  {
11231
- onError: (e) => {
11232
- toast.error(e.message);
11233
- comboboxData.onSearchValueChange("");
11234
- setComboboxValue("");
11235
- },
11236
11180
  onSuccess: () => {
11237
- comboboxData.onSearchValueChange("");
11238
- setComboboxValue("");
11181
+ toast.success("Metadata updated");
11182
+ handleSuccess();
11183
+ },
11184
+ onError: (error) => {
11185
+ toast.error(error.message);
11239
11186
  }
11240
11187
  }
11241
11188
  );
11242
- };
11243
- const { mutateAsync: confirmOrderEdit } = useDraftOrderConfirmEdit(preview.id);
11244
- const { mutateAsync: requestOrderEdit } = useOrderEditRequest(preview.id);
11245
- const onSubmit = async () => {
11246
- setIsSubmitting(true);
11247
- let requestSucceeded = false;
11248
- await requestOrderEdit(void 0, {
11249
- onError: (e) => {
11250
- toast.error(e.message);
11251
- },
11252
- onSuccess: () => {
11253
- requestSucceeded = true;
11254
- }
11255
- });
11256
- if (!requestSucceeded) {
11257
- setIsSubmitting(false);
11258
- return;
11189
+ });
11190
+ const { fields, insert, remove } = useFieldArray({
11191
+ control: form.control,
11192
+ name: "metadata"
11193
+ });
11194
+ function deleteRow(index) {
11195
+ remove(index);
11196
+ if (fields.length === 1) {
11197
+ insert(0, {
11198
+ key: "",
11199
+ value: "",
11200
+ disabled: false
11201
+ });
11259
11202
  }
11260
- await confirmOrderEdit(void 0, {
11261
- onError: (e) => {
11262
- toast.error(e.message);
11263
- },
11264
- onSuccess: () => {
11265
- handleSuccess();
11266
- },
11267
- onSettled: () => {
11268
- setIsSubmitting(false);
11269
- }
11203
+ }
11204
+ function insertRow(index, position) {
11205
+ insert(index + (position === "above" ? 0 : 1), {
11206
+ key: "",
11207
+ value: "",
11208
+ disabled: false
11270
11209
  });
11271
- };
11272
- if (isError) {
11273
- throw error;
11274
11210
  }
11275
- return /* @__PURE__ */ jsxs(KeyboundForm, { className: "flex flex-1 flex-col", onSubmit, children: [
11276
- /* @__PURE__ */ jsx(RouteDrawer.Body, { children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
11277
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
11278
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
11279
- /* @__PURE__ */ jsx(Label$1, { size: "small", weight: "plus", htmlFor: "promotion-combobox", children: "Apply promotions" }),
11280
- /* @__PURE__ */ jsx(Hint$1, { id: "promotion-combobox-hint", children: "Manage promotions that should be applied to the order." })
11281
- ] }),
11282
- /* @__PURE__ */ jsx(
11283
- Combobox,
11284
- {
11285
- id: "promotion-combobox",
11286
- "aria-describedby": "promotion-combobox-hint",
11287
- isFetchingNextPage: comboboxData.isFetchingNextPage,
11288
- fetchNextPage: comboboxData.fetchNextPage,
11289
- options: comboboxData.options,
11290
- onSearchValueChange: comboboxData.onSearchValueChange,
11291
- searchValue: comboboxData.searchValue,
11292
- disabled: comboboxData.disabled || isAddingPromotions,
11293
- onChange: add,
11294
- value: comboboxValue
11295
- }
11296
- )
11297
- ] }),
11298
- /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
11299
- /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-2", children: promotions == null ? void 0 : promotions.map((promotion) => /* @__PURE__ */ jsx(
11300
- PromotionItem,
11301
- {
11302
- promotion,
11303
- orderId: preview.id,
11304
- isLoading: isPending
11305
- },
11306
- promotion.id
11307
- )) })
11308
- ] }) }),
11309
- /* @__PURE__ */ jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
11310
- /* @__PURE__ */ jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
11311
- /* @__PURE__ */ jsx(
11312
- Button,
11313
- {
11314
- size: "small",
11315
- type: "submit",
11316
- isLoading: isSubmitting || isAddingPromotions,
11317
- children: "Save"
11318
- }
11211
+ return /* @__PURE__ */ jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxs(
11212
+ KeyboundForm,
11213
+ {
11214
+ onSubmit: handleSubmit,
11215
+ className: "flex flex-1 flex-col overflow-hidden",
11216
+ children: [
11217
+ /* @__PURE__ */ jsxs(RouteDrawer.Body, { className: "flex flex-1 flex-col gap-y-8 overflow-y-auto", children: [
11218
+ /* @__PURE__ */ jsxs("div", { className: "bg-ui-bg-base shadow-elevation-card-rest grid grid-cols-1 divide-y rounded-lg", children: [
11219
+ /* @__PURE__ */ jsxs("div", { className: "bg-ui-bg-subtle grid grid-cols-2 divide-x rounded-t-lg", children: [
11220
+ /* @__PURE__ */ jsx("div", { className: "txt-compact-small-plus text-ui-fg-subtle px-2 py-1.5", children: /* @__PURE__ */ jsx("label", { id: METADATA_KEY_LABEL_ID, children: "Key" }) }),
11221
+ /* @__PURE__ */ jsx("div", { className: "txt-compact-small-plus text-ui-fg-subtle px-2 py-1.5", children: /* @__PURE__ */ jsx("label", { id: METADATA_VALUE_LABEL_ID, children: "Value" }) })
11222
+ ] }),
11223
+ fields.map((field, index) => {
11224
+ const isDisabled = field.disabled || false;
11225
+ let placeholder = "-";
11226
+ if (typeof field.value === "object") {
11227
+ placeholder = "{ ... }";
11228
+ }
11229
+ if (Array.isArray(field.value)) {
11230
+ placeholder = "[ ... ]";
11231
+ }
11232
+ return /* @__PURE__ */ jsx(
11233
+ ConditionalTooltip,
11234
+ {
11235
+ showTooltip: isDisabled,
11236
+ content: "This row is disabled because it contains non-primitive data.",
11237
+ children: /* @__PURE__ */ jsxs("div", { className: "group/table relative", children: [
11238
+ /* @__PURE__ */ jsxs(
11239
+ "div",
11240
+ {
11241
+ className: clx("grid grid-cols-2 divide-x", {
11242
+ "overflow-hidden rounded-b-lg": index === fields.length - 1
11243
+ }),
11244
+ children: [
11245
+ /* @__PURE__ */ jsx(
11246
+ Form$2.Field,
11247
+ {
11248
+ control: form.control,
11249
+ name: `metadata.${index}.key`,
11250
+ render: ({ field: field2 }) => {
11251
+ return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
11252
+ GridInput,
11253
+ {
11254
+ "aria-labelledby": METADATA_KEY_LABEL_ID,
11255
+ ...field2,
11256
+ disabled: isDisabled,
11257
+ placeholder: "Key"
11258
+ }
11259
+ ) }) });
11260
+ }
11261
+ }
11262
+ ),
11263
+ /* @__PURE__ */ jsx(
11264
+ Form$2.Field,
11265
+ {
11266
+ control: form.control,
11267
+ name: `metadata.${index}.value`,
11268
+ render: ({ field: { value, ...field2 } }) => {
11269
+ return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
11270
+ GridInput,
11271
+ {
11272
+ "aria-labelledby": METADATA_VALUE_LABEL_ID,
11273
+ ...field2,
11274
+ value: isDisabled ? placeholder : value,
11275
+ disabled: isDisabled,
11276
+ placeholder: "Value"
11277
+ }
11278
+ ) }) });
11279
+ }
11280
+ }
11281
+ )
11282
+ ]
11283
+ }
11284
+ ),
11285
+ /* @__PURE__ */ jsxs(DropdownMenu, { children: [
11286
+ /* @__PURE__ */ jsx(
11287
+ DropdownMenu.Trigger,
11288
+ {
11289
+ className: clx(
11290
+ "invisible absolute inset-y-0 -right-2.5 my-auto group-hover/table:visible data-[state='open']:visible",
11291
+ {
11292
+ hidden: isDisabled
11293
+ }
11294
+ ),
11295
+ disabled: isDisabled,
11296
+ asChild: true,
11297
+ children: /* @__PURE__ */ jsx(IconButton, { size: "2xsmall", children: /* @__PURE__ */ jsx(EllipsisVertical, {}) })
11298
+ }
11299
+ ),
11300
+ /* @__PURE__ */ jsxs(DropdownMenu.Content, { children: [
11301
+ /* @__PURE__ */ jsxs(
11302
+ DropdownMenu.Item,
11303
+ {
11304
+ className: "gap-x-2",
11305
+ onClick: () => insertRow(index, "above"),
11306
+ children: [
11307
+ /* @__PURE__ */ jsx(ArrowUpMini, { className: "text-ui-fg-subtle" }),
11308
+ "Insert row above"
11309
+ ]
11310
+ }
11311
+ ),
11312
+ /* @__PURE__ */ jsxs(
11313
+ DropdownMenu.Item,
11314
+ {
11315
+ className: "gap-x-2",
11316
+ onClick: () => insertRow(index, "below"),
11317
+ children: [
11318
+ /* @__PURE__ */ jsx(ArrowDownMini, { className: "text-ui-fg-subtle" }),
11319
+ "Insert row below"
11320
+ ]
11321
+ }
11322
+ ),
11323
+ /* @__PURE__ */ jsx(DropdownMenu.Separator, {}),
11324
+ /* @__PURE__ */ jsxs(
11325
+ DropdownMenu.Item,
11326
+ {
11327
+ className: "gap-x-2",
11328
+ onClick: () => deleteRow(index),
11329
+ children: [
11330
+ /* @__PURE__ */ jsx(Trash, { className: "text-ui-fg-subtle" }),
11331
+ "Delete row"
11332
+ ]
11333
+ }
11334
+ )
11335
+ ] })
11336
+ ] })
11337
+ ] })
11338
+ },
11339
+ field.id
11340
+ );
11341
+ })
11342
+ ] }),
11343
+ hasUneditableRows && /* @__PURE__ */ jsx(InlineTip, { variant: "warning", label: "Some rows are disabled", children: "This object contains non-primitive metadata, such as arrays or objects, that can't be edited here. To edit the disabled rows, use the API directly." })
11344
+ ] }),
11345
+ /* @__PURE__ */ jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
11346
+ /* @__PURE__ */ jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
11347
+ /* @__PURE__ */ jsx(Button, { size: "small", type: "submit", isLoading: isPending, children: "Save" })
11348
+ ] }) })
11349
+ ]
11350
+ }
11351
+ ) });
11352
+ };
11353
+ const GridInput = forwardRef(({ className, ...props }, ref) => {
11354
+ return /* @__PURE__ */ jsx(
11355
+ "input",
11356
+ {
11357
+ ref,
11358
+ ...props,
11359
+ autoComplete: "off",
11360
+ className: clx(
11361
+ "txt-compact-small text-ui-fg-base placeholder:text-ui-fg-muted disabled:text-ui-fg-disabled disabled:bg-ui-bg-base bg-transparent px-2 py-1.5 outline-none",
11362
+ className
11319
11363
  )
11364
+ }
11365
+ );
11366
+ });
11367
+ GridInput.displayName = "MetadataForm.GridInput";
11368
+ const PlaceholderInner = () => {
11369
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col overflow-hidden", children: [
11370
+ /* @__PURE__ */ jsx(RouteDrawer.Body, { children: /* @__PURE__ */ jsx(Skeleton, { className: "h-[148ox] w-full rounded-lg" }) }),
11371
+ /* @__PURE__ */ jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
11372
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-7 w-12 rounded-md" }),
11373
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-7 w-12 rounded-md" })
11320
11374
  ] }) })
11321
11375
  ] });
11322
11376
  };
11323
- const PromotionItem = ({
11324
- promotion,
11325
- orderId,
11326
- isLoading
11327
- }) => {
11328
- var _a;
11329
- const { mutateAsync: removePromotions, isPending } = useDraftOrderRemovePromotions(orderId);
11330
- const onRemove = async () => {
11331
- removePromotions(
11332
- {
11333
- promo_codes: [promotion.code]
11334
- },
11377
+ const EDITABLE_TYPES = ["string", "number", "boolean"];
11378
+ function getDefaultValues(metadata) {
11379
+ if (!metadata || !Object.keys(metadata).length) {
11380
+ return [
11335
11381
  {
11336
- onError: (e) => {
11337
- toast.error(e.message);
11338
- }
11382
+ key: "",
11383
+ value: "",
11384
+ disabled: false
11339
11385
  }
11340
- );
11341
- };
11342
- const displayValue = getDisplayValue(promotion);
11343
- return /* @__PURE__ */ jsxs(
11344
- "div",
11345
- {
11346
- className: clx(
11347
- "bg-ui-bg-component shadow-elevation-card-rest flex items-center justify-between rounded-lg px-3 py-2",
11348
- {
11349
- "animate-pulse": isLoading
11350
- }
11351
- ),
11352
- children: [
11353
- /* @__PURE__ */ jsxs("div", { children: [
11354
- /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: promotion.code }),
11355
- /* @__PURE__ */ jsxs("div", { className: "text-ui-fg-subtle flex items-center gap-1.5", children: [
11356
- displayValue && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
11357
- /* @__PURE__ */ jsx(Text, { size: "small", leading: "compact", children: displayValue }),
11358
- /* @__PURE__ */ jsx(Text, { size: "small", leading: "compact", children: "·" })
11359
- ] }),
11360
- /* @__PURE__ */ jsx(Text, { size: "small", leading: "compact", className: "capitalize", children: (_a = promotion.application_method) == null ? void 0 : _a.allocation })
11361
- ] })
11362
- ] }),
11363
- /* @__PURE__ */ jsx(
11364
- IconButton,
11365
- {
11366
- size: "small",
11367
- type: "button",
11368
- variant: "transparent",
11369
- onClick: onRemove,
11370
- isLoading: isPending || isLoading,
11371
- children: /* @__PURE__ */ jsx(XMark, {})
11372
- }
11373
- )
11374
- ]
11375
- },
11376
- promotion.id
11377
- );
11378
- };
11379
- function getDisplayValue(promotion) {
11380
- var _a, _b, _c, _d;
11381
- const value = (_a = promotion.application_method) == null ? void 0 : _a.value;
11382
- if (!value) {
11383
- return null;
11386
+ ];
11384
11387
  }
11385
- if (((_b = promotion.application_method) == null ? void 0 : _b.type) === "fixed") {
11386
- const currency = (_c = promotion.application_method) == null ? void 0 : _c.currency_code;
11387
- if (!currency) {
11388
- return null;
11388
+ return Object.entries(metadata).map(([key, value]) => {
11389
+ if (!EDITABLE_TYPES.includes(typeof value)) {
11390
+ return {
11391
+ key,
11392
+ value,
11393
+ disabled: true
11394
+ };
11389
11395
  }
11390
- return getLocaleAmount(value, currency);
11391
- } else if (((_d = promotion.application_method) == null ? void 0 : _d.type) === "percentage") {
11392
- return formatPercentage(value);
11393
- }
11394
- return null;
11396
+ let stringValue = value;
11397
+ if (typeof value !== "string") {
11398
+ stringValue = JSON.stringify(value);
11399
+ }
11400
+ return {
11401
+ key,
11402
+ value: stringValue,
11403
+ original_key: key
11404
+ };
11405
+ });
11395
11406
  }
11396
- const formatter = new Intl.NumberFormat([], {
11397
- style: "percent",
11398
- minimumFractionDigits: 2
11399
- });
11400
- const formatPercentage = (value, isPercentageValue = false) => {
11401
- let val = value || 0;
11402
- if (!isPercentageValue) {
11403
- val = val / 100;
11407
+ function parseValues(values) {
11408
+ const metadata = values.metadata;
11409
+ const isEmpty = !metadata.length || metadata.length === 1 && !metadata[0].key && !metadata[0].value;
11410
+ if (isEmpty) {
11411
+ return null;
11404
11412
  }
11405
- return formatter.format(val);
11406
- };
11407
- function getPromotionIds(items, shippingMethods) {
11408
- const promotionIds = /* @__PURE__ */ new Set();
11409
- for (const item of items) {
11410
- if (item.adjustments) {
11411
- for (const adjustment of item.adjustments) {
11412
- if (adjustment.promotion_id) {
11413
- promotionIds.add(adjustment.promotion_id);
11414
- }
11415
- }
11413
+ const update = {};
11414
+ metadata.forEach((field) => {
11415
+ let key = field.key;
11416
+ let value = field.value;
11417
+ const disabled = field.disabled;
11418
+ if (!key || !value) {
11419
+ return;
11416
11420
  }
11417
- }
11418
- for (const shippingMethod of shippingMethods) {
11419
- if (shippingMethod.adjustments) {
11420
- for (const adjustment of shippingMethod.adjustments) {
11421
- if (adjustment.promotion_id) {
11422
- promotionIds.add(adjustment.promotion_id);
11423
- }
11421
+ if (disabled) {
11422
+ update[key] = value;
11423
+ return;
11424
+ }
11425
+ key = key.trim();
11426
+ value = value.trim();
11427
+ if (value === "true") {
11428
+ update[key] = true;
11429
+ } else if (value === "false") {
11430
+ update[key] = false;
11431
+ } else {
11432
+ const parsedNumber = parseFloat(value);
11433
+ if (!isNaN(parsedNumber)) {
11434
+ update[key] = parsedNumber;
11435
+ } else {
11436
+ update[key] = value;
11424
11437
  }
11425
11438
  }
11439
+ });
11440
+ return update;
11441
+ }
11442
+ function getHasUneditableRows(metadata) {
11443
+ if (!metadata) {
11444
+ return false;
11426
11445
  }
11427
- return Array.from(promotionIds);
11446
+ return Object.values(metadata).some(
11447
+ (value) => !EDITABLE_TYPES.includes(typeof value)
11448
+ );
11428
11449
  }
11429
11450
  const SalesChannel = () => {
11430
11451
  const { id } = useParams();
@@ -11454,7 +11475,7 @@ const SalesChannelForm = ({ order }) => {
11454
11475
  defaultValues: {
11455
11476
  sales_channel_id: order.sales_channel_id || ""
11456
11477
  },
11457
- resolver: zodResolver(schema$3)
11478
+ resolver: zodResolver(schema$2)
11458
11479
  });
11459
11480
  const { mutateAsync, isPending } = useUpdateDraftOrder(order.id);
11460
11481
  const { handleSuccess } = useRouteModal();
@@ -11529,7 +11550,7 @@ const SalesChannelField = ({ control, order }) => {
11529
11550
  }
11530
11551
  );
11531
11552
  };
11532
- const schema$3 = objectType({
11553
+ const schema$2 = objectType({
11533
11554
  sales_channel_id: stringType().min(1)
11534
11555
  });
11535
11556
  const STACKED_FOCUS_MODAL_ID = "shipping-form";
@@ -12371,7 +12392,7 @@ const ShippingAddressForm = ({ order }) => {
12371
12392
  postal_code: ((_i = order.shipping_address) == null ? void 0 : _i.postal_code) ?? "",
12372
12393
  phone: ((_j = order.shipping_address) == null ? void 0 : _j.phone) ?? ""
12373
12394
  },
12374
- resolver: zodResolver(schema$2)
12395
+ resolver: zodResolver(schema$1)
12375
12396
  });
12376
12397
  const { mutateAsync, isPending } = useUpdateDraftOrder(order.id);
12377
12398
  const { handleSuccess } = useRouteModal();
@@ -12541,7 +12562,7 @@ const ShippingAddressForm = ({ order }) => {
12541
12562
  }
12542
12563
  ) });
12543
12564
  };
12544
- const schema$2 = addressSchema;
12565
+ const schema$1 = addressSchema;
12545
12566
  const TransferOwnership = () => {
12546
12567
  const { id } = useParams();
12547
12568
  const { draft_order, isPending, isError, error } = useDraftOrder(id, {
@@ -12565,7 +12586,7 @@ const TransferOwnershipForm = ({ order }) => {
12565
12586
  defaultValues: {
12566
12587
  customer_id: order.customer_id || ""
12567
12588
  },
12568
- resolver: zodResolver(schema$1)
12589
+ resolver: zodResolver(schema)
12569
12590
  });
12570
12591
  const { mutateAsync, isPending } = useUpdateDraftOrder(order.id);
12571
12592
  const { handleSuccess } = useRouteModal();
@@ -13015,29 +13036,8 @@ const Illustration = () => {
13015
13036
  }
13016
13037
  );
13017
13038
  };
13018
- const schema$1 = objectType({
13019
- customer_id: stringType().min(1)
13020
- });
13021
- const CustomItems = () => {
13022
- return /* @__PURE__ */ jsxs(RouteDrawer, { children: [
13023
- /* @__PURE__ */ jsx(RouteDrawer.Header, { children: /* @__PURE__ */ jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Edit Custom Items" }) }) }),
13024
- /* @__PURE__ */ jsx(CustomItemsForm, {})
13025
- ] });
13026
- };
13027
- const CustomItemsForm = () => {
13028
- const form = useForm({
13029
- resolver: zodResolver(schema)
13030
- });
13031
- return /* @__PURE__ */ jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxs(KeyboundForm, { className: "flex flex-1 flex-col", children: [
13032
- /* @__PURE__ */ jsx(RouteDrawer.Body, {}),
13033
- /* @__PURE__ */ jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
13034
- /* @__PURE__ */ jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
13035
- /* @__PURE__ */ jsx(Button, { size: "small", type: "submit", children: "Save" })
13036
- ] }) })
13037
- ] }) });
13038
- };
13039
13039
  const schema = objectType({
13040
- email: stringType().email()
13040
+ customer_id: stringType().min(1)
13041
13041
  });
13042
13042
  const widgetModule = { widgets: [] };
13043
13043
  const routeModule = {
@@ -13068,17 +13068,21 @@ const routeModule = {
13068
13068
  path: "/draft-orders/:id/email"
13069
13069
  },
13070
13070
  {
13071
- Component: Items,
13072
- path: "/draft-orders/:id/items"
13071
+ Component: CustomItems,
13072
+ path: "/draft-orders/:id/custom-items"
13073
13073
  },
13074
13074
  {
13075
- Component: Metadata,
13076
- path: "/draft-orders/:id/metadata"
13075
+ Component: Items,
13076
+ path: "/draft-orders/:id/items"
13077
13077
  },
13078
13078
  {
13079
13079
  Component: Promotions,
13080
13080
  path: "/draft-orders/:id/promotions"
13081
13081
  },
13082
+ {
13083
+ Component: Metadata,
13084
+ path: "/draft-orders/:id/metadata"
13085
+ },
13082
13086
  {
13083
13087
  Component: SalesChannel,
13084
13088
  path: "/draft-orders/:id/sales-channel"
@@ -13094,10 +13098,6 @@ const routeModule = {
13094
13098
  {
13095
13099
  Component: TransferOwnership,
13096
13100
  path: "/draft-orders/:id/transfer-ownership"
13097
- },
13098
- {
13099
- Component: CustomItems,
13100
- path: "/draft-orders/:id/custom-items"
13101
13101
  }
13102
13102
  ]
13103
13103
  }