@medusajs/draft-order 2.10.1 → 2.10.2-snapshot-20250829071156

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, EllipsisVertical, ArrowUpMini, ArrowDownMini, Minus, PencilSquare } 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, Minus, PencilSquare, EllipsisVertical, ArrowUpMini, ArrowDownMini } 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,1712 +9833,1712 @@ const EmailForm = ({ order }) => {
9833
9833
  const schema$3 = objectType({
9834
9834
  email: stringType().email()
9835
9835
  });
9836
- const InlineTip = forwardRef(
9837
- ({ variant = "tip", label, className, children, ...props }, ref) => {
9838
- const labelValue = label || (variant === "warning" ? "Warning" : "Tip");
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
+ };
9839
9866
  return /* @__PURE__ */ jsxs(
9840
9867
  "div",
9841
9868
  {
9842
- ref,
9843
9869
  className: clx(
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",
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
+ },
9845
9876
  className
9846
9877
  ),
9847
- ...props,
9848
9878
  children: [
9849
9879
  /* @__PURE__ */ jsx(
9850
- "div",
9880
+ "input",
9851
9881
  {
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
- })
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
9856
9895
  }
9857
9896
  ),
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
- ] })
9897
+ /* @__PURE__ */ jsxs(
9898
+ "button",
9899
+ {
9900
+ className: clx(
9901
+ "flex items-center justify-center outline-none transition-fg",
9902
+ "disabled:cursor-not-allowed disabled:text-ui-fg-muted",
9903
+ "focus:bg-ui-bg-field-component-hover",
9904
+ "hover:bg-ui-bg-field-component-hover",
9905
+ {
9906
+ "size-7": size === "small",
9907
+ "size-8": size === "base"
9908
+ }
9909
+ ),
9910
+ type: "button",
9911
+ onClick: handleDecrement,
9912
+ disabled: min !== void 0 && value <= min || disabled,
9913
+ children: [
9914
+ /* @__PURE__ */ jsx(Minus, {}),
9915
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: `Decrease by ${step}` })
9916
+ ]
9917
+ }
9918
+ ),
9919
+ /* @__PURE__ */ jsxs(
9920
+ "button",
9921
+ {
9922
+ className: clx(
9923
+ "flex items-center justify-center outline-none transition-fg",
9924
+ "disabled:cursor-not-allowed disabled:text-ui-fg-muted",
9925
+ "focus:bg-ui-bg-field-hover",
9926
+ "hover:bg-ui-bg-field-hover",
9927
+ {
9928
+ "size-7": size === "small",
9929
+ "size-8": size === "base"
9930
+ }
9931
+ ),
9932
+ type: "button",
9933
+ onClick: handleIncrement,
9934
+ disabled: max !== void 0 && value >= max || disabled,
9935
+ children: [
9936
+ /* @__PURE__ */ jsx(Plus, {}),
9937
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: `Increase by ${step}` })
9938
+ ]
9939
+ }
9940
+ )
9866
9941
  ]
9867
9942
  }
9868
9943
  );
9869
9944
  }
9870
9945
  );
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 = () => {
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 = () => {
9881
10012
  const { id } = useParams();
9882
- const { order, isPending, isError, error } = useOrder(id, {
9883
- fields: "metadata"
10013
+ const {
10014
+ order: preview,
10015
+ isPending: isPreviewPending,
10016
+ isError: isPreviewError,
10017
+ error: previewError
10018
+ } = useOrderPreview(id, void 0, {
10019
+ placeholderData: keepPreviousData
9884
10020
  });
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 });
9885
10032
  if (isError) {
9886
10033
  throw error;
9887
10034
  }
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
- ] });
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
+ ] }) });
9896
10043
  };
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 }) => {
10044
+ const ItemsForm = ({ preview, currencyCode }) => {
10045
+ var _a;
10046
+ const [isSubmitting, setIsSubmitting] = useState(false);
10047
+ const [modalContent, setModalContent] = useState(
10048
+ null
10049
+ );
9900
10050
  const { handleSuccess } = useRouteModal();
9901
- const hasUneditableRows = getHasUneditableRows(metadata);
9902
- const { mutateAsync, isPending } = useUpdateDraftOrder(orderId);
9903
- const form = useForm({
9904
- defaultValues: {
9905
- metadata: getDefaultValues(metadata)
9906
- },
9907
- resolver: zodResolver(MetadataSchema)
9908
- });
9909
- const handleSubmit = form.handleSubmit(async (data) => {
9910
- const parsedData = parseValues(data);
9911
- await mutateAsync(
9912
- {
9913
- metadata: parsedData
9914
- },
9915
- {
9916
- onSuccess: () => {
9917
- toast.success("Metadata updated");
9918
- handleSuccess();
9919
- },
9920
- onError: (error) => {
9921
- toast.error(error.message);
9922
- }
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;
9923
10069
  }
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
- });
10070
+ });
10071
+ if (!requestSucceeded) {
10072
+ setIsSubmitting(false);
10073
+ return;
9938
10074
  }
9939
- }
9940
- function insertRow(index, position) {
9941
- insert(index + (position === "above" ? 0 : 1), {
9942
- key: "",
9943
- value: "",
9944
- disabled: false
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
+ }
9945
10085
  });
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" }) })
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
+ }
10095
+ },
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,
10108
+ {
10109
+ id: STACKED_MODAL_ID,
10110
+ onOpenChangeCallback: (open) => {
10111
+ if (!open) {
10112
+ setModalContent(null);
10113
+ }
10114
+ },
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." }) })
9958
10120
  ] }),
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: [
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: [
10022
10141
  /* @__PURE__ */ jsx(
10023
- DropdownMenu.Trigger,
10142
+ StackedModalTrigger$1,
10024
10143
  {
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, {}) })
10144
+ type: "add-items",
10145
+ setModalContent
10034
10146
  }
10035
10147
  ),
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
- ] })
10148
+ /* @__PURE__ */ jsx(
10149
+ StackedModalTrigger$1,
10150
+ {
10151
+ type: "add-custom-item",
10152
+ setModalContent
10153
+ }
10154
+ )
10072
10155
  ] })
10073
10156
  ] })
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
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
+ ]
10214
+ }
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"
10226
+ }
10099
10227
  )
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
10228
  ] }) })
10111
10229
  ] });
10112
10230
  };
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
- ];
10231
+ const Item = ({ item, preview, currencyCode }) => {
10232
+ if (item.variant_id) {
10233
+ return /* @__PURE__ */ jsx(VariantItem, { item, preview, currencyCode });
10123
10234
  }
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
- };
10235
+ return /* @__PURE__ */ jsx(CustomItem, { item, preview, currencyCode });
10236
+ };
10237
+ const VariantItem = ({ item, preview, currencyCode }) => {
10238
+ const [editing, setEditing] = useState(false);
10239
+ const form = useForm({
10240
+ defaultValues: {
10241
+ quantity: item.quantity,
10242
+ unit_price: item.unit_price
10243
+ },
10244
+ resolver: zodResolver(variantItemSchema)
10141
10245
  });
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) {
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);
10155
10256
  return;
10156
10257
  }
10157
- if (disabled) {
10158
- update[key] = value;
10258
+ if (!actionId) {
10259
+ await updateOriginalItem(
10260
+ {
10261
+ item_id: item.id,
10262
+ quantity: data.quantity,
10263
+ unit_price: convertNumber(data.unit_price)
10264
+ },
10265
+ {
10266
+ onSuccess: () => {
10267
+ setEditing(false);
10268
+ },
10269
+ onError: (e) => {
10270
+ toast.error(e.message);
10271
+ }
10272
+ }
10273
+ );
10159
10274
  return;
10160
10275
  }
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);
10276
+ await updateActionItem(
10277
+ {
10278
+ action_id: actionId,
10279
+ quantity: data.quantity,
10280
+ unit_price: convertNumber(data.unit_price)
10216
10281
  },
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;
10235
- }
10236
- if (preview.order_change) {
10237
- return;
10238
- }
10239
- IS_REQUEST_RUNNING = true;
10240
- await mutateAsync(void 0, {
10282
+ {
10283
+ onSuccess: () => {
10284
+ setEditing(false);
10285
+ },
10241
10286
  onError: (e) => {
10242
10287
  toast.error(e.message);
10243
- navigate(`/draft-orders/${preview.id}`, { replace: true });
10244
- return;
10245
10288
  }
10246
- });
10247
- IS_REQUEST_RUNNING = false;
10248
- }
10249
- run();
10250
- }, [preview, navigate, mutateAsync]);
10251
- };
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;
10263
- }
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
- ] });
10289
+ }
10290
+ );
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
+ ] }) }) });
10269
10370
  };
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
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
10280
10383
  },
10281
- {
10282
- enabled: !!promoCodes.length
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);
10404
+ return;
10283
10405
  }
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
10406
+ if (!actionId) {
10407
+ await updateOriginalItem(
10408
+ {
10409
+ item_id: item.id,
10410
+ quantity: data.quantity,
10411
+ unit_price: convertNumber(data.unit_price)
10412
+ },
10413
+ {
10414
+ onSuccess: () => {
10415
+ setEditing(false);
10416
+ },
10417
+ onError: (e) => {
10418
+ toast.error(e.message);
10419
+ }
10292
10420
  }
10293
- });
10294
- },
10295
- getOptions: (data) => {
10296
- return data.promotions.map((promotion) => ({
10297
- label: promotion.code,
10298
- value: promotion.code
10299
- }));
10421
+ );
10422
+ return;
10300
10423
  }
10301
- });
10302
- const add = async (value) => {
10303
- if (!value) {
10424
+ if (data.quantity === 0) {
10425
+ await removeActionItem(actionId, {
10426
+ onSuccess: () => {
10427
+ setEditing(false);
10428
+ },
10429
+ onError: (e) => {
10430
+ toast.error(e.message);
10431
+ }
10432
+ });
10304
10433
  return;
10305
10434
  }
10306
- addPromotions(
10435
+ await updateActionItem(
10307
10436
  {
10308
- promo_codes: [value]
10437
+ action_id: actionId,
10438
+ quantity: data.quantity,
10439
+ unit_price: convertNumber(data.unit_price)
10309
10440
  },
10310
10441
  {
10442
+ onSuccess: () => {
10443
+ setEditing(false);
10444
+ },
10311
10445
  onError: (e) => {
10312
10446
  toast.error(e.message);
10313
- comboboxData.onSearchValueChange("");
10314
- setComboboxValue("");
10315
- },
10316
- onSuccess: () => {
10317
- comboboxData.onSearchValueChange("");
10318
- setComboboxValue("");
10319
10447
  }
10320
10448
  }
10321
10449
  );
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;
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,
10455
+ {
10456
+ thumbnail: item.thumbnail,
10457
+ alt: item.title ?? void 0
10458
+ }
10459
+ ),
10460
+ editing ? /* @__PURE__ */ jsx(
10461
+ Form$2.Field,
10462
+ {
10463
+ control: form.control,
10464
+ name: "title",
10465
+ render: ({ field }) => {
10466
+ return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(Input, { ...field }) }) });
10467
+ }
10468
+ }
10469
+ ) : /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: item.title })
10470
+ ] }),
10471
+ editing ? /* @__PURE__ */ jsx(
10472
+ Form$2.Field,
10473
+ {
10474
+ control: form.control,
10475
+ name: "quantity",
10476
+ render: ({ field }) => {
10477
+ return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(NumberInput, { ...field }) }) });
10478
+ }
10334
10479
  }
10335
- });
10336
- if (!requestSucceeded) {
10337
- setIsSubmitting(false);
10338
- return;
10339
- }
10340
- await confirmOrderEdit(void 0, {
10341
- onError: (e) => {
10342
- toast.error(e.message);
10343
- },
10344
- onSuccess: () => {
10345
- handleSuccess();
10346
- },
10347
- onSettled: () => {
10348
- setIsSubmitting(false);
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
+ }
10349
10497
  }
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,
10381
- {
10382
- promotion,
10383
- orderId: preview.id,
10384
- isLoading: isPending
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);
10385
10506
  },
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,
10393
- {
10394
- size: "small",
10395
- type: "submit",
10396
- isLoading: isSubmitting || isAddingPromotions,
10397
- children: "Save"
10398
- }
10399
- )
10400
- ] }) })
10401
- ] });
10507
+ disabled: isPending,
10508
+ children: editing ? /* @__PURE__ */ jsx(Check, {}) : /* @__PURE__ */ jsx(PencilSquare, {})
10509
+ }
10510
+ )
10511
+ ] }) }) });
10402
10512
  };
10403
- const PromotionItem = ({
10404
- promotion,
10405
- orderId,
10406
- isLoading
10513
+ const StackedModalTrigger$1 = ({
10514
+ type,
10515
+ setModalContent
10407
10516
  }) => {
10408
- var _a;
10409
- const { mutateAsync: removePromotions, isPending } = useDraftOrderRemovePromotions(orderId);
10410
- const onRemove = async () => {
10411
- removePromotions(
10517
+ const { setIsOpen } = useStackedModal();
10518
+ const onClick = useCallback(() => {
10519
+ setModalContent(type);
10520
+ setIsOpen(STACKED_MODAL_ID, true);
10521
+ }, [setModalContent, setIsOpen, type]);
10522
+ return /* @__PURE__ */ jsx(StackedFocusModal.Trigger, { asChild: true, children: /* @__PURE__ */ jsx(DropdownMenu.Item, { onClick, children: type === "add-items" ? "Add items" : "Add custom item" }) });
10523
+ };
10524
+ const VARIANT_PREFIX = "items";
10525
+ const LIMIT = 50;
10526
+ const ExistingItemsForm = ({ orderId, items }) => {
10527
+ const { setIsOpen } = useStackedModal();
10528
+ const [rowSelection, setRowSelection] = useState(
10529
+ items.reduce((acc, item) => {
10530
+ acc[item.variant_id] = true;
10531
+ return acc;
10532
+ }, {})
10533
+ );
10534
+ useEffect(() => {
10535
+ setRowSelection(
10536
+ items.reduce((acc, item) => {
10537
+ if (item.variant_id) {
10538
+ acc[item.variant_id] = true;
10539
+ }
10540
+ return acc;
10541
+ }, {})
10542
+ );
10543
+ }, [items]);
10544
+ const { q, order, offset } = useQueryParams(
10545
+ ["q", "order", "offset"],
10546
+ VARIANT_PREFIX
10547
+ );
10548
+ const { variants, count, isPending, isError, error } = useProductVariants(
10549
+ {
10550
+ q,
10551
+ order,
10552
+ offset: offset ? parseInt(offset) : void 0,
10553
+ limit: LIMIT
10554
+ },
10555
+ {
10556
+ placeholderData: keepPreviousData
10557
+ }
10558
+ );
10559
+ const columns = useColumns();
10560
+ const { mutateAsync } = useDraftOrderAddItems(orderId);
10561
+ const onSubmit = async () => {
10562
+ const ids = Object.keys(rowSelection).filter(
10563
+ (id) => !items.find((i) => i.variant_id === id)
10564
+ );
10565
+ await mutateAsync(
10412
10566
  {
10413
- promo_codes: [promotion.code]
10567
+ items: ids.map((id) => ({
10568
+ variant_id: id,
10569
+ quantity: 1
10570
+ }))
10414
10571
  },
10415
10572
  {
10573
+ onSuccess: () => {
10574
+ setRowSelection({});
10575
+ setIsOpen(STACKED_MODAL_ID, false);
10576
+ },
10416
10577
  onError: (e) => {
10417
10578
  toast.error(e.message);
10418
10579
  }
10419
10580
  }
10420
10581
  );
10421
10582
  };
10422
- const displayValue = getDisplayValue(promotion);
10583
+ if (isError) {
10584
+ throw error;
10585
+ }
10423
10586
  return /* @__PURE__ */ jsxs(
10424
- "div",
10587
+ StackedFocusModal.Content,
10425
10588
  {
10426
- className: clx(
10427
- "px-3 py-2 rounded-lg bg-ui-bg-component shadow-elevation-card-rest flex items-center justify-between",
10428
- {
10429
- "animate-pulse": isLoading
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();
10430
10596
  }
10431
- ),
10597
+ },
10432
10598
  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
- ] })
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." }) })
10442
10602
  ] }),
10443
- /* @__PURE__ */ jsx(
10444
- IconButton,
10603
+ /* @__PURE__ */ jsx(StackedFocusModal.Body, { className: "flex-1 overflow-hidden", children: /* @__PURE__ */ jsx(
10604
+ DataTable,
10445
10605
  {
10446
- size: "small",
10447
- type: "button",
10448
- variant: "transparent",
10449
- onClick: onRemove,
10450
- isLoading: isPending || isLoading,
10451
- children: /* @__PURE__ */ jsx(XMark, {})
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
10452
10621
  }
10453
- )
10622
+ ) }),
10623
+ /* @__PURE__ */ jsx(StackedFocusModal.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-2 justify-end", children: [
10624
+ /* @__PURE__ */ jsx(StackedFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
10625
+ /* @__PURE__ */ jsx(Button, { size: "small", type: "button", onClick: onSubmit, children: "Update items" })
10626
+ ] }) })
10454
10627
  ]
10455
- },
10456
- promotion.id
10457
- );
10458
- };
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
10628
  }
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);
10629
+ );
10486
10630
  };
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);
10503
- }
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,
10513
- {
10514
- fields: "+sales_channel_id"
10515
- },
10516
- {
10517
- enabled: !!id
10518
- }
10519
- );
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
- ] });
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,
10669
+ {
10670
+ content: getFullDate({ date: getValue(), includeTime: true }),
10671
+ children: /* @__PURE__ */ jsx("span", { children: getFullDate({ date: getValue() }) })
10672
+ }
10673
+ );
10674
+ },
10675
+ enableSorting: true,
10676
+ sortAscLabel: "Oldest first",
10677
+ sortDescLabel: "Newest first"
10678
+ }),
10679
+ columnHelper.accessor("created_at", {
10680
+ header: "Created",
10681
+ cell: ({ getValue }) => {
10682
+ return /* @__PURE__ */ jsx(
10683
+ Tooltip,
10684
+ {
10685
+ content: getFullDate({ date: getValue(), includeTime: true }),
10686
+ children: /* @__PURE__ */ jsx("span", { children: getFullDate({ date: getValue() }) })
10687
+ }
10688
+ );
10689
+ },
10690
+ enableSorting: true,
10691
+ sortAscLabel: "Oldest first",
10692
+ sortDescLabel: "Newest first"
10693
+ })
10694
+ ];
10695
+ }, []);
10531
10696
  };
10532
- const SalesChannelForm = ({ order }) => {
10697
+ const CustomItemForm = ({ orderId, currencyCode }) => {
10698
+ const { setIsOpen } = useStackedModal();
10699
+ const { mutateAsync: addItems } = useDraftOrderAddItems(orderId);
10533
10700
  const form = useForm({
10534
10701
  defaultValues: {
10535
- sales_channel_id: order.sales_channel_id || ""
10702
+ title: "",
10703
+ quantity: 1,
10704
+ unit_price: ""
10536
10705
  },
10537
- resolver: zodResolver(schema$2)
10706
+ resolver: zodResolver(customItemSchema)
10538
10707
  });
10539
- const { mutateAsync, isPending } = useUpdateDraftOrder(order.id);
10540
- const { handleSuccess } = useRouteModal();
10541
10708
  const onSubmit = form.handleSubmit(async (data) => {
10542
- await mutateAsync(
10709
+ await addItems(
10543
10710
  {
10544
- sales_channel_id: data.sales_channel_id
10711
+ items: [
10712
+ {
10713
+ title: data.title,
10714
+ quantity: data.quantity,
10715
+ unit_price: convertNumber(data.unit_price)
10716
+ }
10717
+ ]
10545
10718
  },
10546
10719
  {
10547
10720
  onSuccess: () => {
10548
- toast.success("Sales channel updated");
10549
- handleSuccess();
10721
+ setIsOpen(STACKED_MODAL_ID, false);
10550
10722
  },
10551
- onError: (error) => {
10552
- toast.error(error.message);
10723
+ onError: (e) => {
10724
+ toast.error(e.message);
10553
10725
  }
10554
10726
  }
10555
10727
  );
10556
10728
  });
10557
- return /* @__PURE__ */ jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxs(
10558
- KeyboundForm,
10559
- {
10560
- className: "flex flex-1 flex-col overflow-hidden",
10561
- onSubmit,
10562
- children: [
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" })
10567
- ] }) })
10568
- ]
10569
- }
10570
- ) });
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
+ ] }) }) });
10571
10804
  };
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
- }
10610
- );
10611
- };
10612
- const schema$2 = objectType({
10613
- sales_channel_id: stringType().min(1)
10805
+ const customItemSchema = objectType({
10806
+ title: stringType().min(1),
10807
+ quantity: numberType(),
10808
+ unit_price: unionType([numberType(), stringType()])
10614
10809
  });
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
- };
10810
+ const InlineTip = forwardRef(
10811
+ ({ variant = "tip", label, className, children, ...props }, ref) => {
10812
+ const labelValue = label || (variant === "warning" ? "Warning" : "Tip");
10645
10813
  return /* @__PURE__ */ jsxs(
10646
10814
  "div",
10647
10815
  {
10816
+ ref,
10648
10817
  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
- },
10818
+ "bg-ui-bg-component txt-small text-ui-fg-subtle grid grid-cols-[4px_1fr] items-start gap-3 rounded-lg border p-3",
10655
10819
  className
10656
10820
  ),
10821
+ ...props,
10657
10822
  children: [
10658
10823
  /* @__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",
10824
+ "div",
10678
10825
  {
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
- ]
10826
+ role: "presentation",
10827
+ className: clx("w-4px bg-ui-tag-neutral-icon h-full rounded-full", {
10828
+ "bg-ui-tag-orange-icon": variant === "warning"
10829
+ })
10696
10830
  }
10697
10831
  ),
10698
- /* @__PURE__ */ jsxs(
10699
- "button",
10700
- {
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
- ]
10718
- }
10719
- )
10832
+ /* @__PURE__ */ jsxs("div", { className: "text-pretty", children: [
10833
+ /* @__PURE__ */ jsxs("strong", { className: "txt-small-plus text-ui-fg-base", children: [
10834
+ labelValue,
10835
+ ":"
10836
+ ] }),
10837
+ " ",
10838
+ children
10839
+ ] })
10720
10840
  ]
10721
10841
  }
10722
10842
  );
10723
10843
  }
10724
10844
  );
10725
- const PRODUCT_VARIANTS_QUERY_KEY = "product-variants";
10726
- const productVariantsQueryKeys = {
10727
- list: (query2) => [
10728
- PRODUCT_VARIANTS_QUERY_KEY,
10729
- query2 ? query2 : void 0
10730
- ]
10731
- };
10732
- const useProductVariants = (query2, options) => {
10733
- const { data, ...rest } = useQuery({
10734
- queryKey: productVariantsQueryKeys.list(query2),
10735
- queryFn: async () => await sdk.admin.productVariant.list(query2),
10736
- ...options
10737
- });
10738
- return { ...data, ...rest };
10739
- };
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 = () => {
10845
+ InlineTip.displayName = "InlineTip";
10846
+ const MetadataFieldSchema = objectType({
10847
+ key: stringType(),
10848
+ disabled: booleanType().optional(),
10849
+ value: anyType()
10850
+ });
10851
+ const MetadataSchema = objectType({
10852
+ metadata: arrayType(MetadataFieldSchema)
10853
+ });
10854
+ const Metadata = () => {
10745
10855
  const { id } = useParams();
10746
- const {
10747
- order: preview,
10748
- isPending: isPreviewPending,
10749
- isError: isPreviewError,
10750
- error: previewError
10751
- } = useOrderPreview(id, void 0, {
10752
- placeholderData: keepPreviousData
10856
+ const { order, isPending, isError, error } = useOrder(id, {
10857
+ fields: "metadata"
10753
10858
  });
10754
- useInitiateOrderEdit({ preview });
10755
- const { draft_order, isPending, isError, error } = useDraftOrder(
10756
- id,
10757
- {
10758
- fields: "currency_code"
10759
- },
10760
- {
10761
- enabled: !!id
10762
- }
10763
- );
10764
- const { onCancel } = useCancelOrderEdit({ preview });
10765
10859
  if (isError) {
10766
10860
  throw error;
10767
10861
  }
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
- ] }) });
10862
+ const isReady = !isPending && !!order;
10863
+ return /* @__PURE__ */ jsxs(RouteDrawer, { children: [
10864
+ /* @__PURE__ */ jsxs(RouteDrawer.Header, { children: [
10865
+ /* @__PURE__ */ jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Metadata" }) }),
10866
+ /* @__PURE__ */ jsx(RouteDrawer.Description, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Add metadata to the draft order." }) })
10867
+ ] }),
10868
+ !isReady ? /* @__PURE__ */ jsx(PlaceholderInner, {}) : /* @__PURE__ */ jsx(MetadataForm, { orderId: id, metadata: order == null ? void 0 : order.metadata })
10869
+ ] });
10776
10870
  };
10777
- const ItemsForm = ({ preview, currencyCode }) => {
10778
- var _a;
10779
- const [isSubmitting, setIsSubmitting] = useState(false);
10780
- const [modalContent, setModalContent] = useState(
10781
- null
10782
- );
10871
+ const METADATA_KEY_LABEL_ID = "metadata-form-key-label";
10872
+ const METADATA_VALUE_LABEL_ID = "metadata-form-value-label";
10873
+ const MetadataForm = ({ orderId, metadata }) => {
10783
10874
  const { handleSuccess } = useRouteModal();
10784
- const { searchValue, onSearchValueChange, query: query2 } = useDebouncedSearch();
10785
- const { mutateAsync: confirmOrderEdit } = useDraftOrderConfirmEdit(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]);
10793
- const onSubmit = async () => {
10794
- setIsSubmitting(true);
10795
- let requestSucceeded = false;
10796
- await requestOrderEdit(void 0, {
10797
- onError: (e) => {
10798
- toast.error(`Failed to request order edit: ${e.message}`);
10875
+ const hasUneditableRows = getHasUneditableRows(metadata);
10876
+ const { mutateAsync, isPending } = useUpdateDraftOrder(orderId);
10877
+ const form = useForm({
10878
+ defaultValues: {
10879
+ metadata: getDefaultValues(metadata)
10880
+ },
10881
+ resolver: zodResolver(MetadataSchema)
10882
+ });
10883
+ const handleSubmit = form.handleSubmit(async (data) => {
10884
+ const parsedData = parseValues(data);
10885
+ await mutateAsync(
10886
+ {
10887
+ metadata: parsedData
10799
10888
  },
10800
- onSuccess: () => {
10801
- requestSucceeded = true;
10889
+ {
10890
+ onSuccess: () => {
10891
+ toast.success("Metadata updated");
10892
+ handleSuccess();
10893
+ },
10894
+ onError: (error) => {
10895
+ toast.error(error.message);
10896
+ }
10802
10897
  }
10803
- });
10804
- if (!requestSucceeded) {
10805
- setIsSubmitting(false);
10806
- return;
10898
+ );
10899
+ });
10900
+ const { fields, insert, remove } = useFieldArray({
10901
+ control: form.control,
10902
+ name: "metadata"
10903
+ });
10904
+ function deleteRow(index) {
10905
+ remove(index);
10906
+ if (fields.length === 1) {
10907
+ insert(0, {
10908
+ key: "",
10909
+ value: "",
10910
+ disabled: false
10911
+ });
10807
10912
  }
10808
- await confirmOrderEdit(void 0, {
10809
- onError: (e) => {
10810
- toast.error(`Failed to confirm order edit: ${e.message}`);
10811
- },
10812
- onSuccess: () => {
10813
- handleSuccess();
10814
- },
10815
- onSettled: () => {
10816
- setIsSubmitting(false);
10817
- }
10913
+ }
10914
+ function insertRow(index, position) {
10915
+ insert(index + (position === "above" ? 0 : 1), {
10916
+ key: "",
10917
+ value: "",
10918
+ disabled: false
10818
10919
  });
10819
- };
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);
10846
- }
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." }) })
10920
+ }
10921
+ return /* @__PURE__ */ jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxs(
10922
+ KeyboundForm,
10923
+ {
10924
+ onSubmit: handleSubmit,
10925
+ className: "flex flex-1 flex-col overflow-hidden",
10926
+ children: [
10927
+ /* @__PURE__ */ jsxs(RouteDrawer.Body, { className: "flex flex-1 flex-col gap-y-8 overflow-y-auto", children: [
10928
+ /* @__PURE__ */ jsxs("div", { className: "bg-ui-bg-base shadow-elevation-card-rest grid grid-cols-1 divide-y rounded-lg", children: [
10929
+ /* @__PURE__ */ jsxs("div", { className: "bg-ui-bg-subtle grid grid-cols-2 divide-x rounded-t-lg", children: [
10930
+ /* @__PURE__ */ jsx("div", { className: "txt-compact-small-plus text-ui-fg-subtle px-2 py-1.5", children: /* @__PURE__ */ jsx("label", { id: METADATA_KEY_LABEL_ID, children: "Key" }) }),
10931
+ /* @__PURE__ */ jsx("div", { className: "txt-compact-small-plus text-ui-fg-subtle px-2 py-1.5", children: /* @__PURE__ */ jsx("label", { id: METADATA_VALUE_LABEL_ID, children: "Value" }) })
10853
10932
  ] }),
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: [
10933
+ fields.map((field, index) => {
10934
+ const isDisabled = field.disabled || false;
10935
+ let placeholder = "-";
10936
+ if (typeof field.value === "object") {
10937
+ placeholder = "{ ... }";
10938
+ }
10939
+ if (Array.isArray(field.value)) {
10940
+ placeholder = "[ ... ]";
10941
+ }
10942
+ return /* @__PURE__ */ jsx(
10943
+ ConditionalTooltip,
10944
+ {
10945
+ showTooltip: isDisabled,
10946
+ content: "This row is disabled because it contains non-primitive data.",
10947
+ children: /* @__PURE__ */ jsxs("div", { className: "group/table relative", children: [
10948
+ /* @__PURE__ */ jsxs(
10949
+ "div",
10950
+ {
10951
+ className: clx("grid grid-cols-2 divide-x", {
10952
+ "overflow-hidden rounded-b-lg": index === fields.length - 1
10953
+ }),
10954
+ children: [
10955
+ /* @__PURE__ */ jsx(
10956
+ Form$2.Field,
10957
+ {
10958
+ control: form.control,
10959
+ name: `metadata.${index}.key`,
10960
+ render: ({ field: field2 }) => {
10961
+ return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
10962
+ GridInput,
10963
+ {
10964
+ "aria-labelledby": METADATA_KEY_LABEL_ID,
10965
+ ...field2,
10966
+ disabled: isDisabled,
10967
+ placeholder: "Key"
10968
+ }
10969
+ ) }) });
10970
+ }
10971
+ }
10972
+ ),
10973
+ /* @__PURE__ */ jsx(
10974
+ Form$2.Field,
10975
+ {
10976
+ control: form.control,
10977
+ name: `metadata.${index}.value`,
10978
+ render: ({ field: { value, ...field2 } }) => {
10979
+ return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
10980
+ GridInput,
10981
+ {
10982
+ "aria-labelledby": METADATA_VALUE_LABEL_ID,
10983
+ ...field2,
10984
+ value: isDisabled ? placeholder : value,
10985
+ disabled: isDisabled,
10986
+ placeholder: "Value"
10987
+ }
10988
+ ) }) });
10989
+ }
10990
+ }
10991
+ )
10992
+ ]
10993
+ }
10994
+ ),
10995
+ /* @__PURE__ */ jsxs(DropdownMenu, { children: [
10874
10996
  /* @__PURE__ */ jsx(
10875
- StackedModalTrigger$1,
10997
+ DropdownMenu.Trigger,
10876
10998
  {
10877
- type: "add-items",
10878
- setModalContent
10999
+ className: clx(
11000
+ "invisible absolute inset-y-0 -right-2.5 my-auto group-hover/table:visible data-[state='open']:visible",
11001
+ {
11002
+ hidden: isDisabled
11003
+ }
11004
+ ),
11005
+ disabled: isDisabled,
11006
+ asChild: true,
11007
+ children: /* @__PURE__ */ jsx(IconButton, { size: "2xsmall", children: /* @__PURE__ */ jsx(EllipsisVertical, {}) })
10879
11008
  }
10880
11009
  ),
10881
- /* @__PURE__ */ jsx(
10882
- StackedModalTrigger$1,
10883
- {
10884
- type: "add-custom-item",
10885
- setModalContent
10886
- }
10887
- )
11010
+ /* @__PURE__ */ jsxs(DropdownMenu.Content, { children: [
11011
+ /* @__PURE__ */ jsxs(
11012
+ DropdownMenu.Item,
11013
+ {
11014
+ className: "gap-x-2",
11015
+ onClick: () => insertRow(index, "above"),
11016
+ children: [
11017
+ /* @__PURE__ */ jsx(ArrowUpMini, { className: "text-ui-fg-subtle" }),
11018
+ "Insert row above"
11019
+ ]
11020
+ }
11021
+ ),
11022
+ /* @__PURE__ */ jsxs(
11023
+ DropdownMenu.Item,
11024
+ {
11025
+ className: "gap-x-2",
11026
+ onClick: () => insertRow(index, "below"),
11027
+ children: [
11028
+ /* @__PURE__ */ jsx(ArrowDownMini, { className: "text-ui-fg-subtle" }),
11029
+ "Insert row below"
11030
+ ]
11031
+ }
11032
+ ),
11033
+ /* @__PURE__ */ jsx(DropdownMenu.Separator, {}),
11034
+ /* @__PURE__ */ jsxs(
11035
+ DropdownMenu.Item,
11036
+ {
11037
+ className: "gap-x-2",
11038
+ onClick: () => deleteRow(index),
11039
+ children: [
11040
+ /* @__PURE__ */ jsx(Trash, { className: "text-ui-fg-subtle" }),
11041
+ "Delete row"
11042
+ ]
11043
+ }
11044
+ )
11045
+ ] })
10888
11046
  ] })
10889
11047
  ] })
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(
10993
- {
10994
- item_id: item.id,
10995
- quantity: data.quantity,
10996
- unit_price: convertNumber(data.unit_price)
10997
- },
10998
- {
10999
- onSuccess: () => {
11000
- setEditing(false);
11001
- },
11002
- onError: (e) => {
11003
- toast.error(e.message);
11004
- }
11005
- }
11006
- );
11007
- return;
11008
- }
11009
- await updateActionItem(
11010
- {
11011
- action_id: actionId,
11012
- quantity: data.quantity,
11013
- unit_price: convertNumber(data.unit_price)
11014
- },
11015
- {
11016
- onSuccess: () => {
11017
- setEditing(false);
11018
- },
11019
- onError: (e) => {
11020
- toast.error(e.message);
11021
- }
11022
- }
11023
- );
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,
11029
- {
11030
- thumbnail: item.thumbnail,
11031
- alt: item.product_title ?? void 0
11032
- }
11033
- ),
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
- )
11048
+ },
11049
+ field.id
11050
+ );
11051
+ })
11052
+ ] }),
11053
+ hasUneditableRows && /* @__PURE__ */ jsx(InlineTip, { variant: "warning", label: "Some rows are disabled", children: "This object contains non-primitive metadata, such as arrays or objects, that can't be edited here. To edit the disabled rows, use the API directly." })
11050
11054
  ] }),
11051
- /* @__PURE__ */ jsx(
11052
- Text,
11053
- {
11054
- size: "small",
11055
- leading: "compact",
11056
- className: "text-ui-fg-subtle",
11057
- children: item.variant_sku
11058
- }
11059
- )
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 }) }) });
11069
- }
11070
- }
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
- ) }) });
11087
- }
11088
- }
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
- ] }) }) });
11055
+ /* @__PURE__ */ jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
11056
+ /* @__PURE__ */ jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
11057
+ /* @__PURE__ */ jsx(Button, { size: "small", type: "submit", isLoading: isPending, children: "Save" })
11058
+ ] }) })
11059
+ ]
11060
+ }
11061
+ ) });
11103
11062
  };
11104
- const variantItemSchema = objectType({
11105
- quantity: numberType(),
11106
- unit_price: unionType([numberType(), stringType()])
11063
+ const GridInput = forwardRef(({ className, ...props }, ref) => {
11064
+ return /* @__PURE__ */ jsx(
11065
+ "input",
11066
+ {
11067
+ ref,
11068
+ ...props,
11069
+ autoComplete: "off",
11070
+ className: clx(
11071
+ "txt-compact-small text-ui-fg-base placeholder:text-ui-fg-muted disabled:text-ui-fg-disabled disabled:bg-ui-bg-base bg-transparent px-2 py-1.5 outline-none",
11072
+ className
11073
+ )
11074
+ }
11075
+ );
11107
11076
  });
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
11116
- },
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;
11077
+ GridInput.displayName = "MetadataForm.GridInput";
11078
+ const PlaceholderInner = () => {
11079
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col overflow-hidden", children: [
11080
+ /* @__PURE__ */ jsx(RouteDrawer.Body, { children: /* @__PURE__ */ jsx(Skeleton, { className: "h-[148ox] w-full rounded-lg" }) }),
11081
+ /* @__PURE__ */ jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
11082
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-7 w-12 rounded-md" }),
11083
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-7 w-12 rounded-md" })
11084
+ ] }) })
11085
+ ] });
11086
+ };
11087
+ const EDITABLE_TYPES = ["string", "number", "boolean"];
11088
+ function getDefaultValues(metadata) {
11089
+ if (!metadata || !Object.keys(metadata).length) {
11090
+ return [
11091
+ {
11092
+ key: "",
11093
+ value: "",
11094
+ disabled: false
11095
+ }
11096
+ ];
11097
+ }
11098
+ return Object.entries(metadata).map(([key, value]) => {
11099
+ if (!EDITABLE_TYPES.includes(typeof value)) {
11100
+ return {
11101
+ key,
11102
+ value,
11103
+ disabled: true
11104
+ };
11138
11105
  }
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
- );
11106
+ let stringValue = value;
11107
+ if (typeof value !== "string") {
11108
+ stringValue = JSON.stringify(value);
11109
+ }
11110
+ return {
11111
+ key,
11112
+ value: stringValue,
11113
+ original_key: key
11114
+ };
11115
+ });
11116
+ }
11117
+ function parseValues(values) {
11118
+ const metadata = values.metadata;
11119
+ const isEmpty = !metadata.length || metadata.length === 1 && !metadata[0].key && !metadata[0].value;
11120
+ if (isEmpty) {
11121
+ return null;
11122
+ }
11123
+ const update = {};
11124
+ metadata.forEach((field) => {
11125
+ let key = field.key;
11126
+ let value = field.value;
11127
+ const disabled = field.disabled;
11128
+ if (!key || !value) {
11155
11129
  return;
11156
11130
  }
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
- });
11131
+ if (disabled) {
11132
+ update[key] = value;
11166
11133
  return;
11167
11134
  }
11168
- await updateActionItem(
11169
- {
11170
- action_id: actionId,
11171
- quantity: data.quantity,
11172
- unit_price: convertNumber(data.unit_price)
11173
- },
11174
- {
11175
- onSuccess: () => {
11176
- setEditing(false);
11177
- },
11178
- onError: (e) => {
11179
- toast.error(e.message);
11180
- }
11135
+ key = key.trim();
11136
+ value = value.trim();
11137
+ if (value === "true") {
11138
+ update[key] = true;
11139
+ } else if (value === "false") {
11140
+ update[key] = false;
11141
+ } else {
11142
+ const parsedNumber = parseFloat(value);
11143
+ if (!isNaN(parsedNumber)) {
11144
+ update[key] = parsedNumber;
11145
+ } else {
11146
+ update[key] = value;
11181
11147
  }
11182
- );
11148
+ }
11183
11149
  });
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
- }
11212
- }
11213
- ) : /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: item.quantity }),
11214
- editing ? /* @__PURE__ */ jsx(
11215
- Form$2.Field,
11216
- {
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,
11222
- {
11223
- ...field,
11224
- symbol: getNativeSymbol(currencyCode),
11225
- code: currencyCode,
11226
- onValueChange: (_value, _name, values) => onChange(values == null ? void 0 : values.value)
11227
- }
11228
- ) }) });
11229
- }
11230
- }
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
- ] }) }) });
11150
+ return update;
11151
+ }
11152
+ function getHasUneditableRows(metadata) {
11153
+ if (!metadata) {
11154
+ return false;
11155
+ }
11156
+ return Object.values(metadata).some(
11157
+ (value) => !EDITABLE_TYPES.includes(typeof value)
11158
+ );
11159
+ }
11160
+ const PROMOTION_QUERY_KEY = "promotions";
11161
+ const promotionsQueryKeys = {
11162
+ list: (query2) => [
11163
+ PROMOTION_QUERY_KEY,
11164
+ query2 ? query2 : void 0
11165
+ ],
11166
+ detail: (id, query2) => [
11167
+ PROMOTION_QUERY_KEY,
11168
+ id,
11169
+ query2 ? query2 : void 0
11170
+ ]
11245
11171
  };
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" }) });
11172
+ const usePromotions = (query2, options) => {
11173
+ const { data, ...rest } = useQuery({
11174
+ queryKey: promotionsQueryKeys.list(query2),
11175
+ queryFn: async () => sdk.admin.promotion.list(query2),
11176
+ ...options
11177
+ });
11178
+ return { ...data, ...rest };
11256
11179
  };
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(
11180
+ const Promotions = () => {
11181
+ const { id } = useParams();
11182
+ const {
11183
+ order: preview,
11184
+ isError: isPreviewError,
11185
+ error: previewError
11186
+ } = useOrderPreview(id, void 0);
11187
+ useInitiateOrderEdit({ preview });
11188
+ const { onCancel } = useCancelOrderEdit({ preview });
11189
+ if (isPreviewError) {
11190
+ throw previewError;
11191
+ }
11192
+ const isReady = !!preview;
11193
+ return /* @__PURE__ */ jsxs(RouteDrawer, { onClose: onCancel, children: [
11194
+ /* @__PURE__ */ jsx(RouteDrawer.Header, { children: /* @__PURE__ */ jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Edit Promotions" }) }) }),
11195
+ isReady && /* @__PURE__ */ jsx(PromotionForm, { preview })
11196
+ ] });
11197
+ };
11198
+ const PromotionForm = ({ preview }) => {
11199
+ const { items, shipping_methods } = preview;
11200
+ const [isSubmitting, setIsSubmitting] = useState(false);
11201
+ const [comboboxValue, setComboboxValue] = useState("");
11202
+ const { handleSuccess } = useRouteModal();
11203
+ const { mutateAsync: addPromotions, isPending: isAddingPromotions } = useDraftOrderAddPromotions(preview.id);
11204
+ const promoCodes = getPromotionCodes(items, shipping_methods);
11205
+ const { promotions, isPending, isError, error } = usePromotions(
11282
11206
  {
11283
- q,
11284
- order,
11285
- offset: offset ? parseInt(offset) : void 0,
11286
- limit: LIMIT
11207
+ code: promoCodes
11287
11208
  },
11288
11209
  {
11289
- placeholderData: keepPreviousData
11210
+ enabled: !!promoCodes.length
11290
11211
  }
11291
11212
  );
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
- );
11298
- await mutateAsync(
11213
+ const comboboxData = useComboboxData({
11214
+ queryKey: ["promotions", "combobox", promoCodes],
11215
+ queryFn: async (params) => {
11216
+ return await sdk.admin.promotion.list({
11217
+ ...params,
11218
+ code: {
11219
+ $nin: promoCodes
11220
+ }
11221
+ });
11222
+ },
11223
+ getOptions: (data) => {
11224
+ return data.promotions.map((promotion) => ({
11225
+ label: promotion.code,
11226
+ value: promotion.code
11227
+ }));
11228
+ }
11229
+ });
11230
+ const add = async (value) => {
11231
+ if (!value) {
11232
+ return;
11233
+ }
11234
+ addPromotions(
11299
11235
  {
11300
- items: ids.map((id) => ({
11301
- variant_id: id,
11302
- quantity: 1
11303
- }))
11236
+ promo_codes: [value]
11304
11237
  },
11305
11238
  {
11306
- onSuccess: () => {
11307
- setRowSelection({});
11308
- setIsOpen(STACKED_MODAL_ID, false);
11309
- },
11310
11239
  onError: (e) => {
11311
11240
  toast.error(e.message);
11241
+ comboboxData.onSearchValueChange("");
11242
+ setComboboxValue("");
11243
+ },
11244
+ onSuccess: () => {
11245
+ comboboxData.onSearchValueChange("");
11246
+ setComboboxValue("");
11312
11247
  }
11313
11248
  }
11314
11249
  );
11315
11250
  };
11251
+ const { mutateAsync: confirmOrderEdit } = useDraftOrderConfirmEdit(preview.id);
11252
+ const { mutateAsync: requestOrderEdit } = useOrderEditRequest(preview.id);
11253
+ const onSubmit = async () => {
11254
+ setIsSubmitting(true);
11255
+ let requestSucceeded = false;
11256
+ await requestOrderEdit(void 0, {
11257
+ onError: (e) => {
11258
+ toast.error(e.message);
11259
+ },
11260
+ onSuccess: () => {
11261
+ requestSucceeded = true;
11262
+ }
11263
+ });
11264
+ if (!requestSucceeded) {
11265
+ setIsSubmitting(false);
11266
+ return;
11267
+ }
11268
+ await confirmOrderEdit(void 0, {
11269
+ onError: (e) => {
11270
+ toast.error(e.message);
11271
+ },
11272
+ onSuccess: () => {
11273
+ handleSuccess();
11274
+ },
11275
+ onSettled: () => {
11276
+ setIsSubmitting(false);
11277
+ }
11278
+ });
11279
+ };
11316
11280
  if (isError) {
11317
11281
  throw error;
11318
11282
  }
11283
+ return /* @__PURE__ */ jsxs(KeyboundForm, { className: "flex flex-1 flex-col", onSubmit, children: [
11284
+ /* @__PURE__ */ jsx(RouteDrawer.Body, { children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
11285
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
11286
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
11287
+ /* @__PURE__ */ jsx(Label$1, { size: "small", weight: "plus", htmlFor: "promotion-combobox", children: "Apply promotions" }),
11288
+ /* @__PURE__ */ jsx(Hint$1, { id: "promotion-combobox-hint", children: "Manage promotions that should be applied to the order." })
11289
+ ] }),
11290
+ /* @__PURE__ */ jsx(
11291
+ Combobox,
11292
+ {
11293
+ id: "promotion-combobox",
11294
+ "aria-describedby": "promotion-combobox-hint",
11295
+ isFetchingNextPage: comboboxData.isFetchingNextPage,
11296
+ fetchNextPage: comboboxData.fetchNextPage,
11297
+ options: comboboxData.options,
11298
+ onSearchValueChange: comboboxData.onSearchValueChange,
11299
+ searchValue: comboboxData.searchValue,
11300
+ disabled: comboboxData.disabled || isAddingPromotions,
11301
+ onChange: add,
11302
+ value: comboboxValue
11303
+ }
11304
+ )
11305
+ ] }),
11306
+ /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
11307
+ /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-2", children: promotions == null ? void 0 : promotions.map((promotion) => /* @__PURE__ */ jsx(
11308
+ PromotionItem,
11309
+ {
11310
+ promotion,
11311
+ orderId: preview.id,
11312
+ isLoading: isPending
11313
+ },
11314
+ promotion.id
11315
+ )) })
11316
+ ] }) }),
11317
+ /* @__PURE__ */ jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
11318
+ /* @__PURE__ */ jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
11319
+ /* @__PURE__ */ jsx(
11320
+ Button,
11321
+ {
11322
+ size: "small",
11323
+ type: "submit",
11324
+ isLoading: isSubmitting || isAddingPromotions,
11325
+ children: "Save"
11326
+ }
11327
+ )
11328
+ ] }) })
11329
+ ] });
11330
+ };
11331
+ const PromotionItem = ({
11332
+ promotion,
11333
+ orderId,
11334
+ isLoading
11335
+ }) => {
11336
+ var _a;
11337
+ const { mutateAsync: removePromotions, isPending } = useDraftOrderRemovePromotions(orderId);
11338
+ const onRemove = async () => {
11339
+ removePromotions(
11340
+ {
11341
+ promo_codes: [promotion.code]
11342
+ },
11343
+ {
11344
+ onError: (e) => {
11345
+ toast.error(e.message);
11346
+ }
11347
+ }
11348
+ );
11349
+ };
11350
+ const displayValue = getDisplayValue(promotion);
11319
11351
  return /* @__PURE__ */ jsxs(
11320
- StackedFocusModal.Content,
11352
+ "div",
11321
11353
  {
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();
11354
+ className: clx(
11355
+ "px-3 py-2 rounded-lg bg-ui-bg-component shadow-elevation-card-rest flex items-center justify-between",
11356
+ {
11357
+ "animate-pulse": isLoading
11329
11358
  }
11330
- },
11359
+ ),
11331
11360
  children: [
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." }) })
11361
+ /* @__PURE__ */ jsxs("div", { children: [
11362
+ /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: promotion.code }),
11363
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 text-ui-fg-subtle", children: [
11364
+ displayValue && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
11365
+ /* @__PURE__ */ jsx(Text, { size: "small", leading: "compact", children: displayValue }),
11366
+ /* @__PURE__ */ jsx(Text, { size: "small", leading: "compact", children: "·" })
11367
+ ] }),
11368
+ /* @__PURE__ */ jsx(Text, { size: "small", leading: "compact", className: "capitalize", children: (_a = promotion.application_method) == null ? void 0 : _a.allocation })
11369
+ ] })
11335
11370
  ] }),
11336
- /* @__PURE__ */ jsx(StackedFocusModal.Body, { className: "flex-1 overflow-hidden", children: /* @__PURE__ */ jsx(
11337
- DataTable,
11371
+ /* @__PURE__ */ jsx(
11372
+ IconButton,
11338
11373
  {
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
11374
+ size: "small",
11375
+ type: "button",
11376
+ variant: "transparent",
11377
+ onClick: onRemove,
11378
+ isLoading: isPending || isLoading,
11379
+ children: /* @__PURE__ */ jsx(XMark, {})
11354
11380
  }
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
- ] }) })
11381
+ )
11360
11382
  ]
11383
+ },
11384
+ promotion.id
11385
+ );
11386
+ };
11387
+ function getDisplayValue(promotion) {
11388
+ var _a, _b, _c, _d;
11389
+ const value = (_a = promotion.application_method) == null ? void 0 : _a.value;
11390
+ if (!value) {
11391
+ return null;
11392
+ }
11393
+ if (((_b = promotion.application_method) == null ? void 0 : _b.type) === "fixed") {
11394
+ const currency = (_c = promotion.application_method) == null ? void 0 : _c.currency_code;
11395
+ if (!currency) {
11396
+ return null;
11397
+ }
11398
+ return getLocaleAmount(value, currency);
11399
+ } else if (((_d = promotion.application_method) == null ? void 0 : _d.type) === "percentage") {
11400
+ return formatPercentage(value);
11401
+ }
11402
+ return null;
11403
+ }
11404
+ const formatter = new Intl.NumberFormat([], {
11405
+ style: "percent",
11406
+ minimumFractionDigits: 2
11407
+ });
11408
+ const formatPercentage = (value, isPercentageValue = false) => {
11409
+ let val = value || 0;
11410
+ if (!isPercentageValue) {
11411
+ val = val / 100;
11412
+ }
11413
+ return formatter.format(val);
11414
+ };
11415
+ function getPromotionCodes(items, shippingMethods) {
11416
+ const codes = /* @__PURE__ */ new Set();
11417
+ for (const item of items) {
11418
+ if (item.adjustments) {
11419
+ for (const adjustment of item.adjustments) {
11420
+ if (adjustment.code) {
11421
+ codes.add(adjustment.code);
11422
+ }
11423
+ }
11424
+ }
11425
+ }
11426
+ for (const shippingMethod of shippingMethods) {
11427
+ if (shippingMethod.adjustments) {
11428
+ for (const adjustment of shippingMethod.adjustments) {
11429
+ if (adjustment.code) {
11430
+ codes.add(adjustment.code);
11431
+ }
11432
+ }
11433
+ }
11434
+ }
11435
+ return Array.from(codes);
11436
+ }
11437
+ const SalesChannel = () => {
11438
+ const { id } = useParams();
11439
+ const { draft_order, isPending, isError, error } = useDraftOrder(
11440
+ id,
11441
+ {
11442
+ fields: "+sales_channel_id"
11443
+ },
11444
+ {
11445
+ enabled: !!id
11361
11446
  }
11362
11447
  );
11448
+ if (isError) {
11449
+ throw error;
11450
+ }
11451
+ const ISrEADY = !!draft_order && !isPending;
11452
+ return /* @__PURE__ */ jsxs(RouteDrawer, { children: [
11453
+ /* @__PURE__ */ jsxs(RouteDrawer.Header, { children: [
11454
+ /* @__PURE__ */ jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Edit Sales Channel" }) }),
11455
+ /* @__PURE__ */ jsx(RouteDrawer.Description, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Update which sales channel the draft order is associated with" }) })
11456
+ ] }),
11457
+ ISrEADY && /* @__PURE__ */ jsx(SalesChannelForm, { order: draft_order })
11458
+ ] });
11363
11459
  };
11364
- const columnHelper = createDataTableColumnHelper();
11365
- const useColumns = () => {
11366
- return useMemo(() => {
11367
- return [
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
- })
11427
- ];
11428
- }, []);
11429
- };
11430
- const CustomItemForm = ({ orderId, currencyCode }) => {
11431
- const { setIsOpen } = useStackedModal();
11432
- const { mutateAsync: addItems } = useDraftOrderAddItems(orderId);
11460
+ const SalesChannelForm = ({ order }) => {
11433
11461
  const form = useForm({
11434
11462
  defaultValues: {
11435
- title: "",
11436
- quantity: 1,
11437
- unit_price: ""
11463
+ sales_channel_id: order.sales_channel_id || ""
11438
11464
  },
11439
- resolver: zodResolver(customItemSchema)
11465
+ resolver: zodResolver(schema$2)
11440
11466
  });
11467
+ const { mutateAsync, isPending } = useUpdateDraftOrder(order.id);
11468
+ const { handleSuccess } = useRouteModal();
11441
11469
  const onSubmit = form.handleSubmit(async (data) => {
11442
- await addItems(
11470
+ await mutateAsync(
11443
11471
  {
11444
- items: [
11445
- {
11446
- title: data.title,
11447
- quantity: data.quantity,
11448
- unit_price: convertNumber(data.unit_price)
11449
- }
11450
- ]
11472
+ sales_channel_id: data.sales_channel_id
11451
11473
  },
11452
11474
  {
11453
11475
  onSuccess: () => {
11454
- setIsOpen(STACKED_MODAL_ID, false);
11476
+ toast.success("Sales channel updated");
11477
+ handleSuccess();
11455
11478
  },
11456
- onError: (e) => {
11457
- toast.error(e.message);
11479
+ onError: (error) => {
11480
+ toast.error(error.message);
11458
11481
  }
11459
11482
  }
11460
11483
  );
11461
11484
  });
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
- ] }) }) });
11485
+ return /* @__PURE__ */ jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxs(
11486
+ KeyboundForm,
11487
+ {
11488
+ className: "flex flex-1 flex-col overflow-hidden",
11489
+ onSubmit,
11490
+ children: [
11491
+ /* @__PURE__ */ jsx(RouteDrawer.Body, { className: "flex flex-col gap-y-6 overflow-y-auto", children: /* @__PURE__ */ jsx(SalesChannelField, { control: form.control, order }) }),
11492
+ /* @__PURE__ */ jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
11493
+ /* @__PURE__ */ jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
11494
+ /* @__PURE__ */ jsx(Button, { size: "small", type: "submit", isLoading: isPending, children: "Save" })
11495
+ ] }) })
11496
+ ]
11497
+ }
11498
+ ) });
11537
11499
  };
11538
- const customItemSchema = objectType({
11539
- title: stringType().min(1),
11540
- quantity: numberType(),
11541
- unit_price: unionType([numberType(), stringType()])
11500
+ const SalesChannelField = ({ control, order }) => {
11501
+ const salesChannels = useComboboxData({
11502
+ queryFn: async (params) => {
11503
+ return await sdk.admin.salesChannel.list(params);
11504
+ },
11505
+ queryKey: ["sales-channels"],
11506
+ getOptions: (data) => {
11507
+ return data.sales_channels.map((salesChannel) => ({
11508
+ label: salesChannel.name,
11509
+ value: salesChannel.id
11510
+ }));
11511
+ },
11512
+ defaultValue: order.sales_channel_id || void 0
11513
+ });
11514
+ return /* @__PURE__ */ jsx(
11515
+ Form$2.Field,
11516
+ {
11517
+ control,
11518
+ name: "sales_channel_id",
11519
+ render: ({ field }) => {
11520
+ return /* @__PURE__ */ jsxs(Form$2.Item, { children: [
11521
+ /* @__PURE__ */ jsx(Form$2.Label, { children: "Sales Channel" }),
11522
+ /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
11523
+ Combobox,
11524
+ {
11525
+ options: salesChannels.options,
11526
+ fetchNextPage: salesChannels.fetchNextPage,
11527
+ isFetchingNextPage: salesChannels.isFetchingNextPage,
11528
+ searchValue: salesChannels.searchValue,
11529
+ onSearchValueChange: salesChannels.onSearchValueChange,
11530
+ placeholder: "Select sales channel",
11531
+ ...field
11532
+ }
11533
+ ) }),
11534
+ /* @__PURE__ */ jsx(Form$2.ErrorMessage, {})
11535
+ ] });
11536
+ }
11537
+ }
11538
+ );
11539
+ };
11540
+ const schema$2 = objectType({
11541
+ sales_channel_id: stringType().min(1)
11542
11542
  });
11543
11543
  const STACKED_FOCUS_MODAL_ID = "shipping-form";
11544
11544
  const Shipping = () => {
@@ -13058,6 +13058,10 @@ const routeModule = {
13058
13058
  Component: Email,
13059
13059
  path: "/draft-orders/:id/email"
13060
13060
  },
13061
+ {
13062
+ Component: Items,
13063
+ path: "/draft-orders/:id/items"
13064
+ },
13061
13065
  {
13062
13066
  Component: Metadata,
13063
13067
  path: "/draft-orders/:id/metadata"
@@ -13070,10 +13074,6 @@ const routeModule = {
13070
13074
  Component: SalesChannel,
13071
13075
  path: "/draft-orders/:id/sales-channel"
13072
13076
  },
13073
- {
13074
- Component: Items,
13075
- path: "/draft-orders/:id/items"
13076
- },
13077
13077
  {
13078
13078
  Component: Shipping,
13079
13079
  path: "/draft-orders/:id/shipping"