@medusajs/draft-order 2.10.1-snapshot-20250828204656 → 2.10.1

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