@medusajs/draft-order 2.10.0-snapshot-20250828115945 → 2.10.0-snapshot-20250828124740

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";
@@ -9744,6 +9744,27 @@ const BillingAddressForm = ({ order }) => {
9744
9744
  ) });
9745
9745
  };
9746
9746
  const schema$5 = addressSchema;
9747
+ const CustomItems = () => {
9748
+ return /* @__PURE__ */ jsxs(RouteDrawer, { children: [
9749
+ /* @__PURE__ */ jsx(RouteDrawer.Header, { children: /* @__PURE__ */ jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Edit Custom Items" }) }) }),
9750
+ /* @__PURE__ */ jsx(CustomItemsForm, {})
9751
+ ] });
9752
+ };
9753
+ const CustomItemsForm = () => {
9754
+ const form = useForm({
9755
+ resolver: zodResolver(schema$4)
9756
+ });
9757
+ return /* @__PURE__ */ jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxs(KeyboundForm, { className: "flex flex-1 flex-col", children: [
9758
+ /* @__PURE__ */ jsx(RouteDrawer.Body, {}),
9759
+ /* @__PURE__ */ jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
9760
+ /* @__PURE__ */ jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
9761
+ /* @__PURE__ */ jsx(Button, { size: "small", type: "submit", children: "Save" })
9762
+ ] }) })
9763
+ ] }) });
9764
+ };
9765
+ const schema$4 = objectType({
9766
+ email: stringType().email()
9767
+ });
9747
9768
  const Email = () => {
9748
9769
  const { id } = useParams();
9749
9770
  const { order, isPending, isError, error } = useOrder(id, {
@@ -9766,7 +9787,7 @@ const EmailForm = ({ order }) => {
9766
9787
  defaultValues: {
9767
9788
  email: order.email ?? ""
9768
9789
  },
9769
- resolver: zodResolver(schema$4)
9790
+ resolver: zodResolver(schema$3)
9770
9791
  });
9771
9792
  const { mutateAsync, isPending } = useUpdateDraftOrder(order.id);
9772
9793
  const { handleSuccess } = useRouteModal();
@@ -9809,151 +9830,25 @@ const EmailForm = ({ order }) => {
9809
9830
  }
9810
9831
  ) });
9811
9832
  };
9812
- const schema$4 = objectType({
9813
- email: stringType().email()
9814
- });
9815
- const CustomItems = () => {
9816
- return /* @__PURE__ */ jsxs(RouteDrawer, { children: [
9817
- /* @__PURE__ */ jsx(RouteDrawer.Header, { children: /* @__PURE__ */ jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Edit Custom Items" }) }) }),
9818
- /* @__PURE__ */ jsx(CustomItemsForm, {})
9819
- ] });
9820
- };
9821
- const CustomItemsForm = () => {
9822
- const form = useForm({
9823
- resolver: zodResolver(schema$3)
9824
- });
9825
- return /* @__PURE__ */ jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxs(KeyboundForm, { className: "flex flex-1 flex-col", children: [
9826
- /* @__PURE__ */ jsx(RouteDrawer.Body, {}),
9827
- /* @__PURE__ */ jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
9828
- /* @__PURE__ */ jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
9829
- /* @__PURE__ */ jsx(Button, { size: "small", type: "submit", children: "Save" })
9830
- ] }) })
9831
- ] }) });
9832
- };
9833
9833
  const schema$3 = objectType({
9834
9834
  email: stringType().email()
9835
9835
  });
9836
- const NumberInput = forwardRef(
9837
- ({
9838
- value,
9839
- onChange,
9840
- size = "base",
9841
- min = 0,
9842
- max = 100,
9843
- step = 1,
9844
- className,
9845
- disabled,
9846
- ...props
9847
- }, ref) => {
9848
- const handleChange = (event) => {
9849
- const newValue = event.target.value === "" ? min : Number(event.target.value);
9850
- if (!isNaN(newValue) && (max === void 0 || newValue <= max) && (min === void 0 || newValue >= min)) {
9851
- onChange(newValue);
9852
- }
9853
- };
9854
- const handleIncrement = () => {
9855
- const newValue = value + step;
9856
- if (max === void 0 || newValue <= max) {
9857
- onChange(newValue);
9858
- }
9859
- };
9860
- const handleDecrement = () => {
9861
- const newValue = value - step;
9862
- if (min === void 0 || newValue >= min) {
9863
- onChange(newValue);
9864
- }
9865
- };
9866
- return /* @__PURE__ */ jsxs(
9867
- "div",
9868
- {
9869
- className: clx(
9870
- "inline-flex rounded-md bg-ui-bg-field shadow-borders-base overflow-hidden divide-x transition-fg",
9871
- "[&:has(input:focus)]:shadow-borders-interactive-with-active",
9872
- {
9873
- "h-7": size === "small",
9874
- "h-8": size === "base"
9875
- },
9876
- className
9877
- ),
9878
- children: [
9879
- /* @__PURE__ */ jsx(
9880
- "input",
9881
- {
9882
- ref,
9883
- type: "number",
9884
- value,
9885
- onChange: handleChange,
9886
- min,
9887
- max,
9888
- step,
9889
- className: clx(
9890
- "flex-1 px-2 py-1 bg-transparent txt-compact-small text-ui-fg-base outline-none [appearance:textfield]",
9891
- "[&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none",
9892
- "placeholder:text-ui-fg-muted"
9893
- ),
9894
- ...props
9895
- }
9896
- ),
9897
- /* @__PURE__ */ jsxs(
9898
- "button",
9899
- {
9900
- className: clx(
9901
- "flex items-center justify-center outline-none transition-fg",
9902
- "disabled:cursor-not-allowed disabled:text-ui-fg-muted",
9903
- "focus:bg-ui-bg-field-component-hover",
9904
- "hover:bg-ui-bg-field-component-hover",
9905
- {
9906
- "size-7": size === "small",
9907
- "size-8": size === "base"
9908
- }
9909
- ),
9910
- type: "button",
9911
- onClick: handleDecrement,
9912
- disabled: min !== void 0 && value <= min || disabled,
9913
- children: [
9914
- /* @__PURE__ */ jsx(Minus, {}),
9915
- /* @__PURE__ */ jsx("span", { className: "sr-only", children: `Decrease by ${step}` })
9916
- ]
9917
- }
9918
- ),
9919
- /* @__PURE__ */ jsxs(
9920
- "button",
9921
- {
9922
- className: clx(
9923
- "flex items-center justify-center outline-none transition-fg",
9924
- "disabled:cursor-not-allowed disabled:text-ui-fg-muted",
9925
- "focus:bg-ui-bg-field-hover",
9926
- "hover:bg-ui-bg-field-hover",
9927
- {
9928
- "size-7": size === "small",
9929
- "size-8": size === "base"
9930
- }
9931
- ),
9932
- type: "button",
9933
- onClick: handleIncrement,
9934
- disabled: max !== void 0 && value >= max || disabled,
9935
- children: [
9936
- /* @__PURE__ */ jsx(Plus, {}),
9937
- /* @__PURE__ */ jsx("span", { className: "sr-only", children: `Increase by ${step}` })
9938
- ]
9939
- }
9940
- )
9941
- ]
9942
- }
9943
- );
9944
- }
9945
- );
9946
- const PRODUCT_VARIANTS_QUERY_KEY = "product-variants";
9947
- const productVariantsQueryKeys = {
9836
+ const PROMOTION_QUERY_KEY = "promotions";
9837
+ const promotionsQueryKeys = {
9948
9838
  list: (query2) => [
9949
- PRODUCT_VARIANTS_QUERY_KEY,
9839
+ PROMOTION_QUERY_KEY,
9840
+ query2 ? query2 : void 0
9841
+ ],
9842
+ detail: (id, query2) => [
9843
+ PROMOTION_QUERY_KEY,
9844
+ id,
9950
9845
  query2 ? query2 : void 0
9951
9846
  ]
9952
9847
  };
9953
- const useProductVariants = (query2, options) => {
9848
+ const usePromotions = (query2, options) => {
9954
9849
  const { data, ...rest } = useQuery({
9955
- queryKey: productVariantsQueryKeys.list(query2),
9956
- queryFn: async () => await sdk.admin.productVariant.list(query2),
9850
+ queryKey: promotionsQueryKeys.list(query2),
9851
+ queryFn: async () => sdk.admin.promotion.list(query2),
9957
9852
  ...options
9958
9853
  });
9959
9854
  return { ...data, ...rest };
@@ -10004,891 +9899,653 @@ const useInitiateOrderEdit = ({
10004
9899
  run();
10005
9900
  }, [preview, navigate, mutateAsync]);
10006
9901
  };
10007
- function convertNumber(value) {
10008
- return typeof value === "string" ? Number(value.replace(",", ".")) : value;
10009
- }
10010
- const STACKED_MODAL_ID = "items_stacked_modal";
10011
- const Items = () => {
9902
+ const Promotions = () => {
10012
9903
  const { id } = useParams();
10013
9904
  const {
10014
9905
  order: preview,
10015
- isPending: isPreviewPending,
10016
9906
  isError: isPreviewError,
10017
9907
  error: previewError
10018
- } = useOrderPreview(id, void 0, {
10019
- placeholderData: keepPreviousData
10020
- });
9908
+ } = useOrderPreview(id, void 0);
10021
9909
  useInitiateOrderEdit({ preview });
10022
- const { draft_order, isPending, isError, error } = useDraftOrder(
10023
- id,
10024
- {
10025
- fields: "currency_code"
10026
- },
10027
- {
10028
- enabled: !!id
10029
- }
10030
- );
10031
9910
  const { onCancel } = useCancelOrderEdit({ preview });
10032
- if (isError) {
10033
- throw error;
10034
- }
10035
9911
  if (isPreviewError) {
10036
9912
  throw previewError;
10037
9913
  }
10038
- const ready = !!preview && !isPreviewPending && !!draft_order && !isPending;
10039
- return /* @__PURE__ */ jsx(RouteFocusModal, { onClose: onCancel, children: ready ? /* @__PURE__ */ jsx(ItemsForm, { preview, currencyCode: draft_order.currency_code }) : /* @__PURE__ */ jsxs("div", { children: [
10040
- /* @__PURE__ */ jsx(RouteFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Edit Items" }) }),
10041
- /* @__PURE__ */ jsx(RouteFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Loading data for the draft order, please wait..." }) })
10042
- ] }) });
9914
+ const isReady = !!preview;
9915
+ return /* @__PURE__ */ jsxs(RouteDrawer, { onClose: onCancel, children: [
9916
+ /* @__PURE__ */ jsx(RouteDrawer.Header, { children: /* @__PURE__ */ jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Edit Promotions" }) }) }),
9917
+ isReady && /* @__PURE__ */ jsx(PromotionForm, { preview })
9918
+ ] });
10043
9919
  };
10044
- const ItemsForm = ({ preview, currencyCode }) => {
10045
- var _a;
9920
+ const PromotionForm = ({ preview }) => {
9921
+ const { items, shipping_methods } = preview;
10046
9922
  const [isSubmitting, setIsSubmitting] = useState(false);
10047
- const [modalContent, setModalContent] = useState(
10048
- null
10049
- );
9923
+ const [comboboxValue, setComboboxValue] = useState("");
10050
9924
  const { handleSuccess } = useRouteModal();
10051
- const { searchValue, onSearchValueChange, query: query2 } = useDebouncedSearch();
10052
- const { mutateAsync: confirmOrderEdit } = useDraftOrderConfirmEdit(preview.id);
10053
- const { mutateAsync: requestOrderEdit } = useDraftOrderRequestEdit(preview.id);
10054
- const itemCount = ((_a = preview.items) == null ? void 0 : _a.reduce((acc, item) => acc + item.quantity, 0)) || 0;
10055
- const matches = useMemo(() => {
10056
- return matchSorter(preview.items, query2, {
10057
- keys: ["product_title", "variant_title", "variant_sku", "title"]
10058
- });
10059
- }, [preview.items, query2]);
10060
- const onSubmit = async () => {
10061
- setIsSubmitting(true);
10062
- let requestSucceeded = false;
10063
- await requestOrderEdit(void 0, {
10064
- onError: (e) => {
10065
- toast.error(`Failed to request order edit: ${e.message}`);
10066
- },
10067
- onSuccess: () => {
10068
- requestSucceeded = true;
10069
- }
10070
- });
10071
- if (!requestSucceeded) {
10072
- setIsSubmitting(false);
10073
- return;
9925
+ const { mutateAsync: addPromotions, isPending: isAddingPromotions } = useDraftOrderAddPromotions(preview.id);
9926
+ const promoCodes = getPromotionCodes(items, shipping_methods);
9927
+ const { promotions, isPending, isError, error } = usePromotions(
9928
+ {
9929
+ code: promoCodes
9930
+ },
9931
+ {
9932
+ enabled: !!promoCodes.length
10074
9933
  }
10075
- await confirmOrderEdit(void 0, {
10076
- onError: (e) => {
10077
- toast.error(`Failed to confirm order edit: ${e.message}`);
10078
- },
10079
- onSuccess: () => {
10080
- handleSuccess();
10081
- },
10082
- onSettled: () => {
10083
- setIsSubmitting(false);
10084
- }
10085
- });
10086
- };
10087
- const onKeyDown = useCallback(
10088
- (e) => {
10089
- if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) {
10090
- if (modalContent || isSubmitting) {
10091
- return;
9934
+ );
9935
+ const comboboxData = useComboboxData({
9936
+ queryKey: ["promotions", "combobox", promoCodes],
9937
+ queryFn: async (params) => {
9938
+ return await sdk.admin.promotion.list({
9939
+ ...params,
9940
+ code: {
9941
+ $nin: promoCodes
10092
9942
  }
10093
- onSubmit();
10094
- }
9943
+ });
10095
9944
  },
10096
- [modalContent, isSubmitting, onSubmit]
10097
- );
10098
- useEffect(() => {
10099
- document.addEventListener("keydown", onKeyDown);
10100
- return () => {
10101
- document.removeEventListener("keydown", onKeyDown);
10102
- };
10103
- }, [onKeyDown]);
10104
- return /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-col overflow-hidden", children: [
10105
- /* @__PURE__ */ jsx(RouteFocusModal.Header, {}),
10106
- /* @__PURE__ */ jsx(RouteFocusModal.Body, { className: "flex flex-1 flex-col overflow-hidden", children: /* @__PURE__ */ jsxs(
10107
- StackedFocusModal,
9945
+ getOptions: (data) => {
9946
+ return data.promotions.map((promotion) => ({
9947
+ label: promotion.code,
9948
+ value: promotion.code
9949
+ }));
9950
+ }
9951
+ });
9952
+ const add = async (value) => {
9953
+ if (!value) {
9954
+ return;
9955
+ }
9956
+ addPromotions(
10108
9957
  {
10109
- id: STACKED_MODAL_ID,
10110
- onOpenChangeCallback: (open) => {
10111
- if (!open) {
10112
- setModalContent(null);
10113
- }
9958
+ promo_codes: [value]
9959
+ },
9960
+ {
9961
+ onError: (e) => {
9962
+ toast.error(e.message);
9963
+ comboboxData.onSearchValueChange("");
9964
+ setComboboxValue("");
10114
9965
  },
10115
- children: [
10116
- /* @__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: [
10117
- /* @__PURE__ */ jsxs("div", { children: [
10118
- /* @__PURE__ */ jsx(RouteFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Edit Items" }) }),
10119
- /* @__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." }) })
10120
- ] }),
10121
- /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
10122
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-y-6", children: [
10123
- /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 items-center gap-3", children: [
10124
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
10125
- /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: "Items" }),
10126
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Choose items from the product catalog." })
10127
- ] }),
10128
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
10129
- /* @__PURE__ */ jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsx(
10130
- Input,
10131
- {
10132
- type: "search",
10133
- placeholder: "Search items",
10134
- value: searchValue,
10135
- onChange: (e) => onSearchValueChange(e.target.value)
10136
- }
10137
- ) }),
10138
- /* @__PURE__ */ jsxs(DropdownMenu, { children: [
10139
- /* @__PURE__ */ jsx(DropdownMenu.Trigger, { asChild: true, children: /* @__PURE__ */ jsx(IconButton, { type: "button", children: /* @__PURE__ */ jsx(Plus, {}) }) }),
10140
- /* @__PURE__ */ jsxs(DropdownMenu.Content, { children: [
10141
- /* @__PURE__ */ jsx(
10142
- StackedModalTrigger$1,
10143
- {
10144
- type: "add-items",
10145
- setModalContent
10146
- }
10147
- ),
10148
- /* @__PURE__ */ jsx(
10149
- StackedModalTrigger$1,
10150
- {
10151
- type: "add-custom-item",
10152
- setModalContent
10153
- }
10154
- )
10155
- ] })
10156
- ] })
10157
- ] })
10158
- ] }),
10159
- /* @__PURE__ */ jsxs("div", { className: "bg-ui-bg-subtle shadow-elevation-card-rest rounded-xl", children: [
10160
- /* @__PURE__ */ jsx("div", { className: "px-[5px]", children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-[1fr_1fr_1fr_28px] gap-3 px-4 py-2 text-ui-fg-muted", children: [
10161
- /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: "Item" }) }),
10162
- /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: "Quantity" }) }),
10163
- /* @__PURE__ */ jsx("div", { className: "text-right", children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: "Price" }) }),
10164
- /* @__PURE__ */ jsx("div", {})
10165
- ] }) }),
10166
- /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-y-1.5 px-[5px] pb-[5px]", children: itemCount <= 0 ? /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center gap-x-3 bg-ui-bg-base rounded-lg p-4 shadow-elevation-card-rest flex-col gap-1", children: [
10167
- /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: "There are no items in this order" }),
10168
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Add items to the order to get started." })
10169
- ] }) : matches.length > 0 ? matches == null ? void 0 : matches.map((item) => /* @__PURE__ */ jsx(
10170
- Item,
10171
- {
10172
- item,
10173
- preview,
10174
- currencyCode
10175
- },
10176
- item.id
10177
- )) : /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center gap-x-3 bg-ui-bg-base rounded-lg p-4 shadow-elevation-card-rest flex-col gap-1", children: [
10178
- /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: "No items found" }),
10179
- /* @__PURE__ */ jsxs(Text, { size: "small", className: "text-ui-fg-subtle", children: [
10180
- 'No items found for "',
10181
- query2,
10182
- '".'
10183
- ] })
10184
- ] }) })
10185
- ] })
10186
- ] }),
10187
- /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
10188
- /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-[1fr_0.5fr_0.5fr] gap-3", children: [
10189
- /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: "Subtotal" }) }),
10190
- /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsxs(
10191
- Text,
10192
- {
10193
- size: "small",
10194
- leading: "compact",
10195
- className: "text-ui-fg-subtle",
10196
- children: [
10197
- itemCount,
10198
- " ",
10199
- itemCount === 1 ? "item" : "items"
10200
- ]
10201
- }
10202
- ) }),
10203
- /* @__PURE__ */ jsx("div", { className: "text-right", children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: getStylizedAmount(preview.item_subtotal, currencyCode) }) })
10204
- ] })
10205
- ] }) }),
10206
- modalContent && (modalContent === "add-items" ? /* @__PURE__ */ jsx(ExistingItemsForm, { orderId: preview.id, items: preview.items }) : modalContent === "add-custom-item" ? /* @__PURE__ */ jsx(
10207
- CustomItemForm,
10208
- {
10209
- orderId: preview.id,
10210
- currencyCode
10211
- }
10212
- ) : null)
10213
- ]
9966
+ onSuccess: () => {
9967
+ comboboxData.onSearchValueChange("");
9968
+ setComboboxValue("");
9969
+ }
10214
9970
  }
10215
- ) }),
10216
- /* @__PURE__ */ jsx(RouteFocusModal.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-2 justify-end", children: [
10217
- /* @__PURE__ */ jsx(RouteFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
9971
+ );
9972
+ };
9973
+ const { mutateAsync: confirmOrderEdit } = useDraftOrderConfirmEdit(preview.id);
9974
+ const { mutateAsync: requestOrderEdit } = useOrderEditRequest(preview.id);
9975
+ const onSubmit = async () => {
9976
+ setIsSubmitting(true);
9977
+ let requestSucceeded = false;
9978
+ await requestOrderEdit(void 0, {
9979
+ onError: (e) => {
9980
+ toast.error(e.message);
9981
+ },
9982
+ onSuccess: () => {
9983
+ requestSucceeded = true;
9984
+ }
9985
+ });
9986
+ if (!requestSucceeded) {
9987
+ setIsSubmitting(false);
9988
+ return;
9989
+ }
9990
+ await confirmOrderEdit(void 0, {
9991
+ onError: (e) => {
9992
+ toast.error(e.message);
9993
+ },
9994
+ onSuccess: () => {
9995
+ handleSuccess();
9996
+ },
9997
+ onSettled: () => {
9998
+ setIsSubmitting(false);
9999
+ }
10000
+ });
10001
+ };
10002
+ if (isError) {
10003
+ throw error;
10004
+ }
10005
+ return /* @__PURE__ */ jsxs(KeyboundForm, { className: "flex flex-1 flex-col", onSubmit, children: [
10006
+ /* @__PURE__ */ jsx(RouteDrawer.Body, { children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
10007
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
10008
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
10009
+ /* @__PURE__ */ jsx(Label$1, { size: "small", weight: "plus", htmlFor: "promotion-combobox", children: "Apply promotions" }),
10010
+ /* @__PURE__ */ jsx(Hint$1, { id: "promotion-combobox-hint", children: "Manage promotions that should be applied to the order." })
10011
+ ] }),
10012
+ /* @__PURE__ */ jsx(
10013
+ Combobox,
10014
+ {
10015
+ id: "promotion-combobox",
10016
+ "aria-describedby": "promotion-combobox-hint",
10017
+ isFetchingNextPage: comboboxData.isFetchingNextPage,
10018
+ fetchNextPage: comboboxData.fetchNextPage,
10019
+ options: comboboxData.options,
10020
+ onSearchValueChange: comboboxData.onSearchValueChange,
10021
+ searchValue: comboboxData.searchValue,
10022
+ disabled: comboboxData.disabled || isAddingPromotions,
10023
+ onChange: add,
10024
+ value: comboboxValue
10025
+ }
10026
+ )
10027
+ ] }),
10028
+ /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
10029
+ /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-2", children: promotions == null ? void 0 : promotions.map((promotion) => /* @__PURE__ */ jsx(
10030
+ PromotionItem,
10031
+ {
10032
+ promotion,
10033
+ orderId: preview.id,
10034
+ isLoading: isPending
10035
+ },
10036
+ promotion.id
10037
+ )) })
10038
+ ] }) }),
10039
+ /* @__PURE__ */ jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
10040
+ /* @__PURE__ */ jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
10218
10041
  /* @__PURE__ */ jsx(
10219
10042
  Button,
10220
10043
  {
10221
10044
  size: "small",
10222
- type: "button",
10223
- onClick: onSubmit,
10224
- isLoading: isSubmitting,
10045
+ type: "submit",
10046
+ isLoading: isSubmitting || isAddingPromotions,
10225
10047
  children: "Save"
10226
10048
  }
10227
10049
  )
10228
10050
  ] }) })
10229
10051
  ] });
10230
10052
  };
10231
- const Item = ({ item, preview, currencyCode }) => {
10232
- if (item.variant_id) {
10233
- return /* @__PURE__ */ jsx(VariantItem, { item, preview, currencyCode });
10234
- }
10235
- return /* @__PURE__ */ jsx(CustomItem, { item, preview, currencyCode });
10236
- };
10237
- const VariantItem = ({ item, preview, currencyCode }) => {
10238
- const [editing, setEditing] = useState(false);
10239
- const form = useForm({
10240
- defaultValues: {
10241
- quantity: item.quantity,
10242
- unit_price: item.unit_price
10243
- },
10244
- resolver: zodResolver(variantItemSchema)
10245
- });
10246
- const actionId = useMemo(() => {
10247
- var _a, _b;
10248
- return (_b = (_a = item.actions) == null ? void 0 : _a.find((a) => a.action === "ITEM_ADD")) == null ? void 0 : _b.id;
10249
- }, [item]);
10250
- const { mutateAsync: updateActionItem, isPending: isUpdatingActionItem } = useDraftOrderUpdateActionItem(preview.id);
10251
- const { mutateAsync: updateOriginalItem, isPending: isUpdatingOriginalItem } = useDraftOrderUpdateItem(preview.id);
10252
- const isPending = isUpdatingActionItem || isUpdatingOriginalItem;
10253
- const onSubmit = form.handleSubmit(async (data) => {
10254
- if (convertNumber(data.unit_price) === item.unit_price && data.quantity === item.quantity) {
10255
- setEditing(false);
10256
- return;
10257
- }
10258
- if (!actionId) {
10259
- await updateOriginalItem(
10260
- {
10261
- item_id: item.id,
10262
- quantity: data.quantity,
10263
- unit_price: convertNumber(data.unit_price)
10264
- },
10265
- {
10266
- onSuccess: () => {
10267
- setEditing(false);
10268
- },
10269
- onError: (e) => {
10270
- toast.error(e.message);
10271
- }
10272
- }
10273
- );
10274
- return;
10275
- }
10276
- await updateActionItem(
10053
+ const PromotionItem = ({
10054
+ promotion,
10055
+ orderId,
10056
+ isLoading
10057
+ }) => {
10058
+ var _a;
10059
+ const { mutateAsync: removePromotions, isPending } = useDraftOrderRemovePromotions(orderId);
10060
+ const onRemove = async () => {
10061
+ removePromotions(
10277
10062
  {
10278
- action_id: actionId,
10279
- quantity: data.quantity,
10280
- unit_price: convertNumber(data.unit_price)
10063
+ promo_codes: [promotion.code]
10281
10064
  },
10282
10065
  {
10283
- onSuccess: () => {
10284
- setEditing(false);
10285
- },
10286
10066
  onError: (e) => {
10287
10067
  toast.error(e.message);
10288
10068
  }
10289
10069
  }
10290
10070
  );
10291
- });
10292
- return /* @__PURE__ */ jsx(Form$2, { ...form, children: /* @__PURE__ */ jsx("form", { onSubmit, children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-[minmax(0,1fr)_minmax(0,1fr)_minmax(0,1fr)_28px] gap-3 px-4 py-2 bg-ui-bg-base shadow-elevation-card-rest rounded-lg items-center", children: [
10293
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-3 w-full", children: [
10294
- /* @__PURE__ */ jsx(
10295
- Thumbnail,
10071
+ };
10072
+ const displayValue = getDisplayValue(promotion);
10073
+ return /* @__PURE__ */ jsxs(
10074
+ "div",
10075
+ {
10076
+ className: clx(
10077
+ "px-3 py-2 rounded-lg bg-ui-bg-component shadow-elevation-card-rest flex items-center justify-between",
10296
10078
  {
10297
- thumbnail: item.thumbnail,
10298
- alt: item.product_title ?? void 0
10079
+ "animate-pulse": isLoading
10299
10080
  }
10300
10081
  ),
10301
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
10302
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-1", children: [
10303
- /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: item.product_title }),
10304
- /* @__PURE__ */ jsxs(
10305
- Text,
10306
- {
10307
- size: "small",
10308
- leading: "compact",
10309
- className: "text-ui-fg-subtle",
10310
- children: [
10311
- "(",
10312
- item.variant_title,
10313
- ")"
10314
- ]
10315
- }
10316
- )
10082
+ children: [
10083
+ /* @__PURE__ */ jsxs("div", { children: [
10084
+ /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: promotion.code }),
10085
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 text-ui-fg-subtle", children: [
10086
+ displayValue && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
10087
+ /* @__PURE__ */ jsx(Text, { size: "small", leading: "compact", children: displayValue }),
10088
+ /* @__PURE__ */ jsx(Text, { size: "small", leading: "compact", children: "·" })
10089
+ ] }),
10090
+ /* @__PURE__ */ jsx(Text, { size: "small", leading: "compact", className: "capitalize", children: (_a = promotion.application_method) == null ? void 0 : _a.allocation })
10091
+ ] })
10317
10092
  ] }),
10318
10093
  /* @__PURE__ */ jsx(
10319
- Text,
10094
+ IconButton,
10320
10095
  {
10321
10096
  size: "small",
10322
- leading: "compact",
10323
- className: "text-ui-fg-subtle",
10324
- children: item.variant_sku
10097
+ type: "button",
10098
+ variant: "transparent",
10099
+ onClick: onRemove,
10100
+ isLoading: isPending || isLoading,
10101
+ children: /* @__PURE__ */ jsx(XMark, {})
10325
10102
  }
10326
10103
  )
10327
- ] })
10328
- ] }),
10329
- editing ? /* @__PURE__ */ jsx("div", { className: "flex-1 w-full", children: /* @__PURE__ */ jsx(
10330
- Form$2.Field,
10331
- {
10332
- control: form.control,
10333
- name: "quantity",
10334
- render: ({ field }) => {
10335
- return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(NumberInput, { ...field }) }) });
10104
+ ]
10105
+ },
10106
+ promotion.id
10107
+ );
10108
+ };
10109
+ function getDisplayValue(promotion) {
10110
+ var _a, _b, _c, _d;
10111
+ const value = (_a = promotion.application_method) == null ? void 0 : _a.value;
10112
+ if (!value) {
10113
+ return null;
10114
+ }
10115
+ if (((_b = promotion.application_method) == null ? void 0 : _b.type) === "fixed") {
10116
+ const currency = (_c = promotion.application_method) == null ? void 0 : _c.currency_code;
10117
+ if (!currency) {
10118
+ return null;
10119
+ }
10120
+ return getLocaleAmount(value, currency);
10121
+ } else if (((_d = promotion.application_method) == null ? void 0 : _d.type) === "percentage") {
10122
+ return formatPercentage(value);
10123
+ }
10124
+ return null;
10125
+ }
10126
+ const formatter = new Intl.NumberFormat([], {
10127
+ style: "percent",
10128
+ minimumFractionDigits: 2
10129
+ });
10130
+ const formatPercentage = (value, isPercentageValue = false) => {
10131
+ let val = value || 0;
10132
+ if (!isPercentageValue) {
10133
+ val = val / 100;
10134
+ }
10135
+ return formatter.format(val);
10136
+ };
10137
+ function getPromotionCodes(items, shippingMethods) {
10138
+ const codes = /* @__PURE__ */ new Set();
10139
+ for (const item of items) {
10140
+ if (item.adjustments) {
10141
+ for (const adjustment of item.adjustments) {
10142
+ if (adjustment.code) {
10143
+ codes.add(adjustment.code);
10336
10144
  }
10337
10145
  }
10338
- ) }) : /* @__PURE__ */ jsx("div", { className: "flex-1 w-full", children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: item.quantity }) }),
10339
- editing ? /* @__PURE__ */ jsx("div", { className: "flex-1 w-full", children: /* @__PURE__ */ jsx(
10340
- Form$2.Field,
10341
- {
10342
- control: form.control,
10343
- name: "unit_price",
10344
- render: ({ field: { onChange, ...field } }) => {
10345
- return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
10346
- CurrencyInput,
10347
- {
10348
- ...field,
10349
- symbol: getNativeSymbol(currencyCode),
10350
- code: currencyCode,
10351
- onValueChange: (_value, _name, values) => onChange(values == null ? void 0 : values.value)
10352
- }
10353
- ) }) });
10146
+ }
10147
+ }
10148
+ for (const shippingMethod of shippingMethods) {
10149
+ if (shippingMethod.adjustments) {
10150
+ for (const adjustment of shippingMethod.adjustments) {
10151
+ if (adjustment.code) {
10152
+ codes.add(adjustment.code);
10354
10153
  }
10355
10154
  }
10356
- ) }) : /* @__PURE__ */ jsx("div", { className: "flex-1 flex items-center justify-end w-full", children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: getLocaleAmount(item.unit_price, currencyCode) }) }),
10357
- /* @__PURE__ */ jsx(
10358
- IconButton,
10155
+ }
10156
+ }
10157
+ return Array.from(codes);
10158
+ }
10159
+ const InlineTip = forwardRef(
10160
+ ({ variant = "tip", label, className, children, ...props }, ref) => {
10161
+ const labelValue = label || (variant === "warning" ? "Warning" : "Tip");
10162
+ return /* @__PURE__ */ jsxs(
10163
+ "div",
10359
10164
  {
10360
- type: "button",
10361
- size: "small",
10362
- onClick: editing ? onSubmit : () => {
10363
- setEditing(true);
10364
- },
10365
- disabled: isPending,
10366
- children: editing ? /* @__PURE__ */ jsx(Check, {}) : /* @__PURE__ */ jsx(PencilSquare, {})
10165
+ ref,
10166
+ className: clx(
10167
+ "bg-ui-bg-component txt-small text-ui-fg-subtle grid grid-cols-[4px_1fr] items-start gap-3 rounded-lg border p-3",
10168
+ className
10169
+ ),
10170
+ ...props,
10171
+ children: [
10172
+ /* @__PURE__ */ jsx(
10173
+ "div",
10174
+ {
10175
+ role: "presentation",
10176
+ className: clx("w-4px bg-ui-tag-neutral-icon h-full rounded-full", {
10177
+ "bg-ui-tag-orange-icon": variant === "warning"
10178
+ })
10179
+ }
10180
+ ),
10181
+ /* @__PURE__ */ jsxs("div", { className: "text-pretty", children: [
10182
+ /* @__PURE__ */ jsxs("strong", { className: "txt-small-plus text-ui-fg-base", children: [
10183
+ labelValue,
10184
+ ":"
10185
+ ] }),
10186
+ " ",
10187
+ children
10188
+ ] })
10189
+ ]
10367
10190
  }
10368
- )
10369
- ] }) }) });
10370
- };
10371
- const variantItemSchema = objectType({
10372
- quantity: numberType(),
10373
- unit_price: unionType([numberType(), stringType()])
10191
+ );
10192
+ }
10193
+ );
10194
+ InlineTip.displayName = "InlineTip";
10195
+ const MetadataFieldSchema = objectType({
10196
+ key: stringType(),
10197
+ disabled: booleanType().optional(),
10198
+ value: anyType()
10374
10199
  });
10375
- const CustomItem = ({ item, preview, currencyCode }) => {
10376
- const [editing, setEditing] = useState(false);
10377
- const { quantity, unit_price, title } = item;
10200
+ const MetadataSchema = objectType({
10201
+ metadata: arrayType(MetadataFieldSchema)
10202
+ });
10203
+ const Metadata = () => {
10204
+ const { id } = useParams();
10205
+ const { order, isPending, isError, error } = useOrder(id, {
10206
+ fields: "metadata"
10207
+ });
10208
+ if (isError) {
10209
+ throw error;
10210
+ }
10211
+ const isReady = !isPending && !!order;
10212
+ return /* @__PURE__ */ jsxs(RouteDrawer, { children: [
10213
+ /* @__PURE__ */ jsxs(RouteDrawer.Header, { children: [
10214
+ /* @__PURE__ */ jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Metadata" }) }),
10215
+ /* @__PURE__ */ jsx(RouteDrawer.Description, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Add metadata to the draft order." }) })
10216
+ ] }),
10217
+ !isReady ? /* @__PURE__ */ jsx(PlaceholderInner, {}) : /* @__PURE__ */ jsx(MetadataForm, { orderId: id, metadata: order == null ? void 0 : order.metadata })
10218
+ ] });
10219
+ };
10220
+ const METADATA_KEY_LABEL_ID = "metadata-form-key-label";
10221
+ const METADATA_VALUE_LABEL_ID = "metadata-form-value-label";
10222
+ const MetadataForm = ({ orderId, metadata }) => {
10223
+ const { handleSuccess } = useRouteModal();
10224
+ const hasUneditableRows = getHasUneditableRows(metadata);
10225
+ const { mutateAsync, isPending } = useUpdateDraftOrder(orderId);
10378
10226
  const form = useForm({
10379
10227
  defaultValues: {
10380
- title,
10381
- quantity,
10382
- unit_price
10228
+ metadata: getDefaultValues(metadata)
10383
10229
  },
10384
- resolver: zodResolver(customItemSchema)
10230
+ resolver: zodResolver(MetadataSchema)
10385
10231
  });
10386
- useEffect(() => {
10387
- form.reset({
10388
- title,
10389
- quantity,
10390
- unit_price
10391
- });
10392
- }, [form, title, quantity, unit_price]);
10393
- const actionId = useMemo(() => {
10394
- var _a, _b;
10395
- return (_b = (_a = item.actions) == null ? void 0 : _a.find((a) => a.action === "ITEM_ADD")) == null ? void 0 : _b.id;
10396
- }, [item]);
10397
- const { mutateAsync: updateActionItem, isPending: isUpdatingActionItem } = useDraftOrderUpdateActionItem(preview.id);
10398
- const { mutateAsync: removeActionItem, isPending: isRemovingActionItem } = useDraftOrderRemoveActionItem(preview.id);
10399
- const { mutateAsync: updateOriginalItem, isPending: isUpdatingOriginalItem } = useDraftOrderUpdateItem(preview.id);
10400
- const isPending = isUpdatingActionItem || isUpdatingOriginalItem;
10401
- const onSubmit = form.handleSubmit(async (data) => {
10402
- if (convertNumber(data.unit_price) === item.unit_price && data.quantity === item.quantity && data.title === item.title) {
10403
- setEditing(false);
10404
- return;
10405
- }
10406
- if (!actionId) {
10407
- await updateOriginalItem(
10408
- {
10409
- item_id: item.id,
10410
- quantity: data.quantity,
10411
- unit_price: convertNumber(data.unit_price)
10412
- },
10413
- {
10414
- onSuccess: () => {
10415
- setEditing(false);
10416
- },
10417
- onError: (e) => {
10418
- toast.error(e.message);
10419
- }
10420
- }
10421
- );
10422
- return;
10423
- }
10424
- if (data.quantity === 0) {
10425
- await removeActionItem(actionId, {
10426
- onSuccess: () => {
10427
- setEditing(false);
10428
- },
10429
- onError: (e) => {
10430
- toast.error(e.message);
10431
- }
10432
- });
10433
- return;
10434
- }
10435
- await updateActionItem(
10232
+ const handleSubmit = form.handleSubmit(async (data) => {
10233
+ const parsedData = parseValues(data);
10234
+ await mutateAsync(
10436
10235
  {
10437
- action_id: actionId,
10438
- quantity: data.quantity,
10439
- unit_price: convertNumber(data.unit_price)
10236
+ metadata: parsedData
10440
10237
  },
10441
10238
  {
10442
10239
  onSuccess: () => {
10443
- setEditing(false);
10240
+ toast.success("Metadata updated");
10241
+ handleSuccess();
10444
10242
  },
10445
- onError: (e) => {
10446
- toast.error(e.message);
10243
+ onError: (error) => {
10244
+ toast.error(error.message);
10447
10245
  }
10448
10246
  }
10449
10247
  );
10450
10248
  });
10451
- return /* @__PURE__ */ jsx(Form$2, { ...form, children: /* @__PURE__ */ jsx("form", { onSubmit, children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-[minmax(0,1fr)_minmax(0,1fr)_minmax(0,1fr)_28px] gap-3 px-4 py-2 bg-ui-bg-base shadow-elevation-card-rest rounded-lg items-center", children: [
10452
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-3", children: [
10453
- /* @__PURE__ */ jsx(
10454
- Thumbnail,
10455
- {
10456
- thumbnail: item.thumbnail,
10457
- alt: item.title ?? void 0
10458
- }
10459
- ),
10460
- editing ? /* @__PURE__ */ jsx(
10461
- Form$2.Field,
10462
- {
10463
- control: form.control,
10464
- name: "title",
10465
- render: ({ field }) => {
10466
- return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(Input, { ...field }) }) });
10467
- }
10468
- }
10469
- ) : /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: item.title })
10470
- ] }),
10471
- editing ? /* @__PURE__ */ jsx(
10472
- Form$2.Field,
10473
- {
10474
- control: form.control,
10475
- name: "quantity",
10476
- render: ({ field }) => {
10477
- return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(NumberInput, { ...field }) }) });
10478
- }
10479
- }
10480
- ) : /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: item.quantity }),
10481
- editing ? /* @__PURE__ */ jsx(
10482
- Form$2.Field,
10483
- {
10484
- control: form.control,
10485
- name: "unit_price",
10486
- render: ({ field: { onChange, ...field } }) => {
10487
- return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
10488
- CurrencyInput,
10489
- {
10490
- ...field,
10491
- symbol: getNativeSymbol(currencyCode),
10492
- code: currencyCode,
10493
- onValueChange: (_value, _name, values) => onChange(values == null ? void 0 : values.value)
10494
- }
10495
- ) }) });
10496
- }
10497
- }
10498
- ) : /* @__PURE__ */ jsx("div", { className: "flex-1 flex items-center justify-end", children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: getLocaleAmount(item.unit_price, currencyCode) }) }),
10499
- /* @__PURE__ */ jsx(
10500
- IconButton,
10501
- {
10502
- type: "button",
10503
- size: "small",
10504
- onClick: editing ? onSubmit : () => {
10505
- setEditing(true);
10506
- },
10507
- disabled: isPending,
10508
- children: editing ? /* @__PURE__ */ jsx(Check, {}) : /* @__PURE__ */ jsx(PencilSquare, {})
10509
- }
10510
- )
10511
- ] }) }) });
10512
- };
10513
- const StackedModalTrigger$1 = ({
10514
- type,
10515
- setModalContent
10516
- }) => {
10517
- const { setIsOpen } = useStackedModal();
10518
- const onClick = useCallback(() => {
10519
- setModalContent(type);
10520
- setIsOpen(STACKED_MODAL_ID, true);
10521
- }, [setModalContent, setIsOpen, type]);
10522
- return /* @__PURE__ */ jsx(StackedFocusModal.Trigger, { asChild: true, children: /* @__PURE__ */ jsx(DropdownMenu.Item, { onClick, children: type === "add-items" ? "Add items" : "Add custom item" }) });
10523
- };
10524
- const VARIANT_PREFIX = "items";
10525
- const LIMIT = 50;
10526
- const ExistingItemsForm = ({ orderId, items }) => {
10527
- const { setIsOpen } = useStackedModal();
10528
- const [rowSelection, setRowSelection] = useState(
10529
- items.reduce((acc, item) => {
10530
- acc[item.variant_id] = true;
10531
- return acc;
10532
- }, {})
10533
- );
10534
- useEffect(() => {
10535
- setRowSelection(
10536
- items.reduce((acc, item) => {
10537
- if (item.variant_id) {
10538
- acc[item.variant_id] = true;
10539
- }
10540
- return acc;
10541
- }, {})
10542
- );
10543
- }, [items]);
10544
- const { q, order, offset } = useQueryParams(
10545
- ["q", "order", "offset"],
10546
- VARIANT_PREFIX
10547
- );
10548
- const { variants, count, isPending, isError, error } = useProductVariants(
10549
- {
10550
- q,
10551
- order,
10552
- offset: offset ? parseInt(offset) : void 0,
10553
- limit: LIMIT
10554
- },
10555
- {
10556
- placeholderData: keepPreviousData
10249
+ const { fields, insert, remove } = useFieldArray({
10250
+ control: form.control,
10251
+ name: "metadata"
10252
+ });
10253
+ function deleteRow(index) {
10254
+ remove(index);
10255
+ if (fields.length === 1) {
10256
+ insert(0, {
10257
+ key: "",
10258
+ value: "",
10259
+ disabled: false
10260
+ });
10557
10261
  }
10558
- );
10559
- const columns = useColumns();
10560
- const { mutateAsync } = useDraftOrderAddItems(orderId);
10561
- const onSubmit = async () => {
10562
- const ids = Object.keys(rowSelection).filter(
10563
- (id) => !items.find((i) => i.variant_id === id)
10564
- );
10565
- await mutateAsync(
10566
- {
10567
- items: ids.map((id) => ({
10568
- variant_id: id,
10569
- quantity: 1
10570
- }))
10571
- },
10572
- {
10573
- onSuccess: () => {
10574
- setRowSelection({});
10575
- setIsOpen(STACKED_MODAL_ID, false);
10576
- },
10577
- onError: (e) => {
10578
- toast.error(e.message);
10579
- }
10580
- }
10581
- );
10582
- };
10583
- if (isError) {
10584
- throw error;
10585
10262
  }
10586
- return /* @__PURE__ */ jsxs(
10587
- StackedFocusModal.Content,
10263
+ function insertRow(index, position) {
10264
+ insert(index + (position === "above" ? 0 : 1), {
10265
+ key: "",
10266
+ value: "",
10267
+ disabled: false
10268
+ });
10269
+ }
10270
+ return /* @__PURE__ */ jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxs(
10271
+ KeyboundForm,
10588
10272
  {
10589
- onOpenAutoFocus: (e) => {
10590
- e.preventDefault();
10591
- const searchInput = document.querySelector(
10592
- "[data-modal-id='modal-search-input']"
10593
- );
10594
- if (searchInput) {
10595
- searchInput.focus();
10596
- }
10597
- },
10273
+ onSubmit: handleSubmit,
10274
+ className: "flex flex-1 flex-col overflow-hidden",
10598
10275
  children: [
10599
- /* @__PURE__ */ jsxs(StackedFocusModal.Header, { children: [
10600
- /* @__PURE__ */ jsx(StackedFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Product Variants" }) }),
10601
- /* @__PURE__ */ jsx(StackedFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Choose product variants to add to the order." }) })
10602
- ] }),
10603
- /* @__PURE__ */ jsx(StackedFocusModal.Body, { className: "flex-1 overflow-hidden", children: /* @__PURE__ */ jsx(
10604
- DataTable,
10605
- {
10606
- data: variants,
10607
- columns,
10608
- isLoading: isPending,
10609
- getRowId: (row) => row.id,
10610
- rowCount: count,
10611
- prefix: VARIANT_PREFIX,
10612
- layout: "fill",
10613
- rowSelection: {
10614
- state: rowSelection,
10615
- onRowSelectionChange: setRowSelection,
10616
- enableRowSelection: (row) => {
10617
- return !items.find((i) => i.variant_id === row.original.id);
10618
- }
10619
- },
10620
- autoFocusSearch: true
10621
- }
10622
- ) }),
10623
- /* @__PURE__ */ jsx(StackedFocusModal.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-2 justify-end", children: [
10624
- /* @__PURE__ */ jsx(StackedFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
10625
- /* @__PURE__ */ jsx(Button, { size: "small", type: "button", onClick: onSubmit, children: "Update items" })
10626
- ] }) })
10627
- ]
10276
+ /* @__PURE__ */ jsxs(RouteDrawer.Body, { className: "flex flex-1 flex-col gap-y-8 overflow-y-auto", children: [
10277
+ /* @__PURE__ */ jsxs("div", { className: "bg-ui-bg-base shadow-elevation-card-rest grid grid-cols-1 divide-y rounded-lg", children: [
10278
+ /* @__PURE__ */ jsxs("div", { className: "bg-ui-bg-subtle grid grid-cols-2 divide-x rounded-t-lg", children: [
10279
+ /* @__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" }) }),
10280
+ /* @__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" }) })
10281
+ ] }),
10282
+ fields.map((field, index) => {
10283
+ const isDisabled = field.disabled || false;
10284
+ let placeholder = "-";
10285
+ if (typeof field.value === "object") {
10286
+ placeholder = "{ ... }";
10287
+ }
10288
+ if (Array.isArray(field.value)) {
10289
+ placeholder = "[ ... ]";
10290
+ }
10291
+ return /* @__PURE__ */ jsx(
10292
+ ConditionalTooltip,
10293
+ {
10294
+ showTooltip: isDisabled,
10295
+ content: "This row is disabled because it contains non-primitive data.",
10296
+ children: /* @__PURE__ */ jsxs("div", { className: "group/table relative", children: [
10297
+ /* @__PURE__ */ jsxs(
10298
+ "div",
10299
+ {
10300
+ className: clx("grid grid-cols-2 divide-x", {
10301
+ "overflow-hidden rounded-b-lg": index === fields.length - 1
10302
+ }),
10303
+ children: [
10304
+ /* @__PURE__ */ jsx(
10305
+ Form$2.Field,
10306
+ {
10307
+ control: form.control,
10308
+ name: `metadata.${index}.key`,
10309
+ render: ({ field: field2 }) => {
10310
+ return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
10311
+ GridInput,
10312
+ {
10313
+ "aria-labelledby": METADATA_KEY_LABEL_ID,
10314
+ ...field2,
10315
+ disabled: isDisabled,
10316
+ placeholder: "Key"
10317
+ }
10318
+ ) }) });
10319
+ }
10320
+ }
10321
+ ),
10322
+ /* @__PURE__ */ jsx(
10323
+ Form$2.Field,
10324
+ {
10325
+ control: form.control,
10326
+ name: `metadata.${index}.value`,
10327
+ render: ({ field: { value, ...field2 } }) => {
10328
+ return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
10329
+ GridInput,
10330
+ {
10331
+ "aria-labelledby": METADATA_VALUE_LABEL_ID,
10332
+ ...field2,
10333
+ value: isDisabled ? placeholder : value,
10334
+ disabled: isDisabled,
10335
+ placeholder: "Value"
10336
+ }
10337
+ ) }) });
10338
+ }
10339
+ }
10340
+ )
10341
+ ]
10342
+ }
10343
+ ),
10344
+ /* @__PURE__ */ jsxs(DropdownMenu, { children: [
10345
+ /* @__PURE__ */ jsx(
10346
+ DropdownMenu.Trigger,
10347
+ {
10348
+ className: clx(
10349
+ "invisible absolute inset-y-0 -right-2.5 my-auto group-hover/table:visible data-[state='open']:visible",
10350
+ {
10351
+ hidden: isDisabled
10352
+ }
10353
+ ),
10354
+ disabled: isDisabled,
10355
+ asChild: true,
10356
+ children: /* @__PURE__ */ jsx(IconButton, { size: "2xsmall", children: /* @__PURE__ */ jsx(EllipsisVertical, {}) })
10357
+ }
10358
+ ),
10359
+ /* @__PURE__ */ jsxs(DropdownMenu.Content, { children: [
10360
+ /* @__PURE__ */ jsxs(
10361
+ DropdownMenu.Item,
10362
+ {
10363
+ className: "gap-x-2",
10364
+ onClick: () => insertRow(index, "above"),
10365
+ children: [
10366
+ /* @__PURE__ */ jsx(ArrowUpMini, { className: "text-ui-fg-subtle" }),
10367
+ "Insert row above"
10368
+ ]
10369
+ }
10370
+ ),
10371
+ /* @__PURE__ */ jsxs(
10372
+ DropdownMenu.Item,
10373
+ {
10374
+ className: "gap-x-2",
10375
+ onClick: () => insertRow(index, "below"),
10376
+ children: [
10377
+ /* @__PURE__ */ jsx(ArrowDownMini, { className: "text-ui-fg-subtle" }),
10378
+ "Insert row below"
10379
+ ]
10380
+ }
10381
+ ),
10382
+ /* @__PURE__ */ jsx(DropdownMenu.Separator, {}),
10383
+ /* @__PURE__ */ jsxs(
10384
+ DropdownMenu.Item,
10385
+ {
10386
+ className: "gap-x-2",
10387
+ onClick: () => deleteRow(index),
10388
+ children: [
10389
+ /* @__PURE__ */ jsx(Trash, { className: "text-ui-fg-subtle" }),
10390
+ "Delete row"
10391
+ ]
10392
+ }
10393
+ )
10394
+ ] })
10395
+ ] })
10396
+ ] })
10397
+ },
10398
+ field.id
10399
+ );
10400
+ })
10401
+ ] }),
10402
+ 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." })
10403
+ ] }),
10404
+ /* @__PURE__ */ jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
10405
+ /* @__PURE__ */ jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
10406
+ /* @__PURE__ */ jsx(Button, { size: "small", type: "submit", isLoading: isPending, children: "Save" })
10407
+ ] }) })
10408
+ ]
10409
+ }
10410
+ ) });
10411
+ };
10412
+ const GridInput = forwardRef(({ className, ...props }, ref) => {
10413
+ return /* @__PURE__ */ jsx(
10414
+ "input",
10415
+ {
10416
+ ref,
10417
+ ...props,
10418
+ autoComplete: "off",
10419
+ className: clx(
10420
+ "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",
10421
+ className
10422
+ )
10628
10423
  }
10629
10424
  );
10425
+ });
10426
+ GridInput.displayName = "MetadataForm.GridInput";
10427
+ const PlaceholderInner = () => {
10428
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col overflow-hidden", children: [
10429
+ /* @__PURE__ */ jsx(RouteDrawer.Body, { children: /* @__PURE__ */ jsx(Skeleton, { className: "h-[148ox] w-full rounded-lg" }) }),
10430
+ /* @__PURE__ */ jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
10431
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-7 w-12 rounded-md" }),
10432
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-7 w-12 rounded-md" })
10433
+ ] }) })
10434
+ ] });
10630
10435
  };
10631
- const columnHelper = createDataTableColumnHelper();
10632
- const useColumns = () => {
10633
- return useMemo(() => {
10436
+ const EDITABLE_TYPES = ["string", "number", "boolean"];
10437
+ function getDefaultValues(metadata) {
10438
+ if (!metadata || !Object.keys(metadata).length) {
10634
10439
  return [
10635
- columnHelper.select(),
10636
- columnHelper.accessor("product.title", {
10637
- header: "Product",
10638
- cell: ({ row }) => {
10639
- var _a, _b, _c;
10640
- return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-2", children: [
10641
- /* @__PURE__ */ jsx(
10642
- Thumbnail,
10643
- {
10644
- thumbnail: (_a = row.original.product) == null ? void 0 : _a.thumbnail,
10645
- alt: (_b = row.original.product) == null ? void 0 : _b.title
10646
- }
10647
- ),
10648
- /* @__PURE__ */ jsx("span", { children: (_c = row.original.product) == null ? void 0 : _c.title })
10649
- ] });
10650
- },
10651
- enableSorting: true
10652
- }),
10653
- columnHelper.accessor("title", {
10654
- header: "Variant",
10655
- enableSorting: true
10656
- }),
10657
- columnHelper.accessor("sku", {
10658
- header: "SKU",
10659
- cell: ({ getValue }) => {
10660
- return getValue() ?? "-";
10661
- },
10662
- enableSorting: true
10663
- }),
10664
- columnHelper.accessor("updated_at", {
10665
- header: "Updated",
10666
- cell: ({ getValue }) => {
10667
- return /* @__PURE__ */ jsx(
10668
- Tooltip,
10669
- {
10670
- content: getFullDate({ date: getValue(), includeTime: true }),
10671
- children: /* @__PURE__ */ jsx("span", { children: getFullDate({ date: getValue() }) })
10672
- }
10673
- );
10674
- },
10675
- enableSorting: true,
10676
- sortAscLabel: "Oldest first",
10677
- sortDescLabel: "Newest first"
10678
- }),
10679
- columnHelper.accessor("created_at", {
10680
- header: "Created",
10681
- cell: ({ getValue }) => {
10682
- return /* @__PURE__ */ jsx(
10683
- Tooltip,
10684
- {
10685
- content: getFullDate({ date: getValue(), includeTime: true }),
10686
- children: /* @__PURE__ */ jsx("span", { children: getFullDate({ date: getValue() }) })
10687
- }
10688
- );
10689
- },
10690
- enableSorting: true,
10691
- sortAscLabel: "Oldest first",
10692
- sortDescLabel: "Newest first"
10693
- })
10694
- ];
10695
- }, []);
10696
- };
10697
- const CustomItemForm = ({ orderId, currencyCode }) => {
10698
- const { setIsOpen } = useStackedModal();
10699
- const { mutateAsync: addItems } = useDraftOrderAddItems(orderId);
10700
- const form = useForm({
10701
- defaultValues: {
10702
- title: "",
10703
- quantity: 1,
10704
- unit_price: ""
10705
- },
10706
- resolver: zodResolver(customItemSchema)
10707
- });
10708
- const onSubmit = form.handleSubmit(async (data) => {
10709
- await addItems(
10710
- {
10711
- items: [
10712
- {
10713
- title: data.title,
10714
- quantity: data.quantity,
10715
- unit_price: convertNumber(data.unit_price)
10716
- }
10717
- ]
10718
- },
10719
10440
  {
10720
- onSuccess: () => {
10721
- setIsOpen(STACKED_MODAL_ID, false);
10722
- },
10723
- onError: (e) => {
10724
- toast.error(e.message);
10725
- }
10441
+ key: "",
10442
+ value: "",
10443
+ disabled: false
10726
10444
  }
10727
- );
10445
+ ];
10446
+ }
10447
+ return Object.entries(metadata).map(([key, value]) => {
10448
+ if (!EDITABLE_TYPES.includes(typeof value)) {
10449
+ return {
10450
+ key,
10451
+ value,
10452
+ disabled: true
10453
+ };
10454
+ }
10455
+ let stringValue = value;
10456
+ if (typeof value !== "string") {
10457
+ stringValue = JSON.stringify(value);
10458
+ }
10459
+ return {
10460
+ key,
10461
+ value: stringValue,
10462
+ original_key: key
10463
+ };
10728
10464
  });
10729
- return /* @__PURE__ */ jsx(Form$2, { ...form, children: /* @__PURE__ */ jsx(KeyboundForm, { onSubmit, children: /* @__PURE__ */ jsxs(StackedFocusModal.Content, { children: [
10730
- /* @__PURE__ */ jsx(StackedFocusModal.Header, {}),
10731
- /* @__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: [
10732
- /* @__PURE__ */ jsxs("div", { children: [
10733
- /* @__PURE__ */ jsx(StackedFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Add custom item" }) }),
10734
- /* @__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." }) })
10735
- ] }),
10736
- /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
10737
- /* @__PURE__ */ jsx(
10738
- Form$2.Field,
10739
- {
10740
- control: form.control,
10741
- name: "title",
10742
- render: ({ field }) => /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
10743
- /* @__PURE__ */ jsxs("div", { children: [
10744
- /* @__PURE__ */ jsx(Form$2.Label, { children: "Title" }),
10745
- /* @__PURE__ */ jsx(Form$2.Hint, { children: "Enter the title of the item" })
10746
- ] }),
10747
- /* @__PURE__ */ jsxs("div", { children: [
10748
- /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(Input, { ...field }) }),
10749
- /* @__PURE__ */ jsx(Form$2.ErrorMessage, {})
10750
- ] })
10751
- ] }) })
10752
- }
10753
- ),
10754
- /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
10755
- /* @__PURE__ */ jsx(
10756
- Form$2.Field,
10757
- {
10758
- control: form.control,
10759
- name: "unit_price",
10760
- render: ({ field: { onChange, ...field } }) => /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
10761
- /* @__PURE__ */ jsxs("div", { children: [
10762
- /* @__PURE__ */ jsx(Form$2.Label, { children: "Unit price" }),
10763
- /* @__PURE__ */ jsx(Form$2.Hint, { children: "Enter the unit price of the item" })
10764
- ] }),
10765
- /* @__PURE__ */ jsxs("div", { children: [
10766
- /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
10767
- CurrencyInput,
10768
- {
10769
- symbol: getNativeSymbol(currencyCode),
10770
- code: currencyCode,
10771
- onValueChange: (_value, _name, values) => onChange(values == null ? void 0 : values.value),
10772
- ...field
10773
- }
10774
- ) }),
10775
- /* @__PURE__ */ jsx(Form$2.ErrorMessage, {})
10776
- ] })
10777
- ] }) })
10778
- }
10779
- ),
10780
- /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
10781
- /* @__PURE__ */ jsx(
10782
- Form$2.Field,
10783
- {
10784
- control: form.control,
10785
- name: "quantity",
10786
- render: ({ field }) => /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
10787
- /* @__PURE__ */ jsxs("div", { children: [
10788
- /* @__PURE__ */ jsx(Form$2.Label, { children: "Quantity" }),
10789
- /* @__PURE__ */ jsx(Form$2.Hint, { children: "Enter the quantity of the item" })
10790
- ] }),
10791
- /* @__PURE__ */ jsxs("div", { className: "flex-1 w-full", children: [
10792
- /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx("div", { className: "flex-1 w-full", children: /* @__PURE__ */ jsx(NumberInput, { ...field, className: "w-full" }) }) }),
10793
- /* @__PURE__ */ jsx(Form$2.ErrorMessage, {})
10794
- ] })
10795
- ] }) })
10796
- }
10797
- )
10798
- ] }) }) }),
10799
- /* @__PURE__ */ jsx(StackedFocusModal.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-2 justify-end", children: [
10800
- /* @__PURE__ */ jsx(StackedFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
10801
- /* @__PURE__ */ jsx(Button, { size: "small", type: "button", onClick: onSubmit, children: "Add item" })
10802
- ] }) })
10803
- ] }) }) });
10804
- };
10805
- const customItemSchema = objectType({
10806
- title: stringType().min(1),
10807
- quantity: numberType(),
10808
- unit_price: unionType([numberType(), stringType()])
10809
- });
10810
- const InlineTip = forwardRef(
10811
- ({ variant = "tip", label, className, children, ...props }, ref) => {
10812
- const labelValue = label || (variant === "warning" ? "Warning" : "Tip");
10813
- return /* @__PURE__ */ jsxs(
10814
- "div",
10815
- {
10816
- ref,
10817
- className: clx(
10818
- "bg-ui-bg-component txt-small text-ui-fg-subtle grid grid-cols-[4px_1fr] items-start gap-3 rounded-lg border p-3",
10819
- className
10820
- ),
10821
- ...props,
10822
- children: [
10823
- /* @__PURE__ */ jsx(
10824
- "div",
10825
- {
10826
- role: "presentation",
10827
- className: clx("w-4px bg-ui-tag-neutral-icon h-full rounded-full", {
10828
- "bg-ui-tag-orange-icon": variant === "warning"
10829
- })
10830
- }
10831
- ),
10832
- /* @__PURE__ */ jsxs("div", { className: "text-pretty", children: [
10833
- /* @__PURE__ */ jsxs("strong", { className: "txt-small-plus text-ui-fg-base", children: [
10834
- labelValue,
10835
- ":"
10836
- ] }),
10837
- " ",
10838
- children
10839
- ] })
10840
- ]
10465
+ }
10466
+ function parseValues(values) {
10467
+ const metadata = values.metadata;
10468
+ const isEmpty = !metadata.length || metadata.length === 1 && !metadata[0].key && !metadata[0].value;
10469
+ if (isEmpty) {
10470
+ return null;
10471
+ }
10472
+ const update = {};
10473
+ metadata.forEach((field) => {
10474
+ let key = field.key;
10475
+ let value = field.value;
10476
+ const disabled = field.disabled;
10477
+ if (!key || !value) {
10478
+ return;
10479
+ }
10480
+ if (disabled) {
10481
+ update[key] = value;
10482
+ return;
10483
+ }
10484
+ key = key.trim();
10485
+ value = value.trim();
10486
+ if (value === "true") {
10487
+ update[key] = true;
10488
+ } else if (value === "false") {
10489
+ update[key] = false;
10490
+ } else {
10491
+ const parsedNumber = parseFloat(value);
10492
+ if (!isNaN(parsedNumber)) {
10493
+ update[key] = parsedNumber;
10494
+ } else {
10495
+ update[key] = value;
10841
10496
  }
10842
- );
10497
+ }
10498
+ });
10499
+ return update;
10500
+ }
10501
+ function getHasUneditableRows(metadata) {
10502
+ if (!metadata) {
10503
+ return false;
10843
10504
  }
10844
- );
10845
- InlineTip.displayName = "InlineTip";
10846
- const MetadataFieldSchema = objectType({
10847
- key: stringType(),
10848
- disabled: booleanType().optional(),
10849
- value: anyType()
10850
- });
10851
- const MetadataSchema = objectType({
10852
- metadata: arrayType(MetadataFieldSchema)
10853
- });
10854
- const Metadata = () => {
10505
+ return Object.values(metadata).some(
10506
+ (value) => !EDITABLE_TYPES.includes(typeof value)
10507
+ );
10508
+ }
10509
+ const SalesChannel = () => {
10855
10510
  const { id } = useParams();
10856
- const { order, isPending, isError, error } = useOrder(id, {
10857
- fields: "metadata"
10858
- });
10511
+ const { draft_order, isPending, isError, error } = useDraftOrder(
10512
+ id,
10513
+ {
10514
+ fields: "+sales_channel_id"
10515
+ },
10516
+ {
10517
+ enabled: !!id
10518
+ }
10519
+ );
10859
10520
  if (isError) {
10860
10521
  throw error;
10861
10522
  }
10862
- const isReady = !isPending && !!order;
10523
+ const ISrEADY = !!draft_order && !isPending;
10863
10524
  return /* @__PURE__ */ jsxs(RouteDrawer, { children: [
10864
10525
  /* @__PURE__ */ jsxs(RouteDrawer.Header, { children: [
10865
- /* @__PURE__ */ jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Metadata" }) }),
10866
- /* @__PURE__ */ jsx(RouteDrawer.Description, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Add metadata to the draft order." }) })
10526
+ /* @__PURE__ */ jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Edit Sales Channel" }) }),
10527
+ /* @__PURE__ */ jsx(RouteDrawer.Description, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Update which sales channel the draft order is associated with" }) })
10867
10528
  ] }),
10868
- !isReady ? /* @__PURE__ */ jsx(PlaceholderInner, {}) : /* @__PURE__ */ jsx(MetadataForm, { orderId: id, metadata: order == null ? void 0 : order.metadata })
10529
+ ISrEADY && /* @__PURE__ */ jsx(SalesChannelForm, { order: draft_order })
10869
10530
  ] });
10870
10531
  };
10871
- const METADATA_KEY_LABEL_ID = "metadata-form-key-label";
10872
- const METADATA_VALUE_LABEL_ID = "metadata-form-value-label";
10873
- const MetadataForm = ({ orderId, metadata }) => {
10874
- const { handleSuccess } = useRouteModal();
10875
- const hasUneditableRows = getHasUneditableRows(metadata);
10876
- const { mutateAsync, isPending } = useUpdateDraftOrder(orderId);
10532
+ const SalesChannelForm = ({ order }) => {
10877
10533
  const form = useForm({
10878
10534
  defaultValues: {
10879
- metadata: getDefaultValues(metadata)
10535
+ sales_channel_id: order.sales_channel_id || ""
10880
10536
  },
10881
- resolver: zodResolver(MetadataSchema)
10537
+ resolver: zodResolver(schema$2)
10882
10538
  });
10883
- const handleSubmit = form.handleSubmit(async (data) => {
10884
- const parsedData = parseValues(data);
10539
+ const { mutateAsync, isPending } = useUpdateDraftOrder(order.id);
10540
+ const { handleSuccess } = useRouteModal();
10541
+ const onSubmit = form.handleSubmit(async (data) => {
10885
10542
  await mutateAsync(
10886
10543
  {
10887
- metadata: parsedData
10544
+ sales_channel_id: data.sales_channel_id
10888
10545
  },
10889
10546
  {
10890
10547
  onSuccess: () => {
10891
- toast.success("Metadata updated");
10548
+ toast.success("Sales channel updated");
10892
10549
  handleSuccess();
10893
10550
  },
10894
10551
  onError: (error) => {
@@ -10897,365 +10554,138 @@ const MetadataForm = ({ orderId, metadata }) => {
10897
10554
  }
10898
10555
  );
10899
10556
  });
10900
- const { fields, insert, remove } = useFieldArray({
10901
- control: form.control,
10902
- name: "metadata"
10903
- });
10904
- function deleteRow(index) {
10905
- remove(index);
10906
- if (fields.length === 1) {
10907
- insert(0, {
10908
- key: "",
10909
- value: "",
10910
- disabled: false
10911
- });
10912
- }
10913
- }
10914
- function insertRow(index, position) {
10915
- insert(index + (position === "above" ? 0 : 1), {
10916
- key: "",
10917
- value: "",
10918
- disabled: false
10919
- });
10920
- }
10921
10557
  return /* @__PURE__ */ jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxs(
10922
10558
  KeyboundForm,
10923
10559
  {
10924
- onSubmit: handleSubmit,
10925
10560
  className: "flex flex-1 flex-col overflow-hidden",
10561
+ onSubmit,
10926
10562
  children: [
10927
- /* @__PURE__ */ jsxs(RouteDrawer.Body, { className: "flex flex-1 flex-col gap-y-8 overflow-y-auto", children: [
10928
- /* @__PURE__ */ jsxs("div", { className: "bg-ui-bg-base shadow-elevation-card-rest grid grid-cols-1 divide-y rounded-lg", children: [
10929
- /* @__PURE__ */ jsxs("div", { className: "bg-ui-bg-subtle grid grid-cols-2 divide-x rounded-t-lg", children: [
10930
- /* @__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" }) }),
10931
- /* @__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" }) })
10932
- ] }),
10933
- fields.map((field, index) => {
10934
- const isDisabled = field.disabled || false;
10935
- let placeholder = "-";
10936
- if (typeof field.value === "object") {
10937
- placeholder = "{ ... }";
10938
- }
10939
- if (Array.isArray(field.value)) {
10940
- placeholder = "[ ... ]";
10941
- }
10942
- return /* @__PURE__ */ jsx(
10943
- ConditionalTooltip,
10944
- {
10945
- showTooltip: isDisabled,
10946
- content: "This row is disabled because it contains non-primitive data.",
10947
- children: /* @__PURE__ */ jsxs("div", { className: "group/table relative", children: [
10948
- /* @__PURE__ */ jsxs(
10949
- "div",
10950
- {
10951
- className: clx("grid grid-cols-2 divide-x", {
10952
- "overflow-hidden rounded-b-lg": index === fields.length - 1
10953
- }),
10954
- children: [
10955
- /* @__PURE__ */ jsx(
10956
- Form$2.Field,
10957
- {
10958
- control: form.control,
10959
- name: `metadata.${index}.key`,
10960
- render: ({ field: field2 }) => {
10961
- return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
10962
- GridInput,
10963
- {
10964
- "aria-labelledby": METADATA_KEY_LABEL_ID,
10965
- ...field2,
10966
- disabled: isDisabled,
10967
- placeholder: "Key"
10968
- }
10969
- ) }) });
10970
- }
10971
- }
10972
- ),
10973
- /* @__PURE__ */ jsx(
10974
- Form$2.Field,
10975
- {
10976
- control: form.control,
10977
- name: `metadata.${index}.value`,
10978
- render: ({ field: { value, ...field2 } }) => {
10979
- return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
10980
- GridInput,
10981
- {
10982
- "aria-labelledby": METADATA_VALUE_LABEL_ID,
10983
- ...field2,
10984
- value: isDisabled ? placeholder : value,
10985
- disabled: isDisabled,
10986
- placeholder: "Value"
10987
- }
10988
- ) }) });
10989
- }
10990
- }
10991
- )
10992
- ]
10993
- }
10994
- ),
10995
- /* @__PURE__ */ jsxs(DropdownMenu, { children: [
10996
- /* @__PURE__ */ jsx(
10997
- DropdownMenu.Trigger,
10998
- {
10999
- className: clx(
11000
- "invisible absolute inset-y-0 -right-2.5 my-auto group-hover/table:visible data-[state='open']:visible",
11001
- {
11002
- hidden: isDisabled
11003
- }
11004
- ),
11005
- disabled: isDisabled,
11006
- asChild: true,
11007
- children: /* @__PURE__ */ jsx(IconButton, { size: "2xsmall", children: /* @__PURE__ */ jsx(EllipsisVertical, {}) })
11008
- }
11009
- ),
11010
- /* @__PURE__ */ jsxs(DropdownMenu.Content, { children: [
11011
- /* @__PURE__ */ jsxs(
11012
- DropdownMenu.Item,
11013
- {
11014
- className: "gap-x-2",
11015
- onClick: () => insertRow(index, "above"),
11016
- children: [
11017
- /* @__PURE__ */ jsx(ArrowUpMini, { className: "text-ui-fg-subtle" }),
11018
- "Insert row above"
11019
- ]
11020
- }
11021
- ),
11022
- /* @__PURE__ */ jsxs(
11023
- DropdownMenu.Item,
11024
- {
11025
- className: "gap-x-2",
11026
- onClick: () => insertRow(index, "below"),
11027
- children: [
11028
- /* @__PURE__ */ jsx(ArrowDownMini, { className: "text-ui-fg-subtle" }),
11029
- "Insert row below"
11030
- ]
11031
- }
11032
- ),
11033
- /* @__PURE__ */ jsx(DropdownMenu.Separator, {}),
11034
- /* @__PURE__ */ jsxs(
11035
- DropdownMenu.Item,
11036
- {
11037
- className: "gap-x-2",
11038
- onClick: () => deleteRow(index),
11039
- children: [
11040
- /* @__PURE__ */ jsx(Trash, { className: "text-ui-fg-subtle" }),
11041
- "Delete row"
11042
- ]
11043
- }
11044
- )
11045
- ] })
11046
- ] })
11047
- ] })
11048
- },
11049
- field.id
11050
- );
11051
- })
11052
- ] }),
11053
- 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." })
11054
- ] }),
11055
- /* @__PURE__ */ jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
11056
- /* @__PURE__ */ jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
10563
+ /* @__PURE__ */ jsx(RouteDrawer.Body, { className: "flex flex-col gap-y-6 overflow-y-auto", children: /* @__PURE__ */ jsx(SalesChannelField, { control: form.control, order }) }),
10564
+ /* @__PURE__ */ jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
10565
+ /* @__PURE__ */ jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
11057
10566
  /* @__PURE__ */ jsx(Button, { size: "small", type: "submit", isLoading: isPending, children: "Save" })
11058
10567
  ] }) })
11059
10568
  ]
11060
10569
  }
11061
10570
  ) });
11062
10571
  };
11063
- const GridInput = forwardRef(({ className, ...props }, ref) => {
10572
+ const SalesChannelField = ({ control, order }) => {
10573
+ const salesChannels = useComboboxData({
10574
+ queryFn: async (params) => {
10575
+ return await sdk.admin.salesChannel.list(params);
10576
+ },
10577
+ queryKey: ["sales-channels"],
10578
+ getOptions: (data) => {
10579
+ return data.sales_channels.map((salesChannel) => ({
10580
+ label: salesChannel.name,
10581
+ value: salesChannel.id
10582
+ }));
10583
+ },
10584
+ defaultValue: order.sales_channel_id || void 0
10585
+ });
11064
10586
  return /* @__PURE__ */ jsx(
11065
- "input",
10587
+ Form$2.Field,
11066
10588
  {
11067
- ref,
11068
- ...props,
11069
- autoComplete: "off",
11070
- className: clx(
11071
- "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",
11072
- className
11073
- )
10589
+ control,
10590
+ name: "sales_channel_id",
10591
+ render: ({ field }) => {
10592
+ return /* @__PURE__ */ jsxs(Form$2.Item, { children: [
10593
+ /* @__PURE__ */ jsx(Form$2.Label, { children: "Sales Channel" }),
10594
+ /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
10595
+ Combobox,
10596
+ {
10597
+ options: salesChannels.options,
10598
+ fetchNextPage: salesChannels.fetchNextPage,
10599
+ isFetchingNextPage: salesChannels.isFetchingNextPage,
10600
+ searchValue: salesChannels.searchValue,
10601
+ onSearchValueChange: salesChannels.onSearchValueChange,
10602
+ placeholder: "Select sales channel",
10603
+ ...field
10604
+ }
10605
+ ) }),
10606
+ /* @__PURE__ */ jsx(Form$2.ErrorMessage, {})
10607
+ ] });
10608
+ }
11074
10609
  }
11075
10610
  );
11076
- });
11077
- GridInput.displayName = "MetadataForm.GridInput";
11078
- const PlaceholderInner = () => {
11079
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col overflow-hidden", children: [
11080
- /* @__PURE__ */ jsx(RouteDrawer.Body, { children: /* @__PURE__ */ jsx(Skeleton, { className: "h-[148ox] w-full rounded-lg" }) }),
11081
- /* @__PURE__ */ jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
11082
- /* @__PURE__ */ jsx(Skeleton, { className: "h-7 w-12 rounded-md" }),
11083
- /* @__PURE__ */ jsx(Skeleton, { className: "h-7 w-12 rounded-md" })
11084
- ] }) })
11085
- ] });
11086
10611
  };
11087
- const EDITABLE_TYPES = ["string", "number", "boolean"];
11088
- function getDefaultValues(metadata) {
11089
- if (!metadata || !Object.keys(metadata).length) {
11090
- return [
11091
- {
11092
- key: "",
11093
- value: "",
11094
- disabled: false
11095
- }
11096
- ];
11097
- }
11098
- return Object.entries(metadata).map(([key, value]) => {
11099
- if (!EDITABLE_TYPES.includes(typeof value)) {
11100
- return {
11101
- key,
11102
- value,
11103
- disabled: true
11104
- };
11105
- }
11106
- let stringValue = value;
11107
- if (typeof value !== "string") {
11108
- stringValue = JSON.stringify(value);
11109
- }
11110
- return {
11111
- key,
11112
- value: stringValue,
11113
- original_key: key
11114
- };
11115
- });
10612
+ const schema$2 = objectType({
10613
+ sales_channel_id: stringType().min(1)
10614
+ });
10615
+ function convertNumber(value) {
10616
+ return typeof value === "string" ? Number(value.replace(",", ".")) : value;
11116
10617
  }
11117
- function parseValues(values) {
11118
- const metadata = values.metadata;
11119
- const isEmpty = !metadata.length || metadata.length === 1 && !metadata[0].key && !metadata[0].value;
11120
- if (isEmpty) {
11121
- return null;
11122
- }
11123
- const update = {};
11124
- metadata.forEach((field) => {
11125
- let key = field.key;
11126
- let value = field.value;
11127
- const disabled = field.disabled;
11128
- if (!key || !value) {
11129
- return;
11130
- }
11131
- if (disabled) {
11132
- update[key] = value;
11133
- return;
11134
- }
11135
- key = key.trim();
11136
- value = value.trim();
11137
- if (value === "true") {
11138
- update[key] = true;
11139
- } else if (value === "false") {
11140
- update[key] = false;
11141
- } else {
11142
- const parsedNumber = parseFloat(value);
11143
- if (!isNaN(parsedNumber)) {
11144
- update[key] = parsedNumber;
11145
- } else {
11146
- update[key] = value;
11147
- }
11148
- }
10618
+ const STACKED_FOCUS_MODAL_ID = "shipping-form";
10619
+ const Shipping = () => {
10620
+ var _a;
10621
+ const { id } = useParams();
10622
+ const { order, isPending, isError, error } = useOrder(id, {
10623
+ fields: "+items.*,+items.variant.*,+items.variant.product.*,+items.variant.product.shipping_profile.*,+currency_code"
11149
10624
  });
11150
- return update;
11151
- }
11152
- function getHasUneditableRows(metadata) {
11153
- if (!metadata) {
11154
- return false;
11155
- }
11156
- return Object.values(metadata).some(
11157
- (value) => !EDITABLE_TYPES.includes(typeof value)
11158
- );
11159
- }
11160
- const PROMOTION_QUERY_KEY = "promotions";
11161
- const promotionsQueryKeys = {
11162
- list: (query2) => [
11163
- PROMOTION_QUERY_KEY,
11164
- query2 ? query2 : void 0
11165
- ],
11166
- detail: (id, query2) => [
11167
- PROMOTION_QUERY_KEY,
11168
- id,
11169
- query2 ? query2 : void 0
11170
- ]
11171
- };
11172
- const usePromotions = (query2, options) => {
11173
- const { data, ...rest } = useQuery({
11174
- queryKey: promotionsQueryKeys.list(query2),
11175
- queryFn: async () => sdk.admin.promotion.list(query2),
11176
- ...options
11177
- });
11178
- return { ...data, ...rest };
11179
- };
11180
- const Promotions = () => {
11181
- const { id } = useParams();
11182
10625
  const {
11183
10626
  order: preview,
10627
+ isPending: isPreviewPending,
11184
10628
  isError: isPreviewError,
11185
10629
  error: previewError
11186
- } = useOrderPreview(id, void 0);
10630
+ } = useOrderPreview(id);
11187
10631
  useInitiateOrderEdit({ preview });
11188
10632
  const { onCancel } = useCancelOrderEdit({ preview });
10633
+ if (isError) {
10634
+ throw error;
10635
+ }
11189
10636
  if (isPreviewError) {
11190
10637
  throw previewError;
11191
10638
  }
11192
- const isReady = !!preview;
11193
- return /* @__PURE__ */ jsxs(RouteDrawer, { onClose: onCancel, children: [
11194
- /* @__PURE__ */ jsx(RouteDrawer.Header, { children: /* @__PURE__ */ jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Edit Promotions" }) }) }),
11195
- isReady && /* @__PURE__ */ jsx(PromotionForm, { preview })
11196
- ] });
10639
+ const orderHasItems = (((_a = order == null ? void 0 : order.items) == null ? void 0 : _a.length) || 0) > 0;
10640
+ const isReady = preview && !isPreviewPending && order && !isPending;
10641
+ return /* @__PURE__ */ jsx(RouteFocusModal, { onClose: onCancel, children: !orderHasItems ? /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-col overflow-hidden ", children: [
10642
+ /* @__PURE__ */ jsx(RouteFocusModal.Header, {}),
10643
+ /* @__PURE__ */ jsx(RouteFocusModal.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 py-16 px-6", children: [
10644
+ /* @__PURE__ */ jsx(RouteFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Shipping" }) }),
10645
+ /* @__PURE__ */ jsx(RouteFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "This draft order currently has no items. Add items to the order before adding shipping." }) })
10646
+ ] }) }) }),
10647
+ /* @__PURE__ */ jsx(RouteFocusModal.Footer, { children: /* @__PURE__ */ jsx(RouteFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }) })
10648
+ ] }) : isReady ? /* @__PURE__ */ jsx(ShippingForm, { preview, order }) : /* @__PURE__ */ jsxs("div", { children: [
10649
+ /* @__PURE__ */ jsx(RouteFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Edit Shipping" }) }),
10650
+ /* @__PURE__ */ jsx(RouteFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Loading data for the draft order, please wait..." }) })
10651
+ ] }) });
11197
10652
  };
11198
- const PromotionForm = ({ preview }) => {
11199
- const { items, shipping_methods } = preview;
10653
+ const ShippingForm = ({ preview, order }) => {
10654
+ var _a;
10655
+ const { setIsOpen } = useStackedModal();
11200
10656
  const [isSubmitting, setIsSubmitting] = useState(false);
11201
- const [comboboxValue, setComboboxValue] = useState("");
11202
- const { handleSuccess } = useRouteModal();
11203
- const { mutateAsync: addPromotions, isPending: isAddingPromotions } = useDraftOrderAddPromotions(preview.id);
11204
- const promoCodes = getPromotionCodes(items, shipping_methods);
11205
- const { promotions, isPending, isError, error } = usePromotions(
10657
+ const [data, setData] = useState(null);
10658
+ const appliedShippingOptionIds = (_a = preview.shipping_methods) == null ? void 0 : _a.map((method) => method.shipping_option_id).filter(Boolean);
10659
+ const { shipping_options } = useShippingOptions(
11206
10660
  {
11207
- code: promoCodes
10661
+ id: appliedShippingOptionIds,
10662
+ fields: "+service_zone.*,+service_zone.fulfillment_set.*,+service_zone.fulfillment_set.location.*"
11208
10663
  },
11209
10664
  {
11210
- enabled: !!promoCodes.length
10665
+ enabled: appliedShippingOptionIds.length > 0
11211
10666
  }
11212
10667
  );
11213
- const comboboxData = useComboboxData({
11214
- queryKey: ["promotions", "combobox", promoCodes],
11215
- queryFn: async (params) => {
11216
- return await sdk.admin.promotion.list({
11217
- ...params,
11218
- code: {
11219
- $nin: promoCodes
11220
- }
11221
- });
11222
- },
11223
- getOptions: (data) => {
11224
- return data.promotions.map((promotion) => ({
11225
- label: promotion.code,
11226
- value: promotion.code
11227
- }));
11228
- }
11229
- });
11230
- const add = async (value) => {
11231
- if (!value) {
11232
- return;
11233
- }
11234
- addPromotions(
11235
- {
11236
- promo_codes: [value]
11237
- },
11238
- {
11239
- onError: (e) => {
11240
- toast.error(e.message);
11241
- comboboxData.onSearchValueChange("");
11242
- setComboboxValue("");
11243
- },
11244
- onSuccess: () => {
11245
- comboboxData.onSearchValueChange("");
11246
- setComboboxValue("");
11247
- }
11248
- }
11249
- );
11250
- };
10668
+ const uniqueShippingProfiles = useMemo(() => {
10669
+ const profiles = /* @__PURE__ */ new Map();
10670
+ getUniqueShippingProfiles(order.items).forEach((profile) => {
10671
+ profiles.set(profile.id, profile);
10672
+ });
10673
+ shipping_options == null ? void 0 : shipping_options.forEach((option) => {
10674
+ profiles.set(option.shipping_profile_id, option.shipping_profile);
10675
+ });
10676
+ return Array.from(profiles.values());
10677
+ }, [order.items, shipping_options]);
10678
+ const { handleSuccess } = useRouteModal();
11251
10679
  const { mutateAsync: confirmOrderEdit } = useDraftOrderConfirmEdit(preview.id);
11252
- const { mutateAsync: requestOrderEdit } = useOrderEditRequest(preview.id);
10680
+ const { mutateAsync: requestOrderEdit } = useDraftOrderRequestEdit(preview.id);
10681
+ const { mutateAsync: removeShippingMethod } = useDraftOrderRemoveShippingMethod(preview.id);
10682
+ const { mutateAsync: removeActionShippingMethod } = useDraftOrderRemoveActionShippingMethod(preview.id);
11253
10683
  const onSubmit = async () => {
11254
10684
  setIsSubmitting(true);
11255
10685
  let requestSucceeded = false;
11256
10686
  await requestOrderEdit(void 0, {
11257
10687
  onError: (e) => {
11258
- toast.error(e.message);
10688
+ toast.error(`Failed to request order edit: ${e.message}`);
11259
10689
  },
11260
10690
  onSuccess: () => {
11261
10691
  requestSucceeded = true;
@@ -11267,7 +10697,7 @@ const PromotionForm = ({ preview }) => {
11267
10697
  }
11268
10698
  await confirmOrderEdit(void 0, {
11269
10699
  onError: (e) => {
11270
- toast.error(e.message);
10700
+ toast.error(`Failed to confirm order edit: ${e.message}`);
11271
10701
  },
11272
10702
  onSuccess: () => {
11273
10703
  handleSuccess();
@@ -11277,371 +10707,16 @@ const PromotionForm = ({ preview }) => {
11277
10707
  }
11278
10708
  });
11279
10709
  };
11280
- if (isError) {
11281
- throw error;
11282
- }
11283
- return /* @__PURE__ */ jsxs(KeyboundForm, { className: "flex flex-1 flex-col", onSubmit, children: [
11284
- /* @__PURE__ */ jsx(RouteDrawer.Body, { children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
11285
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
11286
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
11287
- /* @__PURE__ */ jsx(Label$1, { size: "small", weight: "plus", htmlFor: "promotion-combobox", children: "Apply promotions" }),
11288
- /* @__PURE__ */ jsx(Hint$1, { id: "promotion-combobox-hint", children: "Manage promotions that should be applied to the order." })
11289
- ] }),
11290
- /* @__PURE__ */ jsx(
11291
- Combobox,
11292
- {
11293
- id: "promotion-combobox",
11294
- "aria-describedby": "promotion-combobox-hint",
11295
- isFetchingNextPage: comboboxData.isFetchingNextPage,
11296
- fetchNextPage: comboboxData.fetchNextPage,
11297
- options: comboboxData.options,
11298
- onSearchValueChange: comboboxData.onSearchValueChange,
11299
- searchValue: comboboxData.searchValue,
11300
- disabled: comboboxData.disabled || isAddingPromotions,
11301
- onChange: add,
11302
- value: comboboxValue
11303
- }
11304
- )
11305
- ] }),
11306
- /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
11307
- /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-2", children: promotions == null ? void 0 : promotions.map((promotion) => /* @__PURE__ */ jsx(
11308
- PromotionItem,
11309
- {
11310
- promotion,
11311
- orderId: preview.id,
11312
- isLoading: isPending
11313
- },
11314
- promotion.id
11315
- )) })
11316
- ] }) }),
11317
- /* @__PURE__ */ jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
11318
- /* @__PURE__ */ jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
11319
- /* @__PURE__ */ jsx(
11320
- Button,
11321
- {
11322
- size: "small",
11323
- type: "submit",
11324
- isLoading: isSubmitting || isAddingPromotions,
11325
- children: "Save"
11326
- }
11327
- )
11328
- ] }) })
11329
- ] });
11330
- };
11331
- const PromotionItem = ({
11332
- promotion,
11333
- orderId,
11334
- isLoading
11335
- }) => {
11336
- var _a;
11337
- const { mutateAsync: removePromotions, isPending } = useDraftOrderRemovePromotions(orderId);
11338
- const onRemove = async () => {
11339
- removePromotions(
11340
- {
11341
- promo_codes: [promotion.code]
11342
- },
11343
- {
11344
- onError: (e) => {
11345
- toast.error(e.message);
10710
+ const onKeydown = useCallback(
10711
+ (e) => {
10712
+ if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) {
10713
+ if (data || isSubmitting) {
10714
+ return;
11346
10715
  }
10716
+ onSubmit();
11347
10717
  }
11348
- );
11349
- };
11350
- const displayValue = getDisplayValue(promotion);
11351
- return /* @__PURE__ */ jsxs(
11352
- "div",
11353
- {
11354
- className: clx(
11355
- "px-3 py-2 rounded-lg bg-ui-bg-component shadow-elevation-card-rest flex items-center justify-between",
11356
- {
11357
- "animate-pulse": isLoading
11358
- }
11359
- ),
11360
- children: [
11361
- /* @__PURE__ */ jsxs("div", { children: [
11362
- /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: promotion.code }),
11363
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 text-ui-fg-subtle", children: [
11364
- displayValue && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
11365
- /* @__PURE__ */ jsx(Text, { size: "small", leading: "compact", children: displayValue }),
11366
- /* @__PURE__ */ jsx(Text, { size: "small", leading: "compact", children: "·" })
11367
- ] }),
11368
- /* @__PURE__ */ jsx(Text, { size: "small", leading: "compact", className: "capitalize", children: (_a = promotion.application_method) == null ? void 0 : _a.allocation })
11369
- ] })
11370
- ] }),
11371
- /* @__PURE__ */ jsx(
11372
- IconButton,
11373
- {
11374
- size: "small",
11375
- type: "button",
11376
- variant: "transparent",
11377
- onClick: onRemove,
11378
- isLoading: isPending || isLoading,
11379
- children: /* @__PURE__ */ jsx(XMark, {})
11380
- }
11381
- )
11382
- ]
11383
10718
  },
11384
- promotion.id
11385
- );
11386
- };
11387
- function getDisplayValue(promotion) {
11388
- var _a, _b, _c, _d;
11389
- const value = (_a = promotion.application_method) == null ? void 0 : _a.value;
11390
- if (!value) {
11391
- return null;
11392
- }
11393
- if (((_b = promotion.application_method) == null ? void 0 : _b.type) === "fixed") {
11394
- const currency = (_c = promotion.application_method) == null ? void 0 : _c.currency_code;
11395
- if (!currency) {
11396
- return null;
11397
- }
11398
- return getLocaleAmount(value, currency);
11399
- } else if (((_d = promotion.application_method) == null ? void 0 : _d.type) === "percentage") {
11400
- return formatPercentage(value);
11401
- }
11402
- return null;
11403
- }
11404
- const formatter = new Intl.NumberFormat([], {
11405
- style: "percent",
11406
- minimumFractionDigits: 2
11407
- });
11408
- const formatPercentage = (value, isPercentageValue = false) => {
11409
- let val = value || 0;
11410
- if (!isPercentageValue) {
11411
- val = val / 100;
11412
- }
11413
- return formatter.format(val);
11414
- };
11415
- function getPromotionCodes(items, shippingMethods) {
11416
- const codes = /* @__PURE__ */ new Set();
11417
- for (const item of items) {
11418
- if (item.adjustments) {
11419
- for (const adjustment of item.adjustments) {
11420
- if (adjustment.code) {
11421
- codes.add(adjustment.code);
11422
- }
11423
- }
11424
- }
11425
- }
11426
- for (const shippingMethod of shippingMethods) {
11427
- if (shippingMethod.adjustments) {
11428
- for (const adjustment of shippingMethod.adjustments) {
11429
- if (adjustment.code) {
11430
- codes.add(adjustment.code);
11431
- }
11432
- }
11433
- }
11434
- }
11435
- return Array.from(codes);
11436
- }
11437
- const SalesChannel = () => {
11438
- const { id } = useParams();
11439
- const { draft_order, isPending, isError, error } = useDraftOrder(
11440
- id,
11441
- {
11442
- fields: "+sales_channel_id"
11443
- },
11444
- {
11445
- enabled: !!id
11446
- }
11447
- );
11448
- if (isError) {
11449
- throw error;
11450
- }
11451
- const ISrEADY = !!draft_order && !isPending;
11452
- return /* @__PURE__ */ jsxs(RouteDrawer, { children: [
11453
- /* @__PURE__ */ jsxs(RouteDrawer.Header, { children: [
11454
- /* @__PURE__ */ jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Edit Sales Channel" }) }),
11455
- /* @__PURE__ */ jsx(RouteDrawer.Description, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Update which sales channel the draft order is associated with" }) })
11456
- ] }),
11457
- ISrEADY && /* @__PURE__ */ jsx(SalesChannelForm, { order: draft_order })
11458
- ] });
11459
- };
11460
- const SalesChannelForm = ({ order }) => {
11461
- const form = useForm({
11462
- defaultValues: {
11463
- sales_channel_id: order.sales_channel_id || ""
11464
- },
11465
- resolver: zodResolver(schema$2)
11466
- });
11467
- const { mutateAsync, isPending } = useUpdateDraftOrder(order.id);
11468
- const { handleSuccess } = useRouteModal();
11469
- const onSubmit = form.handleSubmit(async (data) => {
11470
- await mutateAsync(
11471
- {
11472
- sales_channel_id: data.sales_channel_id
11473
- },
11474
- {
11475
- onSuccess: () => {
11476
- toast.success("Sales channel updated");
11477
- handleSuccess();
11478
- },
11479
- onError: (error) => {
11480
- toast.error(error.message);
11481
- }
11482
- }
11483
- );
11484
- });
11485
- return /* @__PURE__ */ jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxs(
11486
- KeyboundForm,
11487
- {
11488
- className: "flex flex-1 flex-col overflow-hidden",
11489
- onSubmit,
11490
- children: [
11491
- /* @__PURE__ */ jsx(RouteDrawer.Body, { className: "flex flex-col gap-y-6 overflow-y-auto", children: /* @__PURE__ */ jsx(SalesChannelField, { control: form.control, order }) }),
11492
- /* @__PURE__ */ jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
11493
- /* @__PURE__ */ jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
11494
- /* @__PURE__ */ jsx(Button, { size: "small", type: "submit", isLoading: isPending, children: "Save" })
11495
- ] }) })
11496
- ]
11497
- }
11498
- ) });
11499
- };
11500
- const SalesChannelField = ({ control, order }) => {
11501
- const salesChannels = useComboboxData({
11502
- queryFn: async (params) => {
11503
- return await sdk.admin.salesChannel.list(params);
11504
- },
11505
- queryKey: ["sales-channels"],
11506
- getOptions: (data) => {
11507
- return data.sales_channels.map((salesChannel) => ({
11508
- label: salesChannel.name,
11509
- value: salesChannel.id
11510
- }));
11511
- },
11512
- defaultValue: order.sales_channel_id || void 0
11513
- });
11514
- return /* @__PURE__ */ jsx(
11515
- Form$2.Field,
11516
- {
11517
- control,
11518
- name: "sales_channel_id",
11519
- render: ({ field }) => {
11520
- return /* @__PURE__ */ jsxs(Form$2.Item, { children: [
11521
- /* @__PURE__ */ jsx(Form$2.Label, { children: "Sales Channel" }),
11522
- /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
11523
- Combobox,
11524
- {
11525
- options: salesChannels.options,
11526
- fetchNextPage: salesChannels.fetchNextPage,
11527
- isFetchingNextPage: salesChannels.isFetchingNextPage,
11528
- searchValue: salesChannels.searchValue,
11529
- onSearchValueChange: salesChannels.onSearchValueChange,
11530
- placeholder: "Select sales channel",
11531
- ...field
11532
- }
11533
- ) }),
11534
- /* @__PURE__ */ jsx(Form$2.ErrorMessage, {})
11535
- ] });
11536
- }
11537
- }
11538
- );
11539
- };
11540
- const schema$2 = objectType({
11541
- sales_channel_id: stringType().min(1)
11542
- });
11543
- const STACKED_FOCUS_MODAL_ID = "shipping-form";
11544
- const Shipping = () => {
11545
- var _a;
11546
- const { id } = useParams();
11547
- const { order, isPending, isError, error } = useOrder(id, {
11548
- fields: "+items.*,+items.variant.*,+items.variant.product.*,+items.variant.product.shipping_profile.*,+currency_code"
11549
- });
11550
- const {
11551
- order: preview,
11552
- isPending: isPreviewPending,
11553
- isError: isPreviewError,
11554
- error: previewError
11555
- } = useOrderPreview(id);
11556
- useInitiateOrderEdit({ preview });
11557
- const { onCancel } = useCancelOrderEdit({ preview });
11558
- if (isError) {
11559
- throw error;
11560
- }
11561
- if (isPreviewError) {
11562
- throw previewError;
11563
- }
11564
- const orderHasItems = (((_a = order == null ? void 0 : order.items) == null ? void 0 : _a.length) || 0) > 0;
11565
- const isReady = preview && !isPreviewPending && order && !isPending;
11566
- return /* @__PURE__ */ jsx(RouteFocusModal, { onClose: onCancel, children: !orderHasItems ? /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-col overflow-hidden ", children: [
11567
- /* @__PURE__ */ jsx(RouteFocusModal.Header, {}),
11568
- /* @__PURE__ */ jsx(RouteFocusModal.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 py-16 px-6", children: [
11569
- /* @__PURE__ */ jsx(RouteFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Shipping" }) }),
11570
- /* @__PURE__ */ jsx(RouteFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "This draft order currently has no items. Add items to the order before adding shipping." }) })
11571
- ] }) }) }),
11572
- /* @__PURE__ */ jsx(RouteFocusModal.Footer, { children: /* @__PURE__ */ jsx(RouteFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }) })
11573
- ] }) : isReady ? /* @__PURE__ */ jsx(ShippingForm, { preview, order }) : /* @__PURE__ */ jsxs("div", { children: [
11574
- /* @__PURE__ */ jsx(RouteFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Edit Shipping" }) }),
11575
- /* @__PURE__ */ jsx(RouteFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Loading data for the draft order, please wait..." }) })
11576
- ] }) });
11577
- };
11578
- const ShippingForm = ({ preview, order }) => {
11579
- var _a;
11580
- const { setIsOpen } = useStackedModal();
11581
- const [isSubmitting, setIsSubmitting] = useState(false);
11582
- const [data, setData] = useState(null);
11583
- const appliedShippingOptionIds = (_a = preview.shipping_methods) == null ? void 0 : _a.map((method) => method.shipping_option_id).filter(Boolean);
11584
- const { shipping_options } = useShippingOptions(
11585
- {
11586
- id: appliedShippingOptionIds,
11587
- fields: "+service_zone.*,+service_zone.fulfillment_set.*,+service_zone.fulfillment_set.location.*"
11588
- },
11589
- {
11590
- enabled: appliedShippingOptionIds.length > 0
11591
- }
11592
- );
11593
- const uniqueShippingProfiles = useMemo(() => {
11594
- const profiles = /* @__PURE__ */ new Map();
11595
- getUniqueShippingProfiles(order.items).forEach((profile) => {
11596
- profiles.set(profile.id, profile);
11597
- });
11598
- shipping_options == null ? void 0 : shipping_options.forEach((option) => {
11599
- profiles.set(option.shipping_profile_id, option.shipping_profile);
11600
- });
11601
- return Array.from(profiles.values());
11602
- }, [order.items, shipping_options]);
11603
- const { handleSuccess } = useRouteModal();
11604
- const { mutateAsync: confirmOrderEdit } = useDraftOrderConfirmEdit(preview.id);
11605
- const { mutateAsync: requestOrderEdit } = useDraftOrderRequestEdit(preview.id);
11606
- const { mutateAsync: removeShippingMethod } = useDraftOrderRemoveShippingMethod(preview.id);
11607
- const { mutateAsync: removeActionShippingMethod } = useDraftOrderRemoveActionShippingMethod(preview.id);
11608
- const onSubmit = async () => {
11609
- setIsSubmitting(true);
11610
- let requestSucceeded = false;
11611
- await requestOrderEdit(void 0, {
11612
- onError: (e) => {
11613
- toast.error(`Failed to request order edit: ${e.message}`);
11614
- },
11615
- onSuccess: () => {
11616
- requestSucceeded = true;
11617
- }
11618
- });
11619
- if (!requestSucceeded) {
11620
- setIsSubmitting(false);
11621
- return;
11622
- }
11623
- await confirmOrderEdit(void 0, {
11624
- onError: (e) => {
11625
- toast.error(`Failed to confirm order edit: ${e.message}`);
11626
- },
11627
- onSuccess: () => {
11628
- handleSuccess();
11629
- },
11630
- onSettled: () => {
11631
- setIsSubmitting(false);
11632
- }
11633
- });
11634
- };
11635
- const onKeydown = useCallback(
11636
- (e) => {
11637
- if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) {
11638
- if (data || isSubmitting) {
11639
- return;
11640
- }
11641
- onSubmit();
11642
- }
11643
- },
11644
- [data, isSubmitting, onSubmit]
10719
+ [data, isSubmitting, onSubmit]
11645
10720
  );
11646
10721
  useEffect(() => {
11647
10722
  document.addEventListener("keydown", onKeydown);
@@ -11847,7 +10922,7 @@ const ShippingForm = ({ preview, order }) => {
11847
10922
  ]
11848
10923
  }
11849
10924
  ) : /* @__PURE__ */ jsx(
11850
- StackedModalTrigger,
10925
+ StackedModalTrigger$1,
11851
10926
  {
11852
10927
  shippingProfileId: profile.id,
11853
10928
  shippingOption,
@@ -11958,7 +11033,7 @@ const ShippingForm = ({ preview, order }) => {
11958
11033
  ] }) })
11959
11034
  ] });
11960
11035
  };
11961
- const StackedModalTrigger = ({
11036
+ const StackedModalTrigger$1 = ({
11962
11037
  shippingProfileId,
11963
11038
  shippingOption,
11964
11039
  shippingMethod,
@@ -13003,28 +12078,953 @@ const Illustration = () => {
13003
12078
  /* @__PURE__ */ jsx("clipPath", { id: "clip4_20915_38670", children: /* @__PURE__ */ jsx(
13004
12079
  "rect",
13005
12080
  {
13006
- width: "12",
13007
- height: "12",
13008
- fill: "white",
13009
- transform: "matrix(0.865865 0.500278 -0.871576 0.490261 131.318 90.4594)"
12081
+ width: "12",
12082
+ height: "12",
12083
+ fill: "white",
12084
+ transform: "matrix(0.865865 0.500278 -0.871576 0.490261 131.318 90.4594)"
12085
+ }
12086
+ ) }),
12087
+ /* @__PURE__ */ jsx("clipPath", { id: "clip5_20915_38670", children: /* @__PURE__ */ jsx(
12088
+ "rect",
12089
+ {
12090
+ width: "12",
12091
+ height: "12",
12092
+ fill: "white",
12093
+ transform: "matrix(0.865865 0.500278 -0.871576 0.490261 141.709 96.4627)"
12094
+ }
12095
+ ) })
12096
+ ] })
12097
+ ]
12098
+ }
12099
+ );
12100
+ };
12101
+ const schema = objectType({
12102
+ customer_id: stringType().min(1)
12103
+ });
12104
+ const NumberInput = forwardRef(
12105
+ ({
12106
+ value,
12107
+ onChange,
12108
+ size = "base",
12109
+ min = 0,
12110
+ max = 100,
12111
+ step = 1,
12112
+ className,
12113
+ disabled,
12114
+ ...props
12115
+ }, ref) => {
12116
+ const handleChange = (event) => {
12117
+ const newValue = event.target.value === "" ? min : Number(event.target.value);
12118
+ if (!isNaN(newValue) && (max === void 0 || newValue <= max) && (min === void 0 || newValue >= min)) {
12119
+ onChange(newValue);
12120
+ }
12121
+ };
12122
+ const handleIncrement = () => {
12123
+ const newValue = value + step;
12124
+ if (max === void 0 || newValue <= max) {
12125
+ onChange(newValue);
12126
+ }
12127
+ };
12128
+ const handleDecrement = () => {
12129
+ const newValue = value - step;
12130
+ if (min === void 0 || newValue >= min) {
12131
+ onChange(newValue);
12132
+ }
12133
+ };
12134
+ return /* @__PURE__ */ jsxs(
12135
+ "div",
12136
+ {
12137
+ className: clx(
12138
+ "inline-flex rounded-md bg-ui-bg-field shadow-borders-base overflow-hidden divide-x transition-fg",
12139
+ "[&:has(input:focus)]:shadow-borders-interactive-with-active",
12140
+ {
12141
+ "h-7": size === "small",
12142
+ "h-8": size === "base"
12143
+ },
12144
+ className
12145
+ ),
12146
+ children: [
12147
+ /* @__PURE__ */ jsx(
12148
+ "input",
12149
+ {
12150
+ ref,
12151
+ type: "number",
12152
+ value,
12153
+ onChange: handleChange,
12154
+ min,
12155
+ max,
12156
+ step,
12157
+ className: clx(
12158
+ "flex-1 px-2 py-1 bg-transparent txt-compact-small text-ui-fg-base outline-none [appearance:textfield]",
12159
+ "[&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none",
12160
+ "placeholder:text-ui-fg-muted"
12161
+ ),
12162
+ ...props
12163
+ }
12164
+ ),
12165
+ /* @__PURE__ */ jsxs(
12166
+ "button",
12167
+ {
12168
+ className: clx(
12169
+ "flex items-center justify-center outline-none transition-fg",
12170
+ "disabled:cursor-not-allowed disabled:text-ui-fg-muted",
12171
+ "focus:bg-ui-bg-field-component-hover",
12172
+ "hover:bg-ui-bg-field-component-hover",
12173
+ {
12174
+ "size-7": size === "small",
12175
+ "size-8": size === "base"
12176
+ }
12177
+ ),
12178
+ type: "button",
12179
+ onClick: handleDecrement,
12180
+ disabled: min !== void 0 && value <= min || disabled,
12181
+ children: [
12182
+ /* @__PURE__ */ jsx(Minus, {}),
12183
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: `Decrease by ${step}` })
12184
+ ]
12185
+ }
12186
+ ),
12187
+ /* @__PURE__ */ jsxs(
12188
+ "button",
12189
+ {
12190
+ className: clx(
12191
+ "flex items-center justify-center outline-none transition-fg",
12192
+ "disabled:cursor-not-allowed disabled:text-ui-fg-muted",
12193
+ "focus:bg-ui-bg-field-hover",
12194
+ "hover:bg-ui-bg-field-hover",
12195
+ {
12196
+ "size-7": size === "small",
12197
+ "size-8": size === "base"
12198
+ }
12199
+ ),
12200
+ type: "button",
12201
+ onClick: handleIncrement,
12202
+ disabled: max !== void 0 && value >= max || disabled,
12203
+ children: [
12204
+ /* @__PURE__ */ jsx(Plus, {}),
12205
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: `Increase by ${step}` })
12206
+ ]
12207
+ }
12208
+ )
12209
+ ]
12210
+ }
12211
+ );
12212
+ }
12213
+ );
12214
+ const PRODUCT_VARIANTS_QUERY_KEY = "product-variants";
12215
+ const productVariantsQueryKeys = {
12216
+ list: (query2) => [
12217
+ PRODUCT_VARIANTS_QUERY_KEY,
12218
+ query2 ? query2 : void 0
12219
+ ]
12220
+ };
12221
+ const useProductVariants = (query2, options) => {
12222
+ const { data, ...rest } = useQuery({
12223
+ queryKey: productVariantsQueryKeys.list(query2),
12224
+ queryFn: async () => await sdk.admin.productVariant.list(query2),
12225
+ ...options
12226
+ });
12227
+ return { ...data, ...rest };
12228
+ };
12229
+ const STACKED_MODAL_ID = "items_stacked_modal";
12230
+ const Items = () => {
12231
+ const { id } = useParams();
12232
+ const {
12233
+ order: preview,
12234
+ isPending: isPreviewPending,
12235
+ isError: isPreviewError,
12236
+ error: previewError
12237
+ } = useOrderPreview(id, void 0, {
12238
+ placeholderData: keepPreviousData
12239
+ });
12240
+ useInitiateOrderEdit({ preview });
12241
+ const { draft_order, isPending, isError, error } = useDraftOrder(
12242
+ id,
12243
+ {
12244
+ fields: "currency_code"
12245
+ },
12246
+ {
12247
+ enabled: !!id
12248
+ }
12249
+ );
12250
+ const { onCancel } = useCancelOrderEdit({ preview });
12251
+ if (isError) {
12252
+ throw error;
12253
+ }
12254
+ if (isPreviewError) {
12255
+ throw previewError;
12256
+ }
12257
+ const ready = !!preview && !isPreviewPending && !!draft_order && !isPending;
12258
+ return /* @__PURE__ */ jsx(RouteFocusModal, { onClose: onCancel, children: ready ? /* @__PURE__ */ jsx(ItemsForm, { preview, currencyCode: draft_order.currency_code }) : /* @__PURE__ */ jsxs("div", { children: [
12259
+ /* @__PURE__ */ jsx(RouteFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Edit Items" }) }),
12260
+ /* @__PURE__ */ jsx(RouteFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Loading data for the draft order, please wait..." }) })
12261
+ ] }) });
12262
+ };
12263
+ const ItemsForm = ({ preview, currencyCode }) => {
12264
+ var _a;
12265
+ const [isSubmitting, setIsSubmitting] = useState(false);
12266
+ const [modalContent, setModalContent] = useState(
12267
+ null
12268
+ );
12269
+ const { handleSuccess } = useRouteModal();
12270
+ const { searchValue, onSearchValueChange, query: query2 } = useDebouncedSearch();
12271
+ const { mutateAsync: confirmOrderEdit } = useDraftOrderConfirmEdit(preview.id);
12272
+ const { mutateAsync: requestOrderEdit } = useDraftOrderRequestEdit(preview.id);
12273
+ const itemCount = ((_a = preview.items) == null ? void 0 : _a.reduce((acc, item) => acc + item.quantity, 0)) || 0;
12274
+ const matches = useMemo(() => {
12275
+ return matchSorter(preview.items, query2, {
12276
+ keys: ["product_title", "variant_title", "variant_sku", "title"]
12277
+ });
12278
+ }, [preview.items, query2]);
12279
+ const onSubmit = async () => {
12280
+ setIsSubmitting(true);
12281
+ let requestSucceeded = false;
12282
+ await requestOrderEdit(void 0, {
12283
+ onError: (e) => {
12284
+ toast.error(`Failed to request order edit: ${e.message}`);
12285
+ },
12286
+ onSuccess: () => {
12287
+ requestSucceeded = true;
12288
+ }
12289
+ });
12290
+ if (!requestSucceeded) {
12291
+ setIsSubmitting(false);
12292
+ return;
12293
+ }
12294
+ await confirmOrderEdit(void 0, {
12295
+ onError: (e) => {
12296
+ toast.error(`Failed to confirm order edit: ${e.message}`);
12297
+ },
12298
+ onSuccess: () => {
12299
+ handleSuccess();
12300
+ },
12301
+ onSettled: () => {
12302
+ setIsSubmitting(false);
12303
+ }
12304
+ });
12305
+ };
12306
+ const onKeyDown = useCallback(
12307
+ (e) => {
12308
+ if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) {
12309
+ if (modalContent || isSubmitting) {
12310
+ return;
12311
+ }
12312
+ onSubmit();
12313
+ }
12314
+ },
12315
+ [modalContent, isSubmitting, onSubmit]
12316
+ );
12317
+ useEffect(() => {
12318
+ document.addEventListener("keydown", onKeyDown);
12319
+ return () => {
12320
+ document.removeEventListener("keydown", onKeyDown);
12321
+ };
12322
+ }, [onKeyDown]);
12323
+ return /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-col overflow-hidden", children: [
12324
+ /* @__PURE__ */ jsx(RouteFocusModal.Header, {}),
12325
+ /* @__PURE__ */ jsx(RouteFocusModal.Body, { className: "flex flex-1 flex-col overflow-hidden", children: /* @__PURE__ */ jsxs(
12326
+ StackedFocusModal,
12327
+ {
12328
+ id: STACKED_MODAL_ID,
12329
+ onOpenChangeCallback: (open) => {
12330
+ if (!open) {
12331
+ setModalContent(null);
12332
+ }
12333
+ },
12334
+ children: [
12335
+ /* @__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: [
12336
+ /* @__PURE__ */ jsxs("div", { children: [
12337
+ /* @__PURE__ */ jsx(RouteFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Edit Items" }) }),
12338
+ /* @__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." }) })
12339
+ ] }),
12340
+ /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
12341
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-y-6", children: [
12342
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 items-center gap-3", children: [
12343
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
12344
+ /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: "Items" }),
12345
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Choose items from the product catalog." })
12346
+ ] }),
12347
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
12348
+ /* @__PURE__ */ jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsx(
12349
+ Input,
12350
+ {
12351
+ type: "search",
12352
+ placeholder: "Search items",
12353
+ value: searchValue,
12354
+ onChange: (e) => onSearchValueChange(e.target.value)
12355
+ }
12356
+ ) }),
12357
+ /* @__PURE__ */ jsxs(DropdownMenu, { children: [
12358
+ /* @__PURE__ */ jsx(DropdownMenu.Trigger, { asChild: true, children: /* @__PURE__ */ jsx(IconButton, { type: "button", children: /* @__PURE__ */ jsx(Plus, {}) }) }),
12359
+ /* @__PURE__ */ jsxs(DropdownMenu.Content, { children: [
12360
+ /* @__PURE__ */ jsx(
12361
+ StackedModalTrigger,
12362
+ {
12363
+ type: "add-items",
12364
+ setModalContent
12365
+ }
12366
+ ),
12367
+ /* @__PURE__ */ jsx(
12368
+ StackedModalTrigger,
12369
+ {
12370
+ type: "add-custom-item",
12371
+ setModalContent
12372
+ }
12373
+ )
12374
+ ] })
12375
+ ] })
12376
+ ] })
12377
+ ] }),
12378
+ /* @__PURE__ */ jsxs("div", { className: "bg-ui-bg-subtle shadow-elevation-card-rest rounded-xl", children: [
12379
+ /* @__PURE__ */ jsx("div", { className: "px-[5px]", children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-[1fr_1fr_1fr_28px] gap-3 px-4 py-2 text-ui-fg-muted", children: [
12380
+ /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: "Item" }) }),
12381
+ /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: "Quantity" }) }),
12382
+ /* @__PURE__ */ jsx("div", { className: "text-right", children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: "Price" }) }),
12383
+ /* @__PURE__ */ jsx("div", {})
12384
+ ] }) }),
12385
+ /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-y-1.5 px-[5px] pb-[5px]", children: itemCount <= 0 ? /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center gap-x-3 bg-ui-bg-base rounded-lg p-4 shadow-elevation-card-rest flex-col gap-1", children: [
12386
+ /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: "There are no items in this order" }),
12387
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Add items to the order to get started." })
12388
+ ] }) : matches.length > 0 ? matches == null ? void 0 : matches.map((item) => /* @__PURE__ */ jsx(
12389
+ Item,
12390
+ {
12391
+ item,
12392
+ preview,
12393
+ currencyCode
12394
+ },
12395
+ item.id
12396
+ )) : /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center gap-x-3 bg-ui-bg-base rounded-lg p-4 shadow-elevation-card-rest flex-col gap-1", children: [
12397
+ /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: "No items found" }),
12398
+ /* @__PURE__ */ jsxs(Text, { size: "small", className: "text-ui-fg-subtle", children: [
12399
+ 'No items found for "',
12400
+ query2,
12401
+ '".'
12402
+ ] })
12403
+ ] }) })
12404
+ ] })
12405
+ ] }),
12406
+ /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
12407
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-[1fr_0.5fr_0.5fr] gap-3", children: [
12408
+ /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: "Subtotal" }) }),
12409
+ /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsxs(
12410
+ Text,
12411
+ {
12412
+ size: "small",
12413
+ leading: "compact",
12414
+ className: "text-ui-fg-subtle",
12415
+ children: [
12416
+ itemCount,
12417
+ " ",
12418
+ itemCount === 1 ? "item" : "items"
12419
+ ]
12420
+ }
12421
+ ) }),
12422
+ /* @__PURE__ */ jsx("div", { className: "text-right", children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: getStylizedAmount(preview.item_subtotal, currencyCode) }) })
12423
+ ] })
12424
+ ] }) }),
12425
+ modalContent && (modalContent === "add-items" ? /* @__PURE__ */ jsx(ExistingItemsForm, { orderId: preview.id, items: preview.items }) : modalContent === "add-custom-item" ? /* @__PURE__ */ jsx(
12426
+ CustomItemForm,
12427
+ {
12428
+ orderId: preview.id,
12429
+ currencyCode
12430
+ }
12431
+ ) : null)
12432
+ ]
12433
+ }
12434
+ ) }),
12435
+ /* @__PURE__ */ jsx(RouteFocusModal.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-2 justify-end", children: [
12436
+ /* @__PURE__ */ jsx(RouteFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
12437
+ /* @__PURE__ */ jsx(
12438
+ Button,
12439
+ {
12440
+ size: "small",
12441
+ type: "button",
12442
+ onClick: onSubmit,
12443
+ isLoading: isSubmitting,
12444
+ children: "Save"
12445
+ }
12446
+ )
12447
+ ] }) })
12448
+ ] });
12449
+ };
12450
+ const Item = ({ item, preview, currencyCode }) => {
12451
+ if (item.variant_id) {
12452
+ return /* @__PURE__ */ jsx(VariantItem, { item, preview, currencyCode });
12453
+ }
12454
+ return /* @__PURE__ */ jsx(CustomItem, { item, preview, currencyCode });
12455
+ };
12456
+ const VariantItem = ({ item, preview, currencyCode }) => {
12457
+ const [editing, setEditing] = useState(false);
12458
+ const form = useForm({
12459
+ defaultValues: {
12460
+ quantity: item.quantity,
12461
+ unit_price: item.unit_price
12462
+ },
12463
+ resolver: zodResolver(variantItemSchema)
12464
+ });
12465
+ const actionId = useMemo(() => {
12466
+ var _a, _b;
12467
+ return (_b = (_a = item.actions) == null ? void 0 : _a.find((a) => a.action === "ITEM_ADD")) == null ? void 0 : _b.id;
12468
+ }, [item]);
12469
+ const { mutateAsync: updateActionItem, isPending: isUpdatingActionItem } = useDraftOrderUpdateActionItem(preview.id);
12470
+ const { mutateAsync: updateOriginalItem, isPending: isUpdatingOriginalItem } = useDraftOrderUpdateItem(preview.id);
12471
+ const isPending = isUpdatingActionItem || isUpdatingOriginalItem;
12472
+ const onSubmit = form.handleSubmit(async (data) => {
12473
+ if (convertNumber(data.unit_price) === item.unit_price && data.quantity === item.quantity) {
12474
+ setEditing(false);
12475
+ return;
12476
+ }
12477
+ if (!actionId) {
12478
+ await updateOriginalItem(
12479
+ {
12480
+ item_id: item.id,
12481
+ quantity: data.quantity,
12482
+ unit_price: convertNumber(data.unit_price)
12483
+ },
12484
+ {
12485
+ onSuccess: () => {
12486
+ setEditing(false);
12487
+ },
12488
+ onError: (e) => {
12489
+ toast.error(e.message);
12490
+ }
12491
+ }
12492
+ );
12493
+ return;
12494
+ }
12495
+ await updateActionItem(
12496
+ {
12497
+ action_id: actionId,
12498
+ quantity: data.quantity,
12499
+ unit_price: convertNumber(data.unit_price)
12500
+ },
12501
+ {
12502
+ onSuccess: () => {
12503
+ setEditing(false);
12504
+ },
12505
+ onError: (e) => {
12506
+ toast.error(e.message);
12507
+ }
12508
+ }
12509
+ );
12510
+ });
12511
+ return /* @__PURE__ */ jsx(Form$2, { ...form, children: /* @__PURE__ */ jsx("form", { onSubmit, children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-[minmax(0,1fr)_minmax(0,1fr)_minmax(0,1fr)_28px] gap-3 px-4 py-2 bg-ui-bg-base shadow-elevation-card-rest rounded-lg items-center", children: [
12512
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-3 w-full", children: [
12513
+ /* @__PURE__ */ jsx(
12514
+ Thumbnail,
12515
+ {
12516
+ thumbnail: item.thumbnail,
12517
+ alt: item.product_title ?? void 0
12518
+ }
12519
+ ),
12520
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
12521
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-1", children: [
12522
+ /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: item.product_title }),
12523
+ /* @__PURE__ */ jsxs(
12524
+ Text,
12525
+ {
12526
+ size: "small",
12527
+ leading: "compact",
12528
+ className: "text-ui-fg-subtle",
12529
+ children: [
12530
+ "(",
12531
+ item.variant_title,
12532
+ ")"
12533
+ ]
12534
+ }
12535
+ )
12536
+ ] }),
12537
+ /* @__PURE__ */ jsx(
12538
+ Text,
12539
+ {
12540
+ size: "small",
12541
+ leading: "compact",
12542
+ className: "text-ui-fg-subtle",
12543
+ children: item.variant_sku
12544
+ }
12545
+ )
12546
+ ] })
12547
+ ] }),
12548
+ editing ? /* @__PURE__ */ jsx("div", { className: "flex-1 w-full", children: /* @__PURE__ */ jsx(
12549
+ Form$2.Field,
12550
+ {
12551
+ control: form.control,
12552
+ name: "quantity",
12553
+ render: ({ field }) => {
12554
+ return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(NumberInput, { ...field }) }) });
12555
+ }
12556
+ }
12557
+ ) }) : /* @__PURE__ */ jsx("div", { className: "flex-1 w-full", children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: item.quantity }) }),
12558
+ editing ? /* @__PURE__ */ jsx("div", { className: "flex-1 w-full", children: /* @__PURE__ */ jsx(
12559
+ Form$2.Field,
12560
+ {
12561
+ control: form.control,
12562
+ name: "unit_price",
12563
+ render: ({ field: { onChange, ...field } }) => {
12564
+ return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
12565
+ CurrencyInput,
12566
+ {
12567
+ ...field,
12568
+ symbol: getNativeSymbol(currencyCode),
12569
+ code: currencyCode,
12570
+ onValueChange: (_value, _name, values) => onChange(values == null ? void 0 : values.value)
12571
+ }
12572
+ ) }) });
12573
+ }
12574
+ }
12575
+ ) }) : /* @__PURE__ */ jsx("div", { className: "flex-1 flex items-center justify-end w-full", children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: getLocaleAmount(item.unit_price, currencyCode) }) }),
12576
+ /* @__PURE__ */ jsx(
12577
+ IconButton,
12578
+ {
12579
+ type: "button",
12580
+ size: "small",
12581
+ onClick: editing ? onSubmit : () => {
12582
+ setEditing(true);
12583
+ },
12584
+ disabled: isPending,
12585
+ children: editing ? /* @__PURE__ */ jsx(Check, {}) : /* @__PURE__ */ jsx(PencilSquare, {})
12586
+ }
12587
+ )
12588
+ ] }) }) });
12589
+ };
12590
+ const variantItemSchema = objectType({
12591
+ quantity: numberType(),
12592
+ unit_price: unionType([numberType(), stringType()])
12593
+ });
12594
+ const CustomItem = ({ item, preview, currencyCode }) => {
12595
+ const [editing, setEditing] = useState(false);
12596
+ const { quantity, unit_price, title } = item;
12597
+ const form = useForm({
12598
+ defaultValues: {
12599
+ title,
12600
+ quantity,
12601
+ unit_price
12602
+ },
12603
+ resolver: zodResolver(customItemSchema)
12604
+ });
12605
+ useEffect(() => {
12606
+ form.reset({
12607
+ title,
12608
+ quantity,
12609
+ unit_price
12610
+ });
12611
+ }, [form, title, quantity, unit_price]);
12612
+ const actionId = useMemo(() => {
12613
+ var _a, _b;
12614
+ return (_b = (_a = item.actions) == null ? void 0 : _a.find((a) => a.action === "ITEM_ADD")) == null ? void 0 : _b.id;
12615
+ }, [item]);
12616
+ const { mutateAsync: updateActionItem, isPending: isUpdatingActionItem } = useDraftOrderUpdateActionItem(preview.id);
12617
+ const { mutateAsync: removeActionItem, isPending: isRemovingActionItem } = useDraftOrderRemoveActionItem(preview.id);
12618
+ const { mutateAsync: updateOriginalItem, isPending: isUpdatingOriginalItem } = useDraftOrderUpdateItem(preview.id);
12619
+ const isPending = isUpdatingActionItem || isUpdatingOriginalItem;
12620
+ const onSubmit = form.handleSubmit(async (data) => {
12621
+ if (convertNumber(data.unit_price) === item.unit_price && data.quantity === item.quantity && data.title === item.title) {
12622
+ setEditing(false);
12623
+ return;
12624
+ }
12625
+ if (!actionId) {
12626
+ await updateOriginalItem(
12627
+ {
12628
+ item_id: item.id,
12629
+ quantity: data.quantity,
12630
+ unit_price: convertNumber(data.unit_price)
12631
+ },
12632
+ {
12633
+ onSuccess: () => {
12634
+ setEditing(false);
12635
+ },
12636
+ onError: (e) => {
12637
+ toast.error(e.message);
12638
+ }
12639
+ }
12640
+ );
12641
+ return;
12642
+ }
12643
+ if (data.quantity === 0) {
12644
+ await removeActionItem(actionId, {
12645
+ onSuccess: () => {
12646
+ setEditing(false);
12647
+ },
12648
+ onError: (e) => {
12649
+ toast.error(e.message);
12650
+ }
12651
+ });
12652
+ return;
12653
+ }
12654
+ await updateActionItem(
12655
+ {
12656
+ action_id: actionId,
12657
+ quantity: data.quantity,
12658
+ unit_price: convertNumber(data.unit_price)
12659
+ },
12660
+ {
12661
+ onSuccess: () => {
12662
+ setEditing(false);
12663
+ },
12664
+ onError: (e) => {
12665
+ toast.error(e.message);
12666
+ }
12667
+ }
12668
+ );
12669
+ });
12670
+ return /* @__PURE__ */ jsx(Form$2, { ...form, children: /* @__PURE__ */ jsx("form", { onSubmit, children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-[minmax(0,1fr)_minmax(0,1fr)_minmax(0,1fr)_28px] gap-3 px-4 py-2 bg-ui-bg-base shadow-elevation-card-rest rounded-lg items-center", children: [
12671
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-3", children: [
12672
+ /* @__PURE__ */ jsx(
12673
+ Thumbnail,
12674
+ {
12675
+ thumbnail: item.thumbnail,
12676
+ alt: item.title ?? void 0
12677
+ }
12678
+ ),
12679
+ editing ? /* @__PURE__ */ jsx(
12680
+ Form$2.Field,
12681
+ {
12682
+ control: form.control,
12683
+ name: "title",
12684
+ render: ({ field }) => {
12685
+ return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(Input, { ...field }) }) });
12686
+ }
12687
+ }
12688
+ ) : /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: item.title })
12689
+ ] }),
12690
+ editing ? /* @__PURE__ */ jsx(
12691
+ Form$2.Field,
12692
+ {
12693
+ control: form.control,
12694
+ name: "quantity",
12695
+ render: ({ field }) => {
12696
+ return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(NumberInput, { ...field }) }) });
12697
+ }
12698
+ }
12699
+ ) : /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: item.quantity }),
12700
+ editing ? /* @__PURE__ */ jsx(
12701
+ Form$2.Field,
12702
+ {
12703
+ control: form.control,
12704
+ name: "unit_price",
12705
+ render: ({ field: { onChange, ...field } }) => {
12706
+ return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
12707
+ CurrencyInput,
12708
+ {
12709
+ ...field,
12710
+ symbol: getNativeSymbol(currencyCode),
12711
+ code: currencyCode,
12712
+ onValueChange: (_value, _name, values) => onChange(values == null ? void 0 : values.value)
12713
+ }
12714
+ ) }) });
12715
+ }
12716
+ }
12717
+ ) : /* @__PURE__ */ jsx("div", { className: "flex-1 flex items-center justify-end", children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: getLocaleAmount(item.unit_price, currencyCode) }) }),
12718
+ /* @__PURE__ */ jsx(
12719
+ IconButton,
12720
+ {
12721
+ type: "button",
12722
+ size: "small",
12723
+ onClick: editing ? onSubmit : () => {
12724
+ setEditing(true);
12725
+ },
12726
+ disabled: isPending,
12727
+ children: editing ? /* @__PURE__ */ jsx(Check, {}) : /* @__PURE__ */ jsx(PencilSquare, {})
12728
+ }
12729
+ )
12730
+ ] }) }) });
12731
+ };
12732
+ const StackedModalTrigger = ({
12733
+ type,
12734
+ setModalContent
12735
+ }) => {
12736
+ const { setIsOpen } = useStackedModal();
12737
+ const onClick = useCallback(() => {
12738
+ setModalContent(type);
12739
+ setIsOpen(STACKED_MODAL_ID, true);
12740
+ }, [setModalContent, setIsOpen, type]);
12741
+ return /* @__PURE__ */ jsx(StackedFocusModal.Trigger, { asChild: true, children: /* @__PURE__ */ jsx(DropdownMenu.Item, { onClick, children: type === "add-items" ? "Add items" : "Add custom item" }) });
12742
+ };
12743
+ const VARIANT_PREFIX = "items";
12744
+ const LIMIT = 50;
12745
+ const ExistingItemsForm = ({ orderId, items }) => {
12746
+ const { setIsOpen } = useStackedModal();
12747
+ const [rowSelection, setRowSelection] = useState(
12748
+ items.reduce((acc, item) => {
12749
+ acc[item.variant_id] = true;
12750
+ return acc;
12751
+ }, {})
12752
+ );
12753
+ useEffect(() => {
12754
+ setRowSelection(
12755
+ items.reduce((acc, item) => {
12756
+ if (item.variant_id) {
12757
+ acc[item.variant_id] = true;
12758
+ }
12759
+ return acc;
12760
+ }, {})
12761
+ );
12762
+ }, [items]);
12763
+ const { q, order, offset } = useQueryParams(
12764
+ ["q", "order", "offset"],
12765
+ VARIANT_PREFIX
12766
+ );
12767
+ const { variants, count, isPending, isError, error } = useProductVariants(
12768
+ {
12769
+ q,
12770
+ order,
12771
+ offset: offset ? parseInt(offset) : void 0,
12772
+ limit: LIMIT
12773
+ },
12774
+ {
12775
+ placeholderData: keepPreviousData
12776
+ }
12777
+ );
12778
+ const columns = useColumns();
12779
+ const { mutateAsync } = useDraftOrderAddItems(orderId);
12780
+ const onSubmit = async () => {
12781
+ const ids = Object.keys(rowSelection).filter(
12782
+ (id) => !items.find((i) => i.variant_id === id)
12783
+ );
12784
+ await mutateAsync(
12785
+ {
12786
+ items: ids.map((id) => ({
12787
+ variant_id: id,
12788
+ quantity: 1
12789
+ }))
12790
+ },
12791
+ {
12792
+ onSuccess: () => {
12793
+ setRowSelection({});
12794
+ setIsOpen(STACKED_MODAL_ID, false);
12795
+ },
12796
+ onError: (e) => {
12797
+ toast.error(e.message);
12798
+ }
12799
+ }
12800
+ );
12801
+ };
12802
+ if (isError) {
12803
+ throw error;
12804
+ }
12805
+ return /* @__PURE__ */ jsxs(
12806
+ StackedFocusModal.Content,
12807
+ {
12808
+ onOpenAutoFocus: (e) => {
12809
+ e.preventDefault();
12810
+ const searchInput = document.querySelector(
12811
+ "[data-modal-id='modal-search-input']"
12812
+ );
12813
+ if (searchInput) {
12814
+ searchInput.focus();
12815
+ }
12816
+ },
12817
+ children: [
12818
+ /* @__PURE__ */ jsxs(StackedFocusModal.Header, { children: [
12819
+ /* @__PURE__ */ jsx(StackedFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Product Variants" }) }),
12820
+ /* @__PURE__ */ jsx(StackedFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Choose product variants to add to the order." }) })
12821
+ ] }),
12822
+ /* @__PURE__ */ jsx(StackedFocusModal.Body, { className: "flex-1 overflow-hidden", children: /* @__PURE__ */ jsx(
12823
+ DataTable,
12824
+ {
12825
+ data: variants,
12826
+ columns,
12827
+ isLoading: isPending,
12828
+ getRowId: (row) => row.id,
12829
+ rowCount: count,
12830
+ prefix: VARIANT_PREFIX,
12831
+ layout: "fill",
12832
+ rowSelection: {
12833
+ state: rowSelection,
12834
+ onRowSelectionChange: setRowSelection,
12835
+ enableRowSelection: (row) => {
12836
+ return !items.find((i) => i.variant_id === row.original.id);
12837
+ }
12838
+ },
12839
+ autoFocusSearch: true
12840
+ }
12841
+ ) }),
12842
+ /* @__PURE__ */ jsx(StackedFocusModal.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-2 justify-end", children: [
12843
+ /* @__PURE__ */ jsx(StackedFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
12844
+ /* @__PURE__ */ jsx(Button, { size: "small", type: "button", onClick: onSubmit, children: "Update items" })
12845
+ ] }) })
12846
+ ]
12847
+ }
12848
+ );
12849
+ };
12850
+ const columnHelper = createDataTableColumnHelper();
12851
+ const useColumns = () => {
12852
+ return useMemo(() => {
12853
+ return [
12854
+ columnHelper.select(),
12855
+ columnHelper.accessor("product.title", {
12856
+ header: "Product",
12857
+ cell: ({ row }) => {
12858
+ var _a, _b, _c;
12859
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-2", children: [
12860
+ /* @__PURE__ */ jsx(
12861
+ Thumbnail,
12862
+ {
12863
+ thumbnail: (_a = row.original.product) == null ? void 0 : _a.thumbnail,
12864
+ alt: (_b = row.original.product) == null ? void 0 : _b.title
12865
+ }
12866
+ ),
12867
+ /* @__PURE__ */ jsx("span", { children: (_c = row.original.product) == null ? void 0 : _c.title })
12868
+ ] });
12869
+ },
12870
+ enableSorting: true
12871
+ }),
12872
+ columnHelper.accessor("title", {
12873
+ header: "Variant",
12874
+ enableSorting: true
12875
+ }),
12876
+ columnHelper.accessor("sku", {
12877
+ header: "SKU",
12878
+ cell: ({ getValue }) => {
12879
+ return getValue() ?? "-";
12880
+ },
12881
+ enableSorting: true
12882
+ }),
12883
+ columnHelper.accessor("updated_at", {
12884
+ header: "Updated",
12885
+ cell: ({ getValue }) => {
12886
+ return /* @__PURE__ */ jsx(
12887
+ Tooltip,
12888
+ {
12889
+ content: getFullDate({ date: getValue(), includeTime: true }),
12890
+ children: /* @__PURE__ */ jsx("span", { children: getFullDate({ date: getValue() }) })
13010
12891
  }
13011
- ) }),
13012
- /* @__PURE__ */ jsx("clipPath", { id: "clip5_20915_38670", children: /* @__PURE__ */ jsx(
13013
- "rect",
12892
+ );
12893
+ },
12894
+ enableSorting: true,
12895
+ sortAscLabel: "Oldest first",
12896
+ sortDescLabel: "Newest first"
12897
+ }),
12898
+ columnHelper.accessor("created_at", {
12899
+ header: "Created",
12900
+ cell: ({ getValue }) => {
12901
+ return /* @__PURE__ */ jsx(
12902
+ Tooltip,
13014
12903
  {
13015
- width: "12",
13016
- height: "12",
13017
- fill: "white",
13018
- transform: "matrix(0.865865 0.500278 -0.871576 0.490261 141.709 96.4627)"
12904
+ content: getFullDate({ date: getValue(), includeTime: true }),
12905
+ children: /* @__PURE__ */ jsx("span", { children: getFullDate({ date: getValue() }) })
13019
12906
  }
13020
- ) })
13021
- ] })
13022
- ]
13023
- }
13024
- );
12907
+ );
12908
+ },
12909
+ enableSorting: true,
12910
+ sortAscLabel: "Oldest first",
12911
+ sortDescLabel: "Newest first"
12912
+ })
12913
+ ];
12914
+ }, []);
13025
12915
  };
13026
- const schema = objectType({
13027
- customer_id: stringType().min(1)
12916
+ const CustomItemForm = ({ orderId, currencyCode }) => {
12917
+ const { setIsOpen } = useStackedModal();
12918
+ const { mutateAsync: addItems } = useDraftOrderAddItems(orderId);
12919
+ const form = useForm({
12920
+ defaultValues: {
12921
+ title: "",
12922
+ quantity: 1,
12923
+ unit_price: ""
12924
+ },
12925
+ resolver: zodResolver(customItemSchema)
12926
+ });
12927
+ const onSubmit = form.handleSubmit(async (data) => {
12928
+ await addItems(
12929
+ {
12930
+ items: [
12931
+ {
12932
+ title: data.title,
12933
+ quantity: data.quantity,
12934
+ unit_price: convertNumber(data.unit_price)
12935
+ }
12936
+ ]
12937
+ },
12938
+ {
12939
+ onSuccess: () => {
12940
+ setIsOpen(STACKED_MODAL_ID, false);
12941
+ },
12942
+ onError: (e) => {
12943
+ toast.error(e.message);
12944
+ }
12945
+ }
12946
+ );
12947
+ });
12948
+ return /* @__PURE__ */ jsx(Form$2, { ...form, children: /* @__PURE__ */ jsx(KeyboundForm, { onSubmit, children: /* @__PURE__ */ jsxs(StackedFocusModal.Content, { children: [
12949
+ /* @__PURE__ */ jsx(StackedFocusModal.Header, {}),
12950
+ /* @__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: [
12951
+ /* @__PURE__ */ jsxs("div", { children: [
12952
+ /* @__PURE__ */ jsx(StackedFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Add custom item" }) }),
12953
+ /* @__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." }) })
12954
+ ] }),
12955
+ /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
12956
+ /* @__PURE__ */ jsx(
12957
+ Form$2.Field,
12958
+ {
12959
+ control: form.control,
12960
+ name: "title",
12961
+ render: ({ field }) => /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
12962
+ /* @__PURE__ */ jsxs("div", { children: [
12963
+ /* @__PURE__ */ jsx(Form$2.Label, { children: "Title" }),
12964
+ /* @__PURE__ */ jsx(Form$2.Hint, { children: "Enter the title of the item" })
12965
+ ] }),
12966
+ /* @__PURE__ */ jsxs("div", { children: [
12967
+ /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(Input, { ...field }) }),
12968
+ /* @__PURE__ */ jsx(Form$2.ErrorMessage, {})
12969
+ ] })
12970
+ ] }) })
12971
+ }
12972
+ ),
12973
+ /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
12974
+ /* @__PURE__ */ jsx(
12975
+ Form$2.Field,
12976
+ {
12977
+ control: form.control,
12978
+ name: "unit_price",
12979
+ render: ({ field: { onChange, ...field } }) => /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
12980
+ /* @__PURE__ */ jsxs("div", { children: [
12981
+ /* @__PURE__ */ jsx(Form$2.Label, { children: "Unit price" }),
12982
+ /* @__PURE__ */ jsx(Form$2.Hint, { children: "Enter the unit price of the item" })
12983
+ ] }),
12984
+ /* @__PURE__ */ jsxs("div", { children: [
12985
+ /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
12986
+ CurrencyInput,
12987
+ {
12988
+ symbol: getNativeSymbol(currencyCode),
12989
+ code: currencyCode,
12990
+ onValueChange: (_value, _name, values) => onChange(values == null ? void 0 : values.value),
12991
+ ...field
12992
+ }
12993
+ ) }),
12994
+ /* @__PURE__ */ jsx(Form$2.ErrorMessage, {})
12995
+ ] })
12996
+ ] }) })
12997
+ }
12998
+ ),
12999
+ /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
13000
+ /* @__PURE__ */ jsx(
13001
+ Form$2.Field,
13002
+ {
13003
+ control: form.control,
13004
+ name: "quantity",
13005
+ render: ({ field }) => /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
13006
+ /* @__PURE__ */ jsxs("div", { children: [
13007
+ /* @__PURE__ */ jsx(Form$2.Label, { children: "Quantity" }),
13008
+ /* @__PURE__ */ jsx(Form$2.Hint, { children: "Enter the quantity of the item" })
13009
+ ] }),
13010
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 w-full", children: [
13011
+ /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx("div", { className: "flex-1 w-full", children: /* @__PURE__ */ jsx(NumberInput, { ...field, className: "w-full" }) }) }),
13012
+ /* @__PURE__ */ jsx(Form$2.ErrorMessage, {})
13013
+ ] })
13014
+ ] }) })
13015
+ }
13016
+ )
13017
+ ] }) }) }),
13018
+ /* @__PURE__ */ jsx(StackedFocusModal.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-2 justify-end", children: [
13019
+ /* @__PURE__ */ jsx(StackedFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
13020
+ /* @__PURE__ */ jsx(Button, { size: "small", type: "button", onClick: onSubmit, children: "Add item" })
13021
+ ] }) })
13022
+ ] }) }) });
13023
+ };
13024
+ const customItemSchema = objectType({
13025
+ title: stringType().min(1),
13026
+ quantity: numberType(),
13027
+ unit_price: unionType([numberType(), stringType()])
13028
13028
  });
13029
13029
  const widgetModule = { widgets: [] };
13030
13030
  const routeModule = {
@@ -13050,26 +13050,22 @@ const routeModule = {
13050
13050
  Component: BillingAddress,
13051
13051
  path: "/draft-orders/:id/billing-address"
13052
13052
  },
13053
- {
13054
- Component: Email,
13055
- path: "/draft-orders/:id/email"
13056
- },
13057
13053
  {
13058
13054
  Component: CustomItems,
13059
13055
  path: "/draft-orders/:id/custom-items"
13060
13056
  },
13061
13057
  {
13062
- Component: Items,
13063
- path: "/draft-orders/:id/items"
13064
- },
13065
- {
13066
- Component: Metadata,
13067
- path: "/draft-orders/:id/metadata"
13058
+ Component: Email,
13059
+ path: "/draft-orders/:id/email"
13068
13060
  },
13069
13061
  {
13070
13062
  Component: Promotions,
13071
13063
  path: "/draft-orders/:id/promotions"
13072
13064
  },
13065
+ {
13066
+ Component: Metadata,
13067
+ path: "/draft-orders/:id/metadata"
13068
+ },
13073
13069
  {
13074
13070
  Component: SalesChannel,
13075
13071
  path: "/draft-orders/:id/sales-channel"
@@ -13085,6 +13081,10 @@ const routeModule = {
13085
13081
  {
13086
13082
  Component: TransferOwnership,
13087
13083
  path: "/draft-orders/:id/transfer-ownership"
13084
+ },
13085
+ {
13086
+ Component: Items,
13087
+ path: "/draft-orders/:id/items"
13088
13088
  }
13089
13089
  ]
13090
13090
  }