@medusajs/draft-order 2.10.1-snapshot-20250828204656 → 2.10.2-snapshot-20250829071156

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.
@@ -10813,739 +10813,739 @@ 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
- }
10919
+ }
10920
+ function insertRow(index, position) {
10921
+ insert(index + (position === "above" ? 0 : 1), {
10922
+ key: "",
10923
+ value: "",
10924
+ disabled: false
10934
10925
  });
10935
- };
10936
- if (isError) {
10937
- throw error;
10938
10926
  }
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",
10927
+ return /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxRuntime.jsxs(
10928
+ KeyboundForm,
11009
10929
  {
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
- ),
10930
+ onSubmit: handleSubmit,
10931
+ className: "flex flex-1 flex-col overflow-hidden",
11016
10932
  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: "·" })
10933
+ /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer.Body, { className: "flex flex-1 flex-col gap-y-8 overflow-y-auto", children: [
10934
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-base shadow-elevation-card-rest grid grid-cols-1 divide-y rounded-lg", children: [
10935
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-subtle grid grid-cols-2 divide-x rounded-t-lg", children: [
10936
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "txt-compact-small-plus text-ui-fg-subtle px-2 py-1.5", children: /* @__PURE__ */ jsxRuntime.jsx("label", { id: METADATA_KEY_LABEL_ID, children: "Key" }) }),
10937
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "txt-compact-small-plus text-ui-fg-subtle px-2 py-1.5", children: /* @__PURE__ */ jsxRuntime.jsx("label", { id: METADATA_VALUE_LABEL_ID, children: "Value" }) })
11023
10938
  ] }),
11024
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", leading: "compact", className: "capitalize", children: (_a = promotion.application_method) == null ? void 0 : _a.allocation })
11025
- ] })
10939
+ fields.map((field, index) => {
10940
+ const isDisabled = field.disabled || false;
10941
+ let placeholder = "-";
10942
+ if (typeof field.value === "object") {
10943
+ placeholder = "{ ... }";
10944
+ }
10945
+ if (Array.isArray(field.value)) {
10946
+ placeholder = "[ ... ]";
10947
+ }
10948
+ return /* @__PURE__ */ jsxRuntime.jsx(
10949
+ ConditionalTooltip,
10950
+ {
10951
+ showTooltip: isDisabled,
10952
+ content: "This row is disabled because it contains non-primitive data.",
10953
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "group/table relative", children: [
10954
+ /* @__PURE__ */ jsxRuntime.jsxs(
10955
+ "div",
10956
+ {
10957
+ className: ui.clx("grid grid-cols-2 divide-x", {
10958
+ "overflow-hidden rounded-b-lg": index === fields.length - 1
10959
+ }),
10960
+ children: [
10961
+ /* @__PURE__ */ jsxRuntime.jsx(
10962
+ Form$2.Field,
10963
+ {
10964
+ control: form.control,
10965
+ name: `metadata.${index}.key`,
10966
+ render: ({ field: field2 }) => {
10967
+ return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
10968
+ GridInput,
10969
+ {
10970
+ "aria-labelledby": METADATA_KEY_LABEL_ID,
10971
+ ...field2,
10972
+ disabled: isDisabled,
10973
+ placeholder: "Key"
10974
+ }
10975
+ ) }) });
10976
+ }
10977
+ }
10978
+ ),
10979
+ /* @__PURE__ */ jsxRuntime.jsx(
10980
+ Form$2.Field,
10981
+ {
10982
+ control: form.control,
10983
+ name: `metadata.${index}.value`,
10984
+ render: ({ field: { value, ...field2 } }) => {
10985
+ return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
10986
+ GridInput,
10987
+ {
10988
+ "aria-labelledby": METADATA_VALUE_LABEL_ID,
10989
+ ...field2,
10990
+ value: isDisabled ? placeholder : value,
10991
+ disabled: isDisabled,
10992
+ placeholder: "Value"
10993
+ }
10994
+ ) }) });
10995
+ }
10996
+ }
10997
+ )
10998
+ ]
10999
+ }
11000
+ ),
11001
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu, { children: [
11002
+ /* @__PURE__ */ jsxRuntime.jsx(
11003
+ ui.DropdownMenu.Trigger,
11004
+ {
11005
+ className: ui.clx(
11006
+ "invisible absolute inset-y-0 -right-2.5 my-auto group-hover/table:visible data-[state='open']:visible",
11007
+ {
11008
+ hidden: isDisabled
11009
+ }
11010
+ ),
11011
+ disabled: isDisabled,
11012
+ asChild: true,
11013
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { size: "2xsmall", children: /* @__PURE__ */ jsxRuntime.jsx(icons.EllipsisVertical, {}) })
11014
+ }
11015
+ ),
11016
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu.Content, { children: [
11017
+ /* @__PURE__ */ jsxRuntime.jsxs(
11018
+ ui.DropdownMenu.Item,
11019
+ {
11020
+ className: "gap-x-2",
11021
+ onClick: () => insertRow(index, "above"),
11022
+ children: [
11023
+ /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowUpMini, { className: "text-ui-fg-subtle" }),
11024
+ "Insert row above"
11025
+ ]
11026
+ }
11027
+ ),
11028
+ /* @__PURE__ */ jsxRuntime.jsxs(
11029
+ ui.DropdownMenu.Item,
11030
+ {
11031
+ className: "gap-x-2",
11032
+ onClick: () => insertRow(index, "below"),
11033
+ children: [
11034
+ /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowDownMini, { className: "text-ui-fg-subtle" }),
11035
+ "Insert row below"
11036
+ ]
11037
+ }
11038
+ ),
11039
+ /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenu.Separator, {}),
11040
+ /* @__PURE__ */ jsxRuntime.jsxs(
11041
+ ui.DropdownMenu.Item,
11042
+ {
11043
+ className: "gap-x-2",
11044
+ onClick: () => deleteRow(index),
11045
+ children: [
11046
+ /* @__PURE__ */ jsxRuntime.jsx(icons.Trash, { className: "text-ui-fg-subtle" }),
11047
+ "Delete row"
11048
+ ]
11049
+ }
11050
+ )
11051
+ ] })
11052
+ ] })
11053
+ ] })
11054
+ },
11055
+ field.id
11056
+ );
11057
+ })
11058
+ ] }),
11059
+ hasUneditableRows && /* @__PURE__ */ jsxRuntime.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." })
11026
11060
  ] }),
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
- )
11061
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
11062
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
11063
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", type: "submit", isLoading: isPending, children: "Save" })
11064
+ ] }) })
11038
11065
  ]
11039
- },
11040
- promotion.id
11041
- );
11066
+ }
11067
+ ) });
11042
11068
  };
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;
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
+ )
11053
11080
  }
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
11081
+ );
11063
11082
  });
11064
- const formatPercentage = (value, isPercentageValue = false) => {
11065
- let val = value || 0;
11066
- if (!isPercentageValue) {
11067
- val = val / 100;
11068
- }
11069
- return formatter.format(val);
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
+ ] });
11070
11092
  };
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
- }
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
11079
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);
11080
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;
11081
11128
  }
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
- }
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;
11088
11153
  }
11089
11154
  }
11155
+ });
11156
+ return update;
11157
+ }
11158
+ function getHasUneditableRows(metadata) {
11159
+ if (!metadata) {
11160
+ return false;
11090
11161
  }
11091
- return Array.from(codes);
11162
+ return Object.values(metadata).some(
11163
+ (value) => !EDITABLE_TYPES.includes(typeof value)
11164
+ );
11092
11165
  }
11093
- const SalesChannel = () => {
11094
- const { id } = reactRouterDom.useParams();
11095
- const { draft_order, isPending, isError, error } = useDraftOrder(
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,
11096
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(
11097
11212
  {
11098
- fields: "+sales_channel_id"
11213
+ code: promoCodes
11099
11214
  },
11100
11215
  {
11101
- enabled: !!id
11216
+ enabled: !!promoCodes.length
11102
11217
  }
11103
11218
  );
11104
- if (isError) {
11105
- throw error;
11106
- }
11107
- const ISrEADY = !!draft_order && !isPending;
11108
- return /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer, { children: [
11109
- /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer.Header, { children: [
11110
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Edit Sales Channel" }) }),
11111
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Description, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Update which sales channel the draft order is associated with" }) })
11112
- ] }),
11113
- ISrEADY && /* @__PURE__ */ jsxRuntime.jsx(SalesChannelForm, { order: draft_order })
11114
- ] });
11115
- };
11116
- const SalesChannelForm = ({ order }) => {
11117
- const form = reactHookForm.useForm({
11118
- defaultValues: {
11119
- sales_channel_id: order.sales_channel_id || ""
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
+ });
11120
11228
  },
11121
- resolver: zod.zodResolver(schema$2)
11229
+ getOptions: (data) => {
11230
+ return data.promotions.map((promotion) => ({
11231
+ label: promotion.code,
11232
+ value: promotion.code
11233
+ }));
11234
+ }
11122
11235
  });
11123
- const { mutateAsync, isPending } = useUpdateDraftOrder(order.id);
11124
- const { handleSuccess } = useRouteModal();
11125
- const onSubmit = form.handleSubmit(async (data) => {
11126
- await mutateAsync(
11236
+ const add = async (value) => {
11237
+ if (!value) {
11238
+ return;
11239
+ }
11240
+ addPromotions(
11127
11241
  {
11128
- sales_channel_id: data.sales_channel_id
11242
+ promo_codes: [value]
11129
11243
  },
11130
11244
  {
11131
- onSuccess: () => {
11132
- ui.toast.success("Sales channel updated");
11133
- handleSuccess();
11245
+ onError: (e) => {
11246
+ ui.toast.error(e.message);
11247
+ comboboxData.onSearchValueChange("");
11248
+ setComboboxValue("");
11134
11249
  },
11135
- onError: (error) => {
11136
- ui.toast.error(error.message);
11250
+ onSuccess: () => {
11251
+ comboboxData.onSearchValueChange("");
11252
+ setComboboxValue("");
11137
11253
  }
11138
11254
  }
11139
11255
  );
11140
- });
11141
- return /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxRuntime.jsxs(
11142
- KeyboundForm,
11143
- {
11144
- className: "flex flex-1 flex-col overflow-hidden",
11145
- onSubmit,
11146
- children: [
11147
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Body, { className: "flex flex-col gap-y-6 overflow-y-auto", children: /* @__PURE__ */ jsxRuntime.jsx(SalesChannelField, { control: form.control, order }) }),
11148
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-2", children: [
11149
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
11150
- /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", type: "submit", isLoading: isPending, children: "Save" })
11151
- ] }) })
11152
- ]
11153
- }
11154
- ) });
11155
- };
11156
- const SalesChannelField = ({ control, order }) => {
11157
- const salesChannels = useComboboxData({
11158
- queryFn: async (params) => {
11159
- return await sdk.admin.salesChannel.list(params);
11160
- },
11161
- queryKey: ["sales-channels"],
11162
- getOptions: (data) => {
11163
- return data.sales_channels.map((salesChannel) => ({
11164
- label: salesChannel.name,
11165
- value: salesChannel.id
11166
- }));
11167
- },
11168
- defaultValue: order.sales_channel_id || void 0
11169
- });
11170
- return /* @__PURE__ */ jsxRuntime.jsx(
11171
- Form$2.Field,
11172
- {
11173
- control,
11174
- name: "sales_channel_id",
11175
- render: ({ field }) => {
11176
- return /* @__PURE__ */ jsxRuntime.jsxs(Form$2.Item, { children: [
11177
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.Label, { children: "Sales Channel" }),
11178
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
11179
- Combobox,
11180
- {
11181
- options: salesChannels.options,
11182
- fetchNextPage: salesChannels.fetchNextPage,
11183
- isFetchingNextPage: salesChannels.isFetchingNextPage,
11184
- searchValue: salesChannels.searchValue,
11185
- onSearchValueChange: salesChannels.onSearchValueChange,
11186
- placeholder: "Select sales channel",
11187
- ...field
11188
- }
11189
- ) }),
11190
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.ErrorMessage, {})
11191
- ] });
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;
11192
11268
  }
11269
+ });
11270
+ if (!requestSucceeded) {
11271
+ setIsSubmitting(false);
11272
+ return;
11193
11273
  }
11194
- );
11195
- };
11196
- const schema$2 = objectType({
11197
- sales_channel_id: stringType().min(1)
11198
- });
11199
- const InlineTip = React.forwardRef(
11200
- ({ variant = "tip", label, className, children, ...props }, ref) => {
11201
- const labelValue = label || (variant === "warning" ? "Warning" : "Tip");
11202
- return /* @__PURE__ */ jsxRuntime.jsxs(
11203
- "div",
11204
- {
11205
- ref,
11206
- className: ui.clx(
11207
- "bg-ui-bg-component txt-small text-ui-fg-subtle grid grid-cols-[4px_1fr] items-start gap-3 rounded-lg border p-3",
11208
- className
11209
- ),
11210
- ...props,
11211
- children: [
11212
- /* @__PURE__ */ jsxRuntime.jsx(
11213
- "div",
11214
- {
11215
- role: "presentation",
11216
- className: ui.clx("w-4px bg-ui-tag-neutral-icon h-full rounded-full", {
11217
- "bg-ui-tag-orange-icon": variant === "warning"
11218
- })
11219
- }
11220
- ),
11221
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-pretty", children: [
11222
- /* @__PURE__ */ jsxRuntime.jsxs("strong", { className: "txt-small-plus text-ui-fg-base", children: [
11223
- labelValue,
11224
- ":"
11225
- ] }),
11226
- " ",
11227
- children
11228
- ] })
11229
- ]
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);
11230
11283
  }
11231
- );
11232
- }
11233
- );
11234
- InlineTip.displayName = "InlineTip";
11235
- const MetadataFieldSchema = objectType({
11236
- key: stringType(),
11237
- disabled: booleanType().optional(),
11238
- value: anyType()
11239
- });
11240
- const MetadataSchema = objectType({
11241
- metadata: arrayType(MetadataFieldSchema)
11242
- });
11243
- const Metadata = () => {
11244
- const { id } = reactRouterDom.useParams();
11245
- const { order, isPending, isError, error } = useOrder(id, {
11246
- fields: "metadata"
11247
- });
11284
+ });
11285
+ };
11248
11286
  if (isError) {
11249
11287
  throw error;
11250
11288
  }
11251
- const isReady = !isPending && !!order;
11252
- return /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer, { children: [
11253
- /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer.Header, { children: [
11254
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Metadata" }) }),
11255
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Description, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Add metadata to the draft order." }) })
11256
- ] }),
11257
- !isReady ? /* @__PURE__ */ jsxRuntime.jsx(PlaceholderInner, {}) : /* @__PURE__ */ jsxRuntime.jsx(MetadataForm, { orderId: id, metadata: order == null ? void 0 : order.metadata })
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
+ }
11333
+ )
11334
+ ] }) })
11258
11335
  ] });
11259
11336
  };
11260
- const METADATA_KEY_LABEL_ID = "metadata-form-key-label";
11261
- const METADATA_VALUE_LABEL_ID = "metadata-form-value-label";
11262
- const MetadataForm = ({ orderId, metadata }) => {
11263
- const { handleSuccess } = useRouteModal();
11264
- const hasUneditableRows = getHasUneditableRows(metadata);
11265
- const { mutateAsync, isPending } = useUpdateDraftOrder(orderId);
11266
- const form = reactHookForm.useForm({
11267
- defaultValues: {
11268
- metadata: getDefaultValues(metadata)
11269
- },
11270
- resolver: zod.zodResolver(MetadataSchema)
11271
- });
11272
- const handleSubmit = form.handleSubmit(async (data) => {
11273
- const parsedData = parseValues(data);
11274
- await mutateAsync(
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(
11275
11346
  {
11276
- metadata: parsedData
11347
+ promo_codes: [promotion.code]
11277
11348
  },
11278
11349
  {
11279
- onSuccess: () => {
11280
- ui.toast.success("Metadata updated");
11281
- handleSuccess();
11282
- },
11283
- onError: (error) => {
11284
- ui.toast.error(error.message);
11350
+ onError: (e) => {
11351
+ ui.toast.error(e.message);
11285
11352
  }
11286
11353
  }
11287
11354
  );
11288
- });
11289
- const { fields, insert, remove } = reactHookForm.useFieldArray({
11290
- control: form.control,
11291
- name: "metadata"
11292
- });
11293
- function deleteRow(index) {
11294
- remove(index);
11295
- if (fields.length === 1) {
11296
- insert(0, {
11297
- key: "",
11298
- value: "",
11299
- disabled: false
11300
- });
11301
- }
11302
- }
11303
- function insertRow(index, position) {
11304
- insert(index + (position === "above" ? 0 : 1), {
11305
- key: "",
11306
- value: "",
11307
- disabled: false
11308
- });
11309
- }
11310
- return /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxRuntime.jsxs(
11311
- KeyboundForm,
11355
+ };
11356
+ const displayValue = getDisplayValue(promotion);
11357
+ return /* @__PURE__ */ jsxRuntime.jsxs(
11358
+ "div",
11312
11359
  {
11313
- onSubmit: handleSubmit,
11314
- className: "flex flex-1 flex-col overflow-hidden",
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
+ ),
11315
11366
  children: [
11316
- /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer.Body, { className: "flex flex-1 flex-col gap-y-8 overflow-y-auto", children: [
11317
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-base shadow-elevation-card-rest grid grid-cols-1 divide-y rounded-lg", children: [
11318
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-subtle grid grid-cols-2 divide-x rounded-t-lg", children: [
11319
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "txt-compact-small-plus text-ui-fg-subtle px-2 py-1.5", children: /* @__PURE__ */ jsxRuntime.jsx("label", { id: METADATA_KEY_LABEL_ID, children: "Key" }) }),
11320
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "txt-compact-small-plus text-ui-fg-subtle px-2 py-1.5", children: /* @__PURE__ */ jsxRuntime.jsx("label", { id: METADATA_VALUE_LABEL_ID, children: "Value" }) })
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: "·" })
11321
11373
  ] }),
11322
- fields.map((field, index) => {
11323
- const isDisabled = field.disabled || false;
11324
- let placeholder = "-";
11325
- if (typeof field.value === "object") {
11326
- placeholder = "{ ... }";
11327
- }
11328
- if (Array.isArray(field.value)) {
11329
- placeholder = "[ ... ]";
11330
- }
11331
- return /* @__PURE__ */ jsxRuntime.jsx(
11332
- ConditionalTooltip,
11333
- {
11334
- showTooltip: isDisabled,
11335
- content: "This row is disabled because it contains non-primitive data.",
11336
- children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "group/table relative", children: [
11337
- /* @__PURE__ */ jsxRuntime.jsxs(
11338
- "div",
11339
- {
11340
- className: ui.clx("grid grid-cols-2 divide-x", {
11341
- "overflow-hidden rounded-b-lg": index === fields.length - 1
11342
- }),
11343
- children: [
11344
- /* @__PURE__ */ jsxRuntime.jsx(
11345
- Form$2.Field,
11346
- {
11347
- control: form.control,
11348
- name: `metadata.${index}.key`,
11349
- render: ({ field: field2 }) => {
11350
- return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
11351
- GridInput,
11352
- {
11353
- "aria-labelledby": METADATA_KEY_LABEL_ID,
11354
- ...field2,
11355
- disabled: isDisabled,
11356
- placeholder: "Key"
11357
- }
11358
- ) }) });
11359
- }
11360
- }
11361
- ),
11362
- /* @__PURE__ */ jsxRuntime.jsx(
11363
- Form$2.Field,
11364
- {
11365
- control: form.control,
11366
- name: `metadata.${index}.value`,
11367
- render: ({ field: { value, ...field2 } }) => {
11368
- return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
11369
- GridInput,
11370
- {
11371
- "aria-labelledby": METADATA_VALUE_LABEL_ID,
11372
- ...field2,
11373
- value: isDisabled ? placeholder : value,
11374
- disabled: isDisabled,
11375
- placeholder: "Value"
11376
- }
11377
- ) }) });
11378
- }
11379
- }
11380
- )
11381
- ]
11382
- }
11383
- ),
11384
- /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu, { children: [
11385
- /* @__PURE__ */ jsxRuntime.jsx(
11386
- ui.DropdownMenu.Trigger,
11387
- {
11388
- className: ui.clx(
11389
- "invisible absolute inset-y-0 -right-2.5 my-auto group-hover/table:visible data-[state='open']:visible",
11390
- {
11391
- hidden: isDisabled
11392
- }
11393
- ),
11394
- disabled: isDisabled,
11395
- asChild: true,
11396
- children: /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { size: "2xsmall", children: /* @__PURE__ */ jsxRuntime.jsx(icons.EllipsisVertical, {}) })
11397
- }
11398
- ),
11399
- /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu.Content, { children: [
11400
- /* @__PURE__ */ jsxRuntime.jsxs(
11401
- ui.DropdownMenu.Item,
11402
- {
11403
- className: "gap-x-2",
11404
- onClick: () => insertRow(index, "above"),
11405
- children: [
11406
- /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowUpMini, { className: "text-ui-fg-subtle" }),
11407
- "Insert row above"
11408
- ]
11409
- }
11410
- ),
11411
- /* @__PURE__ */ jsxRuntime.jsxs(
11412
- ui.DropdownMenu.Item,
11413
- {
11414
- className: "gap-x-2",
11415
- onClick: () => insertRow(index, "below"),
11416
- children: [
11417
- /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowDownMini, { className: "text-ui-fg-subtle" }),
11418
- "Insert row below"
11419
- ]
11420
- }
11421
- ),
11422
- /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenu.Separator, {}),
11423
- /* @__PURE__ */ jsxRuntime.jsxs(
11424
- ui.DropdownMenu.Item,
11425
- {
11426
- className: "gap-x-2",
11427
- onClick: () => deleteRow(index),
11428
- children: [
11429
- /* @__PURE__ */ jsxRuntime.jsx(icons.Trash, { className: "text-ui-fg-subtle" }),
11430
- "Delete row"
11431
- ]
11432
- }
11433
- )
11434
- ] })
11435
- ] })
11436
- ] })
11437
- },
11438
- field.id
11439
- );
11440
- })
11441
- ] }),
11442
- hasUneditableRows && /* @__PURE__ */ jsxRuntime.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." })
11374
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", leading: "compact", className: "capitalize", children: (_a = promotion.application_method) == null ? void 0 : _a.allocation })
11375
+ ] })
11443
11376
  ] }),
11444
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
11445
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
11446
- /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", type: "submit", isLoading: isPending, children: "Save" })
11447
- ] }) })
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
+ )
11448
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;
11398
+ }
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;
11449
11403
  }
11450
- ) });
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;
11409
+ }
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;
11418
+ }
11419
+ return formatter.format(val);
11451
11420
  };
11452
- const GridInput = React.forwardRef(({ className, ...props }, ref) => {
11453
- return /* @__PURE__ */ jsxRuntime.jsx(
11454
- "input",
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
+ }
11430
+ }
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
+ }
11438
+ }
11439
+ }
11440
+ }
11441
+ return Array.from(codes);
11442
+ }
11443
+ const SalesChannel = () => {
11444
+ const { id } = reactRouterDom.useParams();
11445
+ const { draft_order, isPending, isError, error } = useDraftOrder(
11446
+ id,
11455
11447
  {
11456
- ref,
11457
- ...props,
11458
- autoComplete: "off",
11459
- className: ui.clx(
11460
- "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",
11461
- className
11462
- )
11448
+ fields: "+sales_channel_id"
11449
+ },
11450
+ {
11451
+ enabled: !!id
11463
11452
  }
11464
11453
  );
11465
- });
11466
- GridInput.displayName = "MetadataForm.GridInput";
11467
- const PlaceholderInner = () => {
11468
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col overflow-hidden", children: [
11469
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Body, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: "h-[148ox] w-full rounded-lg" }) }),
11470
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
11471
- /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: "h-7 w-12 rounded-md" }),
11472
- /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: "h-7 w-12 rounded-md" })
11473
- ] }) })
11454
+ if (isError) {
11455
+ throw error;
11456
+ }
11457
+ const ISrEADY = !!draft_order && !isPending;
11458
+ return /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer, { children: [
11459
+ /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer.Header, { children: [
11460
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Edit Sales Channel" }) }),
11461
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Description, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Update which sales channel the draft order is associated with" }) })
11462
+ ] }),
11463
+ ISrEADY && /* @__PURE__ */ jsxRuntime.jsx(SalesChannelForm, { order: draft_order })
11474
11464
  ] });
11475
11465
  };
11476
- const EDITABLE_TYPES = ["string", "number", "boolean"];
11477
- function getDefaultValues(metadata) {
11478
- if (!metadata || !Object.keys(metadata).length) {
11479
- return [
11466
+ const SalesChannelForm = ({ order }) => {
11467
+ const form = reactHookForm.useForm({
11468
+ defaultValues: {
11469
+ sales_channel_id: order.sales_channel_id || ""
11470
+ },
11471
+ resolver: zod.zodResolver(schema$2)
11472
+ });
11473
+ const { mutateAsync, isPending } = useUpdateDraftOrder(order.id);
11474
+ const { handleSuccess } = useRouteModal();
11475
+ const onSubmit = form.handleSubmit(async (data) => {
11476
+ await mutateAsync(
11480
11477
  {
11481
- key: "",
11482
- value: "",
11483
- disabled: false
11478
+ sales_channel_id: data.sales_channel_id
11479
+ },
11480
+ {
11481
+ onSuccess: () => {
11482
+ ui.toast.success("Sales channel updated");
11483
+ handleSuccess();
11484
+ },
11485
+ onError: (error) => {
11486
+ ui.toast.error(error.message);
11487
+ }
11484
11488
  }
11485
- ];
11486
- }
11487
- return Object.entries(metadata).map(([key, value]) => {
11488
- if (!EDITABLE_TYPES.includes(typeof value)) {
11489
- return {
11490
- key,
11491
- value,
11492
- disabled: true
11493
- };
11494
- }
11495
- let stringValue = value;
11496
- if (typeof value !== "string") {
11497
- stringValue = JSON.stringify(value);
11498
- }
11499
- return {
11500
- key,
11501
- value: stringValue,
11502
- original_key: key
11503
- };
11489
+ );
11504
11490
  });
11505
- }
11506
- function parseValues(values) {
11507
- const metadata = values.metadata;
11508
- const isEmpty = !metadata.length || metadata.length === 1 && !metadata[0].key && !metadata[0].value;
11509
- if (isEmpty) {
11510
- return null;
11511
- }
11512
- const update = {};
11513
- metadata.forEach((field) => {
11514
- let key = field.key;
11515
- let value = field.value;
11516
- const disabled = field.disabled;
11517
- if (!key || !value) {
11518
- return;
11519
- }
11520
- if (disabled) {
11521
- update[key] = value;
11522
- return;
11491
+ return /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxRuntime.jsxs(
11492
+ KeyboundForm,
11493
+ {
11494
+ className: "flex flex-1 flex-col overflow-hidden",
11495
+ onSubmit,
11496
+ children: [
11497
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Body, { className: "flex flex-col gap-y-6 overflow-y-auto", children: /* @__PURE__ */ jsxRuntime.jsx(SalesChannelField, { control: form.control, order }) }),
11498
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-2", children: [
11499
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
11500
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", type: "submit", isLoading: isPending, children: "Save" })
11501
+ ] }) })
11502
+ ]
11523
11503
  }
11524
- key = key.trim();
11525
- value = value.trim();
11526
- if (value === "true") {
11527
- update[key] = true;
11528
- } else if (value === "false") {
11529
- update[key] = false;
11530
- } else {
11531
- const parsedNumber = parseFloat(value);
11532
- if (!isNaN(parsedNumber)) {
11533
- update[key] = parsedNumber;
11534
- } else {
11535
- update[key] = value;
11504
+ ) });
11505
+ };
11506
+ const SalesChannelField = ({ control, order }) => {
11507
+ const salesChannels = useComboboxData({
11508
+ queryFn: async (params) => {
11509
+ return await sdk.admin.salesChannel.list(params);
11510
+ },
11511
+ queryKey: ["sales-channels"],
11512
+ getOptions: (data) => {
11513
+ return data.sales_channels.map((salesChannel) => ({
11514
+ label: salesChannel.name,
11515
+ value: salesChannel.id
11516
+ }));
11517
+ },
11518
+ defaultValue: order.sales_channel_id || void 0
11519
+ });
11520
+ return /* @__PURE__ */ jsxRuntime.jsx(
11521
+ Form$2.Field,
11522
+ {
11523
+ control,
11524
+ name: "sales_channel_id",
11525
+ render: ({ field }) => {
11526
+ return /* @__PURE__ */ jsxRuntime.jsxs(Form$2.Item, { children: [
11527
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.Label, { children: "Sales Channel" }),
11528
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
11529
+ Combobox,
11530
+ {
11531
+ options: salesChannels.options,
11532
+ fetchNextPage: salesChannels.fetchNextPage,
11533
+ isFetchingNextPage: salesChannels.isFetchingNextPage,
11534
+ searchValue: salesChannels.searchValue,
11535
+ onSearchValueChange: salesChannels.onSearchValueChange,
11536
+ placeholder: "Select sales channel",
11537
+ ...field
11538
+ }
11539
+ ) }),
11540
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.ErrorMessage, {})
11541
+ ] });
11536
11542
  }
11537
11543
  }
11538
- });
11539
- return update;
11540
- }
11541
- function getHasUneditableRows(metadata) {
11542
- if (!metadata) {
11543
- return false;
11544
- }
11545
- return Object.values(metadata).some(
11546
- (value) => !EDITABLE_TYPES.includes(typeof value)
11547
11544
  );
11548
- }
11545
+ };
11546
+ const schema$2 = objectType({
11547
+ sales_channel_id: stringType().min(1)
11548
+ });
11549
11549
  const STACKED_FOCUS_MODAL_ID = "shipping-form";
11550
11550
  const Shipping = () => {
11551
11551
  var _a;
@@ -13068,6 +13068,10 @@ const routeModule = {
13068
13068
  Component: Items,
13069
13069
  path: "/draft-orders/:id/items"
13070
13070
  },
13071
+ {
13072
+ Component: Metadata,
13073
+ path: "/draft-orders/:id/metadata"
13074
+ },
13071
13075
  {
13072
13076
  Component: Promotions,
13073
13077
  path: "/draft-orders/:id/promotions"
@@ -13076,10 +13080,6 @@ const routeModule = {
13076
13080
  Component: SalesChannel,
13077
13081
  path: "/draft-orders/:id/sales-channel"
13078
13082
  },
13079
- {
13080
- Component: Metadata,
13081
- path: "/draft-orders/:id/metadata"
13082
- },
13083
13083
  {
13084
13084
  Component: Shipping,
13085
13085
  path: "/draft-orders/:id/shipping"