@medusajs/draft-order 2.13.3-preview-20260227120420 → 2.13.3

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.
@@ -9853,127 +9853,22 @@ const EmailForm = ({ order }) => {
9853
9853
  const schema$3 = objectType({
9854
9854
  email: stringType().email()
9855
9855
  });
9856
- const NumberInput = React.forwardRef(
9857
- ({
9858
- value,
9859
- onChange,
9860
- size = "base",
9861
- min = 0,
9862
- max = 100,
9863
- step = 1,
9864
- className,
9865
- disabled,
9866
- ...props
9867
- }, ref) => {
9868
- const handleChange = (event) => {
9869
- const newValue = event.target.value === "" ? min : Number(event.target.value);
9870
- if (!isNaN(newValue) && (max === void 0 || newValue <= max) && (min === void 0 || newValue >= min)) {
9871
- onChange(newValue);
9872
- }
9873
- };
9874
- const handleIncrement = () => {
9875
- const newValue = value + step;
9876
- if (max === void 0 || newValue <= max) {
9877
- onChange(newValue);
9878
- }
9879
- };
9880
- const handleDecrement = () => {
9881
- const newValue = value - step;
9882
- if (min === void 0 || newValue >= min) {
9883
- onChange(newValue);
9884
- }
9885
- };
9886
- return /* @__PURE__ */ jsxRuntime.jsxs(
9887
- "div",
9888
- {
9889
- className: ui.clx(
9890
- "inline-flex rounded-md bg-ui-bg-field shadow-borders-base overflow-hidden divide-x transition-fg",
9891
- "[&:has(input:focus)]:shadow-borders-interactive-with-active",
9892
- {
9893
- "h-7": size === "small",
9894
- "h-8": size === "base"
9895
- },
9896
- className
9897
- ),
9898
- children: [
9899
- /* @__PURE__ */ jsxRuntime.jsx(
9900
- "input",
9901
- {
9902
- ref,
9903
- type: "number",
9904
- value,
9905
- onChange: handleChange,
9906
- min,
9907
- max,
9908
- step,
9909
- className: ui.clx(
9910
- "flex-1 px-2 py-1 bg-transparent txt-compact-small text-ui-fg-base outline-none [appearance:textfield]",
9911
- "[&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none",
9912
- "placeholder:text-ui-fg-muted"
9913
- ),
9914
- ...props
9915
- }
9916
- ),
9917
- /* @__PURE__ */ jsxRuntime.jsxs(
9918
- "button",
9919
- {
9920
- className: ui.clx(
9921
- "flex items-center justify-center outline-none transition-fg",
9922
- "disabled:cursor-not-allowed disabled:text-ui-fg-muted",
9923
- "focus:bg-ui-bg-field-component-hover",
9924
- "hover:bg-ui-bg-field-component-hover",
9925
- {
9926
- "size-7": size === "small",
9927
- "size-8": size === "base"
9928
- }
9929
- ),
9930
- type: "button",
9931
- onClick: handleDecrement,
9932
- disabled: min !== void 0 && value <= min || disabled,
9933
- children: [
9934
- /* @__PURE__ */ jsxRuntime.jsx(icons.Minus, {}),
9935
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: `Decrease by ${step}` })
9936
- ]
9937
- }
9938
- ),
9939
- /* @__PURE__ */ jsxRuntime.jsxs(
9940
- "button",
9941
- {
9942
- className: ui.clx(
9943
- "flex items-center justify-center outline-none transition-fg",
9944
- "disabled:cursor-not-allowed disabled:text-ui-fg-muted",
9945
- "focus:bg-ui-bg-field-hover",
9946
- "hover:bg-ui-bg-field-hover",
9947
- {
9948
- "size-7": size === "small",
9949
- "size-8": size === "base"
9950
- }
9951
- ),
9952
- type: "button",
9953
- onClick: handleIncrement,
9954
- disabled: max !== void 0 && value >= max || disabled,
9955
- children: [
9956
- /* @__PURE__ */ jsxRuntime.jsx(icons.Plus, {}),
9957
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: `Increase by ${step}` })
9958
- ]
9959
- }
9960
- )
9961
- ]
9962
- }
9963
- );
9964
- }
9965
- );
9966
- const PRODUCT_VARIANTS_QUERY_KEY = "product-variants";
9967
- const productVariantsQueryKeys = {
9856
+ const PROMOTION_QUERY_KEY = "promotions";
9857
+ const promotionsQueryKeys = {
9968
9858
  list: (query2) => [
9969
- PRODUCT_VARIANTS_QUERY_KEY,
9859
+ PROMOTION_QUERY_KEY,
9860
+ query2 ? query2 : void 0
9861
+ ],
9862
+ detail: (id, query2) => [
9863
+ PROMOTION_QUERY_KEY,
9864
+ id,
9970
9865
  query2 ? query2 : void 0
9971
9866
  ]
9972
9867
  };
9973
- const useProductVariants = (query2, options) => {
9868
+ const usePromotions = (query2, options) => {
9974
9869
  const { data, ...rest } = reactQuery.useQuery({
9975
- queryKey: productVariantsQueryKeys.list(query2),
9976
- queryFn: async () => await sdk.admin.productVariant.list(query2),
9870
+ queryKey: promotionsQueryKeys.list(query2),
9871
+ queryFn: async () => sdk.admin.promotion.list(query2),
9977
9872
  ...options
9978
9873
  });
9979
9874
  return { ...data, ...rest };
@@ -10024,65 +9919,85 @@ const useInitiateOrderEdit = ({
10024
9919
  run();
10025
9920
  }, [preview, navigate, mutateAsync]);
10026
9921
  };
10027
- function convertNumber(value) {
10028
- return typeof value === "string" ? Number(value.replace(",", ".")) : value;
10029
- }
10030
- const STACKED_MODAL_ID = "items_stacked_modal";
10031
- const Items = () => {
9922
+ const Promotions = () => {
10032
9923
  const { id } = reactRouterDom.useParams();
10033
9924
  const {
10034
9925
  order: preview,
10035
- isPending: isPreviewPending,
10036
9926
  isError: isPreviewError,
10037
9927
  error: previewError
10038
- } = useOrderPreview(id, void 0, {
10039
- placeholderData: reactQuery.keepPreviousData
10040
- });
9928
+ } = useOrderPreview(id, void 0);
10041
9929
  useInitiateOrderEdit({ preview });
10042
- const { draft_order, isPending, isError, error } = useDraftOrder(
10043
- id,
10044
- {
10045
- fields: "currency_code"
10046
- },
10047
- {
10048
- enabled: !!id
10049
- }
10050
- );
10051
9930
  const { onCancel } = useCancelOrderEdit({ preview });
10052
- if (isError) {
10053
- throw error;
10054
- }
10055
9931
  if (isPreviewError) {
10056
9932
  throw previewError;
10057
9933
  }
10058
- const ready = !!preview && !isPreviewPending && !!draft_order && !isPending;
10059
- return /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal, { onClose: onCancel, children: ready ? /* @__PURE__ */ jsxRuntime.jsx(ItemsForm, { preview, currencyCode: draft_order.currency_code }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
10060
- /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Edit Items" }) }),
10061
- /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Loading data for the draft order, please wait..." }) })
10062
- ] }) });
9934
+ const isReady = !!preview;
9935
+ return /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer, { onClose: onCancel, children: [
9936
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Edit Promotions" }) }) }),
9937
+ isReady && /* @__PURE__ */ jsxRuntime.jsx(PromotionForm, { preview })
9938
+ ] });
10063
9939
  };
10064
- const ItemsForm = ({ preview, currencyCode }) => {
10065
- var _a;
9940
+ const PromotionForm = ({ preview }) => {
9941
+ const { items, shipping_methods } = preview;
10066
9942
  const [isSubmitting, setIsSubmitting] = React.useState(false);
10067
- const [modalContent, setModalContent] = React.useState(
10068
- null
10069
- );
9943
+ const [comboboxValue, setComboboxValue] = React.useState("");
10070
9944
  const { handleSuccess } = useRouteModal();
10071
- const { searchValue, onSearchValueChange, query: query2 } = useDebouncedSearch();
9945
+ const { mutateAsync: addPromotions, isPending: isAddingPromotions } = useDraftOrderAddPromotions(preview.id);
9946
+ const promoIds = getPromotionIds(items, shipping_methods);
9947
+ const { promotions, isPending, isError, error } = usePromotions(
9948
+ {
9949
+ id: promoIds
9950
+ },
9951
+ {
9952
+ enabled: !!promoIds.length
9953
+ }
9954
+ );
9955
+ const comboboxData = useComboboxData({
9956
+ queryKey: ["promotions", "combobox", promoIds],
9957
+ queryFn: async (params) => {
9958
+ return await sdk.admin.promotion.list({
9959
+ ...params,
9960
+ id: {
9961
+ $nin: promoIds
9962
+ }
9963
+ });
9964
+ },
9965
+ getOptions: (data) => {
9966
+ return data.promotions.map((promotion) => ({
9967
+ label: promotion.code,
9968
+ value: promotion.code
9969
+ }));
9970
+ }
9971
+ });
9972
+ const add = async (value) => {
9973
+ if (!value) {
9974
+ return;
9975
+ }
9976
+ addPromotions(
9977
+ {
9978
+ promo_codes: [value]
9979
+ },
9980
+ {
9981
+ onError: (e) => {
9982
+ ui.toast.error(e.message);
9983
+ comboboxData.onSearchValueChange("");
9984
+ setComboboxValue("");
9985
+ },
9986
+ onSuccess: () => {
9987
+ comboboxData.onSearchValueChange("");
9988
+ setComboboxValue("");
9989
+ }
9990
+ }
9991
+ );
9992
+ };
10072
9993
  const { mutateAsync: confirmOrderEdit } = useDraftOrderConfirmEdit(preview.id);
10073
- const { mutateAsync: requestOrderEdit } = useDraftOrderRequestEdit(preview.id);
10074
- const itemCount = ((_a = preview.items) == null ? void 0 : _a.reduce((acc, item) => acc + item.quantity, 0)) || 0;
10075
- const matches = React.useMemo(() => {
10076
- return matchSorter.matchSorter(preview.items, query2, {
10077
- keys: ["product_title", "variant_title", "variant_sku", "title"]
10078
- });
10079
- }, [preview.items, query2]);
9994
+ const { mutateAsync: requestOrderEdit } = useOrderEditRequest(preview.id);
10080
9995
  const onSubmit = async () => {
10081
9996
  setIsSubmitting(true);
10082
9997
  let requestSucceeded = false;
10083
9998
  await requestOrderEdit(void 0, {
10084
9999
  onError: (e) => {
10085
- ui.toast.error(`Failed to request order edit: ${e.message}`);
10000
+ ui.toast.error(e.message);
10086
10001
  },
10087
10002
  onSuccess: () => {
10088
10003
  requestSucceeded = true;
@@ -10094,7 +10009,7 @@ const ItemsForm = ({ preview, currencyCode }) => {
10094
10009
  }
10095
10010
  await confirmOrderEdit(void 0, {
10096
10011
  onError: (e) => {
10097
- ui.toast.error(`Failed to confirm order edit: ${e.message}`);
10012
+ ui.toast.error(e.message);
10098
10013
  },
10099
10014
  onSuccess: () => {
10100
10015
  handleSuccess();
@@ -10104,1461 +10019,1546 @@ const ItemsForm = ({ preview, currencyCode }) => {
10104
10019
  }
10105
10020
  });
10106
10021
  };
10107
- const onKeyDown = React.useCallback(
10108
- (e) => {
10109
- if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) {
10110
- if (modalContent || isSubmitting) {
10111
- return;
10112
- }
10113
- onSubmit();
10114
- }
10115
- },
10116
- [modalContent, isSubmitting, onSubmit]
10117
- );
10118
- React.useEffect(() => {
10119
- document.addEventListener("keydown", onKeyDown);
10120
- return () => {
10121
- document.removeEventListener("keydown", onKeyDown);
10122
- };
10123
- }, [onKeyDown]);
10124
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-full flex-col overflow-hidden", children: [
10125
- /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Header, {}),
10126
- /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Body, { className: "flex flex-1 flex-col overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsxs(
10127
- StackedFocusModal,
10128
- {
10129
- id: STACKED_MODAL_ID,
10130
- onOpenChangeCallback: (open) => {
10131
- if (!open) {
10132
- setModalContent(null);
10133
- }
10022
+ if (isError) {
10023
+ throw error;
10024
+ }
10025
+ return /* @__PURE__ */ jsxRuntime.jsxs(KeyboundForm, { className: "flex flex-1 flex-col", onSubmit, children: [
10026
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Body, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-4", children: [
10027
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3", children: [
10028
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
10029
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: "small", weight: "plus", htmlFor: "promotion-combobox", children: "Apply promotions" }),
10030
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Hint, { id: "promotion-combobox-hint", children: "Manage promotions that should be applied to the order." })
10031
+ ] }),
10032
+ /* @__PURE__ */ jsxRuntime.jsx(
10033
+ Combobox,
10034
+ {
10035
+ id: "promotion-combobox",
10036
+ "aria-describedby": "promotion-combobox-hint",
10037
+ isFetchingNextPage: comboboxData.isFetchingNextPage,
10038
+ fetchNextPage: comboboxData.fetchNextPage,
10039
+ options: comboboxData.options,
10040
+ onSearchValueChange: comboboxData.onSearchValueChange,
10041
+ searchValue: comboboxData.searchValue,
10042
+ disabled: comboboxData.disabled || isAddingPromotions,
10043
+ onChange: add,
10044
+ value: comboboxValue
10045
+ }
10046
+ )
10047
+ ] }),
10048
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { variant: "dashed" }),
10049
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-2", children: promotions == null ? void 0 : promotions.map((promotion) => /* @__PURE__ */ jsxRuntime.jsx(
10050
+ PromotionItem,
10051
+ {
10052
+ promotion,
10053
+ orderId: preview.id,
10054
+ isLoading: isPending
10134
10055
  },
10135
- children: [
10136
- /* @__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: [
10137
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
10138
- /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Edit Items" }) }),
10139
- /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Edit the items in the draft order" }) })
10140
- ] }),
10141
- /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { variant: "dashed" }),
10142
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-6", children: [
10143
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 items-center gap-3", children: [
10144
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
10145
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", leading: "compact", children: "Items" }),
10146
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Choose items from the product catalog." })
10147
- ] }),
10148
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
10149
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(
10150
- ui.Input,
10151
- {
10152
- type: "search",
10153
- placeholder: "Search items",
10154
- value: searchValue,
10155
- onChange: (e) => onSearchValueChange(e.target.value)
10156
- }
10157
- ) }),
10158
- /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu, { children: [
10159
- /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenu.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { type: "button", children: /* @__PURE__ */ jsxRuntime.jsx(icons.Plus, {}) }) }),
10160
- /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu.Content, { children: [
10161
- /* @__PURE__ */ jsxRuntime.jsx(
10162
- StackedModalTrigger$1,
10163
- {
10164
- type: "add-items",
10165
- setModalContent
10166
- }
10167
- ),
10168
- /* @__PURE__ */ jsxRuntime.jsx(
10169
- StackedModalTrigger$1,
10170
- {
10171
- type: "add-custom-item",
10172
- setModalContent
10173
- }
10174
- )
10175
- ] })
10176
- ] })
10177
- ] })
10178
- ] }),
10179
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-subtle shadow-elevation-card-rest rounded-xl", children: [
10180
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-[5px]", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-ui-fg-muted grid grid-cols-[2fr_1fr_2fr_28px] gap-3 px-4 py-2", children: [
10181
- /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: "Item" }) }),
10182
- /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: "Quantity" }) }),
10183
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-right", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: "Price" }) }),
10184
- /* @__PURE__ */ jsxRuntime.jsx("div", {})
10185
- ] }) }),
10186
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-y-1.5 px-[5px] pb-[5px]", children: itemCount <= 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-base shadow-elevation-card-rest flex flex-col items-center justify-center gap-1 gap-x-3 rounded-lg p-4", children: [
10187
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", leading: "compact", children: "There are no items in this order" }),
10188
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Add items to the order to get started." })
10189
- ] }) : matches.length > 0 ? matches == null ? void 0 : matches.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
10190
- Item,
10191
- {
10192
- item,
10193
- preview,
10194
- currencyCode
10195
- },
10196
- item.id
10197
- )) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-base shadow-elevation-card-rest flex flex-col items-center justify-center gap-1 gap-x-3 rounded-lg p-4", children: [
10198
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", leading: "compact", children: "No items found" }),
10199
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: [
10200
- 'No items found for "',
10201
- query2,
10202
- '".'
10203
- ] })
10204
- ] }) })
10205
- ] })
10206
- ] }),
10207
- /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { variant: "dashed" }),
10208
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-[1fr_0.5fr_0.5fr] gap-3", children: [
10209
- /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", leading: "compact", children: "Subtotal" }) }),
10210
- /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsxs(
10211
- ui.Text,
10212
- {
10213
- size: "small",
10214
- leading: "compact",
10215
- className: "text-ui-fg-subtle",
10216
- children: [
10217
- itemCount,
10218
- " ",
10219
- itemCount === 1 ? "item" : "items"
10220
- ]
10221
- }
10222
- ) }),
10223
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-right", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", leading: "compact", children: getStylizedAmount(preview.item_subtotal, currencyCode) }) })
10224
- ] })
10225
- ] }) }),
10226
- modalContent && (modalContent === "add-items" ? /* @__PURE__ */ jsxRuntime.jsx(ExistingItemsForm, { orderId: preview.id, items: preview.items }) : modalContent === "add-custom-item" ? /* @__PURE__ */ jsxRuntime.jsx(
10227
- CustomItemForm,
10228
- {
10229
- orderId: preview.id,
10230
- currencyCode
10231
- }
10232
- ) : null)
10233
- ]
10234
- }
10235
- ) }),
10236
- /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
10237
- /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
10056
+ promotion.id
10057
+ )) })
10058
+ ] }) }),
10059
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-2", children: [
10060
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
10238
10061
  /* @__PURE__ */ jsxRuntime.jsx(
10239
10062
  ui.Button,
10240
10063
  {
10241
10064
  size: "small",
10242
- type: "button",
10243
- onClick: onSubmit,
10244
- isLoading: isSubmitting,
10065
+ type: "submit",
10066
+ isLoading: isSubmitting || isAddingPromotions,
10245
10067
  children: "Save"
10246
10068
  }
10247
10069
  )
10248
10070
  ] }) })
10249
10071
  ] });
10250
10072
  };
10251
- const Item = ({ item, preview, currencyCode }) => {
10252
- if (item.variant_id) {
10253
- return /* @__PURE__ */ jsxRuntime.jsx(VariantItem, { item, preview, currencyCode });
10254
- }
10255
- return /* @__PURE__ */ jsxRuntime.jsx(CustomItem, { item, preview, currencyCode });
10256
- };
10257
- const VariantItem = ({ item, preview, currencyCode }) => {
10258
- const [editing, setEditing] = React.useState(false);
10259
- const form = reactHookForm.useForm({
10260
- defaultValues: {
10261
- quantity: item.quantity,
10262
- unit_price: item.unit_price
10263
- },
10264
- resolver: zod.zodResolver(variantItemSchema)
10265
- });
10266
- const actionId = React.useMemo(() => {
10267
- var _a, _b;
10268
- return (_b = (_a = item.actions) == null ? void 0 : _a.find((a) => a.action === "ITEM_ADD")) == null ? void 0 : _b.id;
10269
- }, [item]);
10270
- const { mutateAsync: updateActionItem, isPending: isUpdatingActionItem } = useDraftOrderUpdateActionItem(preview.id);
10271
- const { mutateAsync: updateOriginalItem, isPending: isUpdatingOriginalItem } = useDraftOrderUpdateItem(preview.id);
10272
- const isPending = isUpdatingActionItem || isUpdatingOriginalItem;
10273
- const onSubmit = form.handleSubmit(async (data) => {
10274
- if (convertNumber(data.unit_price) === item.unit_price && data.quantity === item.quantity) {
10275
- setEditing(false);
10276
- return;
10277
- }
10278
- if (!actionId) {
10279
- await updateOriginalItem(
10280
- {
10281
- item_id: item.id,
10282
- quantity: data.quantity,
10283
- unit_price: convertNumber(data.unit_price)
10284
- },
10285
- {
10286
- onSuccess: () => {
10287
- setEditing(false);
10288
- },
10289
- onError: (e) => {
10290
- ui.toast.error(e.message);
10291
- }
10292
- }
10293
- );
10294
- return;
10295
- }
10296
- await updateActionItem(
10073
+ const PromotionItem = ({
10074
+ promotion,
10075
+ orderId,
10076
+ isLoading
10077
+ }) => {
10078
+ var _a;
10079
+ const { mutateAsync: removePromotions, isPending } = useDraftOrderRemovePromotions(orderId);
10080
+ const onRemove = async () => {
10081
+ removePromotions(
10297
10082
  {
10298
- action_id: actionId,
10299
- quantity: data.quantity,
10300
- unit_price: convertNumber(data.unit_price)
10083
+ promo_codes: [promotion.code]
10301
10084
  },
10302
10085
  {
10303
- onSuccess: () => {
10304
- setEditing(false);
10305
- },
10306
10086
  onError: (e) => {
10307
10087
  ui.toast.error(e.message);
10308
10088
  }
10309
10089
  }
10310
10090
  );
10311
- });
10312
- return /* @__PURE__ */ jsxRuntime.jsx(Form$2, { ...form, children: /* @__PURE__ */ jsxRuntime.jsx("form", { onSubmit, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-base shadow-elevation-card-rest grid grid-cols-[minmax(0,2fr)_minmax(0,1fr)_minmax(0,2fr)_28px] items-center gap-3 rounded-lg px-4 py-2", children: [
10313
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex w-full items-center gap-x-3", children: [
10314
- /* @__PURE__ */ jsxRuntime.jsx(
10315
- Thumbnail,
10091
+ };
10092
+ const displayValue = getDisplayValue(promotion);
10093
+ return /* @__PURE__ */ jsxRuntime.jsxs(
10094
+ "div",
10095
+ {
10096
+ className: ui.clx(
10097
+ "bg-ui-bg-component shadow-elevation-card-rest flex items-center justify-between rounded-lg px-3 py-2",
10316
10098
  {
10317
- thumbnail: item.thumbnail,
10318
- alt: item.product_title ?? void 0
10099
+ "animate-pulse": isLoading
10319
10100
  }
10320
10101
  ),
10321
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
10322
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-x-1", children: [
10323
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", leading: "compact", children: item.product_title }),
10324
- /* @__PURE__ */ jsxRuntime.jsxs(
10325
- ui.Text,
10326
- {
10327
- size: "small",
10328
- leading: "compact",
10329
- className: "text-ui-fg-subtle",
10330
- children: [
10331
- "(",
10332
- item.variant_title,
10333
- ")"
10334
- ]
10335
- }
10336
- )
10102
+ children: [
10103
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
10104
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", leading: "compact", children: promotion.code }),
10105
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-ui-fg-subtle flex items-center gap-1.5", children: [
10106
+ displayValue && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
10107
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", leading: "compact", children: displayValue }),
10108
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", leading: "compact", children: "·" })
10109
+ ] }),
10110
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", leading: "compact", className: "capitalize", children: (_a = promotion.application_method) == null ? void 0 : _a.allocation })
10111
+ ] })
10337
10112
  ] }),
10338
10113
  /* @__PURE__ */ jsxRuntime.jsx(
10339
- ui.Text,
10114
+ ui.IconButton,
10340
10115
  {
10341
10116
  size: "small",
10342
- leading: "compact",
10343
- className: "text-ui-fg-subtle",
10344
- children: item.variant_sku
10345
- }
10346
- )
10347
- ] })
10348
- ] }),
10349
- editing ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(
10350
- Form$2.Field,
10351
- {
10352
- control: form.control,
10353
- name: "quantity",
10354
- render: ({ field }) => {
10355
- return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(NumberInput, { ...field }) }) });
10117
+ type: "button",
10118
+ variant: "transparent",
10119
+ onClick: onRemove,
10120
+ isLoading: isPending || isLoading,
10121
+ children: /* @__PURE__ */ jsxRuntime.jsx(icons.XMark, {})
10122
+ }
10123
+ )
10124
+ ]
10125
+ },
10126
+ promotion.id
10127
+ );
10128
+ };
10129
+ function getDisplayValue(promotion) {
10130
+ var _a, _b, _c, _d;
10131
+ const value = (_a = promotion.application_method) == null ? void 0 : _a.value;
10132
+ if (!value) {
10133
+ return null;
10134
+ }
10135
+ if (((_b = promotion.application_method) == null ? void 0 : _b.type) === "fixed") {
10136
+ const currency = (_c = promotion.application_method) == null ? void 0 : _c.currency_code;
10137
+ if (!currency) {
10138
+ return null;
10139
+ }
10140
+ return getLocaleAmount(value, currency);
10141
+ } else if (((_d = promotion.application_method) == null ? void 0 : _d.type) === "percentage") {
10142
+ return formatPercentage(value);
10143
+ }
10144
+ return null;
10145
+ }
10146
+ const formatter = new Intl.NumberFormat([], {
10147
+ style: "percent",
10148
+ minimumFractionDigits: 2
10149
+ });
10150
+ const formatPercentage = (value, isPercentageValue = false) => {
10151
+ let val = value || 0;
10152
+ if (!isPercentageValue) {
10153
+ val = val / 100;
10154
+ }
10155
+ return formatter.format(val);
10156
+ };
10157
+ function getPromotionIds(items, shippingMethods) {
10158
+ const promotionIds = /* @__PURE__ */ new Set();
10159
+ for (const item of items) {
10160
+ if (item.adjustments) {
10161
+ for (const adjustment of item.adjustments) {
10162
+ if (adjustment.promotion_id) {
10163
+ promotionIds.add(adjustment.promotion_id);
10356
10164
  }
10357
10165
  }
10358
- ) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: item.quantity }) }),
10359
- editing ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(
10360
- Form$2.Field,
10361
- {
10362
- control: form.control,
10363
- name: "unit_price",
10364
- render: ({ field: { onChange, ...field } }) => {
10365
- return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
10366
- ui.CurrencyInput,
10367
- {
10368
- ...field,
10369
- symbol: getNativeSymbol(currencyCode),
10370
- code: currencyCode,
10371
- onValueChange: (_value, _name, values) => onChange(values == null ? void 0 : values.value)
10372
- }
10373
- ) }) });
10166
+ }
10167
+ }
10168
+ for (const shippingMethod of shippingMethods) {
10169
+ if (shippingMethod.adjustments) {
10170
+ for (const adjustment of shippingMethod.adjustments) {
10171
+ if (adjustment.promotion_id) {
10172
+ promotionIds.add(adjustment.promotion_id);
10374
10173
  }
10375
10174
  }
10376
- ) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex w-full flex-1 items-center justify-end", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: getLocaleAmount(item.unit_price, currencyCode) }) }),
10377
- /* @__PURE__ */ jsxRuntime.jsx(
10378
- ui.IconButton,
10175
+ }
10176
+ }
10177
+ return Array.from(promotionIds);
10178
+ }
10179
+ const InlineTip = React.forwardRef(
10180
+ ({ variant = "tip", label, className, children, ...props }, ref) => {
10181
+ const labelValue = label || (variant === "warning" ? "Warning" : "Tip");
10182
+ return /* @__PURE__ */ jsxRuntime.jsxs(
10183
+ "div",
10379
10184
  {
10380
- type: "button",
10381
- size: "small",
10382
- onClick: editing ? onSubmit : () => {
10383
- setEditing(true);
10384
- },
10385
- disabled: isPending,
10386
- children: editing ? /* @__PURE__ */ jsxRuntime.jsx(icons.Check, {}) : /* @__PURE__ */ jsxRuntime.jsx(icons.PencilSquare, {})
10185
+ ref,
10186
+ className: ui.clx(
10187
+ "bg-ui-bg-component txt-small text-ui-fg-subtle grid grid-cols-[4px_1fr] items-start gap-3 rounded-lg border p-3",
10188
+ className
10189
+ ),
10190
+ ...props,
10191
+ children: [
10192
+ /* @__PURE__ */ jsxRuntime.jsx(
10193
+ "div",
10194
+ {
10195
+ role: "presentation",
10196
+ className: ui.clx("w-4px bg-ui-tag-neutral-icon h-full rounded-full", {
10197
+ "bg-ui-tag-orange-icon": variant === "warning"
10198
+ })
10199
+ }
10200
+ ),
10201
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-pretty", children: [
10202
+ /* @__PURE__ */ jsxRuntime.jsxs("strong", { className: "txt-small-plus text-ui-fg-base", children: [
10203
+ labelValue,
10204
+ ":"
10205
+ ] }),
10206
+ " ",
10207
+ children
10208
+ ] })
10209
+ ]
10387
10210
  }
10388
- )
10389
- ] }) }) });
10390
- };
10391
- const variantItemSchema = objectType({
10392
- quantity: numberType(),
10393
- unit_price: unionType([numberType(), stringType()])
10211
+ );
10212
+ }
10213
+ );
10214
+ InlineTip.displayName = "InlineTip";
10215
+ const MetadataFieldSchema = objectType({
10216
+ key: stringType(),
10217
+ disabled: booleanType().optional(),
10218
+ value: anyType()
10394
10219
  });
10395
- const CustomItem = ({ item, preview, currencyCode }) => {
10396
- const [editing, setEditing] = React.useState(false);
10397
- const { quantity, unit_price, title } = item;
10220
+ const MetadataSchema = objectType({
10221
+ metadata: arrayType(MetadataFieldSchema)
10222
+ });
10223
+ const Metadata = () => {
10224
+ const { id } = reactRouterDom.useParams();
10225
+ const { order, isPending, isError, error } = useOrder(id, {
10226
+ fields: "metadata"
10227
+ });
10228
+ if (isError) {
10229
+ throw error;
10230
+ }
10231
+ const isReady = !isPending && !!order;
10232
+ return /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer, { children: [
10233
+ /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer.Header, { children: [
10234
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Metadata" }) }),
10235
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Description, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Add metadata to the draft order." }) })
10236
+ ] }),
10237
+ !isReady ? /* @__PURE__ */ jsxRuntime.jsx(PlaceholderInner, {}) : /* @__PURE__ */ jsxRuntime.jsx(MetadataForm, { orderId: id, metadata: order == null ? void 0 : order.metadata })
10238
+ ] });
10239
+ };
10240
+ const METADATA_KEY_LABEL_ID = "metadata-form-key-label";
10241
+ const METADATA_VALUE_LABEL_ID = "metadata-form-value-label";
10242
+ const MetadataForm = ({ orderId, metadata }) => {
10243
+ const { handleSuccess } = useRouteModal();
10244
+ const hasUneditableRows = getHasUneditableRows(metadata);
10245
+ const { mutateAsync, isPending } = useUpdateDraftOrder(orderId);
10398
10246
  const form = reactHookForm.useForm({
10399
10247
  defaultValues: {
10400
- title,
10401
- quantity,
10402
- unit_price
10248
+ metadata: getDefaultValues(metadata)
10403
10249
  },
10404
- resolver: zod.zodResolver(customItemSchema)
10250
+ resolver: zod.zodResolver(MetadataSchema)
10405
10251
  });
10406
- React.useEffect(() => {
10407
- form.reset({
10408
- title,
10409
- quantity,
10410
- unit_price
10411
- });
10412
- }, [form, title, quantity, unit_price]);
10413
- const actionId = React.useMemo(() => {
10414
- var _a, _b;
10415
- return (_b = (_a = item.actions) == null ? void 0 : _a.find((a) => a.action === "ITEM_ADD")) == null ? void 0 : _b.id;
10416
- }, [item]);
10417
- const { mutateAsync: updateActionItem, isPending: isUpdatingActionItem } = useDraftOrderUpdateActionItem(preview.id);
10418
- const { mutateAsync: removeActionItem, isPending: isRemovingActionItem } = useDraftOrderRemoveActionItem(preview.id);
10419
- const { mutateAsync: updateOriginalItem, isPending: isUpdatingOriginalItem } = useDraftOrderUpdateItem(preview.id);
10420
- const isPending = isUpdatingActionItem || isUpdatingOriginalItem;
10421
- const onSubmit = form.handleSubmit(async (data) => {
10422
- if (convertNumber(data.unit_price) === item.unit_price && data.quantity === item.quantity && data.title === item.title) {
10423
- setEditing(false);
10424
- return;
10425
- }
10426
- if (!actionId) {
10427
- await updateOriginalItem(
10428
- {
10429
- item_id: item.id,
10430
- quantity: data.quantity,
10431
- unit_price: convertNumber(data.unit_price)
10432
- },
10433
- {
10434
- onSuccess: () => {
10435
- setEditing(false);
10436
- },
10437
- onError: (e) => {
10438
- ui.toast.error(e.message);
10439
- }
10440
- }
10441
- );
10442
- return;
10443
- }
10444
- if (data.quantity === 0) {
10445
- await removeActionItem(actionId, {
10446
- onSuccess: () => {
10447
- setEditing(false);
10448
- },
10449
- onError: (e) => {
10450
- ui.toast.error(e.message);
10451
- }
10452
- });
10453
- return;
10454
- }
10455
- await updateActionItem(
10252
+ const handleSubmit = form.handleSubmit(async (data) => {
10253
+ const parsedData = parseValues(data);
10254
+ await mutateAsync(
10456
10255
  {
10457
- action_id: actionId,
10458
- quantity: data.quantity,
10459
- unit_price: convertNumber(data.unit_price)
10256
+ metadata: parsedData
10460
10257
  },
10461
10258
  {
10462
10259
  onSuccess: () => {
10463
- setEditing(false);
10260
+ ui.toast.success("Metadata updated");
10261
+ handleSuccess();
10464
10262
  },
10465
- onError: (e) => {
10466
- ui.toast.error(e.message);
10263
+ onError: (error) => {
10264
+ ui.toast.error(error.message);
10467
10265
  }
10468
10266
  }
10469
10267
  );
10470
10268
  });
10471
- return /* @__PURE__ */ jsxRuntime.jsx(Form$2, { ...form, children: /* @__PURE__ */ jsxRuntime.jsx("form", { onSubmit, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-base shadow-elevation-card-rest grid grid-cols-[minmax(0,2fr)_minmax(0,1fr)_minmax(0,2fr)_28px] items-center gap-3 rounded-lg px-4 py-2", children: [
10472
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-x-3", children: [
10473
- /* @__PURE__ */ jsxRuntime.jsx(
10474
- Thumbnail,
10475
- {
10476
- thumbnail: item.thumbnail,
10477
- alt: item.title ?? void 0
10478
- }
10479
- ),
10480
- editing ? /* @__PURE__ */ jsxRuntime.jsx(
10481
- Form$2.Field,
10482
- {
10483
- control: form.control,
10484
- name: "title",
10485
- render: ({ field }) => {
10486
- return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Input, { ...field }) }) });
10487
- }
10488
- }
10489
- ) : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: item.title })
10490
- ] }),
10491
- editing ? /* @__PURE__ */ jsxRuntime.jsx(
10492
- Form$2.Field,
10493
- {
10494
- control: form.control,
10495
- name: "quantity",
10496
- render: ({ field }) => {
10497
- return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(NumberInput, { ...field }) }) });
10498
- }
10499
- }
10500
- ) : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: item.quantity }),
10501
- editing ? /* @__PURE__ */ jsxRuntime.jsx(
10502
- Form$2.Field,
10503
- {
10504
- control: form.control,
10505
- name: "unit_price",
10506
- render: ({ field: { onChange, ...field } }) => {
10507
- return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
10508
- ui.CurrencyInput,
10509
- {
10510
- ...field,
10511
- symbol: getNativeSymbol(currencyCode),
10512
- code: currencyCode,
10513
- onValueChange: (_value, _name, values) => onChange(values == null ? void 0 : values.value)
10514
- }
10515
- ) }) });
10516
- }
10517
- }
10518
- ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-1 items-center justify-end", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: getLocaleAmount(item.unit_price, currencyCode) }) }),
10519
- /* @__PURE__ */ jsxRuntime.jsx(
10520
- ui.IconButton,
10521
- {
10522
- type: "button",
10523
- size: "small",
10524
- onClick: editing ? onSubmit : () => {
10525
- setEditing(true);
10526
- },
10527
- disabled: isPending,
10528
- children: editing ? /* @__PURE__ */ jsxRuntime.jsx(icons.Check, {}) : /* @__PURE__ */ jsxRuntime.jsx(icons.PencilSquare, {})
10529
- }
10530
- )
10531
- ] }) }) });
10532
- };
10533
- const StackedModalTrigger$1 = ({
10534
- type,
10535
- setModalContent
10536
- }) => {
10537
- const { setIsOpen } = useStackedModal();
10538
- const onClick = React.useCallback(() => {
10539
- setModalContent(type);
10540
- setIsOpen(STACKED_MODAL_ID, true);
10541
- }, [setModalContent, setIsOpen, type]);
10542
- return /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenu.Item, { onClick, children: type === "add-items" ? "Add items" : "Add custom item" }) });
10543
- };
10544
- const VARIANT_PREFIX = "items";
10545
- const LIMIT = 50;
10546
- const ExistingItemsForm = ({ orderId, items }) => {
10547
- const { setIsOpen } = useStackedModal();
10548
- const [rowSelection, setRowSelection] = React.useState(
10549
- items.reduce((acc, item) => {
10550
- acc[item.variant_id] = true;
10551
- return acc;
10552
- }, {})
10553
- );
10554
- React.useEffect(() => {
10555
- setRowSelection(
10556
- items.reduce((acc, item) => {
10557
- if (item.variant_id) {
10558
- acc[item.variant_id] = true;
10559
- }
10560
- return acc;
10561
- }, {})
10562
- );
10563
- }, [items]);
10564
- const { q, order, offset } = useQueryParams(
10565
- ["q", "order", "offset"],
10566
- VARIANT_PREFIX
10567
- );
10568
- const { variants, count, isPending, isError, error } = useProductVariants(
10269
+ const { fields, insert, remove } = reactHookForm.useFieldArray({
10270
+ control: form.control,
10271
+ name: "metadata"
10272
+ });
10273
+ function deleteRow(index) {
10274
+ remove(index);
10275
+ if (fields.length === 1) {
10276
+ insert(0, {
10277
+ key: "",
10278
+ value: "",
10279
+ disabled: false
10280
+ });
10281
+ }
10282
+ }
10283
+ function insertRow(index, position) {
10284
+ insert(index + (position === "above" ? 0 : 1), {
10285
+ key: "",
10286
+ value: "",
10287
+ disabled: false
10288
+ });
10289
+ }
10290
+ return /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxRuntime.jsxs(
10291
+ KeyboundForm,
10569
10292
  {
10570
- q,
10571
- order,
10572
- offset: offset ? parseInt(offset) : void 0,
10573
- limit: LIMIT
10574
- },
10293
+ onSubmit: handleSubmit,
10294
+ className: "flex flex-1 flex-col overflow-hidden",
10295
+ children: [
10296
+ /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer.Body, { className: "flex flex-1 flex-col gap-y-8 overflow-y-auto", children: [
10297
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-base shadow-elevation-card-rest grid grid-cols-1 divide-y rounded-lg", children: [
10298
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-subtle grid grid-cols-2 divide-x rounded-t-lg", children: [
10299
+ /* @__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" }) }),
10300
+ /* @__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" }) })
10301
+ ] }),
10302
+ fields.map((field, index) => {
10303
+ const isDisabled = field.disabled || false;
10304
+ let placeholder = "-";
10305
+ if (typeof field.value === "object") {
10306
+ placeholder = "{ ... }";
10307
+ }
10308
+ if (Array.isArray(field.value)) {
10309
+ placeholder = "[ ... ]";
10310
+ }
10311
+ return /* @__PURE__ */ jsxRuntime.jsx(
10312
+ ConditionalTooltip,
10313
+ {
10314
+ showTooltip: isDisabled,
10315
+ content: "This row is disabled because it contains non-primitive data.",
10316
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "group/table relative", children: [
10317
+ /* @__PURE__ */ jsxRuntime.jsxs(
10318
+ "div",
10319
+ {
10320
+ className: ui.clx("grid grid-cols-2 divide-x", {
10321
+ "overflow-hidden rounded-b-lg": index === fields.length - 1
10322
+ }),
10323
+ children: [
10324
+ /* @__PURE__ */ jsxRuntime.jsx(
10325
+ Form$2.Field,
10326
+ {
10327
+ control: form.control,
10328
+ name: `metadata.${index}.key`,
10329
+ render: ({ field: field2 }) => {
10330
+ return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
10331
+ GridInput,
10332
+ {
10333
+ "aria-labelledby": METADATA_KEY_LABEL_ID,
10334
+ ...field2,
10335
+ disabled: isDisabled,
10336
+ placeholder: "Key"
10337
+ }
10338
+ ) }) });
10339
+ }
10340
+ }
10341
+ ),
10342
+ /* @__PURE__ */ jsxRuntime.jsx(
10343
+ Form$2.Field,
10344
+ {
10345
+ control: form.control,
10346
+ name: `metadata.${index}.value`,
10347
+ render: ({ field: { value, ...field2 } }) => {
10348
+ return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
10349
+ GridInput,
10350
+ {
10351
+ "aria-labelledby": METADATA_VALUE_LABEL_ID,
10352
+ ...field2,
10353
+ value: isDisabled ? placeholder : value,
10354
+ disabled: isDisabled,
10355
+ placeholder: "Value"
10356
+ }
10357
+ ) }) });
10358
+ }
10359
+ }
10360
+ )
10361
+ ]
10362
+ }
10363
+ ),
10364
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu, { children: [
10365
+ /* @__PURE__ */ jsxRuntime.jsx(
10366
+ ui.DropdownMenu.Trigger,
10367
+ {
10368
+ className: ui.clx(
10369
+ "invisible absolute inset-y-0 -right-2.5 my-auto group-hover/table:visible data-[state='open']:visible",
10370
+ {
10371
+ hidden: isDisabled
10372
+ }
10373
+ ),
10374
+ disabled: isDisabled,
10375
+ asChild: true,
10376
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { size: "2xsmall", children: /* @__PURE__ */ jsxRuntime.jsx(icons.EllipsisVertical, {}) })
10377
+ }
10378
+ ),
10379
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu.Content, { children: [
10380
+ /* @__PURE__ */ jsxRuntime.jsxs(
10381
+ ui.DropdownMenu.Item,
10382
+ {
10383
+ className: "gap-x-2",
10384
+ onClick: () => insertRow(index, "above"),
10385
+ children: [
10386
+ /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowUpMini, { className: "text-ui-fg-subtle" }),
10387
+ "Insert row above"
10388
+ ]
10389
+ }
10390
+ ),
10391
+ /* @__PURE__ */ jsxRuntime.jsxs(
10392
+ ui.DropdownMenu.Item,
10393
+ {
10394
+ className: "gap-x-2",
10395
+ onClick: () => insertRow(index, "below"),
10396
+ children: [
10397
+ /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowDownMini, { className: "text-ui-fg-subtle" }),
10398
+ "Insert row below"
10399
+ ]
10400
+ }
10401
+ ),
10402
+ /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenu.Separator, {}),
10403
+ /* @__PURE__ */ jsxRuntime.jsxs(
10404
+ ui.DropdownMenu.Item,
10405
+ {
10406
+ className: "gap-x-2",
10407
+ onClick: () => deleteRow(index),
10408
+ children: [
10409
+ /* @__PURE__ */ jsxRuntime.jsx(icons.Trash, { className: "text-ui-fg-subtle" }),
10410
+ "Delete row"
10411
+ ]
10412
+ }
10413
+ )
10414
+ ] })
10415
+ ] })
10416
+ ] })
10417
+ },
10418
+ field.id
10419
+ );
10420
+ })
10421
+ ] }),
10422
+ 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." })
10423
+ ] }),
10424
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
10425
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
10426
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", type: "submit", isLoading: isPending, children: "Save" })
10427
+ ] }) })
10428
+ ]
10429
+ }
10430
+ ) });
10431
+ };
10432
+ const GridInput = React.forwardRef(({ className, ...props }, ref) => {
10433
+ return /* @__PURE__ */ jsxRuntime.jsx(
10434
+ "input",
10575
10435
  {
10576
- placeholderData: reactQuery.keepPreviousData
10436
+ ref,
10437
+ ...props,
10438
+ autoComplete: "off",
10439
+ className: ui.clx(
10440
+ "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",
10441
+ className
10442
+ )
10577
10443
  }
10578
10444
  );
10579
- const columns = useColumns();
10580
- const { mutateAsync } = useDraftOrderAddItems(orderId);
10581
- const onSubmit = async () => {
10582
- const ids = Object.keys(rowSelection).filter(
10583
- (id) => !items.find((i) => i.variant_id === id)
10584
- );
10585
- await mutateAsync(
10586
- {
10587
- items: ids.map((id) => ({
10588
- variant_id: id,
10589
- quantity: 1
10590
- }))
10591
- },
10445
+ });
10446
+ GridInput.displayName = "MetadataForm.GridInput";
10447
+ const PlaceholderInner = () => {
10448
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col overflow-hidden", children: [
10449
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Body, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: "h-[148ox] w-full rounded-lg" }) }),
10450
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
10451
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: "h-7 w-12 rounded-md" }),
10452
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: "h-7 w-12 rounded-md" })
10453
+ ] }) })
10454
+ ] });
10455
+ };
10456
+ const EDITABLE_TYPES = ["string", "number", "boolean"];
10457
+ function getDefaultValues(metadata) {
10458
+ if (!metadata || !Object.keys(metadata).length) {
10459
+ return [
10592
10460
  {
10593
- onSuccess: () => {
10594
- setRowSelection({});
10595
- setIsOpen(STACKED_MODAL_ID, false);
10596
- },
10597
- onError: (e) => {
10598
- ui.toast.error(e.message);
10599
- }
10461
+ key: "",
10462
+ value: "",
10463
+ disabled: false
10600
10464
  }
10601
- );
10602
- };
10603
- if (isError) {
10604
- throw error;
10465
+ ];
10466
+ }
10467
+ return Object.entries(metadata).map(([key, value]) => {
10468
+ if (!EDITABLE_TYPES.includes(typeof value)) {
10469
+ return {
10470
+ key,
10471
+ value,
10472
+ disabled: true
10473
+ };
10474
+ }
10475
+ let stringValue = value;
10476
+ if (typeof value !== "string") {
10477
+ stringValue = JSON.stringify(value);
10478
+ }
10479
+ return {
10480
+ key,
10481
+ value: stringValue,
10482
+ original_key: key
10483
+ };
10484
+ });
10485
+ }
10486
+ function parseValues(values) {
10487
+ const metadata = values.metadata;
10488
+ const isEmpty = !metadata.length || metadata.length === 1 && !metadata[0].key && !metadata[0].value;
10489
+ if (isEmpty) {
10490
+ return null;
10491
+ }
10492
+ const update = {};
10493
+ metadata.forEach((field) => {
10494
+ let key = field.key;
10495
+ let value = field.value;
10496
+ const disabled = field.disabled;
10497
+ if (!key || !value) {
10498
+ return;
10499
+ }
10500
+ if (disabled) {
10501
+ update[key] = value;
10502
+ return;
10503
+ }
10504
+ key = key.trim();
10505
+ value = value.trim();
10506
+ if (value === "true") {
10507
+ update[key] = true;
10508
+ } else if (value === "false") {
10509
+ update[key] = false;
10510
+ } else {
10511
+ const parsedNumber = parseFloat(value);
10512
+ if (!isNaN(parsedNumber)) {
10513
+ update[key] = parsedNumber;
10514
+ } else {
10515
+ update[key] = value;
10516
+ }
10517
+ }
10518
+ });
10519
+ return update;
10520
+ }
10521
+ function getHasUneditableRows(metadata) {
10522
+ if (!metadata) {
10523
+ return false;
10605
10524
  }
10606
- return /* @__PURE__ */ jsxRuntime.jsxs(
10607
- StackedFocusModal.Content,
10525
+ return Object.values(metadata).some(
10526
+ (value) => !EDITABLE_TYPES.includes(typeof value)
10527
+ );
10528
+ }
10529
+ const SalesChannel = () => {
10530
+ const { id } = reactRouterDom.useParams();
10531
+ const { draft_order, isPending, isError, error } = useDraftOrder(
10532
+ id,
10608
10533
  {
10609
- onOpenAutoFocus: (e) => {
10610
- e.preventDefault();
10611
- const searchInput = document.querySelector(
10612
- "[data-modal-id='modal-search-input']"
10613
- );
10614
- if (searchInput) {
10615
- searchInput.focus();
10616
- }
10617
- },
10618
- children: [
10619
- /* @__PURE__ */ jsxRuntime.jsxs(StackedFocusModal.Header, { children: [
10620
- /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Product Variants" }) }),
10621
- /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Choose product variants to add to the order." }) })
10622
- ] }),
10623
- /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Body, { className: "flex-1 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
10624
- DataTable,
10625
- {
10626
- data: variants,
10627
- columns,
10628
- isLoading: isPending,
10629
- getRowId: (row) => row.id,
10630
- rowCount: count,
10631
- prefix: VARIANT_PREFIX,
10632
- layout: "fill",
10633
- rowSelection: {
10634
- state: rowSelection,
10635
- onRowSelectionChange: setRowSelection,
10636
- enableRowSelection: (row) => {
10637
- return !items.find((i) => i.variant_id === row.original.id);
10638
- }
10639
- },
10640
- autoFocusSearch: true
10641
- }
10642
- ) }),
10643
- /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
10644
- /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
10645
- /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", type: "button", onClick: onSubmit, children: "Update items" })
10646
- ] }) })
10647
- ]
10534
+ fields: "+sales_channel_id"
10535
+ },
10536
+ {
10537
+ enabled: !!id
10648
10538
  }
10649
10539
  );
10540
+ if (isError) {
10541
+ throw error;
10542
+ }
10543
+ const ISrEADY = !!draft_order && !isPending;
10544
+ return /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer, { children: [
10545
+ /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer.Header, { children: [
10546
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Edit Sales Channel" }) }),
10547
+ /* @__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" }) })
10548
+ ] }),
10549
+ ISrEADY && /* @__PURE__ */ jsxRuntime.jsx(SalesChannelForm, { order: draft_order })
10550
+ ] });
10650
10551
  };
10651
- const columnHelper = ui.createDataTableColumnHelper();
10652
- const useColumns = () => {
10653
- return React.useMemo(() => {
10654
- return [
10655
- columnHelper.select(),
10656
- columnHelper.accessor("product.title", {
10657
- header: "Product",
10658
- cell: ({ row }) => {
10659
- var _a, _b, _c;
10660
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-x-2", children: [
10661
- /* @__PURE__ */ jsxRuntime.jsx(
10662
- Thumbnail,
10663
- {
10664
- thumbnail: (_a = row.original.product) == null ? void 0 : _a.thumbnail,
10665
- alt: (_b = row.original.product) == null ? void 0 : _b.title
10666
- }
10667
- ),
10668
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: (_c = row.original.product) == null ? void 0 : _c.title })
10669
- ] });
10670
- },
10671
- enableSorting: true
10672
- }),
10673
- columnHelper.accessor("title", {
10674
- header: "Variant",
10675
- enableSorting: true
10676
- }),
10677
- columnHelper.accessor("sku", {
10678
- header: "SKU",
10679
- cell: ({ getValue }) => {
10680
- return getValue() ?? "-";
10681
- },
10682
- enableSorting: true
10683
- }),
10684
- columnHelper.accessor("updated_at", {
10685
- header: "Updated",
10686
- cell: ({ getValue }) => {
10687
- return /* @__PURE__ */ jsxRuntime.jsx(
10688
- ui.Tooltip,
10689
- {
10690
- content: getFullDate({ date: getValue(), includeTime: true }),
10691
- children: /* @__PURE__ */ jsxRuntime.jsx("span", { children: getFullDate({ date: getValue() }) })
10692
- }
10693
- );
10694
- },
10695
- enableSorting: true,
10696
- sortAscLabel: "Oldest first",
10697
- sortDescLabel: "Newest first"
10698
- }),
10699
- columnHelper.accessor("created_at", {
10700
- header: "Created",
10701
- cell: ({ getValue }) => {
10702
- return /* @__PURE__ */ jsxRuntime.jsx(
10703
- ui.Tooltip,
10704
- {
10705
- content: getFullDate({ date: getValue(), includeTime: true }),
10706
- children: /* @__PURE__ */ jsxRuntime.jsx("span", { children: getFullDate({ date: getValue() }) })
10707
- }
10708
- );
10709
- },
10710
- enableSorting: true,
10711
- sortAscLabel: "Oldest first",
10712
- sortDescLabel: "Newest first"
10713
- })
10714
- ];
10715
- }, []);
10716
- };
10717
- const CustomItemForm = ({ orderId, currencyCode }) => {
10718
- const { setIsOpen } = useStackedModal();
10719
- const { mutateAsync: addItems } = useDraftOrderAddItems(orderId);
10552
+ const SalesChannelForm = ({ order }) => {
10720
10553
  const form = reactHookForm.useForm({
10721
10554
  defaultValues: {
10722
- title: "",
10723
- quantity: 1,
10724
- unit_price: ""
10555
+ sales_channel_id: order.sales_channel_id || ""
10725
10556
  },
10726
- resolver: zod.zodResolver(customItemSchema)
10557
+ resolver: zod.zodResolver(schema$2)
10727
10558
  });
10559
+ const { mutateAsync, isPending } = useUpdateDraftOrder(order.id);
10560
+ const { handleSuccess } = useRouteModal();
10728
10561
  const onSubmit = form.handleSubmit(async (data) => {
10729
- await addItems(
10562
+ await mutateAsync(
10730
10563
  {
10731
- items: [
10732
- {
10733
- title: data.title,
10734
- quantity: data.quantity,
10735
- unit_price: convertNumber(data.unit_price)
10736
- }
10737
- ]
10564
+ sales_channel_id: data.sales_channel_id
10738
10565
  },
10739
10566
  {
10740
10567
  onSuccess: () => {
10741
- setIsOpen(STACKED_MODAL_ID, false);
10568
+ ui.toast.success("Sales channel updated");
10569
+ handleSuccess();
10742
10570
  },
10743
- onError: (e) => {
10744
- ui.toast.error(e.message);
10571
+ onError: (error) => {
10572
+ ui.toast.error(error.message);
10745
10573
  }
10746
10574
  }
10747
10575
  );
10748
10576
  });
10749
- return /* @__PURE__ */ jsxRuntime.jsx(Form$2, { ...form, children: /* @__PURE__ */ jsxRuntime.jsx(KeyboundForm, { onSubmit, children: /* @__PURE__ */ jsxRuntime.jsxs(StackedFocusModal.Content, { children: [
10750
- /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Header, {}),
10751
- /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.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-2 py-16", children: [
10752
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
10753
- /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Add custom item" }) }),
10754
- /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Add a custom item to the order. This will add a new line item that is not associated with an existing product." }) })
10755
- ] }),
10756
- /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { variant: "dashed" }),
10757
- /* @__PURE__ */ jsxRuntime.jsx(
10758
- Form$2.Field,
10759
- {
10760
- control: form.control,
10761
- name: "title",
10762
- render: ({ field }) => /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
10763
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
10764
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.Label, { children: "Title" }),
10765
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.Hint, { children: "Enter the title of the item" })
10766
- ] }),
10767
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
10768
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Input, { ...field }) }),
10769
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.ErrorMessage, {})
10770
- ] })
10771
- ] }) })
10772
- }
10773
- ),
10774
- /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { variant: "dashed" }),
10775
- /* @__PURE__ */ jsxRuntime.jsx(
10776
- Form$2.Field,
10777
- {
10778
- control: form.control,
10779
- name: "unit_price",
10780
- render: ({ field: { onChange, ...field } }) => /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
10781
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
10782
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.Label, { children: "Unit price" }),
10783
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.Hint, { children: "Enter the unit price of the item" })
10784
- ] }),
10785
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
10786
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
10787
- ui.CurrencyInput,
10788
- {
10789
- symbol: getNativeSymbol(currencyCode),
10790
- code: currencyCode,
10791
- onValueChange: (_value, _name, values) => onChange(values == null ? void 0 : values.value),
10792
- ...field
10793
- }
10794
- ) }),
10795
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.ErrorMessage, {})
10796
- ] })
10797
- ] }) })
10798
- }
10799
- ),
10800
- /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { variant: "dashed" }),
10801
- /* @__PURE__ */ jsxRuntime.jsx(
10802
- Form$2.Field,
10803
- {
10804
- control: form.control,
10805
- name: "quantity",
10806
- render: ({ field }) => /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
10807
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
10808
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.Label, { children: "Quantity" }),
10809
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.Hint, { children: "Enter the quantity of the item" })
10810
- ] }),
10811
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full flex-1", children: [
10812
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(NumberInput, { ...field, className: "w-full" }) }) }),
10813
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.ErrorMessage, {})
10814
- ] })
10815
- ] }) })
10816
- }
10817
- )
10818
- ] }) }) }),
10819
- /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
10820
- /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
10821
- /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", type: "button", onClick: onSubmit, children: "Add item" })
10822
- ] }) })
10823
- ] }) }) });
10577
+ return /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxRuntime.jsxs(
10578
+ KeyboundForm,
10579
+ {
10580
+ className: "flex flex-1 flex-col overflow-hidden",
10581
+ onSubmit,
10582
+ children: [
10583
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Body, { className: "flex flex-col gap-y-6 overflow-y-auto", children: /* @__PURE__ */ jsxRuntime.jsx(SalesChannelField, { control: form.control, order }) }),
10584
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-2", children: [
10585
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
10586
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", type: "submit", isLoading: isPending, children: "Save" })
10587
+ ] }) })
10588
+ ]
10589
+ }
10590
+ ) });
10824
10591
  };
10825
- const customItemSchema = objectType({
10826
- title: stringType().min(1),
10827
- quantity: numberType(),
10828
- unit_price: unionType([numberType(), stringType()])
10592
+ const SalesChannelField = ({ control, order }) => {
10593
+ const salesChannels = useComboboxData({
10594
+ queryFn: async (params) => {
10595
+ return await sdk.admin.salesChannel.list(params);
10596
+ },
10597
+ queryKey: ["sales-channels"],
10598
+ getOptions: (data) => {
10599
+ return data.sales_channels.map((salesChannel) => ({
10600
+ label: salesChannel.name,
10601
+ value: salesChannel.id
10602
+ }));
10603
+ },
10604
+ defaultValue: order.sales_channel_id || void 0
10605
+ });
10606
+ return /* @__PURE__ */ jsxRuntime.jsx(
10607
+ Form$2.Field,
10608
+ {
10609
+ control,
10610
+ name: "sales_channel_id",
10611
+ render: ({ field }) => {
10612
+ return /* @__PURE__ */ jsxRuntime.jsxs(Form$2.Item, { children: [
10613
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.Label, { children: "Sales Channel" }),
10614
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
10615
+ Combobox,
10616
+ {
10617
+ options: salesChannels.options,
10618
+ fetchNextPage: salesChannels.fetchNextPage,
10619
+ isFetchingNextPage: salesChannels.isFetchingNextPage,
10620
+ searchValue: salesChannels.searchValue,
10621
+ onSearchValueChange: salesChannels.onSearchValueChange,
10622
+ placeholder: "Select sales channel",
10623
+ ...field
10624
+ }
10625
+ ) }),
10626
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.ErrorMessage, {})
10627
+ ] });
10628
+ }
10629
+ }
10630
+ );
10631
+ };
10632
+ const schema$2 = objectType({
10633
+ sales_channel_id: stringType().min(1)
10829
10634
  });
10830
- const InlineTip = React.forwardRef(
10831
- ({ variant = "tip", label, className, children, ...props }, ref) => {
10832
- const labelValue = label || (variant === "warning" ? "Warning" : "Tip");
10635
+ const NumberInput = React.forwardRef(
10636
+ ({
10637
+ value,
10638
+ onChange,
10639
+ size = "base",
10640
+ min = 0,
10641
+ max = 100,
10642
+ step = 1,
10643
+ className,
10644
+ disabled,
10645
+ ...props
10646
+ }, ref) => {
10647
+ const handleChange = (event) => {
10648
+ const newValue = event.target.value === "" ? min : Number(event.target.value);
10649
+ if (!isNaN(newValue) && (max === void 0 || newValue <= max) && (min === void 0 || newValue >= min)) {
10650
+ onChange(newValue);
10651
+ }
10652
+ };
10653
+ const handleIncrement = () => {
10654
+ const newValue = value + step;
10655
+ if (max === void 0 || newValue <= max) {
10656
+ onChange(newValue);
10657
+ }
10658
+ };
10659
+ const handleDecrement = () => {
10660
+ const newValue = value - step;
10661
+ if (min === void 0 || newValue >= min) {
10662
+ onChange(newValue);
10663
+ }
10664
+ };
10833
10665
  return /* @__PURE__ */ jsxRuntime.jsxs(
10834
10666
  "div",
10835
10667
  {
10836
- ref,
10837
10668
  className: ui.clx(
10838
- "bg-ui-bg-component txt-small text-ui-fg-subtle grid grid-cols-[4px_1fr] items-start gap-3 rounded-lg border p-3",
10669
+ "inline-flex rounded-md bg-ui-bg-field shadow-borders-base overflow-hidden divide-x transition-fg",
10670
+ "[&:has(input:focus)]:shadow-borders-interactive-with-active",
10671
+ {
10672
+ "h-7": size === "small",
10673
+ "h-8": size === "base"
10674
+ },
10839
10675
  className
10840
10676
  ),
10841
- ...props,
10842
10677
  children: [
10843
10678
  /* @__PURE__ */ jsxRuntime.jsx(
10844
- "div",
10679
+ "input",
10845
10680
  {
10846
- role: "presentation",
10847
- className: ui.clx("w-4px bg-ui-tag-neutral-icon h-full rounded-full", {
10848
- "bg-ui-tag-orange-icon": variant === "warning"
10849
- })
10681
+ ref,
10682
+ type: "number",
10683
+ value,
10684
+ onChange: handleChange,
10685
+ min,
10686
+ max,
10687
+ step,
10688
+ className: ui.clx(
10689
+ "flex-1 px-2 py-1 bg-transparent txt-compact-small text-ui-fg-base outline-none [appearance:textfield]",
10690
+ "[&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none",
10691
+ "placeholder:text-ui-fg-muted"
10692
+ ),
10693
+ ...props
10850
10694
  }
10851
10695
  ),
10852
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-pretty", children: [
10853
- /* @__PURE__ */ jsxRuntime.jsxs("strong", { className: "txt-small-plus text-ui-fg-base", children: [
10854
- labelValue,
10855
- ":"
10856
- ] }),
10857
- " ",
10858
- children
10859
- ] })
10696
+ /* @__PURE__ */ jsxRuntime.jsxs(
10697
+ "button",
10698
+ {
10699
+ className: ui.clx(
10700
+ "flex items-center justify-center outline-none transition-fg",
10701
+ "disabled:cursor-not-allowed disabled:text-ui-fg-muted",
10702
+ "focus:bg-ui-bg-field-component-hover",
10703
+ "hover:bg-ui-bg-field-component-hover",
10704
+ {
10705
+ "size-7": size === "small",
10706
+ "size-8": size === "base"
10707
+ }
10708
+ ),
10709
+ type: "button",
10710
+ onClick: handleDecrement,
10711
+ disabled: min !== void 0 && value <= min || disabled,
10712
+ children: [
10713
+ /* @__PURE__ */ jsxRuntime.jsx(icons.Minus, {}),
10714
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: `Decrease by ${step}` })
10715
+ ]
10716
+ }
10717
+ ),
10718
+ /* @__PURE__ */ jsxRuntime.jsxs(
10719
+ "button",
10720
+ {
10721
+ className: ui.clx(
10722
+ "flex items-center justify-center outline-none transition-fg",
10723
+ "disabled:cursor-not-allowed disabled:text-ui-fg-muted",
10724
+ "focus:bg-ui-bg-field-hover",
10725
+ "hover:bg-ui-bg-field-hover",
10726
+ {
10727
+ "size-7": size === "small",
10728
+ "size-8": size === "base"
10729
+ }
10730
+ ),
10731
+ type: "button",
10732
+ onClick: handleIncrement,
10733
+ disabled: max !== void 0 && value >= max || disabled,
10734
+ children: [
10735
+ /* @__PURE__ */ jsxRuntime.jsx(icons.Plus, {}),
10736
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: `Increase by ${step}` })
10737
+ ]
10738
+ }
10739
+ )
10860
10740
  ]
10861
10741
  }
10862
10742
  );
10863
10743
  }
10864
10744
  );
10865
- InlineTip.displayName = "InlineTip";
10866
- const MetadataFieldSchema = objectType({
10867
- key: stringType(),
10868
- disabled: booleanType().optional(),
10869
- value: anyType()
10870
- });
10871
- const MetadataSchema = objectType({
10872
- metadata: arrayType(MetadataFieldSchema)
10873
- });
10874
- const Metadata = () => {
10745
+ const PRODUCT_VARIANTS_QUERY_KEY = "product-variants";
10746
+ const productVariantsQueryKeys = {
10747
+ list: (query2) => [
10748
+ PRODUCT_VARIANTS_QUERY_KEY,
10749
+ query2 ? query2 : void 0
10750
+ ]
10751
+ };
10752
+ const useProductVariants = (query2, options) => {
10753
+ const { data, ...rest } = reactQuery.useQuery({
10754
+ queryKey: productVariantsQueryKeys.list(query2),
10755
+ queryFn: async () => await sdk.admin.productVariant.list(query2),
10756
+ ...options
10757
+ });
10758
+ return { ...data, ...rest };
10759
+ };
10760
+ function convertNumber(value) {
10761
+ return typeof value === "string" ? Number(value.replace(",", ".")) : value;
10762
+ }
10763
+ const STACKED_MODAL_ID = "items_stacked_modal";
10764
+ const Items = () => {
10875
10765
  const { id } = reactRouterDom.useParams();
10876
- const { order, isPending, isError, error } = useOrder(id, {
10877
- fields: "metadata"
10766
+ const {
10767
+ order: preview,
10768
+ isPending: isPreviewPending,
10769
+ isError: isPreviewError,
10770
+ error: previewError
10771
+ } = useOrderPreview(id, void 0, {
10772
+ placeholderData: reactQuery.keepPreviousData
10878
10773
  });
10774
+ useInitiateOrderEdit({ preview });
10775
+ const { draft_order, isPending, isError, error } = useDraftOrder(
10776
+ id,
10777
+ {
10778
+ fields: "currency_code"
10779
+ },
10780
+ {
10781
+ enabled: !!id
10782
+ }
10783
+ );
10784
+ const { onCancel } = useCancelOrderEdit({ preview });
10879
10785
  if (isError) {
10880
10786
  throw error;
10881
10787
  }
10882
- const isReady = !isPending && !!order;
10883
- return /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer, { children: [
10884
- /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer.Header, { children: [
10885
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Metadata" }) }),
10886
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Description, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Add metadata to the draft order." }) })
10887
- ] }),
10888
- !isReady ? /* @__PURE__ */ jsxRuntime.jsx(PlaceholderInner, {}) : /* @__PURE__ */ jsxRuntime.jsx(MetadataForm, { orderId: id, metadata: order == null ? void 0 : order.metadata })
10889
- ] });
10788
+ if (isPreviewError) {
10789
+ throw previewError;
10790
+ }
10791
+ const ready = !!preview && !isPreviewPending && !!draft_order && !isPending;
10792
+ return /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal, { onClose: onCancel, children: ready ? /* @__PURE__ */ jsxRuntime.jsx(ItemsForm, { preview, currencyCode: draft_order.currency_code }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
10793
+ /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Edit Items" }) }),
10794
+ /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Loading data for the draft order, please wait..." }) })
10795
+ ] }) });
10890
10796
  };
10891
- const METADATA_KEY_LABEL_ID = "metadata-form-key-label";
10892
- const METADATA_VALUE_LABEL_ID = "metadata-form-value-label";
10893
- const MetadataForm = ({ orderId, metadata }) => {
10797
+ const ItemsForm = ({ preview, currencyCode }) => {
10798
+ var _a;
10799
+ const [isSubmitting, setIsSubmitting] = React.useState(false);
10800
+ const [modalContent, setModalContent] = React.useState(
10801
+ null
10802
+ );
10894
10803
  const { handleSuccess } = useRouteModal();
10895
- const hasUneditableRows = getHasUneditableRows(metadata);
10896
- const { mutateAsync, isPending } = useUpdateDraftOrder(orderId);
10897
- const form = reactHookForm.useForm({
10898
- defaultValues: {
10899
- metadata: getDefaultValues(metadata)
10900
- },
10901
- resolver: zod.zodResolver(MetadataSchema)
10902
- });
10903
- const handleSubmit = form.handleSubmit(async (data) => {
10904
- const parsedData = parseValues(data);
10905
- await mutateAsync(
10906
- {
10907
- metadata: parsedData
10804
+ const { searchValue, onSearchValueChange, query: query2 } = useDebouncedSearch();
10805
+ const { mutateAsync: confirmOrderEdit } = useDraftOrderConfirmEdit(preview.id);
10806
+ const { mutateAsync: requestOrderEdit } = useDraftOrderRequestEdit(preview.id);
10807
+ const itemCount = ((_a = preview.items) == null ? void 0 : _a.reduce((acc, item) => acc + item.quantity, 0)) || 0;
10808
+ const matches = React.useMemo(() => {
10809
+ return matchSorter.matchSorter(preview.items, query2, {
10810
+ keys: ["product_title", "variant_title", "variant_sku", "title"]
10811
+ });
10812
+ }, [preview.items, query2]);
10813
+ const onSubmit = async () => {
10814
+ setIsSubmitting(true);
10815
+ let requestSucceeded = false;
10816
+ await requestOrderEdit(void 0, {
10817
+ onError: (e) => {
10818
+ ui.toast.error(`Failed to request order edit: ${e.message}`);
10908
10819
  },
10909
- {
10910
- onSuccess: () => {
10911
- ui.toast.success("Metadata updated");
10912
- handleSuccess();
10913
- },
10914
- onError: (error) => {
10915
- ui.toast.error(error.message);
10916
- }
10820
+ onSuccess: () => {
10821
+ requestSucceeded = true;
10917
10822
  }
10918
- );
10919
- });
10920
- const { fields, insert, remove } = reactHookForm.useFieldArray({
10921
- control: form.control,
10922
- name: "metadata"
10923
- });
10924
- function deleteRow(index) {
10925
- remove(index);
10926
- if (fields.length === 1) {
10927
- insert(0, {
10928
- key: "",
10929
- value: "",
10930
- disabled: false
10931
- });
10823
+ });
10824
+ if (!requestSucceeded) {
10825
+ setIsSubmitting(false);
10826
+ return;
10932
10827
  }
10933
- }
10934
- function insertRow(index, position) {
10935
- insert(index + (position === "above" ? 0 : 1), {
10936
- key: "",
10937
- value: "",
10938
- disabled: false
10828
+ await confirmOrderEdit(void 0, {
10829
+ onError: (e) => {
10830
+ ui.toast.error(`Failed to confirm order edit: ${e.message}`);
10831
+ },
10832
+ onSuccess: () => {
10833
+ handleSuccess();
10834
+ },
10835
+ onSettled: () => {
10836
+ setIsSubmitting(false);
10837
+ }
10939
10838
  });
10940
- }
10941
- return /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxRuntime.jsxs(
10942
- KeyboundForm,
10943
- {
10944
- onSubmit: handleSubmit,
10945
- className: "flex flex-1 flex-col overflow-hidden",
10946
- children: [
10947
- /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer.Body, { className: "flex flex-1 flex-col gap-y-8 overflow-y-auto", children: [
10948
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-base shadow-elevation-card-rest grid grid-cols-1 divide-y rounded-lg", children: [
10949
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-subtle grid grid-cols-2 divide-x rounded-t-lg", children: [
10950
- /* @__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" }) }),
10951
- /* @__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" }) })
10839
+ };
10840
+ const onKeyDown = React.useCallback(
10841
+ (e) => {
10842
+ if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) {
10843
+ if (modalContent || isSubmitting) {
10844
+ return;
10845
+ }
10846
+ onSubmit();
10847
+ }
10848
+ },
10849
+ [modalContent, isSubmitting, onSubmit]
10850
+ );
10851
+ React.useEffect(() => {
10852
+ document.addEventListener("keydown", onKeyDown);
10853
+ return () => {
10854
+ document.removeEventListener("keydown", onKeyDown);
10855
+ };
10856
+ }, [onKeyDown]);
10857
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-full flex-col overflow-hidden", children: [
10858
+ /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Header, {}),
10859
+ /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Body, { className: "flex flex-1 flex-col overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsxs(
10860
+ StackedFocusModal,
10861
+ {
10862
+ id: STACKED_MODAL_ID,
10863
+ onOpenChangeCallback: (open) => {
10864
+ if (!open) {
10865
+ setModalContent(null);
10866
+ }
10867
+ },
10868
+ children: [
10869
+ /* @__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: [
10870
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
10871
+ /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Edit Items" }) }),
10872
+ /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Edit the items in the draft order" }) })
10952
10873
  ] }),
10953
- fields.map((field, index) => {
10954
- const isDisabled = field.disabled || false;
10955
- let placeholder = "-";
10956
- if (typeof field.value === "object") {
10957
- placeholder = "{ ... }";
10958
- }
10959
- if (Array.isArray(field.value)) {
10960
- placeholder = "[ ... ]";
10961
- }
10962
- return /* @__PURE__ */ jsxRuntime.jsx(
10963
- ConditionalTooltip,
10964
- {
10965
- showTooltip: isDisabled,
10966
- content: "This row is disabled because it contains non-primitive data.",
10967
- children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "group/table relative", children: [
10968
- /* @__PURE__ */ jsxRuntime.jsxs(
10969
- "div",
10970
- {
10971
- className: ui.clx("grid grid-cols-2 divide-x", {
10972
- "overflow-hidden rounded-b-lg": index === fields.length - 1
10973
- }),
10974
- children: [
10975
- /* @__PURE__ */ jsxRuntime.jsx(
10976
- Form$2.Field,
10977
- {
10978
- control: form.control,
10979
- name: `metadata.${index}.key`,
10980
- render: ({ field: field2 }) => {
10981
- return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
10982
- GridInput,
10983
- {
10984
- "aria-labelledby": METADATA_KEY_LABEL_ID,
10985
- ...field2,
10986
- disabled: isDisabled,
10987
- placeholder: "Key"
10988
- }
10989
- ) }) });
10990
- }
10991
- }
10992
- ),
10993
- /* @__PURE__ */ jsxRuntime.jsx(
10994
- Form$2.Field,
10995
- {
10996
- control: form.control,
10997
- name: `metadata.${index}.value`,
10998
- render: ({ field: { value, ...field2 } }) => {
10999
- return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
11000
- GridInput,
11001
- {
11002
- "aria-labelledby": METADATA_VALUE_LABEL_ID,
11003
- ...field2,
11004
- value: isDisabled ? placeholder : value,
11005
- disabled: isDisabled,
11006
- placeholder: "Value"
11007
- }
11008
- ) }) });
11009
- }
11010
- }
11011
- )
11012
- ]
11013
- }
11014
- ),
11015
- /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu, { children: [
10874
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { variant: "dashed" }),
10875
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-6", children: [
10876
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 items-center gap-3", children: [
10877
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
10878
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", leading: "compact", children: "Items" }),
10879
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Choose items from the product catalog." })
10880
+ ] }),
10881
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
10882
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(
10883
+ ui.Input,
10884
+ {
10885
+ type: "search",
10886
+ placeholder: "Search items",
10887
+ value: searchValue,
10888
+ onChange: (e) => onSearchValueChange(e.target.value)
10889
+ }
10890
+ ) }),
10891
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu, { children: [
10892
+ /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenu.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { type: "button", children: /* @__PURE__ */ jsxRuntime.jsx(icons.Plus, {}) }) }),
10893
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu.Content, { children: [
11016
10894
  /* @__PURE__ */ jsxRuntime.jsx(
11017
- ui.DropdownMenu.Trigger,
10895
+ StackedModalTrigger$1,
11018
10896
  {
11019
- className: ui.clx(
11020
- "invisible absolute inset-y-0 -right-2.5 my-auto group-hover/table:visible data-[state='open']:visible",
11021
- {
11022
- hidden: isDisabled
11023
- }
11024
- ),
11025
- disabled: isDisabled,
11026
- asChild: true,
11027
- children: /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { size: "2xsmall", children: /* @__PURE__ */ jsxRuntime.jsx(icons.EllipsisVertical, {}) })
10897
+ type: "add-items",
10898
+ setModalContent
11028
10899
  }
11029
10900
  ),
11030
- /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu.Content, { children: [
11031
- /* @__PURE__ */ jsxRuntime.jsxs(
11032
- ui.DropdownMenu.Item,
11033
- {
11034
- className: "gap-x-2",
11035
- onClick: () => insertRow(index, "above"),
11036
- children: [
11037
- /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowUpMini, { className: "text-ui-fg-subtle" }),
11038
- "Insert row above"
11039
- ]
11040
- }
11041
- ),
11042
- /* @__PURE__ */ jsxRuntime.jsxs(
11043
- ui.DropdownMenu.Item,
11044
- {
11045
- className: "gap-x-2",
11046
- onClick: () => insertRow(index, "below"),
11047
- children: [
11048
- /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowDownMini, { className: "text-ui-fg-subtle" }),
11049
- "Insert row below"
11050
- ]
11051
- }
11052
- ),
11053
- /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenu.Separator, {}),
11054
- /* @__PURE__ */ jsxRuntime.jsxs(
11055
- ui.DropdownMenu.Item,
11056
- {
11057
- className: "gap-x-2",
11058
- onClick: () => deleteRow(index),
11059
- children: [
11060
- /* @__PURE__ */ jsxRuntime.jsx(icons.Trash, { className: "text-ui-fg-subtle" }),
11061
- "Delete row"
11062
- ]
11063
- }
11064
- )
11065
- ] })
10901
+ /* @__PURE__ */ jsxRuntime.jsx(
10902
+ StackedModalTrigger$1,
10903
+ {
10904
+ type: "add-custom-item",
10905
+ setModalContent
10906
+ }
10907
+ )
11066
10908
  ] })
11067
10909
  ] })
11068
- },
11069
- field.id
11070
- );
11071
- })
11072
- ] }),
11073
- 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." })
11074
- ] }),
11075
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
11076
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
11077
- /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", type: "submit", isLoading: isPending, children: "Save" })
11078
- ] }) })
11079
- ]
11080
- }
11081
- ) });
11082
- };
11083
- const GridInput = React.forwardRef(({ className, ...props }, ref) => {
11084
- return /* @__PURE__ */ jsxRuntime.jsx(
11085
- "input",
11086
- {
11087
- ref,
11088
- ...props,
11089
- autoComplete: "off",
11090
- className: ui.clx(
11091
- "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",
11092
- className
10910
+ ] })
10911
+ ] }),
10912
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-subtle shadow-elevation-card-rest rounded-xl", children: [
10913
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-[5px]", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-ui-fg-muted grid grid-cols-[2fr_1fr_2fr_28px] gap-3 px-4 py-2", children: [
10914
+ /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: "Item" }) }),
10915
+ /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: "Quantity" }) }),
10916
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-right", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: "Price" }) }),
10917
+ /* @__PURE__ */ jsxRuntime.jsx("div", {})
10918
+ ] }) }),
10919
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-y-1.5 px-[5px] pb-[5px]", children: itemCount <= 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-base shadow-elevation-card-rest flex flex-col items-center justify-center gap-1 gap-x-3 rounded-lg p-4", children: [
10920
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", leading: "compact", children: "There are no items in this order" }),
10921
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Add items to the order to get started." })
10922
+ ] }) : matches.length > 0 ? matches == null ? void 0 : matches.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
10923
+ Item,
10924
+ {
10925
+ item,
10926
+ preview,
10927
+ currencyCode
10928
+ },
10929
+ item.id
10930
+ )) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-base shadow-elevation-card-rest flex flex-col items-center justify-center gap-1 gap-x-3 rounded-lg p-4", children: [
10931
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", leading: "compact", children: "No items found" }),
10932
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: [
10933
+ 'No items found for "',
10934
+ query2,
10935
+ '".'
10936
+ ] })
10937
+ ] }) })
10938
+ ] })
10939
+ ] }),
10940
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { variant: "dashed" }),
10941
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-[1fr_0.5fr_0.5fr] gap-3", children: [
10942
+ /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", leading: "compact", children: "Subtotal" }) }),
10943
+ /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsxs(
10944
+ ui.Text,
10945
+ {
10946
+ size: "small",
10947
+ leading: "compact",
10948
+ className: "text-ui-fg-subtle",
10949
+ children: [
10950
+ itemCount,
10951
+ " ",
10952
+ itemCount === 1 ? "item" : "items"
10953
+ ]
10954
+ }
10955
+ ) }),
10956
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-right", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", leading: "compact", children: getStylizedAmount(preview.item_subtotal, currencyCode) }) })
10957
+ ] })
10958
+ ] }) }),
10959
+ modalContent && (modalContent === "add-items" ? /* @__PURE__ */ jsxRuntime.jsx(ExistingItemsForm, { orderId: preview.id, items: preview.items }) : modalContent === "add-custom-item" ? /* @__PURE__ */ jsxRuntime.jsx(
10960
+ CustomItemForm,
10961
+ {
10962
+ orderId: preview.id,
10963
+ currencyCode
10964
+ }
10965
+ ) : null)
10966
+ ]
10967
+ }
10968
+ ) }),
10969
+ /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
10970
+ /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
10971
+ /* @__PURE__ */ jsxRuntime.jsx(
10972
+ ui.Button,
10973
+ {
10974
+ size: "small",
10975
+ type: "button",
10976
+ onClick: onSubmit,
10977
+ isLoading: isSubmitting,
10978
+ children: "Save"
10979
+ }
11093
10980
  )
11094
- }
11095
- );
11096
- });
11097
- GridInput.displayName = "MetadataForm.GridInput";
11098
- const PlaceholderInner = () => {
11099
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col overflow-hidden", children: [
11100
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Body, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: "h-[148ox] w-full rounded-lg" }) }),
11101
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
11102
- /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: "h-7 w-12 rounded-md" }),
11103
- /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: "h-7 w-12 rounded-md" })
11104
10981
  ] }) })
11105
10982
  ] });
11106
10983
  };
11107
- const EDITABLE_TYPES = ["string", "number", "boolean"];
11108
- function getDefaultValues(metadata) {
11109
- if (!metadata || !Object.keys(metadata).length) {
11110
- return [
11111
- {
11112
- key: "",
11113
- value: "",
11114
- disabled: false
11115
- }
11116
- ];
10984
+ const Item = ({ item, preview, currencyCode }) => {
10985
+ if (item.variant_id) {
10986
+ return /* @__PURE__ */ jsxRuntime.jsx(VariantItem, { item, preview, currencyCode });
11117
10987
  }
11118
- return Object.entries(metadata).map(([key, value]) => {
11119
- if (!EDITABLE_TYPES.includes(typeof value)) {
11120
- return {
11121
- key,
11122
- value,
11123
- disabled: true
11124
- };
10988
+ return /* @__PURE__ */ jsxRuntime.jsx(CustomItem, { item, preview, currencyCode });
10989
+ };
10990
+ const VariantItem = ({ item, preview, currencyCode }) => {
10991
+ const [editing, setEditing] = React.useState(false);
10992
+ const form = reactHookForm.useForm({
10993
+ defaultValues: {
10994
+ quantity: item.quantity,
10995
+ unit_price: item.unit_price
10996
+ },
10997
+ resolver: zod.zodResolver(variantItemSchema)
10998
+ });
10999
+ const actionId = React.useMemo(() => {
11000
+ var _a, _b;
11001
+ return (_b = (_a = item.actions) == null ? void 0 : _a.find((a) => a.action === "ITEM_ADD")) == null ? void 0 : _b.id;
11002
+ }, [item]);
11003
+ const { mutateAsync: updateActionItem, isPending: isUpdatingActionItem } = useDraftOrderUpdateActionItem(preview.id);
11004
+ const { mutateAsync: updateOriginalItem, isPending: isUpdatingOriginalItem } = useDraftOrderUpdateItem(preview.id);
11005
+ const isPending = isUpdatingActionItem || isUpdatingOriginalItem;
11006
+ const onSubmit = form.handleSubmit(async (data) => {
11007
+ if (convertNumber(data.unit_price) === item.unit_price && data.quantity === item.quantity) {
11008
+ setEditing(false);
11009
+ return;
11125
11010
  }
11126
- let stringValue = value;
11127
- if (typeof value !== "string") {
11128
- stringValue = JSON.stringify(value);
11011
+ if (!actionId) {
11012
+ await updateOriginalItem(
11013
+ {
11014
+ item_id: item.id,
11015
+ quantity: data.quantity,
11016
+ unit_price: convertNumber(data.unit_price)
11017
+ },
11018
+ {
11019
+ onSuccess: () => {
11020
+ setEditing(false);
11021
+ },
11022
+ onError: (e) => {
11023
+ ui.toast.error(e.message);
11024
+ }
11025
+ }
11026
+ );
11027
+ return;
11129
11028
  }
11130
- return {
11131
- key,
11132
- value: stringValue,
11133
- original_key: key
11134
- };
11029
+ await updateActionItem(
11030
+ {
11031
+ action_id: actionId,
11032
+ quantity: data.quantity,
11033
+ unit_price: convertNumber(data.unit_price)
11034
+ },
11035
+ {
11036
+ onSuccess: () => {
11037
+ setEditing(false);
11038
+ },
11039
+ onError: (e) => {
11040
+ ui.toast.error(e.message);
11041
+ }
11042
+ }
11043
+ );
11044
+ });
11045
+ return /* @__PURE__ */ jsxRuntime.jsx(Form$2, { ...form, children: /* @__PURE__ */ jsxRuntime.jsx("form", { onSubmit, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-base shadow-elevation-card-rest grid grid-cols-[minmax(0,2fr)_minmax(0,1fr)_minmax(0,2fr)_28px] items-center gap-3 rounded-lg px-4 py-2", children: [
11046
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex w-full items-center gap-x-3", children: [
11047
+ /* @__PURE__ */ jsxRuntime.jsx(
11048
+ Thumbnail,
11049
+ {
11050
+ thumbnail: item.thumbnail,
11051
+ alt: item.product_title ?? void 0
11052
+ }
11053
+ ),
11054
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
11055
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-x-1", children: [
11056
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", leading: "compact", children: item.product_title }),
11057
+ /* @__PURE__ */ jsxRuntime.jsxs(
11058
+ ui.Text,
11059
+ {
11060
+ size: "small",
11061
+ leading: "compact",
11062
+ className: "text-ui-fg-subtle",
11063
+ children: [
11064
+ "(",
11065
+ item.variant_title,
11066
+ ")"
11067
+ ]
11068
+ }
11069
+ )
11070
+ ] }),
11071
+ /* @__PURE__ */ jsxRuntime.jsx(
11072
+ ui.Text,
11073
+ {
11074
+ size: "small",
11075
+ leading: "compact",
11076
+ className: "text-ui-fg-subtle",
11077
+ children: item.variant_sku
11078
+ }
11079
+ )
11080
+ ] })
11081
+ ] }),
11082
+ editing ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(
11083
+ Form$2.Field,
11084
+ {
11085
+ control: form.control,
11086
+ name: "quantity",
11087
+ render: ({ field }) => {
11088
+ return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(NumberInput, { ...field }) }) });
11089
+ }
11090
+ }
11091
+ ) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: item.quantity }) }),
11092
+ editing ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(
11093
+ Form$2.Field,
11094
+ {
11095
+ control: form.control,
11096
+ name: "unit_price",
11097
+ render: ({ field: { onChange, ...field } }) => {
11098
+ return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
11099
+ ui.CurrencyInput,
11100
+ {
11101
+ ...field,
11102
+ symbol: getNativeSymbol(currencyCode),
11103
+ code: currencyCode,
11104
+ onValueChange: (_value, _name, values) => onChange(values == null ? void 0 : values.value)
11105
+ }
11106
+ ) }) });
11107
+ }
11108
+ }
11109
+ ) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex w-full flex-1 items-center justify-end", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: getLocaleAmount(item.unit_price, currencyCode) }) }),
11110
+ /* @__PURE__ */ jsxRuntime.jsx(
11111
+ ui.IconButton,
11112
+ {
11113
+ type: "button",
11114
+ size: "small",
11115
+ onClick: editing ? onSubmit : () => {
11116
+ setEditing(true);
11117
+ },
11118
+ disabled: isPending,
11119
+ children: editing ? /* @__PURE__ */ jsxRuntime.jsx(icons.Check, {}) : /* @__PURE__ */ jsxRuntime.jsx(icons.PencilSquare, {})
11120
+ }
11121
+ )
11122
+ ] }) }) });
11123
+ };
11124
+ const variantItemSchema = objectType({
11125
+ quantity: numberType(),
11126
+ unit_price: unionType([numberType(), stringType()])
11127
+ });
11128
+ const CustomItem = ({ item, preview, currencyCode }) => {
11129
+ const [editing, setEditing] = React.useState(false);
11130
+ const { quantity, unit_price, title } = item;
11131
+ const form = reactHookForm.useForm({
11132
+ defaultValues: {
11133
+ title,
11134
+ quantity,
11135
+ unit_price
11136
+ },
11137
+ resolver: zod.zodResolver(customItemSchema)
11135
11138
  });
11136
- }
11137
- function parseValues(values) {
11138
- const metadata = values.metadata;
11139
- const isEmpty = !metadata.length || metadata.length === 1 && !metadata[0].key && !metadata[0].value;
11140
- if (isEmpty) {
11141
- return null;
11142
- }
11143
- const update = {};
11144
- metadata.forEach((field) => {
11145
- let key = field.key;
11146
- let value = field.value;
11147
- const disabled = field.disabled;
11148
- if (!key || !value) {
11139
+ React.useEffect(() => {
11140
+ form.reset({
11141
+ title,
11142
+ quantity,
11143
+ unit_price
11144
+ });
11145
+ }, [form, title, quantity, unit_price]);
11146
+ const actionId = React.useMemo(() => {
11147
+ var _a, _b;
11148
+ return (_b = (_a = item.actions) == null ? void 0 : _a.find((a) => a.action === "ITEM_ADD")) == null ? void 0 : _b.id;
11149
+ }, [item]);
11150
+ const { mutateAsync: updateActionItem, isPending: isUpdatingActionItem } = useDraftOrderUpdateActionItem(preview.id);
11151
+ const { mutateAsync: removeActionItem, isPending: isRemovingActionItem } = useDraftOrderRemoveActionItem(preview.id);
11152
+ const { mutateAsync: updateOriginalItem, isPending: isUpdatingOriginalItem } = useDraftOrderUpdateItem(preview.id);
11153
+ const isPending = isUpdatingActionItem || isUpdatingOriginalItem;
11154
+ const onSubmit = form.handleSubmit(async (data) => {
11155
+ if (convertNumber(data.unit_price) === item.unit_price && data.quantity === item.quantity && data.title === item.title) {
11156
+ setEditing(false);
11149
11157
  return;
11150
11158
  }
11151
- if (disabled) {
11152
- update[key] = value;
11159
+ if (!actionId) {
11160
+ await updateOriginalItem(
11161
+ {
11162
+ item_id: item.id,
11163
+ quantity: data.quantity,
11164
+ unit_price: convertNumber(data.unit_price)
11165
+ },
11166
+ {
11167
+ onSuccess: () => {
11168
+ setEditing(false);
11169
+ },
11170
+ onError: (e) => {
11171
+ ui.toast.error(e.message);
11172
+ }
11173
+ }
11174
+ );
11153
11175
  return;
11154
11176
  }
11155
- key = key.trim();
11156
- value = value.trim();
11157
- if (value === "true") {
11158
- update[key] = true;
11159
- } else if (value === "false") {
11160
- update[key] = false;
11161
- } else {
11162
- const parsedNumber = parseFloat(value);
11163
- if (!isNaN(parsedNumber)) {
11164
- update[key] = parsedNumber;
11165
- } else {
11166
- update[key] = value;
11167
- }
11177
+ if (data.quantity === 0) {
11178
+ await removeActionItem(actionId, {
11179
+ onSuccess: () => {
11180
+ setEditing(false);
11181
+ },
11182
+ onError: (e) => {
11183
+ ui.toast.error(e.message);
11184
+ }
11185
+ });
11186
+ return;
11168
11187
  }
11188
+ await updateActionItem(
11189
+ {
11190
+ action_id: actionId,
11191
+ quantity: data.quantity,
11192
+ unit_price: convertNumber(data.unit_price)
11193
+ },
11194
+ {
11195
+ onSuccess: () => {
11196
+ setEditing(false);
11197
+ },
11198
+ onError: (e) => {
11199
+ ui.toast.error(e.message);
11200
+ }
11201
+ }
11202
+ );
11169
11203
  });
11170
- return update;
11171
- }
11172
- function getHasUneditableRows(metadata) {
11173
- if (!metadata) {
11174
- return false;
11175
- }
11176
- return Object.values(metadata).some(
11177
- (value) => !EDITABLE_TYPES.includes(typeof value)
11178
- );
11179
- }
11180
- const PROMOTION_QUERY_KEY = "promotions";
11181
- const promotionsQueryKeys = {
11182
- list: (query2) => [
11183
- PROMOTION_QUERY_KEY,
11184
- query2 ? query2 : void 0
11185
- ],
11186
- detail: (id, query2) => [
11187
- PROMOTION_QUERY_KEY,
11188
- id,
11189
- query2 ? query2 : void 0
11190
- ]
11191
- };
11192
- const usePromotions = (query2, options) => {
11193
- const { data, ...rest } = reactQuery.useQuery({
11194
- queryKey: promotionsQueryKeys.list(query2),
11195
- queryFn: async () => sdk.admin.promotion.list(query2),
11196
- ...options
11197
- });
11198
- return { ...data, ...rest };
11204
+ return /* @__PURE__ */ jsxRuntime.jsx(Form$2, { ...form, children: /* @__PURE__ */ jsxRuntime.jsx("form", { onSubmit, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-base shadow-elevation-card-rest grid grid-cols-[minmax(0,2fr)_minmax(0,1fr)_minmax(0,2fr)_28px] items-center gap-3 rounded-lg px-4 py-2", children: [
11205
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-x-3", children: [
11206
+ /* @__PURE__ */ jsxRuntime.jsx(
11207
+ Thumbnail,
11208
+ {
11209
+ thumbnail: item.thumbnail,
11210
+ alt: item.title ?? void 0
11211
+ }
11212
+ ),
11213
+ editing ? /* @__PURE__ */ jsxRuntime.jsx(
11214
+ Form$2.Field,
11215
+ {
11216
+ control: form.control,
11217
+ name: "title",
11218
+ render: ({ field }) => {
11219
+ return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Input, { ...field }) }) });
11220
+ }
11221
+ }
11222
+ ) : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: item.title })
11223
+ ] }),
11224
+ editing ? /* @__PURE__ */ jsxRuntime.jsx(
11225
+ Form$2.Field,
11226
+ {
11227
+ control: form.control,
11228
+ name: "quantity",
11229
+ render: ({ field }) => {
11230
+ return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(NumberInput, { ...field }) }) });
11231
+ }
11232
+ }
11233
+ ) : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: item.quantity }),
11234
+ editing ? /* @__PURE__ */ jsxRuntime.jsx(
11235
+ Form$2.Field,
11236
+ {
11237
+ control: form.control,
11238
+ name: "unit_price",
11239
+ render: ({ field: { onChange, ...field } }) => {
11240
+ return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
11241
+ ui.CurrencyInput,
11242
+ {
11243
+ ...field,
11244
+ symbol: getNativeSymbol(currencyCode),
11245
+ code: currencyCode,
11246
+ onValueChange: (_value, _name, values) => onChange(values == null ? void 0 : values.value)
11247
+ }
11248
+ ) }) });
11249
+ }
11250
+ }
11251
+ ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-1 items-center justify-end", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: getLocaleAmount(item.unit_price, currencyCode) }) }),
11252
+ /* @__PURE__ */ jsxRuntime.jsx(
11253
+ ui.IconButton,
11254
+ {
11255
+ type: "button",
11256
+ size: "small",
11257
+ onClick: editing ? onSubmit : () => {
11258
+ setEditing(true);
11259
+ },
11260
+ disabled: isPending,
11261
+ children: editing ? /* @__PURE__ */ jsxRuntime.jsx(icons.Check, {}) : /* @__PURE__ */ jsxRuntime.jsx(icons.PencilSquare, {})
11262
+ }
11263
+ )
11264
+ ] }) }) });
11199
11265
  };
11200
- const Promotions = () => {
11201
- const { id } = reactRouterDom.useParams();
11202
- const {
11203
- order: preview,
11204
- isError: isPreviewError,
11205
- error: previewError
11206
- } = useOrderPreview(id, void 0);
11207
- useInitiateOrderEdit({ preview });
11208
- const { onCancel } = useCancelOrderEdit({ preview });
11209
- if (isPreviewError) {
11210
- throw previewError;
11211
- }
11212
- const isReady = !!preview;
11213
- return /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer, { onClose: onCancel, children: [
11214
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Edit Promotions" }) }) }),
11215
- isReady && /* @__PURE__ */ jsxRuntime.jsx(PromotionForm, { preview })
11216
- ] });
11266
+ const StackedModalTrigger$1 = ({
11267
+ type,
11268
+ setModalContent
11269
+ }) => {
11270
+ const { setIsOpen } = useStackedModal();
11271
+ const onClick = React.useCallback(() => {
11272
+ setModalContent(type);
11273
+ setIsOpen(STACKED_MODAL_ID, true);
11274
+ }, [setModalContent, setIsOpen, type]);
11275
+ return /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenu.Item, { onClick, children: type === "add-items" ? "Add items" : "Add custom item" }) });
11217
11276
  };
11218
- const PromotionForm = ({ preview }) => {
11219
- const { items, shipping_methods } = preview;
11220
- const [isSubmitting, setIsSubmitting] = React.useState(false);
11221
- const [comboboxValue, setComboboxValue] = React.useState("");
11222
- const { handleSuccess } = useRouteModal();
11223
- const { mutateAsync: addPromotions, isPending: isAddingPromotions } = useDraftOrderAddPromotions(preview.id);
11224
- const promoIds = getPromotionIds(items, shipping_methods);
11225
- const { promotions, isPending, isError, error } = usePromotions(
11226
- {
11227
- id: promoIds
11228
- },
11229
- {
11230
- enabled: !!promoIds.length
11231
- }
11277
+ const VARIANT_PREFIX = "items";
11278
+ const LIMIT = 50;
11279
+ const ExistingItemsForm = ({ orderId, items }) => {
11280
+ const { setIsOpen } = useStackedModal();
11281
+ const [rowSelection, setRowSelection] = React.useState(
11282
+ items.reduce((acc, item) => {
11283
+ acc[item.variant_id] = true;
11284
+ return acc;
11285
+ }, {})
11232
11286
  );
11233
- const comboboxData = useComboboxData({
11234
- queryKey: ["promotions", "combobox", promoIds],
11235
- queryFn: async (params) => {
11236
- return await sdk.admin.promotion.list({
11237
- ...params,
11238
- id: {
11239
- $nin: promoIds
11287
+ React.useEffect(() => {
11288
+ setRowSelection(
11289
+ items.reduce((acc, item) => {
11290
+ if (item.variant_id) {
11291
+ acc[item.variant_id] = true;
11240
11292
  }
11241
- });
11293
+ return acc;
11294
+ }, {})
11295
+ );
11296
+ }, [items]);
11297
+ const { q, order, offset } = useQueryParams(
11298
+ ["q", "order", "offset"],
11299
+ VARIANT_PREFIX
11300
+ );
11301
+ const { variants, count, isPending, isError, error } = useProductVariants(
11302
+ {
11303
+ q,
11304
+ order,
11305
+ offset: offset ? parseInt(offset) : void 0,
11306
+ limit: LIMIT
11242
11307
  },
11243
- getOptions: (data) => {
11244
- return data.promotions.map((promotion) => ({
11245
- label: promotion.code,
11246
- value: promotion.code
11247
- }));
11248
- }
11249
- });
11250
- const add = async (value) => {
11251
- if (!value) {
11252
- return;
11308
+ {
11309
+ placeholderData: reactQuery.keepPreviousData
11253
11310
  }
11254
- addPromotions(
11311
+ );
11312
+ const columns = useColumns();
11313
+ const { mutateAsync } = useDraftOrderAddItems(orderId);
11314
+ const onSubmit = async () => {
11315
+ const ids = Object.keys(rowSelection).filter(
11316
+ (id) => !items.find((i) => i.variant_id === id)
11317
+ );
11318
+ await mutateAsync(
11255
11319
  {
11256
- promo_codes: [value]
11320
+ items: ids.map((id) => ({
11321
+ variant_id: id,
11322
+ quantity: 1
11323
+ }))
11257
11324
  },
11258
11325
  {
11326
+ onSuccess: () => {
11327
+ setRowSelection({});
11328
+ setIsOpen(STACKED_MODAL_ID, false);
11329
+ },
11259
11330
  onError: (e) => {
11260
11331
  ui.toast.error(e.message);
11261
- comboboxData.onSearchValueChange("");
11262
- setComboboxValue("");
11263
- },
11264
- onSuccess: () => {
11265
- comboboxData.onSearchValueChange("");
11266
- setComboboxValue("");
11267
11332
  }
11268
11333
  }
11269
11334
  );
11270
11335
  };
11271
- const { mutateAsync: confirmOrderEdit } = useDraftOrderConfirmEdit(preview.id);
11272
- const { mutateAsync: requestOrderEdit } = useOrderEditRequest(preview.id);
11273
- const onSubmit = async () => {
11274
- setIsSubmitting(true);
11275
- let requestSucceeded = false;
11276
- await requestOrderEdit(void 0, {
11277
- onError: (e) => {
11278
- ui.toast.error(e.message);
11279
- },
11280
- onSuccess: () => {
11281
- requestSucceeded = true;
11282
- }
11283
- });
11284
- if (!requestSucceeded) {
11285
- setIsSubmitting(false);
11286
- return;
11287
- }
11288
- await confirmOrderEdit(void 0, {
11289
- onError: (e) => {
11290
- ui.toast.error(e.message);
11291
- },
11292
- onSuccess: () => {
11293
- handleSuccess();
11294
- },
11295
- onSettled: () => {
11296
- setIsSubmitting(false);
11297
- }
11298
- });
11299
- };
11300
11336
  if (isError) {
11301
11337
  throw error;
11302
11338
  }
11303
- return /* @__PURE__ */ jsxRuntime.jsxs(KeyboundForm, { className: "flex flex-1 flex-col", onSubmit, children: [
11304
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Body, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-4", children: [
11305
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3", children: [
11306
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
11307
- /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: "small", weight: "plus", htmlFor: "promotion-combobox", children: "Apply promotions" }),
11308
- /* @__PURE__ */ jsxRuntime.jsx(ui.Hint, { id: "promotion-combobox-hint", children: "Manage promotions that should be applied to the order." })
11309
- ] }),
11310
- /* @__PURE__ */ jsxRuntime.jsx(
11311
- Combobox,
11312
- {
11313
- id: "promotion-combobox",
11314
- "aria-describedby": "promotion-combobox-hint",
11315
- isFetchingNextPage: comboboxData.isFetchingNextPage,
11316
- fetchNextPage: comboboxData.fetchNextPage,
11317
- options: comboboxData.options,
11318
- onSearchValueChange: comboboxData.onSearchValueChange,
11319
- searchValue: comboboxData.searchValue,
11320
- disabled: comboboxData.disabled || isAddingPromotions,
11321
- onChange: add,
11322
- value: comboboxValue
11323
- }
11324
- )
11325
- ] }),
11326
- /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { variant: "dashed" }),
11327
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-2", children: promotions == null ? void 0 : promotions.map((promotion) => /* @__PURE__ */ jsxRuntime.jsx(
11328
- PromotionItem,
11329
- {
11330
- promotion,
11331
- orderId: preview.id,
11332
- isLoading: isPending
11333
- },
11334
- promotion.id
11335
- )) })
11336
- ] }) }),
11337
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-2", children: [
11338
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
11339
- /* @__PURE__ */ jsxRuntime.jsx(
11340
- ui.Button,
11341
- {
11342
- size: "small",
11343
- type: "submit",
11344
- isLoading: isSubmitting || isAddingPromotions,
11345
- children: "Save"
11346
- }
11347
- )
11348
- ] }) })
11349
- ] });
11350
- };
11351
- const PromotionItem = ({
11352
- promotion,
11353
- orderId,
11354
- isLoading
11355
- }) => {
11356
- var _a;
11357
- const { mutateAsync: removePromotions, isPending } = useDraftOrderRemovePromotions(orderId);
11358
- const onRemove = async () => {
11359
- removePromotions(
11360
- {
11361
- promo_codes: [promotion.code]
11362
- },
11363
- {
11364
- onError: (e) => {
11365
- ui.toast.error(e.message);
11366
- }
11367
- }
11368
- );
11369
- };
11370
- const displayValue = getDisplayValue(promotion);
11371
11339
  return /* @__PURE__ */ jsxRuntime.jsxs(
11372
- "div",
11340
+ StackedFocusModal.Content,
11373
11341
  {
11374
- className: ui.clx(
11375
- "bg-ui-bg-component shadow-elevation-card-rest flex items-center justify-between rounded-lg px-3 py-2",
11376
- {
11377
- "animate-pulse": isLoading
11342
+ onOpenAutoFocus: (e) => {
11343
+ e.preventDefault();
11344
+ const searchInput = document.querySelector(
11345
+ "[data-modal-id='modal-search-input']"
11346
+ );
11347
+ if (searchInput) {
11348
+ searchInput.focus();
11378
11349
  }
11379
- ),
11350
+ },
11380
11351
  children: [
11381
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
11382
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", leading: "compact", children: promotion.code }),
11383
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-ui-fg-subtle flex items-center gap-1.5", children: [
11384
- displayValue && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
11385
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", leading: "compact", children: displayValue }),
11386
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", leading: "compact", children: "·" })
11387
- ] }),
11388
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", leading: "compact", className: "capitalize", children: (_a = promotion.application_method) == null ? void 0 : _a.allocation })
11389
- ] })
11352
+ /* @__PURE__ */ jsxRuntime.jsxs(StackedFocusModal.Header, { children: [
11353
+ /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Product Variants" }) }),
11354
+ /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Choose product variants to add to the order." }) })
11390
11355
  ] }),
11391
- /* @__PURE__ */ jsxRuntime.jsx(
11392
- ui.IconButton,
11356
+ /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Body, { className: "flex-1 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
11357
+ DataTable,
11393
11358
  {
11394
- size: "small",
11395
- type: "button",
11396
- variant: "transparent",
11397
- onClick: onRemove,
11398
- isLoading: isPending || isLoading,
11399
- children: /* @__PURE__ */ jsxRuntime.jsx(icons.XMark, {})
11359
+ data: variants,
11360
+ columns,
11361
+ isLoading: isPending,
11362
+ getRowId: (row) => row.id,
11363
+ rowCount: count,
11364
+ prefix: VARIANT_PREFIX,
11365
+ layout: "fill",
11366
+ rowSelection: {
11367
+ state: rowSelection,
11368
+ onRowSelectionChange: setRowSelection,
11369
+ enableRowSelection: (row) => {
11370
+ return !items.find((i) => i.variant_id === row.original.id);
11371
+ }
11372
+ },
11373
+ autoFocusSearch: true
11400
11374
  }
11401
- )
11402
- ]
11403
- },
11404
- promotion.id
11405
- );
11406
- };
11407
- function getDisplayValue(promotion) {
11408
- var _a, _b, _c, _d;
11409
- const value = (_a = promotion.application_method) == null ? void 0 : _a.value;
11410
- if (!value) {
11411
- return null;
11412
- }
11413
- if (((_b = promotion.application_method) == null ? void 0 : _b.type) === "fixed") {
11414
- const currency = (_c = promotion.application_method) == null ? void 0 : _c.currency_code;
11415
- if (!currency) {
11416
- return null;
11417
- }
11418
- return getLocaleAmount(value, currency);
11419
- } else if (((_d = promotion.application_method) == null ? void 0 : _d.type) === "percentage") {
11420
- return formatPercentage(value);
11421
- }
11422
- return null;
11423
- }
11424
- const formatter = new Intl.NumberFormat([], {
11425
- style: "percent",
11426
- minimumFractionDigits: 2
11427
- });
11428
- const formatPercentage = (value, isPercentageValue = false) => {
11429
- let val = value || 0;
11430
- if (!isPercentageValue) {
11431
- val = val / 100;
11432
- }
11433
- return formatter.format(val);
11434
- };
11435
- function getPromotionIds(items, shippingMethods) {
11436
- const promotionIds = /* @__PURE__ */ new Set();
11437
- for (const item of items) {
11438
- if (item.adjustments) {
11439
- for (const adjustment of item.adjustments) {
11440
- if (adjustment.promotion_id) {
11441
- promotionIds.add(adjustment.promotion_id);
11442
- }
11443
- }
11444
- }
11445
- }
11446
- for (const shippingMethod of shippingMethods) {
11447
- if (shippingMethod.adjustments) {
11448
- for (const adjustment of shippingMethod.adjustments) {
11449
- if (adjustment.promotion_id) {
11450
- promotionIds.add(adjustment.promotion_id);
11451
- }
11452
- }
11453
- }
11454
- }
11455
- return Array.from(promotionIds);
11456
- }
11457
- const SalesChannel = () => {
11458
- const { id } = reactRouterDom.useParams();
11459
- const { draft_order, isPending, isError, error } = useDraftOrder(
11460
- id,
11461
- {
11462
- fields: "+sales_channel_id"
11463
- },
11464
- {
11465
- enabled: !!id
11375
+ ) }),
11376
+ /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
11377
+ /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
11378
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", type: "button", onClick: onSubmit, children: "Update items" })
11379
+ ] }) })
11380
+ ]
11466
11381
  }
11467
11382
  );
11468
- if (isError) {
11469
- throw error;
11470
- }
11471
- const ISrEADY = !!draft_order && !isPending;
11472
- return /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer, { children: [
11473
- /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer.Header, { children: [
11474
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Edit Sales Channel" }) }),
11475
- /* @__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" }) })
11476
- ] }),
11477
- ISrEADY && /* @__PURE__ */ jsxRuntime.jsx(SalesChannelForm, { order: draft_order })
11478
- ] });
11479
11383
  };
11480
- const SalesChannelForm = ({ order }) => {
11384
+ const columnHelper = ui.createDataTableColumnHelper();
11385
+ const useColumns = () => {
11386
+ return React.useMemo(() => {
11387
+ return [
11388
+ columnHelper.select(),
11389
+ columnHelper.accessor("product.title", {
11390
+ header: "Product",
11391
+ cell: ({ row }) => {
11392
+ var _a, _b, _c;
11393
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-x-2", children: [
11394
+ /* @__PURE__ */ jsxRuntime.jsx(
11395
+ Thumbnail,
11396
+ {
11397
+ thumbnail: (_a = row.original.product) == null ? void 0 : _a.thumbnail,
11398
+ alt: (_b = row.original.product) == null ? void 0 : _b.title
11399
+ }
11400
+ ),
11401
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: (_c = row.original.product) == null ? void 0 : _c.title })
11402
+ ] });
11403
+ },
11404
+ enableSorting: true
11405
+ }),
11406
+ columnHelper.accessor("title", {
11407
+ header: "Variant",
11408
+ enableSorting: true
11409
+ }),
11410
+ columnHelper.accessor("sku", {
11411
+ header: "SKU",
11412
+ cell: ({ getValue }) => {
11413
+ return getValue() ?? "-";
11414
+ },
11415
+ enableSorting: true
11416
+ }),
11417
+ columnHelper.accessor("updated_at", {
11418
+ header: "Updated",
11419
+ cell: ({ getValue }) => {
11420
+ return /* @__PURE__ */ jsxRuntime.jsx(
11421
+ ui.Tooltip,
11422
+ {
11423
+ content: getFullDate({ date: getValue(), includeTime: true }),
11424
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { children: getFullDate({ date: getValue() }) })
11425
+ }
11426
+ );
11427
+ },
11428
+ enableSorting: true,
11429
+ sortAscLabel: "Oldest first",
11430
+ sortDescLabel: "Newest first"
11431
+ }),
11432
+ columnHelper.accessor("created_at", {
11433
+ header: "Created",
11434
+ cell: ({ getValue }) => {
11435
+ return /* @__PURE__ */ jsxRuntime.jsx(
11436
+ ui.Tooltip,
11437
+ {
11438
+ content: getFullDate({ date: getValue(), includeTime: true }),
11439
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { children: getFullDate({ date: getValue() }) })
11440
+ }
11441
+ );
11442
+ },
11443
+ enableSorting: true,
11444
+ sortAscLabel: "Oldest first",
11445
+ sortDescLabel: "Newest first"
11446
+ })
11447
+ ];
11448
+ }, []);
11449
+ };
11450
+ const CustomItemForm = ({ orderId, currencyCode }) => {
11451
+ const { setIsOpen } = useStackedModal();
11452
+ const { mutateAsync: addItems } = useDraftOrderAddItems(orderId);
11481
11453
  const form = reactHookForm.useForm({
11482
11454
  defaultValues: {
11483
- sales_channel_id: order.sales_channel_id || ""
11455
+ title: "",
11456
+ quantity: 1,
11457
+ unit_price: ""
11484
11458
  },
11485
- resolver: zod.zodResolver(schema$2)
11459
+ resolver: zod.zodResolver(customItemSchema)
11486
11460
  });
11487
- const { mutateAsync, isPending } = useUpdateDraftOrder(order.id);
11488
- const { handleSuccess } = useRouteModal();
11489
11461
  const onSubmit = form.handleSubmit(async (data) => {
11490
- await mutateAsync(
11462
+ await addItems(
11491
11463
  {
11492
- sales_channel_id: data.sales_channel_id
11464
+ items: [
11465
+ {
11466
+ title: data.title,
11467
+ quantity: data.quantity,
11468
+ unit_price: convertNumber(data.unit_price)
11469
+ }
11470
+ ]
11493
11471
  },
11494
11472
  {
11495
11473
  onSuccess: () => {
11496
- ui.toast.success("Sales channel updated");
11497
- handleSuccess();
11474
+ setIsOpen(STACKED_MODAL_ID, false);
11498
11475
  },
11499
- onError: (error) => {
11500
- ui.toast.error(error.message);
11476
+ onError: (e) => {
11477
+ ui.toast.error(e.message);
11501
11478
  }
11502
11479
  }
11503
11480
  );
11504
11481
  });
11505
- return /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxRuntime.jsxs(
11506
- KeyboundForm,
11507
- {
11508
- className: "flex flex-1 flex-col overflow-hidden",
11509
- onSubmit,
11510
- children: [
11511
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Body, { className: "flex flex-col gap-y-6 overflow-y-auto", children: /* @__PURE__ */ jsxRuntime.jsx(SalesChannelField, { control: form.control, order }) }),
11512
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-2", children: [
11513
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
11514
- /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", type: "submit", isLoading: isPending, children: "Save" })
11515
- ] }) })
11516
- ]
11517
- }
11518
- ) });
11519
- };
11520
- const SalesChannelField = ({ control, order }) => {
11521
- const salesChannels = useComboboxData({
11522
- queryFn: async (params) => {
11523
- return await sdk.admin.salesChannel.list(params);
11524
- },
11525
- queryKey: ["sales-channels"],
11526
- getOptions: (data) => {
11527
- return data.sales_channels.map((salesChannel) => ({
11528
- label: salesChannel.name,
11529
- value: salesChannel.id
11530
- }));
11531
- },
11532
- defaultValue: order.sales_channel_id || void 0
11533
- });
11534
- return /* @__PURE__ */ jsxRuntime.jsx(
11535
- Form$2.Field,
11536
- {
11537
- control,
11538
- name: "sales_channel_id",
11539
- render: ({ field }) => {
11540
- return /* @__PURE__ */ jsxRuntime.jsxs(Form$2.Item, { children: [
11541
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.Label, { children: "Sales Channel" }),
11542
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
11543
- Combobox,
11544
- {
11545
- options: salesChannels.options,
11546
- fetchNextPage: salesChannels.fetchNextPage,
11547
- isFetchingNextPage: salesChannels.isFetchingNextPage,
11548
- searchValue: salesChannels.searchValue,
11549
- onSearchValueChange: salesChannels.onSearchValueChange,
11550
- placeholder: "Select sales channel",
11551
- ...field
11552
- }
11553
- ) }),
11554
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.ErrorMessage, {})
11555
- ] });
11556
- }
11557
- }
11558
- );
11482
+ return /* @__PURE__ */ jsxRuntime.jsx(Form$2, { ...form, children: /* @__PURE__ */ jsxRuntime.jsx(KeyboundForm, { onSubmit, children: /* @__PURE__ */ jsxRuntime.jsxs(StackedFocusModal.Content, { children: [
11483
+ /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Header, {}),
11484
+ /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.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-2 py-16", children: [
11485
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
11486
+ /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Add custom item" }) }),
11487
+ /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Add a custom item to the order. This will add a new line item that is not associated with an existing product." }) })
11488
+ ] }),
11489
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { variant: "dashed" }),
11490
+ /* @__PURE__ */ jsxRuntime.jsx(
11491
+ Form$2.Field,
11492
+ {
11493
+ control: form.control,
11494
+ name: "title",
11495
+ render: ({ field }) => /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
11496
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
11497
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.Label, { children: "Title" }),
11498
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.Hint, { children: "Enter the title of the item" })
11499
+ ] }),
11500
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
11501
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Input, { ...field }) }),
11502
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.ErrorMessage, {})
11503
+ ] })
11504
+ ] }) })
11505
+ }
11506
+ ),
11507
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { variant: "dashed" }),
11508
+ /* @__PURE__ */ jsxRuntime.jsx(
11509
+ Form$2.Field,
11510
+ {
11511
+ control: form.control,
11512
+ name: "unit_price",
11513
+ render: ({ field: { onChange, ...field } }) => /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
11514
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
11515
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.Label, { children: "Unit price" }),
11516
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.Hint, { children: "Enter the unit price of the item" })
11517
+ ] }),
11518
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
11519
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
11520
+ ui.CurrencyInput,
11521
+ {
11522
+ symbol: getNativeSymbol(currencyCode),
11523
+ code: currencyCode,
11524
+ onValueChange: (_value, _name, values) => onChange(values == null ? void 0 : values.value),
11525
+ ...field
11526
+ }
11527
+ ) }),
11528
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.ErrorMessage, {})
11529
+ ] })
11530
+ ] }) })
11531
+ }
11532
+ ),
11533
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { variant: "dashed" }),
11534
+ /* @__PURE__ */ jsxRuntime.jsx(
11535
+ Form$2.Field,
11536
+ {
11537
+ control: form.control,
11538
+ name: "quantity",
11539
+ render: ({ field }) => /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
11540
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
11541
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.Label, { children: "Quantity" }),
11542
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.Hint, { children: "Enter the quantity of the item" })
11543
+ ] }),
11544
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full flex-1", children: [
11545
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(NumberInput, { ...field, className: "w-full" }) }) }),
11546
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.ErrorMessage, {})
11547
+ ] })
11548
+ ] }) })
11549
+ }
11550
+ )
11551
+ ] }) }) }),
11552
+ /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
11553
+ /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
11554
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", type: "button", onClick: onSubmit, children: "Add item" })
11555
+ ] }) })
11556
+ ] }) }) });
11559
11557
  };
11560
- const schema$2 = objectType({
11561
- sales_channel_id: stringType().min(1)
11558
+ const customItemSchema = objectType({
11559
+ title: stringType().min(1),
11560
+ quantity: numberType(),
11561
+ unit_price: unionType([numberType(), stringType()])
11562
11562
  });
11563
11563
  const STACKED_FOCUS_MODAL_ID = "shipping-form";
11564
11564
  const Shipping = () => {
@@ -13079,21 +13079,21 @@ const routeModule = {
13079
13079
  path: "/draft-orders/:id/email"
13080
13080
  },
13081
13081
  {
13082
- Component: Items,
13083
- path: "/draft-orders/:id/items"
13082
+ Component: Promotions,
13083
+ path: "/draft-orders/:id/promotions"
13084
13084
  },
13085
13085
  {
13086
13086
  Component: Metadata,
13087
13087
  path: "/draft-orders/:id/metadata"
13088
13088
  },
13089
- {
13090
- Component: Promotions,
13091
- path: "/draft-orders/:id/promotions"
13092
- },
13093
13089
  {
13094
13090
  Component: SalesChannel,
13095
13091
  path: "/draft-orders/:id/sales-channel"
13096
13092
  },
13093
+ {
13094
+ Component: Items,
13095
+ path: "/draft-orders/:id/items"
13096
+ },
13097
13097
  {
13098
13098
  Component: Shipping,
13099
13099
  path: "/draft-orders/:id/shipping"