@medusajs/draft-order 2.11.4-preview-20251106032210 → 2.11.4-preview-20251106090134

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