@medusajs/draft-order 3.0.0-preview-20251214150138 → 3.0.0-preview-20251214180138

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