@medusajs/draft-order 2.10.2-preview-20250904031023 → 2.10.2-preview-20250904060154

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.
@@ -9750,27 +9750,6 @@ const BillingAddressForm = ({ order }) => {
9750
9750
  ) });
9751
9751
  };
9752
9752
  const schema$5 = addressSchema;
9753
- const CustomItems = () => {
9754
- return /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer, { children: [
9755
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Edit Custom Items" }) }) }),
9756
- /* @__PURE__ */ jsxRuntime.jsx(CustomItemsForm, {})
9757
- ] });
9758
- };
9759
- const CustomItemsForm = () => {
9760
- const form = reactHookForm.useForm({
9761
- resolver: zod.zodResolver(schema$4)
9762
- });
9763
- return /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxRuntime.jsxs(KeyboundForm, { className: "flex flex-1 flex-col", children: [
9764
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Body, {}),
9765
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-2", children: [
9766
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
9767
- /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", type: "submit", children: "Save" })
9768
- ] }) })
9769
- ] }) });
9770
- };
9771
- const schema$4 = objectType({
9772
- email: stringType().email()
9773
- });
9774
9753
  const Email = () => {
9775
9754
  const { id } = reactRouterDom.useParams();
9776
9755
  const { order, isPending, isError, error } = useOrder(id, {
@@ -9793,7 +9772,7 @@ const EmailForm = ({ order }) => {
9793
9772
  defaultValues: {
9794
9773
  email: order.email ?? ""
9795
9774
  },
9796
- resolver: zod.zodResolver(schema$3)
9775
+ resolver: zod.zodResolver(schema$4)
9797
9776
  });
9798
9777
  const { mutateAsync, isPending } = useUpdateDraftOrder(order.id);
9799
9778
  const { handleSuccess } = useRouteModal();
@@ -9836,6 +9815,27 @@ const EmailForm = ({ order }) => {
9836
9815
  }
9837
9816
  ) });
9838
9817
  };
9818
+ const schema$4 = objectType({
9819
+ email: stringType().email()
9820
+ });
9821
+ const CustomItems = () => {
9822
+ return /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer, { children: [
9823
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Edit Custom Items" }) }) }),
9824
+ /* @__PURE__ */ jsxRuntime.jsx(CustomItemsForm, {})
9825
+ ] });
9826
+ };
9827
+ const CustomItemsForm = () => {
9828
+ const form = reactHookForm.useForm({
9829
+ resolver: zod.zodResolver(schema$3)
9830
+ });
9831
+ return /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxRuntime.jsxs(KeyboundForm, { className: "flex flex-1 flex-col", children: [
9832
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Body, {}),
9833
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-2", children: [
9834
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
9835
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", type: "submit", children: "Save" })
9836
+ ] }) })
9837
+ ] }) });
9838
+ };
9839
9839
  const schema$3 = objectType({
9840
9840
  email: stringType().email()
9841
9841
  });
@@ -10813,392 +10813,115 @@ const customItemSchema = objectType({
10813
10813
  quantity: numberType(),
10814
10814
  unit_price: unionType([numberType(), stringType()])
10815
10815
  });
10816
- const PROMOTION_QUERY_KEY = "promotions";
10817
- const promotionsQueryKeys = {
10818
- list: (query2) => [
10819
- PROMOTION_QUERY_KEY,
10820
- query2 ? query2 : void 0
10821
- ],
10822
- detail: (id, query2) => [
10823
- PROMOTION_QUERY_KEY,
10824
- id,
10825
- query2 ? query2 : void 0
10826
- ]
10827
- };
10828
- const usePromotions = (query2, options) => {
10829
- const { data, ...rest } = reactQuery.useQuery({
10830
- queryKey: promotionsQueryKeys.list(query2),
10831
- queryFn: async () => sdk.admin.promotion.list(query2),
10832
- ...options
10833
- });
10834
- return { ...data, ...rest };
10835
- };
10836
- const Promotions = () => {
10816
+ const InlineTip = React.forwardRef(
10817
+ ({ variant = "tip", label, className, children, ...props }, ref) => {
10818
+ const labelValue = label || (variant === "warning" ? "Warning" : "Tip");
10819
+ return /* @__PURE__ */ jsxRuntime.jsxs(
10820
+ "div",
10821
+ {
10822
+ ref,
10823
+ className: ui.clx(
10824
+ "bg-ui-bg-component txt-small text-ui-fg-subtle grid grid-cols-[4px_1fr] items-start gap-3 rounded-lg border p-3",
10825
+ className
10826
+ ),
10827
+ ...props,
10828
+ children: [
10829
+ /* @__PURE__ */ jsxRuntime.jsx(
10830
+ "div",
10831
+ {
10832
+ role: "presentation",
10833
+ className: ui.clx("w-4px bg-ui-tag-neutral-icon h-full rounded-full", {
10834
+ "bg-ui-tag-orange-icon": variant === "warning"
10835
+ })
10836
+ }
10837
+ ),
10838
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-pretty", children: [
10839
+ /* @__PURE__ */ jsxRuntime.jsxs("strong", { className: "txt-small-plus text-ui-fg-base", children: [
10840
+ labelValue,
10841
+ ":"
10842
+ ] }),
10843
+ " ",
10844
+ children
10845
+ ] })
10846
+ ]
10847
+ }
10848
+ );
10849
+ }
10850
+ );
10851
+ InlineTip.displayName = "InlineTip";
10852
+ const MetadataFieldSchema = objectType({
10853
+ key: stringType(),
10854
+ disabled: booleanType().optional(),
10855
+ value: anyType()
10856
+ });
10857
+ const MetadataSchema = objectType({
10858
+ metadata: arrayType(MetadataFieldSchema)
10859
+ });
10860
+ const Metadata = () => {
10837
10861
  const { id } = reactRouterDom.useParams();
10838
- const {
10839
- order: preview,
10840
- isError: isPreviewError,
10841
- error: previewError
10842
- } = useOrderPreview(id, void 0);
10843
- useInitiateOrderEdit({ preview });
10844
- const { onCancel } = useCancelOrderEdit({ preview });
10845
- if (isPreviewError) {
10846
- throw previewError;
10862
+ const { order, isPending, isError, error } = useOrder(id, {
10863
+ fields: "metadata"
10864
+ });
10865
+ if (isError) {
10866
+ throw error;
10847
10867
  }
10848
- const isReady = !!preview;
10849
- return /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer, { onClose: onCancel, children: [
10850
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Edit Promotions" }) }) }),
10851
- isReady && /* @__PURE__ */ jsxRuntime.jsx(PromotionForm, { preview })
10868
+ const isReady = !isPending && !!order;
10869
+ return /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer, { children: [
10870
+ /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer.Header, { children: [
10871
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Metadata" }) }),
10872
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Description, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Add metadata to the draft order." }) })
10873
+ ] }),
10874
+ !isReady ? /* @__PURE__ */ jsxRuntime.jsx(PlaceholderInner, {}) : /* @__PURE__ */ jsxRuntime.jsx(MetadataForm, { orderId: id, metadata: order == null ? void 0 : order.metadata })
10852
10875
  ] });
10853
10876
  };
10854
- const PromotionForm = ({ preview }) => {
10855
- const { items, shipping_methods } = preview;
10856
- const [isSubmitting, setIsSubmitting] = React.useState(false);
10857
- const [comboboxValue, setComboboxValue] = React.useState("");
10877
+ const METADATA_KEY_LABEL_ID = "metadata-form-key-label";
10878
+ const METADATA_VALUE_LABEL_ID = "metadata-form-value-label";
10879
+ const MetadataForm = ({ orderId, metadata }) => {
10858
10880
  const { handleSuccess } = useRouteModal();
10859
- const { mutateAsync: addPromotions, isPending: isAddingPromotions } = useDraftOrderAddPromotions(preview.id);
10860
- const promoCodes = getPromotionCodes(items, shipping_methods);
10861
- const { promotions, isPending, isError, error } = usePromotions(
10862
- {
10863
- code: promoCodes
10864
- },
10865
- {
10866
- enabled: !!promoCodes.length
10867
- }
10868
- );
10869
- const comboboxData = useComboboxData({
10870
- queryKey: ["promotions", "combobox", promoCodes],
10871
- queryFn: async (params) => {
10872
- return await sdk.admin.promotion.list({
10873
- ...params,
10874
- code: {
10875
- $nin: promoCodes
10876
- }
10877
- });
10881
+ const hasUneditableRows = getHasUneditableRows(metadata);
10882
+ const { mutateAsync, isPending } = useUpdateDraftOrder(orderId);
10883
+ const form = reactHookForm.useForm({
10884
+ defaultValues: {
10885
+ metadata: getDefaultValues(metadata)
10878
10886
  },
10879
- getOptions: (data) => {
10880
- return data.promotions.map((promotion) => ({
10881
- label: promotion.code,
10882
- value: promotion.code
10883
- }));
10884
- }
10887
+ resolver: zod.zodResolver(MetadataSchema)
10885
10888
  });
10886
- const add = async (value) => {
10887
- if (!value) {
10888
- return;
10889
- }
10890
- addPromotions(
10889
+ const handleSubmit = form.handleSubmit(async (data) => {
10890
+ const parsedData = parseValues(data);
10891
+ await mutateAsync(
10891
10892
  {
10892
- promo_codes: [value]
10893
+ metadata: parsedData
10893
10894
  },
10894
10895
  {
10895
- onError: (e) => {
10896
- ui.toast.error(e.message);
10897
- comboboxData.onSearchValueChange("");
10898
- setComboboxValue("");
10899
- },
10900
10896
  onSuccess: () => {
10901
- comboboxData.onSearchValueChange("");
10902
- setComboboxValue("");
10897
+ ui.toast.success("Metadata updated");
10898
+ handleSuccess();
10899
+ },
10900
+ onError: (error) => {
10901
+ ui.toast.error(error.message);
10903
10902
  }
10904
10903
  }
10905
10904
  );
10906
- };
10907
- const { mutateAsync: confirmOrderEdit } = useDraftOrderConfirmEdit(preview.id);
10908
- const { mutateAsync: requestOrderEdit } = useOrderEditRequest(preview.id);
10909
- const onSubmit = async () => {
10910
- setIsSubmitting(true);
10911
- let requestSucceeded = false;
10912
- await requestOrderEdit(void 0, {
10913
- onError: (e) => {
10914
- ui.toast.error(e.message);
10915
- },
10916
- onSuccess: () => {
10917
- requestSucceeded = true;
10918
- }
10919
- });
10920
- if (!requestSucceeded) {
10921
- setIsSubmitting(false);
10922
- return;
10905
+ });
10906
+ const { fields, insert, remove } = reactHookForm.useFieldArray({
10907
+ control: form.control,
10908
+ name: "metadata"
10909
+ });
10910
+ function deleteRow(index) {
10911
+ remove(index);
10912
+ if (fields.length === 1) {
10913
+ insert(0, {
10914
+ key: "",
10915
+ value: "",
10916
+ disabled: false
10917
+ });
10923
10918
  }
10924
- await confirmOrderEdit(void 0, {
10925
- onError: (e) => {
10926
- ui.toast.error(e.message);
10927
- },
10928
- onSuccess: () => {
10929
- handleSuccess();
10930
- },
10931
- onSettled: () => {
10932
- setIsSubmitting(false);
10933
- }
10934
- });
10935
- };
10936
- if (isError) {
10937
- throw error;
10938
- }
10939
- return /* @__PURE__ */ jsxRuntime.jsxs(KeyboundForm, { className: "flex flex-1 flex-col", onSubmit, children: [
10940
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Body, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-4", children: [
10941
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3", children: [
10942
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
10943
- /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: "small", weight: "plus", htmlFor: "promotion-combobox", children: "Apply promotions" }),
10944
- /* @__PURE__ */ jsxRuntime.jsx(ui.Hint, { id: "promotion-combobox-hint", children: "Manage promotions that should be applied to the order." })
10945
- ] }),
10946
- /* @__PURE__ */ jsxRuntime.jsx(
10947
- Combobox,
10948
- {
10949
- id: "promotion-combobox",
10950
- "aria-describedby": "promotion-combobox-hint",
10951
- isFetchingNextPage: comboboxData.isFetchingNextPage,
10952
- fetchNextPage: comboboxData.fetchNextPage,
10953
- options: comboboxData.options,
10954
- onSearchValueChange: comboboxData.onSearchValueChange,
10955
- searchValue: comboboxData.searchValue,
10956
- disabled: comboboxData.disabled || isAddingPromotions,
10957
- onChange: add,
10958
- value: comboboxValue
10959
- }
10960
- )
10961
- ] }),
10962
- /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { variant: "dashed" }),
10963
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-2", children: promotions == null ? void 0 : promotions.map((promotion) => /* @__PURE__ */ jsxRuntime.jsx(
10964
- PromotionItem,
10965
- {
10966
- promotion,
10967
- orderId: preview.id,
10968
- isLoading: isPending
10969
- },
10970
- promotion.id
10971
- )) })
10972
- ] }) }),
10973
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-2", children: [
10974
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
10975
- /* @__PURE__ */ jsxRuntime.jsx(
10976
- ui.Button,
10977
- {
10978
- size: "small",
10979
- type: "submit",
10980
- isLoading: isSubmitting || isAddingPromotions,
10981
- children: "Save"
10982
- }
10983
- )
10984
- ] }) })
10985
- ] });
10986
- };
10987
- const PromotionItem = ({
10988
- promotion,
10989
- orderId,
10990
- isLoading
10991
- }) => {
10992
- var _a;
10993
- const { mutateAsync: removePromotions, isPending } = useDraftOrderRemovePromotions(orderId);
10994
- const onRemove = async () => {
10995
- removePromotions(
10996
- {
10997
- promo_codes: [promotion.code]
10998
- },
10999
- {
11000
- onError: (e) => {
11001
- ui.toast.error(e.message);
11002
- }
11003
- }
11004
- );
11005
- };
11006
- const displayValue = getDisplayValue(promotion);
11007
- return /* @__PURE__ */ jsxRuntime.jsxs(
11008
- "div",
11009
- {
11010
- className: ui.clx(
11011
- "px-3 py-2 rounded-lg bg-ui-bg-component shadow-elevation-card-rest flex items-center justify-between",
11012
- {
11013
- "animate-pulse": isLoading
11014
- }
11015
- ),
11016
- children: [
11017
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
11018
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", leading: "compact", children: promotion.code }),
11019
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 text-ui-fg-subtle", children: [
11020
- displayValue && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
11021
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", leading: "compact", children: displayValue }),
11022
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", leading: "compact", children: "·" })
11023
- ] }),
11024
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", leading: "compact", className: "capitalize", children: (_a = promotion.application_method) == null ? void 0 : _a.allocation })
11025
- ] })
11026
- ] }),
11027
- /* @__PURE__ */ jsxRuntime.jsx(
11028
- ui.IconButton,
11029
- {
11030
- size: "small",
11031
- type: "button",
11032
- variant: "transparent",
11033
- onClick: onRemove,
11034
- isLoading: isPending || isLoading,
11035
- children: /* @__PURE__ */ jsxRuntime.jsx(icons.XMark, {})
11036
- }
11037
- )
11038
- ]
11039
- },
11040
- promotion.id
11041
- );
11042
- };
11043
- function getDisplayValue(promotion) {
11044
- var _a, _b, _c, _d;
11045
- const value = (_a = promotion.application_method) == null ? void 0 : _a.value;
11046
- if (!value) {
11047
- return null;
11048
- }
11049
- if (((_b = promotion.application_method) == null ? void 0 : _b.type) === "fixed") {
11050
- const currency = (_c = promotion.application_method) == null ? void 0 : _c.currency_code;
11051
- if (!currency) {
11052
- return null;
11053
- }
11054
- return getLocaleAmount(value, currency);
11055
- } else if (((_d = promotion.application_method) == null ? void 0 : _d.type) === "percentage") {
11056
- return formatPercentage(value);
11057
- }
11058
- return null;
11059
- }
11060
- const formatter = new Intl.NumberFormat([], {
11061
- style: "percent",
11062
- minimumFractionDigits: 2
11063
- });
11064
- const formatPercentage = (value, isPercentageValue = false) => {
11065
- let val = value || 0;
11066
- if (!isPercentageValue) {
11067
- val = val / 100;
11068
- }
11069
- return formatter.format(val);
11070
- };
11071
- function getPromotionCodes(items, shippingMethods) {
11072
- const codes = /* @__PURE__ */ new Set();
11073
- for (const item of items) {
11074
- if (item.adjustments) {
11075
- for (const adjustment of item.adjustments) {
11076
- if (adjustment.code) {
11077
- codes.add(adjustment.code);
11078
- }
11079
- }
11080
- }
11081
- }
11082
- for (const shippingMethod of shippingMethods) {
11083
- if (shippingMethod.adjustments) {
11084
- for (const adjustment of shippingMethod.adjustments) {
11085
- if (adjustment.code) {
11086
- codes.add(adjustment.code);
11087
- }
11088
- }
11089
- }
11090
- }
11091
- return Array.from(codes);
11092
- }
11093
- const InlineTip = React.forwardRef(
11094
- ({ variant = "tip", label, className, children, ...props }, ref) => {
11095
- const labelValue = label || (variant === "warning" ? "Warning" : "Tip");
11096
- return /* @__PURE__ */ jsxRuntime.jsxs(
11097
- "div",
11098
- {
11099
- ref,
11100
- className: ui.clx(
11101
- "bg-ui-bg-component txt-small text-ui-fg-subtle grid grid-cols-[4px_1fr] items-start gap-3 rounded-lg border p-3",
11102
- className
11103
- ),
11104
- ...props,
11105
- children: [
11106
- /* @__PURE__ */ jsxRuntime.jsx(
11107
- "div",
11108
- {
11109
- role: "presentation",
11110
- className: ui.clx("w-4px bg-ui-tag-neutral-icon h-full rounded-full", {
11111
- "bg-ui-tag-orange-icon": variant === "warning"
11112
- })
11113
- }
11114
- ),
11115
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-pretty", children: [
11116
- /* @__PURE__ */ jsxRuntime.jsxs("strong", { className: "txt-small-plus text-ui-fg-base", children: [
11117
- labelValue,
11118
- ":"
11119
- ] }),
11120
- " ",
11121
- children
11122
- ] })
11123
- ]
11124
- }
11125
- );
11126
- }
11127
- );
11128
- InlineTip.displayName = "InlineTip";
11129
- const MetadataFieldSchema = objectType({
11130
- key: stringType(),
11131
- disabled: booleanType().optional(),
11132
- value: anyType()
11133
- });
11134
- const MetadataSchema = objectType({
11135
- metadata: arrayType(MetadataFieldSchema)
11136
- });
11137
- const Metadata = () => {
11138
- const { id } = reactRouterDom.useParams();
11139
- const { order, isPending, isError, error } = useOrder(id, {
11140
- fields: "metadata"
11141
- });
11142
- if (isError) {
11143
- throw error;
11144
- }
11145
- const isReady = !isPending && !!order;
11146
- return /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer, { children: [
11147
- /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer.Header, { children: [
11148
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Metadata" }) }),
11149
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Description, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Add metadata to the draft order." }) })
11150
- ] }),
11151
- !isReady ? /* @__PURE__ */ jsxRuntime.jsx(PlaceholderInner, {}) : /* @__PURE__ */ jsxRuntime.jsx(MetadataForm, { orderId: id, metadata: order == null ? void 0 : order.metadata })
11152
- ] });
11153
- };
11154
- const METADATA_KEY_LABEL_ID = "metadata-form-key-label";
11155
- const METADATA_VALUE_LABEL_ID = "metadata-form-value-label";
11156
- const MetadataForm = ({ orderId, metadata }) => {
11157
- const { handleSuccess } = useRouteModal();
11158
- const hasUneditableRows = getHasUneditableRows(metadata);
11159
- const { mutateAsync, isPending } = useUpdateDraftOrder(orderId);
11160
- const form = reactHookForm.useForm({
11161
- defaultValues: {
11162
- metadata: getDefaultValues(metadata)
11163
- },
11164
- resolver: zod.zodResolver(MetadataSchema)
11165
- });
11166
- const handleSubmit = form.handleSubmit(async (data) => {
11167
- const parsedData = parseValues(data);
11168
- await mutateAsync(
11169
- {
11170
- metadata: parsedData
11171
- },
11172
- {
11173
- onSuccess: () => {
11174
- ui.toast.success("Metadata updated");
11175
- handleSuccess();
11176
- },
11177
- onError: (error) => {
11178
- ui.toast.error(error.message);
11179
- }
11180
- }
11181
- );
11182
- });
11183
- const { fields, insert, remove } = reactHookForm.useFieldArray({
11184
- control: form.control,
11185
- name: "metadata"
11186
- });
11187
- function deleteRow(index) {
11188
- remove(index);
11189
- if (fields.length === 1) {
11190
- insert(0, {
11191
- key: "",
11192
- value: "",
11193
- disabled: false
11194
- });
11195
- }
11196
- }
11197
- function insertRow(index, position) {
11198
- insert(index + (position === "above" ? 0 : 1), {
11199
- key: "",
11200
- value: "",
11201
- disabled: false
10919
+ }
10920
+ function insertRow(index, position) {
10921
+ insert(index + (position === "above" ? 0 : 1), {
10922
+ key: "",
10923
+ value: "",
10924
+ disabled: false
11202
10925
  });
11203
10926
  }
11204
10927
  return /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxRuntime.jsxs(
@@ -11341,104 +11064,381 @@ const MetadataForm = ({ orderId, metadata }) => {
11341
11064
  ] }) })
11342
11065
  ]
11343
11066
  }
11344
- ) });
11345
- };
11346
- const GridInput = React.forwardRef(({ className, ...props }, ref) => {
11347
- return /* @__PURE__ */ jsxRuntime.jsx(
11348
- "input",
11349
- {
11350
- ref,
11351
- ...props,
11352
- autoComplete: "off",
11353
- className: ui.clx(
11354
- "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",
11355
- className
11067
+ ) });
11068
+ };
11069
+ const GridInput = React.forwardRef(({ className, ...props }, ref) => {
11070
+ return /* @__PURE__ */ jsxRuntime.jsx(
11071
+ "input",
11072
+ {
11073
+ ref,
11074
+ ...props,
11075
+ autoComplete: "off",
11076
+ className: ui.clx(
11077
+ "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",
11078
+ className
11079
+ )
11080
+ }
11081
+ );
11082
+ });
11083
+ GridInput.displayName = "MetadataForm.GridInput";
11084
+ const PlaceholderInner = () => {
11085
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col overflow-hidden", children: [
11086
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Body, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: "h-[148ox] w-full rounded-lg" }) }),
11087
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
11088
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: "h-7 w-12 rounded-md" }),
11089
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: "h-7 w-12 rounded-md" })
11090
+ ] }) })
11091
+ ] });
11092
+ };
11093
+ const EDITABLE_TYPES = ["string", "number", "boolean"];
11094
+ function getDefaultValues(metadata) {
11095
+ if (!metadata || !Object.keys(metadata).length) {
11096
+ return [
11097
+ {
11098
+ key: "",
11099
+ value: "",
11100
+ disabled: false
11101
+ }
11102
+ ];
11103
+ }
11104
+ return Object.entries(metadata).map(([key, value]) => {
11105
+ if (!EDITABLE_TYPES.includes(typeof value)) {
11106
+ return {
11107
+ key,
11108
+ value,
11109
+ disabled: true
11110
+ };
11111
+ }
11112
+ let stringValue = value;
11113
+ if (typeof value !== "string") {
11114
+ stringValue = JSON.stringify(value);
11115
+ }
11116
+ return {
11117
+ key,
11118
+ value: stringValue,
11119
+ original_key: key
11120
+ };
11121
+ });
11122
+ }
11123
+ function parseValues(values) {
11124
+ const metadata = values.metadata;
11125
+ const isEmpty = !metadata.length || metadata.length === 1 && !metadata[0].key && !metadata[0].value;
11126
+ if (isEmpty) {
11127
+ return null;
11128
+ }
11129
+ const update = {};
11130
+ metadata.forEach((field) => {
11131
+ let key = field.key;
11132
+ let value = field.value;
11133
+ const disabled = field.disabled;
11134
+ if (!key || !value) {
11135
+ return;
11136
+ }
11137
+ if (disabled) {
11138
+ update[key] = value;
11139
+ return;
11140
+ }
11141
+ key = key.trim();
11142
+ value = value.trim();
11143
+ if (value === "true") {
11144
+ update[key] = true;
11145
+ } else if (value === "false") {
11146
+ update[key] = false;
11147
+ } else {
11148
+ const parsedNumber = parseFloat(value);
11149
+ if (!isNaN(parsedNumber)) {
11150
+ update[key] = parsedNumber;
11151
+ } else {
11152
+ update[key] = value;
11153
+ }
11154
+ }
11155
+ });
11156
+ return update;
11157
+ }
11158
+ function getHasUneditableRows(metadata) {
11159
+ if (!metadata) {
11160
+ return false;
11161
+ }
11162
+ return Object.values(metadata).some(
11163
+ (value) => !EDITABLE_TYPES.includes(typeof value)
11164
+ );
11165
+ }
11166
+ const PROMOTION_QUERY_KEY = "promotions";
11167
+ const promotionsQueryKeys = {
11168
+ list: (query2) => [
11169
+ PROMOTION_QUERY_KEY,
11170
+ query2 ? query2 : void 0
11171
+ ],
11172
+ detail: (id, query2) => [
11173
+ PROMOTION_QUERY_KEY,
11174
+ id,
11175
+ query2 ? query2 : void 0
11176
+ ]
11177
+ };
11178
+ const usePromotions = (query2, options) => {
11179
+ const { data, ...rest } = reactQuery.useQuery({
11180
+ queryKey: promotionsQueryKeys.list(query2),
11181
+ queryFn: async () => sdk.admin.promotion.list(query2),
11182
+ ...options
11183
+ });
11184
+ return { ...data, ...rest };
11185
+ };
11186
+ const Promotions = () => {
11187
+ const { id } = reactRouterDom.useParams();
11188
+ const {
11189
+ order: preview,
11190
+ isError: isPreviewError,
11191
+ error: previewError
11192
+ } = useOrderPreview(id, void 0);
11193
+ useInitiateOrderEdit({ preview });
11194
+ const { onCancel } = useCancelOrderEdit({ preview });
11195
+ if (isPreviewError) {
11196
+ throw previewError;
11197
+ }
11198
+ const isReady = !!preview;
11199
+ return /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer, { onClose: onCancel, children: [
11200
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Edit Promotions" }) }) }),
11201
+ isReady && /* @__PURE__ */ jsxRuntime.jsx(PromotionForm, { preview })
11202
+ ] });
11203
+ };
11204
+ const PromotionForm = ({ preview }) => {
11205
+ const { items, shipping_methods } = preview;
11206
+ const [isSubmitting, setIsSubmitting] = React.useState(false);
11207
+ const [comboboxValue, setComboboxValue] = React.useState("");
11208
+ const { handleSuccess } = useRouteModal();
11209
+ const { mutateAsync: addPromotions, isPending: isAddingPromotions } = useDraftOrderAddPromotions(preview.id);
11210
+ const promoCodes = getPromotionCodes(items, shipping_methods);
11211
+ const { promotions, isPending, isError, error } = usePromotions(
11212
+ {
11213
+ code: promoCodes
11214
+ },
11215
+ {
11216
+ enabled: !!promoCodes.length
11217
+ }
11218
+ );
11219
+ const comboboxData = useComboboxData({
11220
+ queryKey: ["promotions", "combobox", promoCodes],
11221
+ queryFn: async (params) => {
11222
+ return await sdk.admin.promotion.list({
11223
+ ...params,
11224
+ code: {
11225
+ $nin: promoCodes
11226
+ }
11227
+ });
11228
+ },
11229
+ getOptions: (data) => {
11230
+ return data.promotions.map((promotion) => ({
11231
+ label: promotion.code,
11232
+ value: promotion.code
11233
+ }));
11234
+ }
11235
+ });
11236
+ const add = async (value) => {
11237
+ if (!value) {
11238
+ return;
11239
+ }
11240
+ addPromotions(
11241
+ {
11242
+ promo_codes: [value]
11243
+ },
11244
+ {
11245
+ onError: (e) => {
11246
+ ui.toast.error(e.message);
11247
+ comboboxData.onSearchValueChange("");
11248
+ setComboboxValue("");
11249
+ },
11250
+ onSuccess: () => {
11251
+ comboboxData.onSearchValueChange("");
11252
+ setComboboxValue("");
11253
+ }
11254
+ }
11255
+ );
11256
+ };
11257
+ const { mutateAsync: confirmOrderEdit } = useDraftOrderConfirmEdit(preview.id);
11258
+ const { mutateAsync: requestOrderEdit } = useOrderEditRequest(preview.id);
11259
+ const onSubmit = async () => {
11260
+ setIsSubmitting(true);
11261
+ let requestSucceeded = false;
11262
+ await requestOrderEdit(void 0, {
11263
+ onError: (e) => {
11264
+ ui.toast.error(e.message);
11265
+ },
11266
+ onSuccess: () => {
11267
+ requestSucceeded = true;
11268
+ }
11269
+ });
11270
+ if (!requestSucceeded) {
11271
+ setIsSubmitting(false);
11272
+ return;
11273
+ }
11274
+ await confirmOrderEdit(void 0, {
11275
+ onError: (e) => {
11276
+ ui.toast.error(e.message);
11277
+ },
11278
+ onSuccess: () => {
11279
+ handleSuccess();
11280
+ },
11281
+ onSettled: () => {
11282
+ setIsSubmitting(false);
11283
+ }
11284
+ });
11285
+ };
11286
+ if (isError) {
11287
+ throw error;
11288
+ }
11289
+ return /* @__PURE__ */ jsxRuntime.jsxs(KeyboundForm, { className: "flex flex-1 flex-col", onSubmit, children: [
11290
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Body, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-4", children: [
11291
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3", children: [
11292
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
11293
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: "small", weight: "plus", htmlFor: "promotion-combobox", children: "Apply promotions" }),
11294
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Hint, { id: "promotion-combobox-hint", children: "Manage promotions that should be applied to the order." })
11295
+ ] }),
11296
+ /* @__PURE__ */ jsxRuntime.jsx(
11297
+ Combobox,
11298
+ {
11299
+ id: "promotion-combobox",
11300
+ "aria-describedby": "promotion-combobox-hint",
11301
+ isFetchingNextPage: comboboxData.isFetchingNextPage,
11302
+ fetchNextPage: comboboxData.fetchNextPage,
11303
+ options: comboboxData.options,
11304
+ onSearchValueChange: comboboxData.onSearchValueChange,
11305
+ searchValue: comboboxData.searchValue,
11306
+ disabled: comboboxData.disabled || isAddingPromotions,
11307
+ onChange: add,
11308
+ value: comboboxValue
11309
+ }
11310
+ )
11311
+ ] }),
11312
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { variant: "dashed" }),
11313
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-2", children: promotions == null ? void 0 : promotions.map((promotion) => /* @__PURE__ */ jsxRuntime.jsx(
11314
+ PromotionItem,
11315
+ {
11316
+ promotion,
11317
+ orderId: preview.id,
11318
+ isLoading: isPending
11319
+ },
11320
+ promotion.id
11321
+ )) })
11322
+ ] }) }),
11323
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-2", children: [
11324
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
11325
+ /* @__PURE__ */ jsxRuntime.jsx(
11326
+ ui.Button,
11327
+ {
11328
+ size: "small",
11329
+ type: "submit",
11330
+ isLoading: isSubmitting || isAddingPromotions,
11331
+ children: "Save"
11332
+ }
11356
11333
  )
11357
- }
11358
- );
11359
- });
11360
- GridInput.displayName = "MetadataForm.GridInput";
11361
- const PlaceholderInner = () => {
11362
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col overflow-hidden", children: [
11363
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Body, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: "h-[148ox] w-full rounded-lg" }) }),
11364
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
11365
- /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: "h-7 w-12 rounded-md" }),
11366
- /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: "h-7 w-12 rounded-md" })
11367
11334
  ] }) })
11368
11335
  ] });
11369
11336
  };
11370
- const EDITABLE_TYPES = ["string", "number", "boolean"];
11371
- function getDefaultValues(metadata) {
11372
- if (!metadata || !Object.keys(metadata).length) {
11373
- return [
11337
+ const PromotionItem = ({
11338
+ promotion,
11339
+ orderId,
11340
+ isLoading
11341
+ }) => {
11342
+ var _a;
11343
+ const { mutateAsync: removePromotions, isPending } = useDraftOrderRemovePromotions(orderId);
11344
+ const onRemove = async () => {
11345
+ removePromotions(
11374
11346
  {
11375
- key: "",
11376
- value: "",
11377
- disabled: false
11347
+ promo_codes: [promotion.code]
11348
+ },
11349
+ {
11350
+ onError: (e) => {
11351
+ ui.toast.error(e.message);
11352
+ }
11378
11353
  }
11379
- ];
11354
+ );
11355
+ };
11356
+ const displayValue = getDisplayValue(promotion);
11357
+ return /* @__PURE__ */ jsxRuntime.jsxs(
11358
+ "div",
11359
+ {
11360
+ className: ui.clx(
11361
+ "px-3 py-2 rounded-lg bg-ui-bg-component shadow-elevation-card-rest flex items-center justify-between",
11362
+ {
11363
+ "animate-pulse": isLoading
11364
+ }
11365
+ ),
11366
+ children: [
11367
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
11368
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", leading: "compact", children: promotion.code }),
11369
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 text-ui-fg-subtle", children: [
11370
+ displayValue && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
11371
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", leading: "compact", children: displayValue }),
11372
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", leading: "compact", children: "·" })
11373
+ ] }),
11374
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", leading: "compact", className: "capitalize", children: (_a = promotion.application_method) == null ? void 0 : _a.allocation })
11375
+ ] })
11376
+ ] }),
11377
+ /* @__PURE__ */ jsxRuntime.jsx(
11378
+ ui.IconButton,
11379
+ {
11380
+ size: "small",
11381
+ type: "button",
11382
+ variant: "transparent",
11383
+ onClick: onRemove,
11384
+ isLoading: isPending || isLoading,
11385
+ children: /* @__PURE__ */ jsxRuntime.jsx(icons.XMark, {})
11386
+ }
11387
+ )
11388
+ ]
11389
+ },
11390
+ promotion.id
11391
+ );
11392
+ };
11393
+ function getDisplayValue(promotion) {
11394
+ var _a, _b, _c, _d;
11395
+ const value = (_a = promotion.application_method) == null ? void 0 : _a.value;
11396
+ if (!value) {
11397
+ return null;
11380
11398
  }
11381
- return Object.entries(metadata).map(([key, value]) => {
11382
- if (!EDITABLE_TYPES.includes(typeof value)) {
11383
- return {
11384
- key,
11385
- value,
11386
- disabled: true
11387
- };
11388
- }
11389
- let stringValue = value;
11390
- if (typeof value !== "string") {
11391
- stringValue = JSON.stringify(value);
11399
+ if (((_b = promotion.application_method) == null ? void 0 : _b.type) === "fixed") {
11400
+ const currency = (_c = promotion.application_method) == null ? void 0 : _c.currency_code;
11401
+ if (!currency) {
11402
+ return null;
11392
11403
  }
11393
- return {
11394
- key,
11395
- value: stringValue,
11396
- original_key: key
11397
- };
11398
- });
11404
+ return getLocaleAmount(value, currency);
11405
+ } else if (((_d = promotion.application_method) == null ? void 0 : _d.type) === "percentage") {
11406
+ return formatPercentage(value);
11407
+ }
11408
+ return null;
11399
11409
  }
11400
- function parseValues(values) {
11401
- const metadata = values.metadata;
11402
- const isEmpty = !metadata.length || metadata.length === 1 && !metadata[0].key && !metadata[0].value;
11403
- if (isEmpty) {
11404
- return null;
11410
+ const formatter = new Intl.NumberFormat([], {
11411
+ style: "percent",
11412
+ minimumFractionDigits: 2
11413
+ });
11414
+ const formatPercentage = (value, isPercentageValue = false) => {
11415
+ let val = value || 0;
11416
+ if (!isPercentageValue) {
11417
+ val = val / 100;
11405
11418
  }
11406
- const update = {};
11407
- metadata.forEach((field) => {
11408
- let key = field.key;
11409
- let value = field.value;
11410
- const disabled = field.disabled;
11411
- if (!key || !value) {
11412
- return;
11413
- }
11414
- if (disabled) {
11415
- update[key] = value;
11416
- return;
11419
+ return formatter.format(val);
11420
+ };
11421
+ function getPromotionCodes(items, shippingMethods) {
11422
+ const codes = /* @__PURE__ */ new Set();
11423
+ for (const item of items) {
11424
+ if (item.adjustments) {
11425
+ for (const adjustment of item.adjustments) {
11426
+ if (adjustment.code) {
11427
+ codes.add(adjustment.code);
11428
+ }
11429
+ }
11417
11430
  }
11418
- key = key.trim();
11419
- value = value.trim();
11420
- if (value === "true") {
11421
- update[key] = true;
11422
- } else if (value === "false") {
11423
- update[key] = false;
11424
- } else {
11425
- const parsedNumber = parseFloat(value);
11426
- if (!isNaN(parsedNumber)) {
11427
- update[key] = parsedNumber;
11428
- } else {
11429
- update[key] = value;
11431
+ }
11432
+ for (const shippingMethod of shippingMethods) {
11433
+ if (shippingMethod.adjustments) {
11434
+ for (const adjustment of shippingMethod.adjustments) {
11435
+ if (adjustment.code) {
11436
+ codes.add(adjustment.code);
11437
+ }
11430
11438
  }
11431
11439
  }
11432
- });
11433
- return update;
11434
- }
11435
- function getHasUneditableRows(metadata) {
11436
- if (!metadata) {
11437
- return false;
11438
11440
  }
11439
- return Object.values(metadata).some(
11440
- (value) => !EDITABLE_TYPES.includes(typeof value)
11441
- );
11441
+ return Array.from(codes);
11442
11442
  }
11443
11443
  const SalesChannel = () => {
11444
11444
  const { id } = reactRouterDom.useParams();
@@ -13056,26 +13056,26 @@ const routeModule = {
13056
13056
  Component: BillingAddress,
13057
13057
  path: "/draft-orders/:id/billing-address"
13058
13058
  },
13059
- {
13060
- Component: CustomItems,
13061
- path: "/draft-orders/:id/custom-items"
13062
- },
13063
13059
  {
13064
13060
  Component: Email,
13065
13061
  path: "/draft-orders/:id/email"
13066
13062
  },
13067
13063
  {
13068
- Component: Items,
13069
- path: "/draft-orders/:id/items"
13064
+ Component: CustomItems,
13065
+ path: "/draft-orders/:id/custom-items"
13070
13066
  },
13071
13067
  {
13072
- Component: Promotions,
13073
- path: "/draft-orders/:id/promotions"
13068
+ Component: Items,
13069
+ path: "/draft-orders/:id/items"
13074
13070
  },
13075
13071
  {
13076
13072
  Component: Metadata,
13077
13073
  path: "/draft-orders/:id/metadata"
13078
13074
  },
13075
+ {
13076
+ Component: Promotions,
13077
+ path: "/draft-orders/:id/promotions"
13078
+ },
13079
13079
  {
13080
13080
  Component: SalesChannel,
13081
13081
  path: "/draft-orders/:id/sales-channel"