@medusajs/draft-order 2.10.4-snapshot-20250918173105 → 2.10.4-snapshot-20250922062130

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