@medusajs/draft-order 2.11.4-preview-20251129210134 → 2.11.4-preview-20251130000310

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.
@@ -10825,88 +10825,46 @@ const customItemSchema = objectType({
10825
10825
  quantity: numberType(),
10826
10826
  unit_price: unionType([numberType(), stringType()])
10827
10827
  });
10828
- const InlineTip = React.forwardRef(
10829
- ({ variant = "tip", label, className, children, ...props }, ref) => {
10830
- const labelValue = label || (variant === "warning" ? "Warning" : "Tip");
10831
- return /* @__PURE__ */ jsxRuntime.jsxs(
10832
- "div",
10833
- {
10834
- ref,
10835
- className: ui.clx(
10836
- "bg-ui-bg-component txt-small text-ui-fg-subtle grid grid-cols-[4px_1fr] items-start gap-3 rounded-lg border p-3",
10837
- className
10838
- ),
10839
- ...props,
10840
- children: [
10841
- /* @__PURE__ */ jsxRuntime.jsx(
10842
- "div",
10843
- {
10844
- role: "presentation",
10845
- className: ui.clx("w-4px bg-ui-tag-neutral-icon h-full rounded-full", {
10846
- "bg-ui-tag-orange-icon": variant === "warning"
10847
- })
10848
- }
10849
- ),
10850
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-pretty", children: [
10851
- /* @__PURE__ */ jsxRuntime.jsxs("strong", { className: "txt-small-plus text-ui-fg-base", children: [
10852
- labelValue,
10853
- ":"
10854
- ] }),
10855
- " ",
10856
- children
10857
- ] })
10858
- ]
10859
- }
10860
- );
10861
- }
10862
- );
10863
- InlineTip.displayName = "InlineTip";
10864
- const MetadataFieldSchema = objectType({
10865
- key: stringType(),
10866
- disabled: booleanType().optional(),
10867
- value: anyType()
10868
- });
10869
- const MetadataSchema = objectType({
10870
- metadata: arrayType(MetadataFieldSchema)
10871
- });
10872
- const Metadata = () => {
10828
+ const SalesChannel = () => {
10873
10829
  const { id } = reactRouterDom.useParams();
10874
- const { order, isPending, isError, error } = useOrder(id, {
10875
- fields: "metadata"
10876
- });
10830
+ const { draft_order, isPending, isError, error } = useDraftOrder(
10831
+ id,
10832
+ {
10833
+ fields: "+sales_channel_id"
10834
+ },
10835
+ {
10836
+ enabled: !!id
10837
+ }
10838
+ );
10877
10839
  if (isError) {
10878
10840
  throw error;
10879
10841
  }
10880
- const isReady = !isPending && !!order;
10842
+ const ISrEADY = !!draft_order && !isPending;
10881
10843
  return /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer, { children: [
10882
10844
  /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer.Header, { children: [
10883
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Metadata" }) }),
10884
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Description, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Add metadata to the draft order." }) })
10845
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Edit Sales Channel" }) }),
10846
+ /* @__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" }) })
10885
10847
  ] }),
10886
- !isReady ? /* @__PURE__ */ jsxRuntime.jsx(PlaceholderInner, {}) : /* @__PURE__ */ jsxRuntime.jsx(MetadataForm, { orderId: id, metadata: order == null ? void 0 : order.metadata })
10848
+ ISrEADY && /* @__PURE__ */ jsxRuntime.jsx(SalesChannelForm, { order: draft_order })
10887
10849
  ] });
10888
10850
  };
10889
- const METADATA_KEY_LABEL_ID = "metadata-form-key-label";
10890
- const METADATA_VALUE_LABEL_ID = "metadata-form-value-label";
10891
- const MetadataForm = ({ orderId, metadata }) => {
10892
- const { handleSuccess } = useRouteModal();
10893
- const hasUneditableRows = getHasUneditableRows(metadata);
10894
- const { mutateAsync, isPending } = useUpdateDraftOrder(orderId);
10851
+ const SalesChannelForm = ({ order }) => {
10895
10852
  const form = reactHookForm.useForm({
10896
10853
  defaultValues: {
10897
- metadata: getDefaultValues(metadata)
10854
+ sales_channel_id: order.sales_channel_id || ""
10898
10855
  },
10899
- resolver: zod.zodResolver(MetadataSchema)
10856
+ resolver: zod.zodResolver(schema$2)
10900
10857
  });
10901
- const handleSubmit = form.handleSubmit(async (data) => {
10902
- const parsedData = parseValues(data);
10858
+ const { mutateAsync, isPending } = useUpdateDraftOrder(order.id);
10859
+ const { handleSuccess } = useRouteModal();
10860
+ const onSubmit = form.handleSubmit(async (data) => {
10903
10861
  await mutateAsync(
10904
10862
  {
10905
- metadata: parsedData
10863
+ sales_channel_id: data.sales_channel_id
10906
10864
  },
10907
10865
  {
10908
10866
  onSuccess: () => {
10909
- ui.toast.success("Metadata updated");
10867
+ ui.toast.success("Sales channel updated");
10910
10868
  handleSuccess();
10911
10869
  },
10912
10870
  onError: (error) => {
@@ -10915,365 +10873,135 @@ const MetadataForm = ({ orderId, metadata }) => {
10915
10873
  }
10916
10874
  );
10917
10875
  });
10918
- const { fields, insert, remove } = reactHookForm.useFieldArray({
10919
- control: form.control,
10920
- name: "metadata"
10921
- });
10922
- function deleteRow(index) {
10923
- remove(index);
10924
- if (fields.length === 1) {
10925
- insert(0, {
10926
- key: "",
10927
- value: "",
10928
- disabled: false
10929
- });
10930
- }
10931
- }
10932
- function insertRow(index, position) {
10933
- insert(index + (position === "above" ? 0 : 1), {
10934
- key: "",
10935
- value: "",
10936
- disabled: false
10937
- });
10938
- }
10939
10876
  return /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxRuntime.jsxs(
10940
10877
  KeyboundForm,
10941
10878
  {
10942
- onSubmit: handleSubmit,
10943
10879
  className: "flex flex-1 flex-col overflow-hidden",
10880
+ onSubmit,
10944
10881
  children: [
10945
- /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer.Body, { className: "flex flex-1 flex-col gap-y-8 overflow-y-auto", children: [
10946
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-base shadow-elevation-card-rest grid grid-cols-1 divide-y rounded-lg", children: [
10947
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-subtle grid grid-cols-2 divide-x rounded-t-lg", children: [
10948
- /* @__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" }) }),
10949
- /* @__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" }) })
10950
- ] }),
10951
- fields.map((field, index) => {
10952
- const isDisabled = field.disabled || false;
10953
- let placeholder = "-";
10954
- if (typeof field.value === "object") {
10955
- placeholder = "{ ... }";
10956
- }
10957
- if (Array.isArray(field.value)) {
10958
- placeholder = "[ ... ]";
10959
- }
10960
- return /* @__PURE__ */ jsxRuntime.jsx(
10961
- ConditionalTooltip,
10962
- {
10963
- showTooltip: isDisabled,
10964
- content: "This row is disabled because it contains non-primitive data.",
10965
- children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "group/table relative", children: [
10966
- /* @__PURE__ */ jsxRuntime.jsxs(
10967
- "div",
10968
- {
10969
- className: ui.clx("grid grid-cols-2 divide-x", {
10970
- "overflow-hidden rounded-b-lg": index === fields.length - 1
10971
- }),
10972
- children: [
10973
- /* @__PURE__ */ jsxRuntime.jsx(
10974
- Form$2.Field,
10975
- {
10976
- control: form.control,
10977
- name: `metadata.${index}.key`,
10978
- render: ({ field: field2 }) => {
10979
- return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
10980
- GridInput,
10981
- {
10982
- "aria-labelledby": METADATA_KEY_LABEL_ID,
10983
- ...field2,
10984
- disabled: isDisabled,
10985
- placeholder: "Key"
10986
- }
10987
- ) }) });
10988
- }
10989
- }
10990
- ),
10991
- /* @__PURE__ */ jsxRuntime.jsx(
10992
- Form$2.Field,
10993
- {
10994
- control: form.control,
10995
- name: `metadata.${index}.value`,
10996
- render: ({ field: { value, ...field2 } }) => {
10997
- return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
10998
- GridInput,
10999
- {
11000
- "aria-labelledby": METADATA_VALUE_LABEL_ID,
11001
- ...field2,
11002
- value: isDisabled ? placeholder : value,
11003
- disabled: isDisabled,
11004
- placeholder: "Value"
11005
- }
11006
- ) }) });
11007
- }
11008
- }
11009
- )
11010
- ]
11011
- }
11012
- ),
11013
- /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu, { children: [
11014
- /* @__PURE__ */ jsxRuntime.jsx(
11015
- ui.DropdownMenu.Trigger,
11016
- {
11017
- className: ui.clx(
11018
- "invisible absolute inset-y-0 -right-2.5 my-auto group-hover/table:visible data-[state='open']:visible",
11019
- {
11020
- hidden: isDisabled
11021
- }
11022
- ),
11023
- disabled: isDisabled,
11024
- asChild: true,
11025
- children: /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { size: "2xsmall", children: /* @__PURE__ */ jsxRuntime.jsx(icons.EllipsisVertical, {}) })
11026
- }
11027
- ),
11028
- /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu.Content, { children: [
11029
- /* @__PURE__ */ jsxRuntime.jsxs(
11030
- ui.DropdownMenu.Item,
11031
- {
11032
- className: "gap-x-2",
11033
- onClick: () => insertRow(index, "above"),
11034
- children: [
11035
- /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowUpMini, { className: "text-ui-fg-subtle" }),
11036
- "Insert row above"
11037
- ]
11038
- }
11039
- ),
11040
- /* @__PURE__ */ jsxRuntime.jsxs(
11041
- ui.DropdownMenu.Item,
11042
- {
11043
- className: "gap-x-2",
11044
- onClick: () => insertRow(index, "below"),
11045
- children: [
11046
- /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowDownMini, { className: "text-ui-fg-subtle" }),
11047
- "Insert row below"
11048
- ]
11049
- }
11050
- ),
11051
- /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenu.Separator, {}),
11052
- /* @__PURE__ */ jsxRuntime.jsxs(
11053
- ui.DropdownMenu.Item,
11054
- {
11055
- className: "gap-x-2",
11056
- onClick: () => deleteRow(index),
11057
- children: [
11058
- /* @__PURE__ */ jsxRuntime.jsx(icons.Trash, { className: "text-ui-fg-subtle" }),
11059
- "Delete row"
11060
- ]
11061
- }
11062
- )
11063
- ] })
11064
- ] })
11065
- ] })
11066
- },
11067
- field.id
11068
- );
11069
- })
11070
- ] }),
11071
- 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." })
11072
- ] }),
11073
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
11074
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
10882
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Body, { className: "flex flex-col gap-y-6 overflow-y-auto", children: /* @__PURE__ */ jsxRuntime.jsx(SalesChannelField, { control: form.control, order }) }),
10883
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-2", children: [
10884
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
11075
10885
  /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", type: "submit", isLoading: isPending, children: "Save" })
11076
10886
  ] }) })
11077
10887
  ]
11078
10888
  }
11079
10889
  ) });
11080
10890
  };
11081
- const GridInput = React.forwardRef(({ className, ...props }, ref) => {
11082
- return /* @__PURE__ */ jsxRuntime.jsx(
11083
- "input",
11084
- {
11085
- ref,
11086
- ...props,
11087
- autoComplete: "off",
11088
- className: ui.clx(
11089
- "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",
11090
- className
11091
- )
11092
- }
11093
- );
11094
- });
11095
- GridInput.displayName = "MetadataForm.GridInput";
11096
- const PlaceholderInner = () => {
11097
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col overflow-hidden", children: [
11098
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Body, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: "h-[148ox] w-full rounded-lg" }) }),
11099
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
11100
- /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: "h-7 w-12 rounded-md" }),
11101
- /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: "h-7 w-12 rounded-md" })
11102
- ] }) })
11103
- ] });
11104
- };
11105
- const EDITABLE_TYPES = ["string", "number", "boolean"];
11106
- function getDefaultValues(metadata) {
11107
- if (!metadata || !Object.keys(metadata).length) {
11108
- return [
11109
- {
11110
- key: "",
11111
- value: "",
11112
- disabled: false
11113
- }
11114
- ];
11115
- }
11116
- return Object.entries(metadata).map(([key, value]) => {
11117
- if (!EDITABLE_TYPES.includes(typeof value)) {
11118
- return {
11119
- key,
11120
- value,
11121
- disabled: true
11122
- };
11123
- }
11124
- let stringValue = value;
11125
- if (typeof value !== "string") {
11126
- stringValue = JSON.stringify(value);
11127
- }
11128
- return {
11129
- key,
11130
- value: stringValue,
11131
- original_key: key
11132
- };
10891
+ const SalesChannelField = ({ control, order }) => {
10892
+ const salesChannels = useComboboxData({
10893
+ queryFn: async (params) => {
10894
+ return await sdk.admin.salesChannel.list(params);
10895
+ },
10896
+ queryKey: ["sales-channels"],
10897
+ getOptions: (data) => {
10898
+ return data.sales_channels.map((salesChannel) => ({
10899
+ label: salesChannel.name,
10900
+ value: salesChannel.id
10901
+ }));
10902
+ },
10903
+ defaultValue: order.sales_channel_id || void 0
11133
10904
  });
11134
- }
11135
- function parseValues(values) {
11136
- const metadata = values.metadata;
11137
- const isEmpty = !metadata.length || metadata.length === 1 && !metadata[0].key && !metadata[0].value;
11138
- if (isEmpty) {
11139
- return null;
11140
- }
11141
- const update = {};
11142
- metadata.forEach((field) => {
11143
- let key = field.key;
11144
- let value = field.value;
11145
- const disabled = field.disabled;
11146
- if (!key || !value) {
11147
- return;
11148
- }
11149
- if (disabled) {
11150
- update[key] = value;
11151
- return;
11152
- }
11153
- key = key.trim();
11154
- value = value.trim();
11155
- if (value === "true") {
11156
- update[key] = true;
11157
- } else if (value === "false") {
11158
- update[key] = false;
11159
- } else {
11160
- const parsedNumber = parseFloat(value);
11161
- if (!isNaN(parsedNumber)) {
11162
- update[key] = parsedNumber;
11163
- } else {
11164
- update[key] = value;
10905
+ return /* @__PURE__ */ jsxRuntime.jsx(
10906
+ Form$2.Field,
10907
+ {
10908
+ control,
10909
+ name: "sales_channel_id",
10910
+ render: ({ field }) => {
10911
+ return /* @__PURE__ */ jsxRuntime.jsxs(Form$2.Item, { children: [
10912
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.Label, { children: "Sales Channel" }),
10913
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
10914
+ Combobox,
10915
+ {
10916
+ options: salesChannels.options,
10917
+ fetchNextPage: salesChannels.fetchNextPage,
10918
+ isFetchingNextPage: salesChannels.isFetchingNextPage,
10919
+ searchValue: salesChannels.searchValue,
10920
+ onSearchValueChange: salesChannels.onSearchValueChange,
10921
+ placeholder: "Select sales channel",
10922
+ ...field
10923
+ }
10924
+ ) }),
10925
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.ErrorMessage, {})
10926
+ ] });
11165
10927
  }
11166
10928
  }
11167
- });
11168
- return update;
11169
- }
11170
- function getHasUneditableRows(metadata) {
11171
- if (!metadata) {
11172
- return false;
11173
- }
11174
- return Object.values(metadata).some(
11175
- (value) => !EDITABLE_TYPES.includes(typeof value)
11176
10929
  );
11177
- }
11178
- const PROMOTION_QUERY_KEY = "promotions";
11179
- const promotionsQueryKeys = {
11180
- list: (query2) => [
11181
- PROMOTION_QUERY_KEY,
11182
- query2 ? query2 : void 0
11183
- ],
11184
- detail: (id, query2) => [
11185
- PROMOTION_QUERY_KEY,
11186
- id,
11187
- query2 ? query2 : void 0
11188
- ]
11189
- };
11190
- const usePromotions = (query2, options) => {
11191
- const { data, ...rest } = reactQuery.useQuery({
11192
- queryKey: promotionsQueryKeys.list(query2),
11193
- queryFn: async () => sdk.admin.promotion.list(query2),
11194
- ...options
11195
- });
11196
- return { ...data, ...rest };
11197
10930
  };
11198
- const Promotions = () => {
10931
+ const schema$2 = objectType({
10932
+ sales_channel_id: stringType().min(1)
10933
+ });
10934
+ const STACKED_FOCUS_MODAL_ID = "shipping-form";
10935
+ const Shipping = () => {
10936
+ var _a;
11199
10937
  const { id } = reactRouterDom.useParams();
10938
+ const { order, isPending, isError, error } = useOrder(id, {
10939
+ fields: "+items.*,+items.variant.*,+items.variant.product.*,+items.variant.product.shipping_profile.*,+currency_code"
10940
+ });
11200
10941
  const {
11201
10942
  order: preview,
10943
+ isPending: isPreviewPending,
11202
10944
  isError: isPreviewError,
11203
10945
  error: previewError
11204
- } = useOrderPreview(id, void 0);
10946
+ } = useOrderPreview(id);
11205
10947
  useInitiateOrderEdit({ preview });
11206
10948
  const { onCancel } = useCancelOrderEdit({ preview });
10949
+ if (isError) {
10950
+ throw error;
10951
+ }
11207
10952
  if (isPreviewError) {
11208
10953
  throw previewError;
11209
10954
  }
11210
- const isReady = !!preview;
11211
- return /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer, { onClose: onCancel, children: [
11212
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Edit Promotions" }) }) }),
11213
- isReady && /* @__PURE__ */ jsxRuntime.jsx(PromotionForm, { preview })
11214
- ] });
10955
+ const orderHasItems = (((_a = order == null ? void 0 : order.items) == null ? void 0 : _a.length) || 0) > 0;
10956
+ const isReady = preview && !isPreviewPending && order && !isPending;
10957
+ return /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal, { onClose: onCancel, children: !orderHasItems ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-full flex-col overflow-hidden ", children: [
10958
+ /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Header, {}),
10959
+ /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Body, { className: "flex flex-1 flex-col overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-1 flex-col items-center overflow-y-auto", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex w-full max-w-[720px] flex-col gap-y-6 px-6 py-16", children: [
10960
+ /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Shipping" }) }),
10961
+ /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "This draft order currently has no items. Add items to the order before adding shipping." }) })
10962
+ ] }) }) }),
10963
+ /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Footer, { children: /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }) })
10964
+ ] }) : isReady ? /* @__PURE__ */ jsxRuntime.jsx(ShippingForm, { preview, order }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
10965
+ /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Edit Shipping" }) }),
10966
+ /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Loading data for the draft order, please wait..." }) })
10967
+ ] }) });
11215
10968
  };
11216
- const PromotionForm = ({ preview }) => {
11217
- const { items, shipping_methods } = preview;
10969
+ const ShippingForm = ({ preview, order }) => {
10970
+ var _a;
10971
+ const { setIsOpen } = useStackedModal();
11218
10972
  const [isSubmitting, setIsSubmitting] = React.useState(false);
11219
- const [comboboxValue, setComboboxValue] = React.useState("");
11220
- const { handleSuccess } = useRouteModal();
11221
- const { mutateAsync: addPromotions, isPending: isAddingPromotions } = useDraftOrderAddPromotions(preview.id);
11222
- const promoIds = getPromotionIds(items, shipping_methods);
11223
- const { promotions, isPending, isError, error } = usePromotions(
10973
+ const [data, setData] = React.useState(null);
10974
+ const appliedShippingOptionIds = (_a = preview.shipping_methods) == null ? void 0 : _a.map((method) => method.shipping_option_id).filter(Boolean);
10975
+ const { shipping_options } = useShippingOptions(
11224
10976
  {
11225
- id: promoIds
10977
+ id: appliedShippingOptionIds,
10978
+ fields: "+service_zone.*,+service_zone.fulfillment_set.*,+service_zone.fulfillment_set.location.*"
11226
10979
  },
11227
10980
  {
11228
- enabled: !!promoIds.length
10981
+ enabled: appliedShippingOptionIds.length > 0
11229
10982
  }
11230
10983
  );
11231
- const comboboxData = useComboboxData({
11232
- queryKey: ["promotions", "combobox", promoIds],
11233
- queryFn: async (params) => {
11234
- return await sdk.admin.promotion.list({
11235
- ...params,
11236
- id: {
11237
- $nin: promoIds
11238
- }
11239
- });
11240
- },
11241
- getOptions: (data) => {
11242
- return data.promotions.map((promotion) => ({
11243
- label: promotion.code,
11244
- value: promotion.code
11245
- }));
11246
- }
11247
- });
11248
- const add = async (value) => {
11249
- if (!value) {
11250
- return;
11251
- }
11252
- addPromotions(
11253
- {
11254
- promo_codes: [value]
11255
- },
11256
- {
11257
- onError: (e) => {
11258
- ui.toast.error(e.message);
11259
- comboboxData.onSearchValueChange("");
11260
- setComboboxValue("");
11261
- },
11262
- onSuccess: () => {
11263
- comboboxData.onSearchValueChange("");
11264
- setComboboxValue("");
11265
- }
11266
- }
11267
- );
11268
- };
10984
+ const uniqueShippingProfiles = React.useMemo(() => {
10985
+ const profiles = /* @__PURE__ */ new Map();
10986
+ getUniqueShippingProfiles(order.items).forEach((profile) => {
10987
+ profiles.set(profile.id, profile);
10988
+ });
10989
+ shipping_options == null ? void 0 : shipping_options.forEach((option) => {
10990
+ profiles.set(option.shipping_profile_id, option.shipping_profile);
10991
+ });
10992
+ return Array.from(profiles.values());
10993
+ }, [order.items, shipping_options]);
10994
+ const { handleSuccess } = useRouteModal();
11269
10995
  const { mutateAsync: confirmOrderEdit } = useDraftOrderConfirmEdit(preview.id);
11270
- const { mutateAsync: requestOrderEdit } = useOrderEditRequest(preview.id);
10996
+ const { mutateAsync: requestOrderEdit } = useDraftOrderRequestEdit(preview.id);
10997
+ const { mutateAsync: removeShippingMethod } = useDraftOrderRemoveShippingMethod(preview.id);
10998
+ const { mutateAsync: removeActionShippingMethod } = useDraftOrderRemoveActionShippingMethod(preview.id);
11271
10999
  const onSubmit = async () => {
11272
11000
  setIsSubmitting(true);
11273
11001
  let requestSucceeded = false;
11274
11002
  await requestOrderEdit(void 0, {
11275
11003
  onError: (e) => {
11276
- ui.toast.error(e.message);
11004
+ ui.toast.error(`Failed to request order edit: ${e.message}`);
11277
11005
  },
11278
11006
  onSuccess: () => {
11279
11007
  requestSucceeded = true;
@@ -11285,7 +11013,7 @@ const PromotionForm = ({ preview }) => {
11285
11013
  }
11286
11014
  await confirmOrderEdit(void 0, {
11287
11015
  onError: (e) => {
11288
- ui.toast.error(e.message);
11016
+ ui.toast.error(`Failed to confirm order edit: ${e.message}`);
11289
11017
  },
11290
11018
  onSuccess: () => {
11291
11019
  handleSuccess();
@@ -11295,371 +11023,16 @@ const PromotionForm = ({ preview }) => {
11295
11023
  }
11296
11024
  });
11297
11025
  };
11298
- if (isError) {
11299
- throw error;
11300
- }
11301
- return /* @__PURE__ */ jsxRuntime.jsxs(KeyboundForm, { className: "flex flex-1 flex-col", onSubmit, children: [
11302
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Body, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-4", children: [
11303
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3", children: [
11304
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
11305
- /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: "small", weight: "plus", htmlFor: "promotion-combobox", children: "Apply promotions" }),
11306
- /* @__PURE__ */ jsxRuntime.jsx(ui.Hint, { id: "promotion-combobox-hint", children: "Manage promotions that should be applied to the order." })
11307
- ] }),
11308
- /* @__PURE__ */ jsxRuntime.jsx(
11309
- Combobox,
11310
- {
11311
- id: "promotion-combobox",
11312
- "aria-describedby": "promotion-combobox-hint",
11313
- isFetchingNextPage: comboboxData.isFetchingNextPage,
11314
- fetchNextPage: comboboxData.fetchNextPage,
11315
- options: comboboxData.options,
11316
- onSearchValueChange: comboboxData.onSearchValueChange,
11317
- searchValue: comboboxData.searchValue,
11318
- disabled: comboboxData.disabled || isAddingPromotions,
11319
- onChange: add,
11320
- value: comboboxValue
11321
- }
11322
- )
11323
- ] }),
11324
- /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { variant: "dashed" }),
11325
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-2", children: promotions == null ? void 0 : promotions.map((promotion) => /* @__PURE__ */ jsxRuntime.jsx(
11326
- PromotionItem,
11327
- {
11328
- promotion,
11329
- orderId: preview.id,
11330
- isLoading: isPending
11331
- },
11332
- promotion.id
11333
- )) })
11334
- ] }) }),
11335
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-2", children: [
11336
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
11337
- /* @__PURE__ */ jsxRuntime.jsx(
11338
- ui.Button,
11339
- {
11340
- size: "small",
11341
- type: "submit",
11342
- isLoading: isSubmitting || isAddingPromotions,
11343
- children: "Save"
11344
- }
11345
- )
11346
- ] }) })
11347
- ] });
11348
- };
11349
- const PromotionItem = ({
11350
- promotion,
11351
- orderId,
11352
- isLoading
11353
- }) => {
11354
- var _a;
11355
- const { mutateAsync: removePromotions, isPending } = useDraftOrderRemovePromotions(orderId);
11356
- const onRemove = async () => {
11357
- removePromotions(
11358
- {
11359
- promo_codes: [promotion.code]
11360
- },
11361
- {
11362
- onError: (e) => {
11363
- ui.toast.error(e.message);
11364
- }
11365
- }
11366
- );
11367
- };
11368
- const displayValue = getDisplayValue(promotion);
11369
- return /* @__PURE__ */ jsxRuntime.jsxs(
11370
- "div",
11371
- {
11372
- className: ui.clx(
11373
- "bg-ui-bg-component shadow-elevation-card-rest flex items-center justify-between rounded-lg px-3 py-2",
11374
- {
11375
- "animate-pulse": isLoading
11376
- }
11377
- ),
11378
- children: [
11379
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
11380
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", leading: "compact", children: promotion.code }),
11381
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-ui-fg-subtle flex items-center gap-1.5", children: [
11382
- displayValue && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
11383
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", leading: "compact", children: displayValue }),
11384
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", leading: "compact", children: "·" })
11385
- ] }),
11386
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", leading: "compact", className: "capitalize", children: (_a = promotion.application_method) == null ? void 0 : _a.allocation })
11387
- ] })
11388
- ] }),
11389
- /* @__PURE__ */ jsxRuntime.jsx(
11390
- ui.IconButton,
11391
- {
11392
- size: "small",
11393
- type: "button",
11394
- variant: "transparent",
11395
- onClick: onRemove,
11396
- isLoading: isPending || isLoading,
11397
- children: /* @__PURE__ */ jsxRuntime.jsx(icons.XMark, {})
11398
- }
11399
- )
11400
- ]
11401
- },
11402
- promotion.id
11403
- );
11404
- };
11405
- function getDisplayValue(promotion) {
11406
- var _a, _b, _c, _d;
11407
- const value = (_a = promotion.application_method) == null ? void 0 : _a.value;
11408
- if (!value) {
11409
- return null;
11410
- }
11411
- if (((_b = promotion.application_method) == null ? void 0 : _b.type) === "fixed") {
11412
- const currency = (_c = promotion.application_method) == null ? void 0 : _c.currency_code;
11413
- if (!currency) {
11414
- return null;
11415
- }
11416
- return getLocaleAmount(value, currency);
11417
- } else if (((_d = promotion.application_method) == null ? void 0 : _d.type) === "percentage") {
11418
- return formatPercentage(value);
11419
- }
11420
- return null;
11421
- }
11422
- const formatter = new Intl.NumberFormat([], {
11423
- style: "percent",
11424
- minimumFractionDigits: 2
11425
- });
11426
- const formatPercentage = (value, isPercentageValue = false) => {
11427
- let val = value || 0;
11428
- if (!isPercentageValue) {
11429
- val = val / 100;
11430
- }
11431
- return formatter.format(val);
11432
- };
11433
- function getPromotionIds(items, shippingMethods) {
11434
- const promotionIds = /* @__PURE__ */ new Set();
11435
- for (const item of items) {
11436
- if (item.adjustments) {
11437
- for (const adjustment of item.adjustments) {
11438
- if (adjustment.promotion_id) {
11439
- promotionIds.add(adjustment.promotion_id);
11440
- }
11441
- }
11442
- }
11443
- }
11444
- for (const shippingMethod of shippingMethods) {
11445
- if (shippingMethod.adjustments) {
11446
- for (const adjustment of shippingMethod.adjustments) {
11447
- if (adjustment.promotion_id) {
11448
- promotionIds.add(adjustment.promotion_id);
11449
- }
11450
- }
11451
- }
11452
- }
11453
- return Array.from(promotionIds);
11454
- }
11455
- const SalesChannel = () => {
11456
- const { id } = reactRouterDom.useParams();
11457
- const { draft_order, isPending, isError, error } = useDraftOrder(
11458
- id,
11459
- {
11460
- fields: "+sales_channel_id"
11461
- },
11462
- {
11463
- enabled: !!id
11464
- }
11465
- );
11466
- if (isError) {
11467
- throw error;
11468
- }
11469
- const ISrEADY = !!draft_order && !isPending;
11470
- return /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer, { children: [
11471
- /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer.Header, { children: [
11472
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Edit Sales Channel" }) }),
11473
- /* @__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" }) })
11474
- ] }),
11475
- ISrEADY && /* @__PURE__ */ jsxRuntime.jsx(SalesChannelForm, { order: draft_order })
11476
- ] });
11477
- };
11478
- const SalesChannelForm = ({ order }) => {
11479
- const form = reactHookForm.useForm({
11480
- defaultValues: {
11481
- sales_channel_id: order.sales_channel_id || ""
11482
- },
11483
- resolver: zod.zodResolver(schema$2)
11484
- });
11485
- const { mutateAsync, isPending } = useUpdateDraftOrder(order.id);
11486
- const { handleSuccess } = useRouteModal();
11487
- const onSubmit = form.handleSubmit(async (data) => {
11488
- await mutateAsync(
11489
- {
11490
- sales_channel_id: data.sales_channel_id
11491
- },
11492
- {
11493
- onSuccess: () => {
11494
- ui.toast.success("Sales channel updated");
11495
- handleSuccess();
11496
- },
11497
- onError: (error) => {
11498
- ui.toast.error(error.message);
11026
+ const onKeydown = React.useCallback(
11027
+ (e) => {
11028
+ if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) {
11029
+ if (data || isSubmitting) {
11030
+ return;
11499
11031
  }
11032
+ onSubmit();
11500
11033
  }
11501
- );
11502
- });
11503
- return /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxRuntime.jsxs(
11504
- KeyboundForm,
11505
- {
11506
- className: "flex flex-1 flex-col overflow-hidden",
11507
- onSubmit,
11508
- children: [
11509
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Body, { className: "flex flex-col gap-y-6 overflow-y-auto", children: /* @__PURE__ */ jsxRuntime.jsx(SalesChannelField, { control: form.control, order }) }),
11510
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-2", children: [
11511
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
11512
- /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", type: "submit", isLoading: isPending, children: "Save" })
11513
- ] }) })
11514
- ]
11515
- }
11516
- ) });
11517
- };
11518
- const SalesChannelField = ({ control, order }) => {
11519
- const salesChannels = useComboboxData({
11520
- queryFn: async (params) => {
11521
- return await sdk.admin.salesChannel.list(params);
11522
- },
11523
- queryKey: ["sales-channels"],
11524
- getOptions: (data) => {
11525
- return data.sales_channels.map((salesChannel) => ({
11526
- label: salesChannel.name,
11527
- value: salesChannel.id
11528
- }));
11529
11034
  },
11530
- defaultValue: order.sales_channel_id || void 0
11531
- });
11532
- return /* @__PURE__ */ jsxRuntime.jsx(
11533
- Form$2.Field,
11534
- {
11535
- control,
11536
- name: "sales_channel_id",
11537
- render: ({ field }) => {
11538
- return /* @__PURE__ */ jsxRuntime.jsxs(Form$2.Item, { children: [
11539
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.Label, { children: "Sales Channel" }),
11540
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
11541
- Combobox,
11542
- {
11543
- options: salesChannels.options,
11544
- fetchNextPage: salesChannels.fetchNextPage,
11545
- isFetchingNextPage: salesChannels.isFetchingNextPage,
11546
- searchValue: salesChannels.searchValue,
11547
- onSearchValueChange: salesChannels.onSearchValueChange,
11548
- placeholder: "Select sales channel",
11549
- ...field
11550
- }
11551
- ) }),
11552
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.ErrorMessage, {})
11553
- ] });
11554
- }
11555
- }
11556
- );
11557
- };
11558
- const schema$2 = objectType({
11559
- sales_channel_id: stringType().min(1)
11560
- });
11561
- const STACKED_FOCUS_MODAL_ID = "shipping-form";
11562
- const Shipping = () => {
11563
- var _a;
11564
- const { id } = reactRouterDom.useParams();
11565
- const { order, isPending, isError, error } = useOrder(id, {
11566
- fields: "+items.*,+items.variant.*,+items.variant.product.*,+items.variant.product.shipping_profile.*,+currency_code"
11567
- });
11568
- const {
11569
- order: preview,
11570
- isPending: isPreviewPending,
11571
- isError: isPreviewError,
11572
- error: previewError
11573
- } = useOrderPreview(id);
11574
- useInitiateOrderEdit({ preview });
11575
- const { onCancel } = useCancelOrderEdit({ preview });
11576
- if (isError) {
11577
- throw error;
11578
- }
11579
- if (isPreviewError) {
11580
- throw previewError;
11581
- }
11582
- const orderHasItems = (((_a = order == null ? void 0 : order.items) == null ? void 0 : _a.length) || 0) > 0;
11583
- const isReady = preview && !isPreviewPending && order && !isPending;
11584
- return /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal, { onClose: onCancel, children: !orderHasItems ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-full flex-col overflow-hidden ", children: [
11585
- /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Header, {}),
11586
- /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Body, { className: "flex flex-1 flex-col overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-1 flex-col items-center overflow-y-auto", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex w-full max-w-[720px] flex-col gap-y-6 px-6 py-16", children: [
11587
- /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Shipping" }) }),
11588
- /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "This draft order currently has no items. Add items to the order before adding shipping." }) })
11589
- ] }) }) }),
11590
- /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Footer, { children: /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }) })
11591
- ] }) : isReady ? /* @__PURE__ */ jsxRuntime.jsx(ShippingForm, { preview, order }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
11592
- /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Edit Shipping" }) }),
11593
- /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Loading data for the draft order, please wait..." }) })
11594
- ] }) });
11595
- };
11596
- const ShippingForm = ({ preview, order }) => {
11597
- var _a;
11598
- const { setIsOpen } = useStackedModal();
11599
- const [isSubmitting, setIsSubmitting] = React.useState(false);
11600
- const [data, setData] = React.useState(null);
11601
- const appliedShippingOptionIds = (_a = preview.shipping_methods) == null ? void 0 : _a.map((method) => method.shipping_option_id).filter(Boolean);
11602
- const { shipping_options } = useShippingOptions(
11603
- {
11604
- id: appliedShippingOptionIds,
11605
- fields: "+service_zone.*,+service_zone.fulfillment_set.*,+service_zone.fulfillment_set.location.*"
11606
- },
11607
- {
11608
- enabled: appliedShippingOptionIds.length > 0
11609
- }
11610
- );
11611
- const uniqueShippingProfiles = React.useMemo(() => {
11612
- const profiles = /* @__PURE__ */ new Map();
11613
- getUniqueShippingProfiles(order.items).forEach((profile) => {
11614
- profiles.set(profile.id, profile);
11615
- });
11616
- shipping_options == null ? void 0 : shipping_options.forEach((option) => {
11617
- profiles.set(option.shipping_profile_id, option.shipping_profile);
11618
- });
11619
- return Array.from(profiles.values());
11620
- }, [order.items, shipping_options]);
11621
- const { handleSuccess } = useRouteModal();
11622
- const { mutateAsync: confirmOrderEdit } = useDraftOrderConfirmEdit(preview.id);
11623
- const { mutateAsync: requestOrderEdit } = useDraftOrderRequestEdit(preview.id);
11624
- const { mutateAsync: removeShippingMethod } = useDraftOrderRemoveShippingMethod(preview.id);
11625
- const { mutateAsync: removeActionShippingMethod } = useDraftOrderRemoveActionShippingMethod(preview.id);
11626
- const onSubmit = async () => {
11627
- setIsSubmitting(true);
11628
- let requestSucceeded = false;
11629
- await requestOrderEdit(void 0, {
11630
- onError: (e) => {
11631
- ui.toast.error(`Failed to request order edit: ${e.message}`);
11632
- },
11633
- onSuccess: () => {
11634
- requestSucceeded = true;
11635
- }
11636
- });
11637
- if (!requestSucceeded) {
11638
- setIsSubmitting(false);
11639
- return;
11640
- }
11641
- await confirmOrderEdit(void 0, {
11642
- onError: (e) => {
11643
- ui.toast.error(`Failed to confirm order edit: ${e.message}`);
11644
- },
11645
- onSuccess: () => {
11646
- handleSuccess();
11647
- },
11648
- onSettled: () => {
11649
- setIsSubmitting(false);
11650
- }
11651
- });
11652
- };
11653
- const onKeydown = React.useCallback(
11654
- (e) => {
11655
- if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) {
11656
- if (data || isSubmitting) {
11657
- return;
11658
- }
11659
- onSubmit();
11660
- }
11661
- },
11662
- [data, isSubmitting, onSubmit]
11035
+ [data, isSubmitting, onSubmit]
11663
11036
  );
11664
11037
  React.useEffect(() => {
11665
11038
  document.addEventListener("keydown", onKeydown);
@@ -12964,86 +12337,713 @@ const Illustration = () => {
12964
12337
  /* @__PURE__ */ jsxRuntime.jsx("g", { clipPath: "url(#clip4_20915_38670)", children: /* @__PURE__ */ jsxRuntime.jsx(
12965
12338
  "path",
12966
12339
  {
12967
- d: "M136.504 95.1945L129.12 95.1519L129.095 99.3617",
12968
- stroke: "#A1A1AA",
12969
- strokeWidth: "1.5",
12970
- strokeLinecap: "round",
12971
- strokeLinejoin: "round"
12340
+ d: "M136.504 95.1945L129.12 95.1519L129.095 99.3617",
12341
+ stroke: "#A1A1AA",
12342
+ strokeWidth: "1.5",
12343
+ strokeLinecap: "round",
12344
+ strokeLinejoin: "round"
12345
+ }
12346
+ ) }),
12347
+ /* @__PURE__ */ jsxRuntime.jsx("g", { clipPath: "url(#clip5_20915_38670)", children: /* @__PURE__ */ jsxRuntime.jsx(
12348
+ "path",
12349
+ {
12350
+ d: "M146.894 101.198L139.51 101.155L139.486 105.365",
12351
+ stroke: "#A1A1AA",
12352
+ strokeWidth: "1.5",
12353
+ strokeLinecap: "round",
12354
+ strokeLinejoin: "round"
12355
+ }
12356
+ ) }),
12357
+ /* @__PURE__ */ jsxRuntime.jsxs("defs", { children: [
12358
+ /* @__PURE__ */ jsxRuntime.jsx("clipPath", { id: "clip0_20915_38670", children: /* @__PURE__ */ jsxRuntime.jsx(
12359
+ "rect",
12360
+ {
12361
+ width: "12",
12362
+ height: "12",
12363
+ fill: "white",
12364
+ transform: "matrix(0.865865 0.500278 -0.871576 0.490261 138.36 74.6508)"
12365
+ }
12366
+ ) }),
12367
+ /* @__PURE__ */ jsxRuntime.jsx("clipPath", { id: "clip1_20915_38670", children: /* @__PURE__ */ jsxRuntime.jsx(
12368
+ "rect",
12369
+ {
12370
+ width: "12",
12371
+ height: "12",
12372
+ fill: "white",
12373
+ transform: "matrix(0.865865 0.500278 -0.871576 0.490261 148.75 80.6541)"
12374
+ }
12375
+ ) }),
12376
+ /* @__PURE__ */ jsxRuntime.jsx("clipPath", { id: "clip2_20915_38670", children: /* @__PURE__ */ jsxRuntime.jsx(
12377
+ "rect",
12378
+ {
12379
+ width: "12",
12380
+ height: "12",
12381
+ fill: "white",
12382
+ transform: "matrix(0.865865 0.500278 -0.871576 0.490261 159.141 86.6575)"
12383
+ }
12384
+ ) }),
12385
+ /* @__PURE__ */ jsxRuntime.jsx("clipPath", { id: "clip3_20915_38670", children: /* @__PURE__ */ jsxRuntime.jsx(
12386
+ "rect",
12387
+ {
12388
+ width: "12",
12389
+ height: "12",
12390
+ fill: "white",
12391
+ transform: "matrix(0.865865 0.500278 -0.871576 0.490261 120.928 84.4561)"
12392
+ }
12393
+ ) }),
12394
+ /* @__PURE__ */ jsxRuntime.jsx("clipPath", { id: "clip4_20915_38670", children: /* @__PURE__ */ jsxRuntime.jsx(
12395
+ "rect",
12396
+ {
12397
+ width: "12",
12398
+ height: "12",
12399
+ fill: "white",
12400
+ transform: "matrix(0.865865 0.500278 -0.871576 0.490261 131.318 90.4594)"
12401
+ }
12402
+ ) }),
12403
+ /* @__PURE__ */ jsxRuntime.jsx("clipPath", { id: "clip5_20915_38670", children: /* @__PURE__ */ jsxRuntime.jsx(
12404
+ "rect",
12405
+ {
12406
+ width: "12",
12407
+ height: "12",
12408
+ fill: "white",
12409
+ transform: "matrix(0.865865 0.500278 -0.871576 0.490261 141.709 96.4627)"
12410
+ }
12411
+ ) })
12412
+ ] })
12413
+ ]
12414
+ }
12415
+ );
12416
+ };
12417
+ const schema = objectType({
12418
+ customer_id: stringType().min(1)
12419
+ });
12420
+ const InlineTip = React.forwardRef(
12421
+ ({ variant = "tip", label, className, children, ...props }, ref) => {
12422
+ const labelValue = label || (variant === "warning" ? "Warning" : "Tip");
12423
+ return /* @__PURE__ */ jsxRuntime.jsxs(
12424
+ "div",
12425
+ {
12426
+ ref,
12427
+ className: ui.clx(
12428
+ "bg-ui-bg-component txt-small text-ui-fg-subtle grid grid-cols-[4px_1fr] items-start gap-3 rounded-lg border p-3",
12429
+ className
12430
+ ),
12431
+ ...props,
12432
+ children: [
12433
+ /* @__PURE__ */ jsxRuntime.jsx(
12434
+ "div",
12435
+ {
12436
+ role: "presentation",
12437
+ className: ui.clx("w-4px bg-ui-tag-neutral-icon h-full rounded-full", {
12438
+ "bg-ui-tag-orange-icon": variant === "warning"
12439
+ })
12440
+ }
12441
+ ),
12442
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-pretty", children: [
12443
+ /* @__PURE__ */ jsxRuntime.jsxs("strong", { className: "txt-small-plus text-ui-fg-base", children: [
12444
+ labelValue,
12445
+ ":"
12446
+ ] }),
12447
+ " ",
12448
+ children
12449
+ ] })
12450
+ ]
12451
+ }
12452
+ );
12453
+ }
12454
+ );
12455
+ InlineTip.displayName = "InlineTip";
12456
+ const MetadataFieldSchema = objectType({
12457
+ key: stringType(),
12458
+ disabled: booleanType().optional(),
12459
+ value: anyType()
12460
+ });
12461
+ const MetadataSchema = objectType({
12462
+ metadata: arrayType(MetadataFieldSchema)
12463
+ });
12464
+ const Metadata = () => {
12465
+ const { id } = reactRouterDom.useParams();
12466
+ const { order, isPending, isError, error } = useOrder(id, {
12467
+ fields: "metadata"
12468
+ });
12469
+ if (isError) {
12470
+ throw error;
12471
+ }
12472
+ const isReady = !isPending && !!order;
12473
+ return /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer, { children: [
12474
+ /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer.Header, { children: [
12475
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Metadata" }) }),
12476
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Description, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Add metadata to the draft order." }) })
12477
+ ] }),
12478
+ !isReady ? /* @__PURE__ */ jsxRuntime.jsx(PlaceholderInner, {}) : /* @__PURE__ */ jsxRuntime.jsx(MetadataForm, { orderId: id, metadata: order == null ? void 0 : order.metadata })
12479
+ ] });
12480
+ };
12481
+ const METADATA_KEY_LABEL_ID = "metadata-form-key-label";
12482
+ const METADATA_VALUE_LABEL_ID = "metadata-form-value-label";
12483
+ const MetadataForm = ({ orderId, metadata }) => {
12484
+ const { handleSuccess } = useRouteModal();
12485
+ const hasUneditableRows = getHasUneditableRows(metadata);
12486
+ const { mutateAsync, isPending } = useUpdateDraftOrder(orderId);
12487
+ const form = reactHookForm.useForm({
12488
+ defaultValues: {
12489
+ metadata: getDefaultValues(metadata)
12490
+ },
12491
+ resolver: zod.zodResolver(MetadataSchema)
12492
+ });
12493
+ const handleSubmit = form.handleSubmit(async (data) => {
12494
+ const parsedData = parseValues(data);
12495
+ await mutateAsync(
12496
+ {
12497
+ metadata: parsedData
12498
+ },
12499
+ {
12500
+ onSuccess: () => {
12501
+ ui.toast.success("Metadata updated");
12502
+ handleSuccess();
12503
+ },
12504
+ onError: (error) => {
12505
+ ui.toast.error(error.message);
12506
+ }
12507
+ }
12508
+ );
12509
+ });
12510
+ const { fields, insert, remove } = reactHookForm.useFieldArray({
12511
+ control: form.control,
12512
+ name: "metadata"
12513
+ });
12514
+ function deleteRow(index) {
12515
+ remove(index);
12516
+ if (fields.length === 1) {
12517
+ insert(0, {
12518
+ key: "",
12519
+ value: "",
12520
+ disabled: false
12521
+ });
12522
+ }
12523
+ }
12524
+ function insertRow(index, position) {
12525
+ insert(index + (position === "above" ? 0 : 1), {
12526
+ key: "",
12527
+ value: "",
12528
+ disabled: false
12529
+ });
12530
+ }
12531
+ return /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxRuntime.jsxs(
12532
+ KeyboundForm,
12533
+ {
12534
+ onSubmit: handleSubmit,
12535
+ className: "flex flex-1 flex-col overflow-hidden",
12536
+ children: [
12537
+ /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer.Body, { className: "flex flex-1 flex-col gap-y-8 overflow-y-auto", children: [
12538
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-base shadow-elevation-card-rest grid grid-cols-1 divide-y rounded-lg", children: [
12539
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-subtle grid grid-cols-2 divide-x rounded-t-lg", children: [
12540
+ /* @__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" }) }),
12541
+ /* @__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" }) })
12542
+ ] }),
12543
+ fields.map((field, index) => {
12544
+ const isDisabled = field.disabled || false;
12545
+ let placeholder = "-";
12546
+ if (typeof field.value === "object") {
12547
+ placeholder = "{ ... }";
12548
+ }
12549
+ if (Array.isArray(field.value)) {
12550
+ placeholder = "[ ... ]";
12551
+ }
12552
+ return /* @__PURE__ */ jsxRuntime.jsx(
12553
+ ConditionalTooltip,
12554
+ {
12555
+ showTooltip: isDisabled,
12556
+ content: "This row is disabled because it contains non-primitive data.",
12557
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "group/table relative", children: [
12558
+ /* @__PURE__ */ jsxRuntime.jsxs(
12559
+ "div",
12560
+ {
12561
+ className: ui.clx("grid grid-cols-2 divide-x", {
12562
+ "overflow-hidden rounded-b-lg": index === fields.length - 1
12563
+ }),
12564
+ children: [
12565
+ /* @__PURE__ */ jsxRuntime.jsx(
12566
+ Form$2.Field,
12567
+ {
12568
+ control: form.control,
12569
+ name: `metadata.${index}.key`,
12570
+ render: ({ field: field2 }) => {
12571
+ return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
12572
+ GridInput,
12573
+ {
12574
+ "aria-labelledby": METADATA_KEY_LABEL_ID,
12575
+ ...field2,
12576
+ disabled: isDisabled,
12577
+ placeholder: "Key"
12578
+ }
12579
+ ) }) });
12580
+ }
12581
+ }
12582
+ ),
12583
+ /* @__PURE__ */ jsxRuntime.jsx(
12584
+ Form$2.Field,
12585
+ {
12586
+ control: form.control,
12587
+ name: `metadata.${index}.value`,
12588
+ render: ({ field: { value, ...field2 } }) => {
12589
+ return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
12590
+ GridInput,
12591
+ {
12592
+ "aria-labelledby": METADATA_VALUE_LABEL_ID,
12593
+ ...field2,
12594
+ value: isDisabled ? placeholder : value,
12595
+ disabled: isDisabled,
12596
+ placeholder: "Value"
12597
+ }
12598
+ ) }) });
12599
+ }
12600
+ }
12601
+ )
12602
+ ]
12603
+ }
12604
+ ),
12605
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu, { children: [
12606
+ /* @__PURE__ */ jsxRuntime.jsx(
12607
+ ui.DropdownMenu.Trigger,
12608
+ {
12609
+ className: ui.clx(
12610
+ "invisible absolute inset-y-0 -right-2.5 my-auto group-hover/table:visible data-[state='open']:visible",
12611
+ {
12612
+ hidden: isDisabled
12613
+ }
12614
+ ),
12615
+ disabled: isDisabled,
12616
+ asChild: true,
12617
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { size: "2xsmall", children: /* @__PURE__ */ jsxRuntime.jsx(icons.EllipsisVertical, {}) })
12618
+ }
12619
+ ),
12620
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu.Content, { children: [
12621
+ /* @__PURE__ */ jsxRuntime.jsxs(
12622
+ ui.DropdownMenu.Item,
12623
+ {
12624
+ className: "gap-x-2",
12625
+ onClick: () => insertRow(index, "above"),
12626
+ children: [
12627
+ /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowUpMini, { className: "text-ui-fg-subtle" }),
12628
+ "Insert row above"
12629
+ ]
12630
+ }
12631
+ ),
12632
+ /* @__PURE__ */ jsxRuntime.jsxs(
12633
+ ui.DropdownMenu.Item,
12634
+ {
12635
+ className: "gap-x-2",
12636
+ onClick: () => insertRow(index, "below"),
12637
+ children: [
12638
+ /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowDownMini, { className: "text-ui-fg-subtle" }),
12639
+ "Insert row below"
12640
+ ]
12641
+ }
12642
+ ),
12643
+ /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenu.Separator, {}),
12644
+ /* @__PURE__ */ jsxRuntime.jsxs(
12645
+ ui.DropdownMenu.Item,
12646
+ {
12647
+ className: "gap-x-2",
12648
+ onClick: () => deleteRow(index),
12649
+ children: [
12650
+ /* @__PURE__ */ jsxRuntime.jsx(icons.Trash, { className: "text-ui-fg-subtle" }),
12651
+ "Delete row"
12652
+ ]
12653
+ }
12654
+ )
12655
+ ] })
12656
+ ] })
12657
+ ] })
12658
+ },
12659
+ field.id
12660
+ );
12661
+ })
12662
+ ] }),
12663
+ 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." })
12664
+ ] }),
12665
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
12666
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
12667
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", type: "submit", isLoading: isPending, children: "Save" })
12668
+ ] }) })
12669
+ ]
12670
+ }
12671
+ ) });
12672
+ };
12673
+ const GridInput = React.forwardRef(({ className, ...props }, ref) => {
12674
+ return /* @__PURE__ */ jsxRuntime.jsx(
12675
+ "input",
12676
+ {
12677
+ ref,
12678
+ ...props,
12679
+ autoComplete: "off",
12680
+ className: ui.clx(
12681
+ "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",
12682
+ className
12683
+ )
12684
+ }
12685
+ );
12686
+ });
12687
+ GridInput.displayName = "MetadataForm.GridInput";
12688
+ const PlaceholderInner = () => {
12689
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col overflow-hidden", children: [
12690
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Body, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: "h-[148ox] w-full rounded-lg" }) }),
12691
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
12692
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: "h-7 w-12 rounded-md" }),
12693
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: "h-7 w-12 rounded-md" })
12694
+ ] }) })
12695
+ ] });
12696
+ };
12697
+ const EDITABLE_TYPES = ["string", "number", "boolean"];
12698
+ function getDefaultValues(metadata) {
12699
+ if (!metadata || !Object.keys(metadata).length) {
12700
+ return [
12701
+ {
12702
+ key: "",
12703
+ value: "",
12704
+ disabled: false
12705
+ }
12706
+ ];
12707
+ }
12708
+ return Object.entries(metadata).map(([key, value]) => {
12709
+ if (!EDITABLE_TYPES.includes(typeof value)) {
12710
+ return {
12711
+ key,
12712
+ value,
12713
+ disabled: true
12714
+ };
12715
+ }
12716
+ let stringValue = value;
12717
+ if (typeof value !== "string") {
12718
+ stringValue = JSON.stringify(value);
12719
+ }
12720
+ return {
12721
+ key,
12722
+ value: stringValue,
12723
+ original_key: key
12724
+ };
12725
+ });
12726
+ }
12727
+ function parseValues(values) {
12728
+ const metadata = values.metadata;
12729
+ const isEmpty = !metadata.length || metadata.length === 1 && !metadata[0].key && !metadata[0].value;
12730
+ if (isEmpty) {
12731
+ return null;
12732
+ }
12733
+ const update = {};
12734
+ metadata.forEach((field) => {
12735
+ let key = field.key;
12736
+ let value = field.value;
12737
+ const disabled = field.disabled;
12738
+ if (!key || !value) {
12739
+ return;
12740
+ }
12741
+ if (disabled) {
12742
+ update[key] = value;
12743
+ return;
12744
+ }
12745
+ key = key.trim();
12746
+ value = value.trim();
12747
+ if (value === "true") {
12748
+ update[key] = true;
12749
+ } else if (value === "false") {
12750
+ update[key] = false;
12751
+ } else {
12752
+ const parsedNumber = parseFloat(value);
12753
+ if (!isNaN(parsedNumber)) {
12754
+ update[key] = parsedNumber;
12755
+ } else {
12756
+ update[key] = value;
12757
+ }
12758
+ }
12759
+ });
12760
+ return update;
12761
+ }
12762
+ function getHasUneditableRows(metadata) {
12763
+ if (!metadata) {
12764
+ return false;
12765
+ }
12766
+ return Object.values(metadata).some(
12767
+ (value) => !EDITABLE_TYPES.includes(typeof value)
12768
+ );
12769
+ }
12770
+ const PROMOTION_QUERY_KEY = "promotions";
12771
+ const promotionsQueryKeys = {
12772
+ list: (query2) => [
12773
+ PROMOTION_QUERY_KEY,
12774
+ query2 ? query2 : void 0
12775
+ ],
12776
+ detail: (id, query2) => [
12777
+ PROMOTION_QUERY_KEY,
12778
+ id,
12779
+ query2 ? query2 : void 0
12780
+ ]
12781
+ };
12782
+ const usePromotions = (query2, options) => {
12783
+ const { data, ...rest } = reactQuery.useQuery({
12784
+ queryKey: promotionsQueryKeys.list(query2),
12785
+ queryFn: async () => sdk.admin.promotion.list(query2),
12786
+ ...options
12787
+ });
12788
+ return { ...data, ...rest };
12789
+ };
12790
+ const Promotions = () => {
12791
+ const { id } = reactRouterDom.useParams();
12792
+ const {
12793
+ order: preview,
12794
+ isError: isPreviewError,
12795
+ error: previewError
12796
+ } = useOrderPreview(id, void 0);
12797
+ useInitiateOrderEdit({ preview });
12798
+ const { onCancel } = useCancelOrderEdit({ preview });
12799
+ if (isPreviewError) {
12800
+ throw previewError;
12801
+ }
12802
+ const isReady = !!preview;
12803
+ return /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer, { onClose: onCancel, children: [
12804
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Edit Promotions" }) }) }),
12805
+ isReady && /* @__PURE__ */ jsxRuntime.jsx(PromotionForm, { preview })
12806
+ ] });
12807
+ };
12808
+ const PromotionForm = ({ preview }) => {
12809
+ const { items, shipping_methods } = preview;
12810
+ const [isSubmitting, setIsSubmitting] = React.useState(false);
12811
+ const [comboboxValue, setComboboxValue] = React.useState("");
12812
+ const { handleSuccess } = useRouteModal();
12813
+ const { mutateAsync: addPromotions, isPending: isAddingPromotions } = useDraftOrderAddPromotions(preview.id);
12814
+ const promoIds = getPromotionIds(items, shipping_methods);
12815
+ const { promotions, isPending, isError, error } = usePromotions(
12816
+ {
12817
+ id: promoIds
12818
+ },
12819
+ {
12820
+ enabled: !!promoIds.length
12821
+ }
12822
+ );
12823
+ const comboboxData = useComboboxData({
12824
+ queryKey: ["promotions", "combobox", promoIds],
12825
+ queryFn: async (params) => {
12826
+ return await sdk.admin.promotion.list({
12827
+ ...params,
12828
+ id: {
12829
+ $nin: promoIds
12830
+ }
12831
+ });
12832
+ },
12833
+ getOptions: (data) => {
12834
+ return data.promotions.map((promotion) => ({
12835
+ label: promotion.code,
12836
+ value: promotion.code
12837
+ }));
12838
+ }
12839
+ });
12840
+ const add = async (value) => {
12841
+ if (!value) {
12842
+ return;
12843
+ }
12844
+ addPromotions(
12845
+ {
12846
+ promo_codes: [value]
12847
+ },
12848
+ {
12849
+ onError: (e) => {
12850
+ ui.toast.error(e.message);
12851
+ comboboxData.onSearchValueChange("");
12852
+ setComboboxValue("");
12853
+ },
12854
+ onSuccess: () => {
12855
+ comboboxData.onSearchValueChange("");
12856
+ setComboboxValue("");
12857
+ }
12858
+ }
12859
+ );
12860
+ };
12861
+ const { mutateAsync: confirmOrderEdit } = useDraftOrderConfirmEdit(preview.id);
12862
+ const { mutateAsync: requestOrderEdit } = useOrderEditRequest(preview.id);
12863
+ const onSubmit = async () => {
12864
+ setIsSubmitting(true);
12865
+ let requestSucceeded = false;
12866
+ await requestOrderEdit(void 0, {
12867
+ onError: (e) => {
12868
+ ui.toast.error(e.message);
12869
+ },
12870
+ onSuccess: () => {
12871
+ requestSucceeded = true;
12872
+ }
12873
+ });
12874
+ if (!requestSucceeded) {
12875
+ setIsSubmitting(false);
12876
+ return;
12877
+ }
12878
+ await confirmOrderEdit(void 0, {
12879
+ onError: (e) => {
12880
+ ui.toast.error(e.message);
12881
+ },
12882
+ onSuccess: () => {
12883
+ handleSuccess();
12884
+ },
12885
+ onSettled: () => {
12886
+ setIsSubmitting(false);
12887
+ }
12888
+ });
12889
+ };
12890
+ if (isError) {
12891
+ throw error;
12892
+ }
12893
+ return /* @__PURE__ */ jsxRuntime.jsxs(KeyboundForm, { className: "flex flex-1 flex-col", onSubmit, children: [
12894
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Body, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-4", children: [
12895
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3", children: [
12896
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
12897
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: "small", weight: "plus", htmlFor: "promotion-combobox", children: "Apply promotions" }),
12898
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Hint, { id: "promotion-combobox-hint", children: "Manage promotions that should be applied to the order." })
12899
+ ] }),
12900
+ /* @__PURE__ */ jsxRuntime.jsx(
12901
+ Combobox,
12902
+ {
12903
+ id: "promotion-combobox",
12904
+ "aria-describedby": "promotion-combobox-hint",
12905
+ isFetchingNextPage: comboboxData.isFetchingNextPage,
12906
+ fetchNextPage: comboboxData.fetchNextPage,
12907
+ options: comboboxData.options,
12908
+ onSearchValueChange: comboboxData.onSearchValueChange,
12909
+ searchValue: comboboxData.searchValue,
12910
+ disabled: comboboxData.disabled || isAddingPromotions,
12911
+ onChange: add,
12912
+ value: comboboxValue
12972
12913
  }
12973
- ) }),
12974
- /* @__PURE__ */ jsxRuntime.jsx("g", { clipPath: "url(#clip5_20915_38670)", children: /* @__PURE__ */ jsxRuntime.jsx(
12975
- "path",
12914
+ )
12915
+ ] }),
12916
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { variant: "dashed" }),
12917
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-2", children: promotions == null ? void 0 : promotions.map((promotion) => /* @__PURE__ */ jsxRuntime.jsx(
12918
+ PromotionItem,
12919
+ {
12920
+ promotion,
12921
+ orderId: preview.id,
12922
+ isLoading: isPending
12923
+ },
12924
+ promotion.id
12925
+ )) })
12926
+ ] }) }),
12927
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-2", children: [
12928
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
12929
+ /* @__PURE__ */ jsxRuntime.jsx(
12930
+ ui.Button,
12931
+ {
12932
+ size: "small",
12933
+ type: "submit",
12934
+ isLoading: isSubmitting || isAddingPromotions,
12935
+ children: "Save"
12936
+ }
12937
+ )
12938
+ ] }) })
12939
+ ] });
12940
+ };
12941
+ const PromotionItem = ({
12942
+ promotion,
12943
+ orderId,
12944
+ isLoading
12945
+ }) => {
12946
+ var _a;
12947
+ const { mutateAsync: removePromotions, isPending } = useDraftOrderRemovePromotions(orderId);
12948
+ const onRemove = async () => {
12949
+ removePromotions(
12950
+ {
12951
+ promo_codes: [promotion.code]
12952
+ },
12953
+ {
12954
+ onError: (e) => {
12955
+ ui.toast.error(e.message);
12956
+ }
12957
+ }
12958
+ );
12959
+ };
12960
+ const displayValue = getDisplayValue(promotion);
12961
+ return /* @__PURE__ */ jsxRuntime.jsxs(
12962
+ "div",
12963
+ {
12964
+ className: ui.clx(
12965
+ "bg-ui-bg-component shadow-elevation-card-rest flex items-center justify-between rounded-lg px-3 py-2",
12966
+ {
12967
+ "animate-pulse": isLoading
12968
+ }
12969
+ ),
12970
+ children: [
12971
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
12972
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", leading: "compact", children: promotion.code }),
12973
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-ui-fg-subtle flex items-center gap-1.5", children: [
12974
+ displayValue && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
12975
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", leading: "compact", children: displayValue }),
12976
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", leading: "compact", children: "·" })
12977
+ ] }),
12978
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", leading: "compact", className: "capitalize", children: (_a = promotion.application_method) == null ? void 0 : _a.allocation })
12979
+ ] })
12980
+ ] }),
12981
+ /* @__PURE__ */ jsxRuntime.jsx(
12982
+ ui.IconButton,
12976
12983
  {
12977
- d: "M146.894 101.198L139.51 101.155L139.486 105.365",
12978
- stroke: "#A1A1AA",
12979
- strokeWidth: "1.5",
12980
- strokeLinecap: "round",
12981
- strokeLinejoin: "round"
12984
+ size: "small",
12985
+ type: "button",
12986
+ variant: "transparent",
12987
+ onClick: onRemove,
12988
+ isLoading: isPending || isLoading,
12989
+ children: /* @__PURE__ */ jsxRuntime.jsx(icons.XMark, {})
12982
12990
  }
12983
- ) }),
12984
- /* @__PURE__ */ jsxRuntime.jsxs("defs", { children: [
12985
- /* @__PURE__ */ jsxRuntime.jsx("clipPath", { id: "clip0_20915_38670", children: /* @__PURE__ */ jsxRuntime.jsx(
12986
- "rect",
12987
- {
12988
- width: "12",
12989
- height: "12",
12990
- fill: "white",
12991
- transform: "matrix(0.865865 0.500278 -0.871576 0.490261 138.36 74.6508)"
12992
- }
12993
- ) }),
12994
- /* @__PURE__ */ jsxRuntime.jsx("clipPath", { id: "clip1_20915_38670", children: /* @__PURE__ */ jsxRuntime.jsx(
12995
- "rect",
12996
- {
12997
- width: "12",
12998
- height: "12",
12999
- fill: "white",
13000
- transform: "matrix(0.865865 0.500278 -0.871576 0.490261 148.75 80.6541)"
13001
- }
13002
- ) }),
13003
- /* @__PURE__ */ jsxRuntime.jsx("clipPath", { id: "clip2_20915_38670", children: /* @__PURE__ */ jsxRuntime.jsx(
13004
- "rect",
13005
- {
13006
- width: "12",
13007
- height: "12",
13008
- fill: "white",
13009
- transform: "matrix(0.865865 0.500278 -0.871576 0.490261 159.141 86.6575)"
13010
- }
13011
- ) }),
13012
- /* @__PURE__ */ jsxRuntime.jsx("clipPath", { id: "clip3_20915_38670", children: /* @__PURE__ */ jsxRuntime.jsx(
13013
- "rect",
13014
- {
13015
- width: "12",
13016
- height: "12",
13017
- fill: "white",
13018
- transform: "matrix(0.865865 0.500278 -0.871576 0.490261 120.928 84.4561)"
13019
- }
13020
- ) }),
13021
- /* @__PURE__ */ jsxRuntime.jsx("clipPath", { id: "clip4_20915_38670", children: /* @__PURE__ */ jsxRuntime.jsx(
13022
- "rect",
13023
- {
13024
- width: "12",
13025
- height: "12",
13026
- fill: "white",
13027
- transform: "matrix(0.865865 0.500278 -0.871576 0.490261 131.318 90.4594)"
13028
- }
13029
- ) }),
13030
- /* @__PURE__ */ jsxRuntime.jsx("clipPath", { id: "clip5_20915_38670", children: /* @__PURE__ */ jsxRuntime.jsx(
13031
- "rect",
13032
- {
13033
- width: "12",
13034
- height: "12",
13035
- fill: "white",
13036
- transform: "matrix(0.865865 0.500278 -0.871576 0.490261 141.709 96.4627)"
13037
- }
13038
- ) })
13039
- ] })
12991
+ )
13040
12992
  ]
13041
- }
12993
+ },
12994
+ promotion.id
13042
12995
  );
13043
12996
  };
13044
- const schema = objectType({
13045
- customer_id: stringType().min(1)
12997
+ function getDisplayValue(promotion) {
12998
+ var _a, _b, _c, _d;
12999
+ const value = (_a = promotion.application_method) == null ? void 0 : _a.value;
13000
+ if (!value) {
13001
+ return null;
13002
+ }
13003
+ if (((_b = promotion.application_method) == null ? void 0 : _b.type) === "fixed") {
13004
+ const currency = (_c = promotion.application_method) == null ? void 0 : _c.currency_code;
13005
+ if (!currency) {
13006
+ return null;
13007
+ }
13008
+ return getLocaleAmount(value, currency);
13009
+ } else if (((_d = promotion.application_method) == null ? void 0 : _d.type) === "percentage") {
13010
+ return formatPercentage(value);
13011
+ }
13012
+ return null;
13013
+ }
13014
+ const formatter = new Intl.NumberFormat([], {
13015
+ style: "percent",
13016
+ minimumFractionDigits: 2
13046
13017
  });
13018
+ const formatPercentage = (value, isPercentageValue = false) => {
13019
+ let val = value || 0;
13020
+ if (!isPercentageValue) {
13021
+ val = val / 100;
13022
+ }
13023
+ return formatter.format(val);
13024
+ };
13025
+ function getPromotionIds(items, shippingMethods) {
13026
+ const promotionIds = /* @__PURE__ */ new Set();
13027
+ for (const item of items) {
13028
+ if (item.adjustments) {
13029
+ for (const adjustment of item.adjustments) {
13030
+ if (adjustment.promotion_id) {
13031
+ promotionIds.add(adjustment.promotion_id);
13032
+ }
13033
+ }
13034
+ }
13035
+ }
13036
+ for (const shippingMethod of shippingMethods) {
13037
+ if (shippingMethod.adjustments) {
13038
+ for (const adjustment of shippingMethod.adjustments) {
13039
+ if (adjustment.promotion_id) {
13040
+ promotionIds.add(adjustment.promotion_id);
13041
+ }
13042
+ }
13043
+ }
13044
+ }
13045
+ return Array.from(promotionIds);
13046
+ }
13047
13047
  const widgetModule = { widgets: [] };
13048
13048
  const routeModule = {
13049
13049
  routes: [
@@ -13080,14 +13080,6 @@ const routeModule = {
13080
13080
  Component: Items,
13081
13081
  path: "/draft-orders/:id/items"
13082
13082
  },
13083
- {
13084
- Component: Metadata,
13085
- path: "/draft-orders/:id/metadata"
13086
- },
13087
- {
13088
- Component: Promotions,
13089
- path: "/draft-orders/:id/promotions"
13090
- },
13091
13083
  {
13092
13084
  Component: SalesChannel,
13093
13085
  path: "/draft-orders/:id/sales-channel"
@@ -13103,6 +13095,14 @@ const routeModule = {
13103
13095
  {
13104
13096
  Component: TransferOwnership,
13105
13097
  path: "/draft-orders/:id/transfer-ownership"
13098
+ },
13099
+ {
13100
+ Component: Metadata,
13101
+ path: "/draft-orders/:id/metadata"
13102
+ },
13103
+ {
13104
+ Component: Promotions,
13105
+ path: "/draft-orders/:id/promotions"
13106
13106
  }
13107
13107
  ]
13108
13108
  }