@medusajs/draft-order 2.10.4-preview-20250928000328 → 2.10.4-preview-20250928060202

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,7 +4,7 @@ import { Tooltip, DropdownMenu, clx, IconButton, useDataTable, DataTable as Data
4
4
  import { useQuery, useQueryClient, useMutation, keepPreviousData, useInfiniteQuery } from "@tanstack/react-query";
5
5
  import React, { useState, useCallback, useMemo, Fragment, createContext, forwardRef, useId, useContext, useTransition, useRef, useImperativeHandle, useDeferredValue, useEffect, Suspense } from "react";
6
6
  import { useSearchParams, Link, useNavigate, Outlet, useBlocker, useLocation, useParams } from "react-router-dom";
7
- import { EllipsisHorizontal, XMark, InformationCircleSolid, XMarkMini, TrianglesMini, CheckMini, EllipseMiniSolid, PlusMini, ExclamationCircleSolid, ArrowPath, FlyingBox, CurrencyDollar, Envelope, Channels, Trash, ArrowUpRightOnBox, TriangleDownMini, Check, SquareTwoStack, Photo, TriangleRightMini, Shopping, Buildings, TruckFast, Plus, ReceiptPercent, Minus, PencilSquare, EllipsisVertical, ArrowUpMini, ArrowDownMini } from "@medusajs/icons";
7
+ import { EllipsisHorizontal, XMark, InformationCircleSolid, XMarkMini, TrianglesMini, CheckMini, EllipseMiniSolid, PlusMini, ExclamationCircleSolid, ArrowPath, FlyingBox, CurrencyDollar, Envelope, Channels, Trash, ArrowUpRightOnBox, TriangleDownMini, Check, SquareTwoStack, Photo, TriangleRightMini, Shopping, Buildings, TruckFast, Plus, ReceiptPercent, EllipsisVertical, ArrowUpMini, ArrowDownMini, Minus, PencilSquare } from "@medusajs/icons";
8
8
  import Medusa from "@medusajs/js-sdk";
9
9
  import { format, formatDistance, sub, subDays, subMonths } from "date-fns";
10
10
  import { enUS } from "date-fns/locale";
@@ -9825,1628 +9825,1351 @@ const EmailForm = ({ order }) => {
9825
9825
  const schema$4 = objectType({
9826
9826
  email: stringType().email()
9827
9827
  });
9828
- const NumberInput = forwardRef(
9829
- ({
9830
- value,
9831
- onChange,
9832
- size = "base",
9833
- min = 0,
9834
- max = 100,
9835
- step = 1,
9836
- className,
9837
- disabled,
9838
- ...props
9839
- }, ref) => {
9840
- const handleChange = (event) => {
9841
- const newValue = event.target.value === "" ? min : Number(event.target.value);
9842
- if (!isNaN(newValue) && (max === void 0 || newValue <= max) && (min === void 0 || newValue >= min)) {
9843
- onChange(newValue);
9844
- }
9845
- };
9846
- const handleIncrement = () => {
9847
- const newValue = value + step;
9848
- if (max === void 0 || newValue <= max) {
9849
- onChange(newValue);
9850
- }
9851
- };
9852
- const handleDecrement = () => {
9853
- const newValue = value - step;
9854
- if (min === void 0 || newValue >= min) {
9855
- onChange(newValue);
9856
- }
9857
- };
9828
+ const CustomItems = () => {
9829
+ return /* @__PURE__ */ jsxs(RouteDrawer, { children: [
9830
+ /* @__PURE__ */ jsx(RouteDrawer.Header, { children: /* @__PURE__ */ jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Edit Custom Items" }) }) }),
9831
+ /* @__PURE__ */ jsx(CustomItemsForm, {})
9832
+ ] });
9833
+ };
9834
+ const CustomItemsForm = () => {
9835
+ const form = useForm({
9836
+ resolver: zodResolver(schema$3)
9837
+ });
9838
+ return /* @__PURE__ */ jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxs(KeyboundForm, { className: "flex flex-1 flex-col", children: [
9839
+ /* @__PURE__ */ jsx(RouteDrawer.Body, {}),
9840
+ /* @__PURE__ */ jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
9841
+ /* @__PURE__ */ jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
9842
+ /* @__PURE__ */ jsx(Button, { size: "small", type: "submit", children: "Save" })
9843
+ ] }) })
9844
+ ] }) });
9845
+ };
9846
+ const schema$3 = objectType({
9847
+ email: stringType().email()
9848
+ });
9849
+ const InlineTip = forwardRef(
9850
+ ({ variant = "tip", label, className, children, ...props }, ref) => {
9851
+ const labelValue = label || (variant === "warning" ? "Warning" : "Tip");
9858
9852
  return /* @__PURE__ */ jsxs(
9859
9853
  "div",
9860
9854
  {
9855
+ ref,
9861
9856
  className: clx(
9862
- "inline-flex rounded-md bg-ui-bg-field shadow-borders-base overflow-hidden divide-x transition-fg",
9863
- "[&:has(input:focus)]:shadow-borders-interactive-with-active",
9864
- {
9865
- "h-7": size === "small",
9866
- "h-8": size === "base"
9867
- },
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",
9868
9858
  className
9869
9859
  ),
9860
+ ...props,
9870
9861
  children: [
9871
9862
  /* @__PURE__ */ jsx(
9872
- "input",
9873
- {
9874
- ref,
9875
- type: "number",
9876
- value,
9877
- onChange: handleChange,
9878
- min,
9879
- max,
9880
- step,
9881
- className: clx(
9882
- "flex-1 px-2 py-1 bg-transparent txt-compact-small text-ui-fg-base outline-none [appearance:textfield]",
9883
- "[&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none",
9884
- "placeholder:text-ui-fg-muted"
9885
- ),
9886
- ...props
9887
- }
9888
- ),
9889
- /* @__PURE__ */ jsxs(
9890
- "button",
9863
+ "div",
9891
9864
  {
9892
- className: clx(
9893
- "flex items-center justify-center outline-none transition-fg",
9894
- "disabled:cursor-not-allowed disabled:text-ui-fg-muted",
9895
- "focus:bg-ui-bg-field-component-hover",
9896
- "hover:bg-ui-bg-field-component-hover",
9897
- {
9898
- "size-7": size === "small",
9899
- "size-8": size === "base"
9900
- }
9901
- ),
9902
- type: "button",
9903
- onClick: handleDecrement,
9904
- disabled: min !== void 0 && value <= min || disabled,
9905
- children: [
9906
- /* @__PURE__ */ jsx(Minus, {}),
9907
- /* @__PURE__ */ jsx("span", { className: "sr-only", children: `Decrease by ${step}` })
9908
- ]
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
+ })
9909
9869
  }
9910
9870
  ),
9911
- /* @__PURE__ */ jsxs(
9912
- "button",
9913
- {
9914
- className: clx(
9915
- "flex items-center justify-center outline-none transition-fg",
9916
- "disabled:cursor-not-allowed disabled:text-ui-fg-muted",
9917
- "focus:bg-ui-bg-field-hover",
9918
- "hover:bg-ui-bg-field-hover",
9919
- {
9920
- "size-7": size === "small",
9921
- "size-8": size === "base"
9922
- }
9923
- ),
9924
- type: "button",
9925
- onClick: handleIncrement,
9926
- disabled: max !== void 0 && value >= max || disabled,
9927
- children: [
9928
- /* @__PURE__ */ jsx(Plus, {}),
9929
- /* @__PURE__ */ jsx("span", { className: "sr-only", children: `Increase by ${step}` })
9930
- ]
9931
- }
9932
- )
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
+ ] })
9933
9879
  ]
9934
9880
  }
9935
9881
  );
9936
9882
  }
9937
9883
  );
9938
- const PRODUCT_VARIANTS_QUERY_KEY = "product-variants";
9939
- const productVariantsQueryKeys = {
9940
- list: (query2) => [
9941
- PRODUCT_VARIANTS_QUERY_KEY,
9942
- query2 ? query2 : void 0
9943
- ]
9944
- };
9945
- const useProductVariants = (query2, options) => {
9946
- const { data, ...rest } = useQuery({
9947
- queryKey: productVariantsQueryKeys.list(query2),
9948
- queryFn: async () => await sdk.admin.productVariant.list(query2),
9949
- ...options
9950
- });
9951
- return { ...data, ...rest };
9952
- };
9953
- const useCancelOrderEdit = ({ preview }) => {
9954
- const { mutateAsync: cancelOrderEdit } = useDraftOrderCancelEdit(preview == null ? void 0 : preview.id);
9955
- const onCancel = useCallback(async () => {
9956
- if (!preview) {
9957
- return true;
9958
- }
9959
- let res = false;
9960
- await cancelOrderEdit(void 0, {
9961
- onError: (e) => {
9962
- toast.error(e.message);
9963
- },
9964
- onSuccess: () => {
9965
- res = true;
9966
- }
9967
- });
9968
- return res;
9969
- }, [preview, cancelOrderEdit]);
9970
- return { onCancel };
9971
- };
9972
- let IS_REQUEST_RUNNING = false;
9973
- const useInitiateOrderEdit = ({
9974
- preview
9975
- }) => {
9976
- const navigate = useNavigate();
9977
- const { mutateAsync } = useDraftOrderBeginEdit(preview == null ? void 0 : preview.id);
9978
- useEffect(() => {
9979
- async function run() {
9980
- if (IS_REQUEST_RUNNING || !preview) {
9981
- return;
9982
- }
9983
- if (preview.order_change) {
9984
- return;
9985
- }
9986
- IS_REQUEST_RUNNING = true;
9987
- await mutateAsync(void 0, {
9988
- onError: (e) => {
9989
- toast.error(e.message);
9990
- navigate(`/draft-orders/${preview.id}`, { replace: true });
9991
- return;
9992
- }
9993
- });
9994
- IS_REQUEST_RUNNING = false;
9995
- }
9996
- run();
9997
- }, [preview, navigate, mutateAsync]);
9998
- };
9999
- function convertNumber(value) {
10000
- return typeof value === "string" ? Number(value.replace(",", ".")) : value;
10001
- }
10002
- const STACKED_MODAL_ID = "items_stacked_modal";
10003
- const Items = () => {
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 = () => {
10004
9894
  const { id } = useParams();
10005
- const {
10006
- order: preview,
10007
- isPending: isPreviewPending,
10008
- isError: isPreviewError,
10009
- error: previewError
10010
- } = useOrderPreview(id, void 0, {
10011
- placeholderData: keepPreviousData
9895
+ const { order, isPending, isError, error } = useOrder(id, {
9896
+ fields: "metadata"
10012
9897
  });
10013
- useInitiateOrderEdit({ preview });
10014
- const { draft_order, isPending, isError, error } = useDraftOrder(
10015
- id,
10016
- {
10017
- fields: "currency_code"
10018
- },
10019
- {
10020
- enabled: !!id
10021
- }
10022
- );
10023
- const { onCancel } = useCancelOrderEdit({ preview });
10024
9898
  if (isError) {
10025
9899
  throw error;
10026
9900
  }
10027
- if (isPreviewError) {
10028
- throw previewError;
10029
- }
10030
- const ready = !!preview && !isPreviewPending && !!draft_order && !isPending;
10031
- return /* @__PURE__ */ jsx(RouteFocusModal, { onClose: onCancel, children: ready ? /* @__PURE__ */ jsx(ItemsForm, { preview, currencyCode: draft_order.currency_code }) : /* @__PURE__ */ jsxs("div", { children: [
10032
- /* @__PURE__ */ jsx(RouteFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Edit Items" }) }),
10033
- /* @__PURE__ */ jsx(RouteFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Loading data for the draft order, please wait..." }) })
10034
- ] }) });
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
+ ] });
10035
9909
  };
10036
- const ItemsForm = ({ preview, currencyCode }) => {
10037
- var _a;
10038
- const [isSubmitting, setIsSubmitting] = useState(false);
10039
- const [modalContent, setModalContent] = useState(
10040
- null
10041
- );
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 }) => {
10042
9913
  const { handleSuccess } = useRouteModal();
10043
- const { searchValue, onSearchValueChange, query: query2 } = useDebouncedSearch();
10044
- const { mutateAsync: confirmOrderEdit } = useDraftOrderConfirmEdit(preview.id);
10045
- const { mutateAsync: requestOrderEdit } = useDraftOrderRequestEdit(preview.id);
10046
- const itemCount = ((_a = preview.items) == null ? void 0 : _a.reduce((acc, item) => acc + item.quantity, 0)) || 0;
10047
- const matches = useMemo(() => {
10048
- return matchSorter(preview.items, query2, {
10049
- keys: ["product_title", "variant_title", "variant_sku", "title"]
10050
- });
10051
- }, [preview.items, query2]);
10052
- const onSubmit = async () => {
10053
- setIsSubmitting(true);
10054
- let requestSucceeded = false;
10055
- await requestOrderEdit(void 0, {
10056
- onError: (e) => {
10057
- toast.error(`Failed to request order edit: ${e.message}`);
10058
- },
10059
- onSuccess: () => {
10060
- requestSucceeded = true;
10061
- }
10062
- });
10063
- if (!requestSucceeded) {
10064
- setIsSubmitting(false);
10065
- return;
10066
- }
10067
- await confirmOrderEdit(void 0, {
10068
- onError: (e) => {
10069
- toast.error(`Failed to confirm order edit: ${e.message}`);
10070
- },
10071
- onSuccess: () => {
10072
- handleSuccess();
10073
- },
10074
- onSettled: () => {
10075
- setIsSubmitting(false);
10076
- }
10077
- });
10078
- };
10079
- const onKeyDown = useCallback(
10080
- (e) => {
10081
- if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) {
10082
- if (modalContent || isSubmitting) {
10083
- return;
10084
- }
10085
- onSubmit();
10086
- }
10087
- },
10088
- [modalContent, isSubmitting, onSubmit]
10089
- );
10090
- useEffect(() => {
10091
- document.addEventListener("keydown", onKeyDown);
10092
- return () => {
10093
- document.removeEventListener("keydown", onKeyDown);
10094
- };
10095
- }, [onKeyDown]);
10096
- return /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-col overflow-hidden", children: [
10097
- /* @__PURE__ */ jsx(RouteFocusModal.Header, {}),
10098
- /* @__PURE__ */ jsx(RouteFocusModal.Body, { className: "flex flex-1 flex-col overflow-hidden", children: /* @__PURE__ */ jsxs(
10099
- StackedFocusModal,
10100
- {
10101
- id: STACKED_MODAL_ID,
10102
- onOpenChangeCallback: (open) => {
10103
- if (!open) {
10104
- setModalContent(null);
10105
- }
10106
- },
10107
- children: [
10108
- /* @__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: [
10109
- /* @__PURE__ */ jsxs("div", { children: [
10110
- /* @__PURE__ */ jsx(RouteFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Edit Items" }) }),
10111
- /* @__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" }) })
10112
- ] }),
10113
- /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
10114
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-y-6", children: [
10115
- /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 items-center gap-3", children: [
10116
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
10117
- /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: "Items" }),
10118
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Choose items from the product catalog." })
10119
- ] }),
10120
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
10121
- /* @__PURE__ */ jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsx(
10122
- Input,
10123
- {
10124
- type: "search",
10125
- placeholder: "Search items",
10126
- value: searchValue,
10127
- onChange: (e) => onSearchValueChange(e.target.value)
10128
- }
10129
- ) }),
10130
- /* @__PURE__ */ jsxs(DropdownMenu, { children: [
10131
- /* @__PURE__ */ jsx(DropdownMenu.Trigger, { asChild: true, children: /* @__PURE__ */ jsx(IconButton, { type: "button", children: /* @__PURE__ */ jsx(Plus, {}) }) }),
10132
- /* @__PURE__ */ jsxs(DropdownMenu.Content, { children: [
10133
- /* @__PURE__ */ jsx(
10134
- StackedModalTrigger$1,
10135
- {
10136
- type: "add-items",
10137
- setModalContent
10138
- }
10139
- ),
10140
- /* @__PURE__ */ jsx(
10141
- StackedModalTrigger$1,
10142
- {
10143
- type: "add-custom-item",
10144
- setModalContent
10145
- }
10146
- )
10147
- ] })
10148
- ] })
10149
- ] })
10150
- ] }),
10151
- /* @__PURE__ */ jsxs("div", { className: "bg-ui-bg-subtle shadow-elevation-card-rest rounded-xl", children: [
10152
- /* @__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: [
10153
- /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: "Item" }) }),
10154
- /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: "Quantity" }) }),
10155
- /* @__PURE__ */ jsx("div", { className: "text-right", children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: "Price" }) }),
10156
- /* @__PURE__ */ jsx("div", {})
10157
- ] }) }),
10158
- /* @__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: [
10159
- /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: "There are no items in this order" }),
10160
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Add items to the order to get started." })
10161
- ] }) : matches.length > 0 ? matches == null ? void 0 : matches.map((item) => /* @__PURE__ */ jsx(
10162
- Item,
10163
- {
10164
- item,
10165
- preview,
10166
- currencyCode
10167
- },
10168
- item.id
10169
- )) : /* @__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: [
10170
- /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: "No items found" }),
10171
- /* @__PURE__ */ jsxs(Text, { size: "small", className: "text-ui-fg-subtle", children: [
10172
- 'No items found for "',
10173
- query2,
10174
- '".'
10175
- ] })
10176
- ] }) })
10177
- ] })
10178
- ] }),
10179
- /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
10180
- /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-[1fr_0.5fr_0.5fr] gap-3", children: [
10181
- /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: "Subtotal" }) }),
10182
- /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsxs(
10183
- Text,
10184
- {
10185
- size: "small",
10186
- leading: "compact",
10187
- className: "text-ui-fg-subtle",
10188
- children: [
10189
- itemCount,
10190
- " ",
10191
- itemCount === 1 ? "item" : "items"
10192
- ]
10193
- }
10194
- ) }),
10195
- /* @__PURE__ */ jsx("div", { className: "text-right", children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: getStylizedAmount(preview.item_subtotal, currencyCode) }) })
10196
- ] })
10197
- ] }) }),
10198
- modalContent && (modalContent === "add-items" ? /* @__PURE__ */ jsx(ExistingItemsForm, { orderId: preview.id, items: preview.items }) : modalContent === "add-custom-item" ? /* @__PURE__ */ jsx(
10199
- CustomItemForm,
10200
- {
10201
- orderId: preview.id,
10202
- currencyCode
10203
- }
10204
- ) : null)
10205
- ]
10206
- }
10207
- ) }),
10208
- /* @__PURE__ */ jsx(RouteFocusModal.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
10209
- /* @__PURE__ */ jsx(RouteFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
10210
- /* @__PURE__ */ jsx(
10211
- Button,
10212
- {
10213
- size: "small",
10214
- type: "button",
10215
- onClick: onSubmit,
10216
- isLoading: isSubmitting,
10217
- children: "Save"
10218
- }
10219
- )
10220
- ] }) })
10221
- ] });
10222
- };
10223
- const Item = ({ item, preview, currencyCode }) => {
10224
- if (item.variant_id) {
10225
- return /* @__PURE__ */ jsx(VariantItem, { item, preview, currencyCode });
10226
- }
10227
- return /* @__PURE__ */ jsx(CustomItem, { item, preview, currencyCode });
10228
- };
10229
- const VariantItem = ({ item, preview, currencyCode }) => {
10230
- const [editing, setEditing] = useState(false);
9914
+ const hasUneditableRows = getHasUneditableRows(metadata);
9915
+ const { mutateAsync, isPending } = useUpdateDraftOrder(orderId);
10231
9916
  const form = useForm({
10232
9917
  defaultValues: {
10233
- quantity: item.quantity,
10234
- unit_price: item.unit_price
9918
+ metadata: getDefaultValues(metadata)
10235
9919
  },
10236
- resolver: zodResolver(variantItemSchema)
9920
+ resolver: zodResolver(MetadataSchema)
10237
9921
  });
10238
- const actionId = useMemo(() => {
10239
- var _a, _b;
10240
- return (_b = (_a = item.actions) == null ? void 0 : _a.find((a) => a.action === "ITEM_ADD")) == null ? void 0 : _b.id;
10241
- }, [item]);
10242
- const { mutateAsync: updateActionItem, isPending: isUpdatingActionItem } = useDraftOrderUpdateActionItem(preview.id);
10243
- const { mutateAsync: updateOriginalItem, isPending: isUpdatingOriginalItem } = useDraftOrderUpdateItem(preview.id);
10244
- const isPending = isUpdatingActionItem || isUpdatingOriginalItem;
10245
- const onSubmit = form.handleSubmit(async (data) => {
10246
- if (convertNumber(data.unit_price) === item.unit_price && data.quantity === item.quantity) {
10247
- setEditing(false);
10248
- return;
10249
- }
10250
- if (!actionId) {
10251
- await updateOriginalItem(
10252
- {
10253
- item_id: item.id,
10254
- quantity: data.quantity,
10255
- unit_price: convertNumber(data.unit_price)
10256
- },
10257
- {
10258
- onSuccess: () => {
10259
- setEditing(false);
10260
- },
10261
- onError: (e) => {
10262
- toast.error(e.message);
10263
- }
10264
- }
10265
- );
10266
- return;
10267
- }
10268
- await updateActionItem(
9922
+ const handleSubmit = form.handleSubmit(async (data) => {
9923
+ const parsedData = parseValues(data);
9924
+ await mutateAsync(
10269
9925
  {
10270
- action_id: actionId,
10271
- quantity: data.quantity,
10272
- unit_price: convertNumber(data.unit_price)
9926
+ metadata: parsedData
10273
9927
  },
10274
9928
  {
10275
9929
  onSuccess: () => {
10276
- setEditing(false);
9930
+ toast.success("Metadata updated");
9931
+ handleSuccess();
10277
9932
  },
10278
- onError: (e) => {
10279
- toast.error(e.message);
9933
+ onError: (error) => {
9934
+ toast.error(error.message);
10280
9935
  }
10281
9936
  }
10282
9937
  );
10283
9938
  });
10284
- 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: [
10285
- /* @__PURE__ */ jsxs("div", { className: "flex w-full items-center gap-x-3", children: [
10286
- /* @__PURE__ */ jsx(
10287
- Thumbnail,
10288
- {
10289
- thumbnail: item.thumbnail,
10290
- alt: item.product_title ?? void 0
10291
- }
10292
- ),
10293
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
10294
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-1", children: [
10295
- /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: item.product_title }),
10296
- /* @__PURE__ */ jsxs(
10297
- Text,
10298
- {
10299
- size: "small",
10300
- leading: "compact",
10301
- className: "text-ui-fg-subtle",
10302
- children: [
10303
- "(",
10304
- item.variant_title,
10305
- ")"
10306
- ]
10307
- }
10308
- )
10309
- ] }),
10310
- /* @__PURE__ */ jsx(
10311
- Text,
10312
- {
10313
- size: "small",
10314
- leading: "compact",
10315
- className: "text-ui-fg-subtle",
10316
- children: item.variant_sku
10317
- }
10318
- )
10319
- ] })
10320
- ] }),
10321
- editing ? /* @__PURE__ */ jsx("div", { className: "w-full flex-1", children: /* @__PURE__ */ jsx(
10322
- Form$2.Field,
10323
- {
10324
- control: form.control,
10325
- name: "quantity",
10326
- render: ({ field }) => {
10327
- return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(NumberInput, { ...field }) }) });
10328
- }
10329
- }
10330
- ) }) : /* @__PURE__ */ jsx("div", { className: "w-full flex-1", children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: item.quantity }) }),
10331
- editing ? /* @__PURE__ */ jsx("div", { className: "w-full flex-1", children: /* @__PURE__ */ jsx(
10332
- Form$2.Field,
10333
- {
10334
- control: form.control,
10335
- name: "unit_price",
10336
- render: ({ field: { onChange, ...field } }) => {
10337
- return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
10338
- CurrencyInput,
10339
- {
10340
- ...field,
10341
- symbol: getNativeSymbol(currencyCode),
10342
- code: currencyCode,
10343
- onValueChange: (_value, _name, values) => onChange(values == null ? void 0 : values.value)
10344
- }
10345
- ) }) });
10346
- }
10347
- }
10348
- ) }) : /* @__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) }) }),
10349
- /* @__PURE__ */ jsx(
10350
- IconButton,
10351
- {
10352
- type: "button",
10353
- size: "small",
10354
- onClick: editing ? onSubmit : () => {
10355
- setEditing(true);
10356
- },
10357
- disabled: isPending,
10358
- children: editing ? /* @__PURE__ */ jsx(Check, {}) : /* @__PURE__ */ jsx(PencilSquare, {})
10359
- }
10360
- )
10361
- ] }) }) });
10362
- };
10363
- const variantItemSchema = objectType({
10364
- quantity: numberType(),
10365
- unit_price: unionType([numberType(), stringType()])
10366
- });
10367
- const CustomItem = ({ item, preview, currencyCode }) => {
10368
- const [editing, setEditing] = useState(false);
10369
- const { quantity, unit_price, title } = item;
10370
- const form = useForm({
10371
- defaultValues: {
10372
- title,
10373
- quantity,
10374
- unit_price
10375
- },
10376
- resolver: zodResolver(customItemSchema)
10377
- });
10378
- useEffect(() => {
10379
- form.reset({
10380
- title,
10381
- quantity,
10382
- unit_price
10383
- });
10384
- }, [form, title, quantity, unit_price]);
10385
- const actionId = useMemo(() => {
10386
- var _a, _b;
10387
- return (_b = (_a = item.actions) == null ? void 0 : _a.find((a) => a.action === "ITEM_ADD")) == null ? void 0 : _b.id;
10388
- }, [item]);
10389
- const { mutateAsync: updateActionItem, isPending: isUpdatingActionItem } = useDraftOrderUpdateActionItem(preview.id);
10390
- const { mutateAsync: removeActionItem, isPending: isRemovingActionItem } = useDraftOrderRemoveActionItem(preview.id);
10391
- const { mutateAsync: updateOriginalItem, isPending: isUpdatingOriginalItem } = useDraftOrderUpdateItem(preview.id);
10392
- const isPending = isUpdatingActionItem || isUpdatingOriginalItem;
10393
- const onSubmit = form.handleSubmit(async (data) => {
10394
- if (convertNumber(data.unit_price) === item.unit_price && data.quantity === item.quantity && data.title === item.title) {
10395
- setEditing(false);
10396
- return;
10397
- }
10398
- if (!actionId) {
10399
- await updateOriginalItem(
10400
- {
10401
- item_id: item.id,
10402
- quantity: data.quantity,
10403
- unit_price: convertNumber(data.unit_price)
10404
- },
10405
- {
10406
- onSuccess: () => {
10407
- setEditing(false);
10408
- },
10409
- onError: (e) => {
10410
- toast.error(e.message);
10411
- }
10412
- }
10413
- );
10414
- return;
10415
- }
10416
- if (data.quantity === 0) {
10417
- await removeActionItem(actionId, {
10418
- onSuccess: () => {
10419
- setEditing(false);
10420
- },
10421
- onError: (e) => {
10422
- toast.error(e.message);
10423
- }
10424
- });
10425
- return;
10426
- }
10427
- await updateActionItem(
10428
- {
10429
- action_id: actionId,
10430
- quantity: data.quantity,
10431
- unit_price: convertNumber(data.unit_price)
10432
- },
10433
- {
10434
- onSuccess: () => {
10435
- setEditing(false);
10436
- },
10437
- onError: (e) => {
10438
- toast.error(e.message);
10439
- }
10440
- }
10441
- );
10442
- });
10443
- 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: [
10444
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-3", children: [
10445
- /* @__PURE__ */ jsx(
10446
- Thumbnail,
10447
- {
10448
- thumbnail: item.thumbnail,
10449
- alt: item.title ?? void 0
10450
- }
10451
- ),
10452
- editing ? /* @__PURE__ */ jsx(
10453
- Form$2.Field,
10454
- {
10455
- control: form.control,
10456
- name: "title",
10457
- render: ({ field }) => {
10458
- return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(Input, { ...field }) }) });
10459
- }
10460
- }
10461
- ) : /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: item.title })
10462
- ] }),
10463
- editing ? /* @__PURE__ */ jsx(
10464
- Form$2.Field,
10465
- {
10466
- control: form.control,
10467
- name: "quantity",
10468
- render: ({ field }) => {
10469
- return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(NumberInput, { ...field }) }) });
10470
- }
10471
- }
10472
- ) : /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: item.quantity }),
10473
- editing ? /* @__PURE__ */ jsx(
10474
- Form$2.Field,
10475
- {
10476
- control: form.control,
10477
- name: "unit_price",
10478
- render: ({ field: { onChange, ...field } }) => {
10479
- return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
10480
- CurrencyInput,
10481
- {
10482
- ...field,
10483
- symbol: getNativeSymbol(currencyCode),
10484
- code: currencyCode,
10485
- onValueChange: (_value, _name, values) => onChange(values == null ? void 0 : values.value)
10486
- }
10487
- ) }) });
10488
- }
10489
- }
10490
- ) : /* @__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) }) }),
10491
- /* @__PURE__ */ jsx(
10492
- IconButton,
10493
- {
10494
- type: "button",
10495
- size: "small",
10496
- onClick: editing ? onSubmit : () => {
10497
- setEditing(true);
10498
- },
10499
- disabled: isPending,
10500
- children: editing ? /* @__PURE__ */ jsx(Check, {}) : /* @__PURE__ */ jsx(PencilSquare, {})
10501
- }
10502
- )
10503
- ] }) }) });
10504
- };
10505
- const StackedModalTrigger$1 = ({
10506
- type,
10507
- setModalContent
10508
- }) => {
10509
- const { setIsOpen } = useStackedModal();
10510
- const onClick = useCallback(() => {
10511
- setModalContent(type);
10512
- setIsOpen(STACKED_MODAL_ID, true);
10513
- }, [setModalContent, setIsOpen, type]);
10514
- return /* @__PURE__ */ jsx(StackedFocusModal.Trigger, { asChild: true, children: /* @__PURE__ */ jsx(DropdownMenu.Item, { onClick, children: type === "add-items" ? "Add items" : "Add custom item" }) });
10515
- };
10516
- const VARIANT_PREFIX = "items";
10517
- const LIMIT = 50;
10518
- const ExistingItemsForm = ({ orderId, items }) => {
10519
- const { setIsOpen } = useStackedModal();
10520
- const [rowSelection, setRowSelection] = useState(
10521
- items.reduce((acc, item) => {
10522
- acc[item.variant_id] = true;
10523
- return acc;
10524
- }, {})
10525
- );
10526
- useEffect(() => {
10527
- setRowSelection(
10528
- items.reduce((acc, item) => {
10529
- if (item.variant_id) {
10530
- acc[item.variant_id] = true;
10531
- }
10532
- return acc;
10533
- }, {})
10534
- );
10535
- }, [items]);
10536
- const { q, order, offset } = useQueryParams(
10537
- ["q", "order", "offset"],
10538
- VARIANT_PREFIX
10539
- );
10540
- const { variants, count, isPending, isError, error } = useProductVariants(
10541
- {
10542
- q,
10543
- order,
10544
- offset: offset ? parseInt(offset) : void 0,
10545
- limit: LIMIT
10546
- },
10547
- {
10548
- placeholderData: keepPreviousData
10549
- }
10550
- );
10551
- const columns = useColumns();
10552
- const { mutateAsync } = useDraftOrderAddItems(orderId);
10553
- const onSubmit = async () => {
10554
- const ids = Object.keys(rowSelection).filter(
10555
- (id) => !items.find((i) => i.variant_id === id)
10556
- );
10557
- await mutateAsync(
10558
- {
10559
- items: ids.map((id) => ({
10560
- variant_id: id,
10561
- quantity: 1
10562
- }))
10563
- },
10564
- {
10565
- onSuccess: () => {
10566
- setRowSelection({});
10567
- setIsOpen(STACKED_MODAL_ID, false);
10568
- },
10569
- onError: (e) => {
10570
- toast.error(e.message);
10571
- }
10572
- }
10573
- );
10574
- };
10575
- if (isError) {
10576
- throw error;
10577
- }
10578
- return /* @__PURE__ */ jsxs(
10579
- StackedFocusModal.Content,
10580
- {
10581
- onOpenAutoFocus: (e) => {
10582
- e.preventDefault();
10583
- const searchInput = document.querySelector(
10584
- "[data-modal-id='modal-search-input']"
10585
- );
10586
- if (searchInput) {
10587
- searchInput.focus();
10588
- }
10589
- },
10590
- children: [
10591
- /* @__PURE__ */ jsxs(StackedFocusModal.Header, { children: [
10592
- /* @__PURE__ */ jsx(StackedFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Product Variants" }) }),
10593
- /* @__PURE__ */ jsx(StackedFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Choose product variants to add to the order." }) })
10594
- ] }),
10595
- /* @__PURE__ */ jsx(StackedFocusModal.Body, { className: "flex-1 overflow-hidden", children: /* @__PURE__ */ jsx(
10596
- DataTable,
10597
- {
10598
- data: variants,
10599
- columns,
10600
- isLoading: isPending,
10601
- getRowId: (row) => row.id,
10602
- rowCount: count,
10603
- prefix: VARIANT_PREFIX,
10604
- layout: "fill",
10605
- rowSelection: {
10606
- state: rowSelection,
10607
- onRowSelectionChange: setRowSelection,
10608
- enableRowSelection: (row) => {
10609
- return !items.find((i) => i.variant_id === row.original.id);
10610
- }
10611
- },
10612
- autoFocusSearch: true
10613
- }
10614
- ) }),
10615
- /* @__PURE__ */ jsx(StackedFocusModal.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
10616
- /* @__PURE__ */ jsx(StackedFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
10617
- /* @__PURE__ */ jsx(Button, { size: "small", type: "button", onClick: onSubmit, children: "Update items" })
10618
- ] }) })
10619
- ]
10620
- }
10621
- );
10622
- };
10623
- const columnHelper = createDataTableColumnHelper();
10624
- const useColumns = () => {
10625
- return useMemo(() => {
10626
- return [
10627
- columnHelper.select(),
10628
- columnHelper.accessor("product.title", {
10629
- header: "Product",
10630
- cell: ({ row }) => {
10631
- var _a, _b, _c;
10632
- return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-2", children: [
10633
- /* @__PURE__ */ jsx(
10634
- Thumbnail,
10635
- {
10636
- thumbnail: (_a = row.original.product) == null ? void 0 : _a.thumbnail,
10637
- alt: (_b = row.original.product) == null ? void 0 : _b.title
10638
- }
10639
- ),
10640
- /* @__PURE__ */ jsx("span", { children: (_c = row.original.product) == null ? void 0 : _c.title })
10641
- ] });
10642
- },
10643
- enableSorting: true
10644
- }),
10645
- columnHelper.accessor("title", {
10646
- header: "Variant",
10647
- enableSorting: true
10648
- }),
10649
- columnHelper.accessor("sku", {
10650
- header: "SKU",
10651
- cell: ({ getValue }) => {
10652
- return getValue() ?? "-";
10653
- },
10654
- enableSorting: true
10655
- }),
10656
- columnHelper.accessor("updated_at", {
10657
- header: "Updated",
10658
- cell: ({ getValue }) => {
10659
- return /* @__PURE__ */ jsx(
10660
- Tooltip,
10661
- {
10662
- content: getFullDate({ date: getValue(), includeTime: true }),
10663
- children: /* @__PURE__ */ jsx("span", { children: getFullDate({ date: getValue() }) })
10664
- }
10665
- );
10666
- },
10667
- enableSorting: true,
10668
- sortAscLabel: "Oldest first",
10669
- sortDescLabel: "Newest first"
10670
- }),
10671
- columnHelper.accessor("created_at", {
10672
- header: "Created",
10673
- cell: ({ getValue }) => {
10674
- return /* @__PURE__ */ jsx(
10675
- Tooltip,
10676
- {
10677
- content: getFullDate({ date: getValue(), includeTime: true }),
10678
- children: /* @__PURE__ */ jsx("span", { children: getFullDate({ date: getValue() }) })
10679
- }
10680
- );
10681
- },
10682
- enableSorting: true,
10683
- sortAscLabel: "Oldest first",
10684
- sortDescLabel: "Newest first"
10685
- })
10686
- ];
10687
- }, []);
10688
- };
10689
- const CustomItemForm = ({ orderId, currencyCode }) => {
10690
- const { setIsOpen } = useStackedModal();
10691
- const { mutateAsync: addItems } = useDraftOrderAddItems(orderId);
10692
- const form = useForm({
10693
- defaultValues: {
10694
- title: "",
10695
- quantity: 1,
10696
- unit_price: ""
10697
- },
10698
- resolver: zodResolver(customItemSchema)
10699
- });
10700
- const onSubmit = form.handleSubmit(async (data) => {
10701
- await addItems(
10702
- {
10703
- items: [
10704
- {
10705
- title: data.title,
10706
- quantity: data.quantity,
10707
- unit_price: convertNumber(data.unit_price)
10708
- }
10709
- ]
10710
- },
10711
- {
10712
- onSuccess: () => {
10713
- setIsOpen(STACKED_MODAL_ID, false);
10714
- },
10715
- onError: (e) => {
10716
- toast.error(e.message);
10717
- }
10718
- }
10719
- );
9939
+ const { fields, insert, remove } = useFieldArray({
9940
+ control: form.control,
9941
+ name: "metadata"
10720
9942
  });
10721
- return /* @__PURE__ */ jsx(Form$2, { ...form, children: /* @__PURE__ */ jsx(KeyboundForm, { onSubmit, children: /* @__PURE__ */ jsxs(StackedFocusModal.Content, { children: [
10722
- /* @__PURE__ */ jsx(StackedFocusModal.Header, {}),
10723
- /* @__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: [
10724
- /* @__PURE__ */ jsxs("div", { children: [
10725
- /* @__PURE__ */ jsx(StackedFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Add custom item" }) }),
10726
- /* @__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." }) })
10727
- ] }),
10728
- /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
10729
- /* @__PURE__ */ jsx(
10730
- Form$2.Field,
10731
- {
10732
- control: form.control,
10733
- name: "title",
10734
- render: ({ field }) => /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
10735
- /* @__PURE__ */ jsxs("div", { children: [
10736
- /* @__PURE__ */ jsx(Form$2.Label, { children: "Title" }),
10737
- /* @__PURE__ */ jsx(Form$2.Hint, { children: "Enter the title of the item" })
10738
- ] }),
10739
- /* @__PURE__ */ jsxs("div", { children: [
10740
- /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(Input, { ...field }) }),
10741
- /* @__PURE__ */ jsx(Form$2.ErrorMessage, {})
10742
- ] })
10743
- ] }) })
10744
- }
10745
- ),
10746
- /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
10747
- /* @__PURE__ */ jsx(
10748
- Form$2.Field,
10749
- {
10750
- control: form.control,
10751
- name: "unit_price",
10752
- render: ({ field: { onChange, ...field } }) => /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
10753
- /* @__PURE__ */ jsxs("div", { children: [
10754
- /* @__PURE__ */ jsx(Form$2.Label, { children: "Unit price" }),
10755
- /* @__PURE__ */ jsx(Form$2.Hint, { children: "Enter the unit price of the item" })
9943
+ function deleteRow(index) {
9944
+ remove(index);
9945
+ if (fields.length === 1) {
9946
+ insert(0, {
9947
+ key: "",
9948
+ value: "",
9949
+ disabled: false
9950
+ });
9951
+ }
9952
+ }
9953
+ function insertRow(index, position) {
9954
+ insert(index + (position === "above" ? 0 : 1), {
9955
+ key: "",
9956
+ value: "",
9957
+ disabled: false
9958
+ });
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" }) })
10756
9971
  ] }),
10757
- /* @__PURE__ */ jsxs("div", { children: [
10758
- /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
10759
- CurrencyInput,
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,
10760
9983
  {
10761
- symbol: getNativeSymbol(currencyCode),
10762
- code: currencyCode,
10763
- onValueChange: (_value, _name, values) => onChange(values == null ? void 0 : values.value),
10764
- ...field
10765
- }
10766
- ) }),
10767
- /* @__PURE__ */ jsx(Form$2.ErrorMessage, {})
10768
- ] })
10769
- ] }) })
10770
- }
10771
- ),
10772
- /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
10773
- /* @__PURE__ */ jsx(
10774
- Form$2.Field,
10775
- {
10776
- control: form.control,
10777
- name: "quantity",
10778
- render: ({ field }) => /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
10779
- /* @__PURE__ */ jsxs("div", { children: [
10780
- /* @__PURE__ */ jsx(Form$2.Label, { children: "Quantity" }),
10781
- /* @__PURE__ */ jsx(Form$2.Hint, { children: "Enter the quantity of the item" })
10782
- ] }),
10783
- /* @__PURE__ */ jsxs("div", { className: "w-full flex-1", children: [
10784
- /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx("div", { className: "w-full flex-1", children: /* @__PURE__ */ jsx(NumberInput, { ...field, className: "w-full" }) }) }),
10785
- /* @__PURE__ */ jsx(Form$2.ErrorMessage, {})
10786
- ] })
10787
- ] }) })
10788
- }
10789
- )
10790
- ] }) }) }),
10791
- /* @__PURE__ */ jsx(StackedFocusModal.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
10792
- /* @__PURE__ */ jsx(StackedFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
10793
- /* @__PURE__ */ jsx(Button, { size: "small", type: "button", onClick: onSubmit, children: "Add item" })
10794
- ] }) })
10795
- ] }) }) });
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: [
10035
+ /* @__PURE__ */ jsx(
10036
+ DropdownMenu.Trigger,
10037
+ {
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, {}) })
10047
+ }
10048
+ ),
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
+ ] })
10085
+ ] })
10086
+ ] })
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
+ ) });
10796
10101
  };
10797
- const customItemSchema = objectType({
10798
- title: stringType().min(1),
10799
- quantity: numberType(),
10800
- unit_price: unionType([numberType(), stringType()])
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
10112
+ )
10113
+ }
10114
+ );
10801
10115
  });
10802
- const CustomItems = () => {
10803
- return /* @__PURE__ */ jsxs(RouteDrawer, { children: [
10804
- /* @__PURE__ */ jsx(RouteDrawer.Header, { children: /* @__PURE__ */ jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Edit Custom Items" }) }) }),
10805
- /* @__PURE__ */ jsx(CustomItemsForm, {})
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
+ ] }) })
10806
10124
  ] });
10807
10125
  };
10808
- const CustomItemsForm = () => {
10809
- const form = useForm({
10810
- resolver: zodResolver(schema$3)
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
+ ];
10136
+ }
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
+ };
10811
10154
  });
10812
- return /* @__PURE__ */ jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxs(KeyboundForm, { className: "flex flex-1 flex-col", children: [
10813
- /* @__PURE__ */ jsx(RouteDrawer.Body, {}),
10814
- /* @__PURE__ */ jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
10815
- /* @__PURE__ */ jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
10816
- /* @__PURE__ */ jsx(Button, { size: "small", type: "submit", children: "Save" })
10817
- ] }) })
10818
- ] }) });
10819
- };
10820
- const schema$3 = objectType({
10821
- email: stringType().email()
10822
- });
10823
- const InlineTip = forwardRef(
10824
- ({ variant = "tip", label, className, children, ...props }, ref) => {
10825
- const labelValue = label || (variant === "warning" ? "Warning" : "Tip");
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) {
10168
+ return;
10169
+ }
10170
+ if (disabled) {
10171
+ update[key] = value;
10172
+ return;
10173
+ }
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 NumberInput = forwardRef(
10200
+ ({
10201
+ value,
10202
+ onChange,
10203
+ size = "base",
10204
+ min = 0,
10205
+ max = 100,
10206
+ step = 1,
10207
+ className,
10208
+ disabled,
10209
+ ...props
10210
+ }, ref) => {
10211
+ const handleChange = (event) => {
10212
+ const newValue = event.target.value === "" ? min : Number(event.target.value);
10213
+ if (!isNaN(newValue) && (max === void 0 || newValue <= max) && (min === void 0 || newValue >= min)) {
10214
+ onChange(newValue);
10215
+ }
10216
+ };
10217
+ const handleIncrement = () => {
10218
+ const newValue = value + step;
10219
+ if (max === void 0 || newValue <= max) {
10220
+ onChange(newValue);
10221
+ }
10222
+ };
10223
+ const handleDecrement = () => {
10224
+ const newValue = value - step;
10225
+ if (min === void 0 || newValue >= min) {
10226
+ onChange(newValue);
10227
+ }
10228
+ };
10826
10229
  return /* @__PURE__ */ jsxs(
10827
10230
  "div",
10828
10231
  {
10829
- ref,
10830
10232
  className: clx(
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",
10233
+ "inline-flex rounded-md bg-ui-bg-field shadow-borders-base overflow-hidden divide-x transition-fg",
10234
+ "[&:has(input:focus)]:shadow-borders-interactive-with-active",
10235
+ {
10236
+ "h-7": size === "small",
10237
+ "h-8": size === "base"
10238
+ },
10832
10239
  className
10833
10240
  ),
10834
- ...props,
10835
10241
  children: [
10836
10242
  /* @__PURE__ */ jsx(
10837
- "div",
10243
+ "input",
10838
10244
  {
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
- })
10245
+ ref,
10246
+ type: "number",
10247
+ value,
10248
+ onChange: handleChange,
10249
+ min,
10250
+ max,
10251
+ step,
10252
+ className: clx(
10253
+ "flex-1 px-2 py-1 bg-transparent txt-compact-small text-ui-fg-base outline-none [appearance:textfield]",
10254
+ "[&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none",
10255
+ "placeholder:text-ui-fg-muted"
10256
+ ),
10257
+ ...props
10258
+ }
10259
+ ),
10260
+ /* @__PURE__ */ jsxs(
10261
+ "button",
10262
+ {
10263
+ className: clx(
10264
+ "flex items-center justify-center outline-none transition-fg",
10265
+ "disabled:cursor-not-allowed disabled:text-ui-fg-muted",
10266
+ "focus:bg-ui-bg-field-component-hover",
10267
+ "hover:bg-ui-bg-field-component-hover",
10268
+ {
10269
+ "size-7": size === "small",
10270
+ "size-8": size === "base"
10271
+ }
10272
+ ),
10273
+ type: "button",
10274
+ onClick: handleDecrement,
10275
+ disabled: min !== void 0 && value <= min || disabled,
10276
+ children: [
10277
+ /* @__PURE__ */ jsx(Minus, {}),
10278
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: `Decrease by ${step}` })
10279
+ ]
10843
10280
  }
10844
10281
  ),
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
- ] })
10282
+ /* @__PURE__ */ jsxs(
10283
+ "button",
10284
+ {
10285
+ className: clx(
10286
+ "flex items-center justify-center outline-none transition-fg",
10287
+ "disabled:cursor-not-allowed disabled:text-ui-fg-muted",
10288
+ "focus:bg-ui-bg-field-hover",
10289
+ "hover:bg-ui-bg-field-hover",
10290
+ {
10291
+ "size-7": size === "small",
10292
+ "size-8": size === "base"
10293
+ }
10294
+ ),
10295
+ type: "button",
10296
+ onClick: handleIncrement,
10297
+ disabled: max !== void 0 && value >= max || disabled,
10298
+ children: [
10299
+ /* @__PURE__ */ jsx(Plus, {}),
10300
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: `Increase by ${step}` })
10301
+ ]
10302
+ }
10303
+ )
10853
10304
  ]
10854
10305
  }
10855
10306
  );
10856
10307
  }
10857
10308
  );
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 = () => {
10309
+ const PRODUCT_VARIANTS_QUERY_KEY = "product-variants";
10310
+ const productVariantsQueryKeys = {
10311
+ list: (query2) => [
10312
+ PRODUCT_VARIANTS_QUERY_KEY,
10313
+ query2 ? query2 : void 0
10314
+ ]
10315
+ };
10316
+ const useProductVariants = (query2, options) => {
10317
+ const { data, ...rest } = useQuery({
10318
+ queryKey: productVariantsQueryKeys.list(query2),
10319
+ queryFn: async () => await sdk.admin.productVariant.list(query2),
10320
+ ...options
10321
+ });
10322
+ return { ...data, ...rest };
10323
+ };
10324
+ const useCancelOrderEdit = ({ preview }) => {
10325
+ const { mutateAsync: cancelOrderEdit } = useDraftOrderCancelEdit(preview == null ? void 0 : preview.id);
10326
+ const onCancel = useCallback(async () => {
10327
+ if (!preview) {
10328
+ return true;
10329
+ }
10330
+ let res = false;
10331
+ await cancelOrderEdit(void 0, {
10332
+ onError: (e) => {
10333
+ toast.error(e.message);
10334
+ },
10335
+ onSuccess: () => {
10336
+ res = true;
10337
+ }
10338
+ });
10339
+ return res;
10340
+ }, [preview, cancelOrderEdit]);
10341
+ return { onCancel };
10342
+ };
10343
+ let IS_REQUEST_RUNNING = false;
10344
+ const useInitiateOrderEdit = ({
10345
+ preview
10346
+ }) => {
10347
+ const navigate = useNavigate();
10348
+ const { mutateAsync } = useDraftOrderBeginEdit(preview == null ? void 0 : preview.id);
10349
+ useEffect(() => {
10350
+ async function run() {
10351
+ if (IS_REQUEST_RUNNING || !preview) {
10352
+ return;
10353
+ }
10354
+ if (preview.order_change) {
10355
+ return;
10356
+ }
10357
+ IS_REQUEST_RUNNING = true;
10358
+ await mutateAsync(void 0, {
10359
+ onError: (e) => {
10360
+ toast.error(e.message);
10361
+ navigate(`/draft-orders/${preview.id}`, { replace: true });
10362
+ return;
10363
+ }
10364
+ });
10365
+ IS_REQUEST_RUNNING = false;
10366
+ }
10367
+ run();
10368
+ }, [preview, navigate, mutateAsync]);
10369
+ };
10370
+ function convertNumber(value) {
10371
+ return typeof value === "string" ? Number(value.replace(",", ".")) : value;
10372
+ }
10373
+ const STACKED_MODAL_ID = "items_stacked_modal";
10374
+ const Items = () => {
10868
10375
  const { id } = useParams();
10869
- const { order, isPending, isError, error } = useOrder(id, {
10870
- fields: "metadata"
10376
+ const {
10377
+ order: preview,
10378
+ isPending: isPreviewPending,
10379
+ isError: isPreviewError,
10380
+ error: previewError
10381
+ } = useOrderPreview(id, void 0, {
10382
+ placeholderData: keepPreviousData
10871
10383
  });
10384
+ useInitiateOrderEdit({ preview });
10385
+ const { draft_order, isPending, isError, error } = useDraftOrder(
10386
+ id,
10387
+ {
10388
+ fields: "currency_code"
10389
+ },
10390
+ {
10391
+ enabled: !!id
10392
+ }
10393
+ );
10394
+ const { onCancel } = useCancelOrderEdit({ preview });
10872
10395
  if (isError) {
10873
10396
  throw error;
10874
10397
  }
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
- ] });
10398
+ if (isPreviewError) {
10399
+ throw previewError;
10400
+ }
10401
+ const ready = !!preview && !isPreviewPending && !!draft_order && !isPending;
10402
+ return /* @__PURE__ */ jsx(RouteFocusModal, { onClose: onCancel, children: ready ? /* @__PURE__ */ jsx(ItemsForm, { preview, currencyCode: draft_order.currency_code }) : /* @__PURE__ */ jsxs("div", { children: [
10403
+ /* @__PURE__ */ jsx(RouteFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Edit Items" }) }),
10404
+ /* @__PURE__ */ jsx(RouteFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Loading data for the draft order, please wait..." }) })
10405
+ ] }) });
10883
10406
  };
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 }) => {
10407
+ const ItemsForm = ({ preview, currencyCode }) => {
10408
+ var _a;
10409
+ const [isSubmitting, setIsSubmitting] = useState(false);
10410
+ const [modalContent, setModalContent] = useState(
10411
+ null
10412
+ );
10887
10413
  const { handleSuccess } = useRouteModal();
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
10414
+ const { searchValue, onSearchValueChange, query: query2 } = useDebouncedSearch();
10415
+ const { mutateAsync: confirmOrderEdit } = useDraftOrderConfirmEdit(preview.id);
10416
+ const { mutateAsync: requestOrderEdit } = useDraftOrderRequestEdit(preview.id);
10417
+ const itemCount = ((_a = preview.items) == null ? void 0 : _a.reduce((acc, item) => acc + item.quantity, 0)) || 0;
10418
+ const matches = useMemo(() => {
10419
+ return matchSorter(preview.items, query2, {
10420
+ keys: ["product_title", "variant_title", "variant_sku", "title"]
10421
+ });
10422
+ }, [preview.items, query2]);
10423
+ const onSubmit = async () => {
10424
+ setIsSubmitting(true);
10425
+ let requestSucceeded = false;
10426
+ await requestOrderEdit(void 0, {
10427
+ onError: (e) => {
10428
+ toast.error(`Failed to request order edit: ${e.message}`);
10901
10429
  },
10902
- {
10903
- onSuccess: () => {
10904
- toast.success("Metadata updated");
10905
- handleSuccess();
10906
- },
10907
- onError: (error) => {
10908
- toast.error(error.message);
10909
- }
10430
+ onSuccess: () => {
10431
+ requestSucceeded = true;
10910
10432
  }
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
- });
10433
+ });
10434
+ if (!requestSucceeded) {
10435
+ setIsSubmitting(false);
10436
+ return;
10925
10437
  }
10926
- }
10927
- function insertRow(index, position) {
10928
- insert(index + (position === "above" ? 0 : 1), {
10929
- key: "",
10930
- value: "",
10931
- disabled: false
10438
+ await confirmOrderEdit(void 0, {
10439
+ onError: (e) => {
10440
+ toast.error(`Failed to confirm order edit: ${e.message}`);
10441
+ },
10442
+ onSuccess: () => {
10443
+ handleSuccess();
10444
+ },
10445
+ onSettled: () => {
10446
+ setIsSubmitting(false);
10447
+ }
10932
10448
  });
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" }) })
10449
+ };
10450
+ const onKeyDown = useCallback(
10451
+ (e) => {
10452
+ if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) {
10453
+ if (modalContent || isSubmitting) {
10454
+ return;
10455
+ }
10456
+ onSubmit();
10457
+ }
10458
+ },
10459
+ [modalContent, isSubmitting, onSubmit]
10460
+ );
10461
+ useEffect(() => {
10462
+ document.addEventListener("keydown", onKeyDown);
10463
+ return () => {
10464
+ document.removeEventListener("keydown", onKeyDown);
10465
+ };
10466
+ }, [onKeyDown]);
10467
+ return /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-col overflow-hidden", children: [
10468
+ /* @__PURE__ */ jsx(RouteFocusModal.Header, {}),
10469
+ /* @__PURE__ */ jsx(RouteFocusModal.Body, { className: "flex flex-1 flex-col overflow-hidden", children: /* @__PURE__ */ jsxs(
10470
+ StackedFocusModal,
10471
+ {
10472
+ id: STACKED_MODAL_ID,
10473
+ onOpenChangeCallback: (open) => {
10474
+ if (!open) {
10475
+ setModalContent(null);
10476
+ }
10477
+ },
10478
+ children: [
10479
+ /* @__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: [
10480
+ /* @__PURE__ */ jsxs("div", { children: [
10481
+ /* @__PURE__ */ jsx(RouteFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Edit Items" }) }),
10482
+ /* @__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" }) })
10945
10483
  ] }),
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: [
10484
+ /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
10485
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-y-6", children: [
10486
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 items-center gap-3", children: [
10487
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
10488
+ /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: "Items" }),
10489
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Choose items from the product catalog." })
10490
+ ] }),
10491
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
10492
+ /* @__PURE__ */ jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsx(
10493
+ Input,
10494
+ {
10495
+ type: "search",
10496
+ placeholder: "Search items",
10497
+ value: searchValue,
10498
+ onChange: (e) => onSearchValueChange(e.target.value)
10499
+ }
10500
+ ) }),
10501
+ /* @__PURE__ */ jsxs(DropdownMenu, { children: [
10502
+ /* @__PURE__ */ jsx(DropdownMenu.Trigger, { asChild: true, children: /* @__PURE__ */ jsx(IconButton, { type: "button", children: /* @__PURE__ */ jsx(Plus, {}) }) }),
10503
+ /* @__PURE__ */ jsxs(DropdownMenu.Content, { children: [
11009
10504
  /* @__PURE__ */ jsx(
11010
- DropdownMenu.Trigger,
10505
+ StackedModalTrigger$1,
11011
10506
  {
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, {}) })
10507
+ type: "add-items",
10508
+ setModalContent
11021
10509
  }
11022
10510
  ),
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
- ] })
10511
+ /* @__PURE__ */ jsx(
10512
+ StackedModalTrigger$1,
10513
+ {
10514
+ type: "add-custom-item",
10515
+ setModalContent
10516
+ }
10517
+ )
11059
10518
  ] })
11060
10519
  ] })
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
- ]
11073
- }
11074
- ) });
11075
- };
11076
- const GridInput = forwardRef(({ className, ...props }, ref) => {
11077
- return /* @__PURE__ */ jsx(
11078
- "input",
11079
- {
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
10520
+ ] })
10521
+ ] }),
10522
+ /* @__PURE__ */ jsxs("div", { className: "bg-ui-bg-subtle shadow-elevation-card-rest rounded-xl", children: [
10523
+ /* @__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: [
10524
+ /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: "Item" }) }),
10525
+ /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: "Quantity" }) }),
10526
+ /* @__PURE__ */ jsx("div", { className: "text-right", children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: "Price" }) }),
10527
+ /* @__PURE__ */ jsx("div", {})
10528
+ ] }) }),
10529
+ /* @__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: [
10530
+ /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: "There are no items in this order" }),
10531
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Add items to the order to get started." })
10532
+ ] }) : matches.length > 0 ? matches == null ? void 0 : matches.map((item) => /* @__PURE__ */ jsx(
10533
+ Item,
10534
+ {
10535
+ item,
10536
+ preview,
10537
+ currencyCode
10538
+ },
10539
+ item.id
10540
+ )) : /* @__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: [
10541
+ /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: "No items found" }),
10542
+ /* @__PURE__ */ jsxs(Text, { size: "small", className: "text-ui-fg-subtle", children: [
10543
+ 'No items found for "',
10544
+ query2,
10545
+ '".'
10546
+ ] })
10547
+ ] }) })
10548
+ ] })
10549
+ ] }),
10550
+ /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
10551
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-[1fr_0.5fr_0.5fr] gap-3", children: [
10552
+ /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: "Subtotal" }) }),
10553
+ /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsxs(
10554
+ Text,
10555
+ {
10556
+ size: "small",
10557
+ leading: "compact",
10558
+ className: "text-ui-fg-subtle",
10559
+ children: [
10560
+ itemCount,
10561
+ " ",
10562
+ itemCount === 1 ? "item" : "items"
10563
+ ]
10564
+ }
10565
+ ) }),
10566
+ /* @__PURE__ */ jsx("div", { className: "text-right", children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: getStylizedAmount(preview.item_subtotal, currencyCode) }) })
10567
+ ] })
10568
+ ] }) }),
10569
+ modalContent && (modalContent === "add-items" ? /* @__PURE__ */ jsx(ExistingItemsForm, { orderId: preview.id, items: preview.items }) : modalContent === "add-custom-item" ? /* @__PURE__ */ jsx(
10570
+ CustomItemForm,
10571
+ {
10572
+ orderId: preview.id,
10573
+ currencyCode
10574
+ }
10575
+ ) : null)
10576
+ ]
10577
+ }
10578
+ ) }),
10579
+ /* @__PURE__ */ jsx(RouteFocusModal.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
10580
+ /* @__PURE__ */ jsx(RouteFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
10581
+ /* @__PURE__ */ jsx(
10582
+ Button,
10583
+ {
10584
+ size: "small",
10585
+ type: "button",
10586
+ onClick: onSubmit,
10587
+ isLoading: isSubmitting,
10588
+ children: "Save"
10589
+ }
11086
10590
  )
11087
- }
11088
- );
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
10591
  ] }) })
11098
10592
  ] });
11099
10593
  };
11100
- const EDITABLE_TYPES = ["string", "number", "boolean"];
11101
- function getDefaultValues(metadata) {
11102
- if (!metadata || !Object.keys(metadata).length) {
11103
- return [
11104
- {
11105
- key: "",
11106
- value: "",
11107
- disabled: false
11108
- }
11109
- ];
10594
+ const Item = ({ item, preview, currencyCode }) => {
10595
+ if (item.variant_id) {
10596
+ return /* @__PURE__ */ jsx(VariantItem, { item, preview, currencyCode });
11110
10597
  }
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
- };
10598
+ return /* @__PURE__ */ jsx(CustomItem, { item, preview, currencyCode });
10599
+ };
10600
+ const VariantItem = ({ item, preview, currencyCode }) => {
10601
+ const [editing, setEditing] = useState(false);
10602
+ const form = useForm({
10603
+ defaultValues: {
10604
+ quantity: item.quantity,
10605
+ unit_price: item.unit_price
10606
+ },
10607
+ resolver: zodResolver(variantItemSchema)
11128
10608
  });
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) {
10609
+ const actionId = useMemo(() => {
10610
+ var _a, _b;
10611
+ return (_b = (_a = item.actions) == null ? void 0 : _a.find((a) => a.action === "ITEM_ADD")) == null ? void 0 : _b.id;
10612
+ }, [item]);
10613
+ const { mutateAsync: updateActionItem, isPending: isUpdatingActionItem } = useDraftOrderUpdateActionItem(preview.id);
10614
+ const { mutateAsync: updateOriginalItem, isPending: isUpdatingOriginalItem } = useDraftOrderUpdateItem(preview.id);
10615
+ const isPending = isUpdatingActionItem || isUpdatingOriginalItem;
10616
+ const onSubmit = form.handleSubmit(async (data) => {
10617
+ if (convertNumber(data.unit_price) === item.unit_price && data.quantity === item.quantity) {
10618
+ setEditing(false);
11142
10619
  return;
11143
10620
  }
11144
- if (disabled) {
11145
- update[key] = value;
10621
+ if (!actionId) {
10622
+ await updateOriginalItem(
10623
+ {
10624
+ item_id: item.id,
10625
+ quantity: data.quantity,
10626
+ unit_price: convertNumber(data.unit_price)
10627
+ },
10628
+ {
10629
+ onSuccess: () => {
10630
+ setEditing(false);
10631
+ },
10632
+ onError: (e) => {
10633
+ toast.error(e.message);
10634
+ }
10635
+ }
10636
+ );
11146
10637
  return;
11147
10638
  }
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;
10639
+ await updateActionItem(
10640
+ {
10641
+ action_id: actionId,
10642
+ quantity: data.quantity,
10643
+ unit_price: convertNumber(data.unit_price)
10644
+ },
10645
+ {
10646
+ onSuccess: () => {
10647
+ setEditing(false);
10648
+ },
10649
+ onError: (e) => {
10650
+ toast.error(e.message);
10651
+ }
11160
10652
  }
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)
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
- ]
11184
- };
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
10653
+ );
11190
10654
  });
11191
- return { ...data, ...rest };
11192
- };
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
10655
+ 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: [
10656
+ /* @__PURE__ */ jsxs("div", { className: "flex w-full items-center gap-x-3", children: [
10657
+ /* @__PURE__ */ jsx(
10658
+ Thumbnail,
10659
+ {
10660
+ thumbnail: item.thumbnail,
10661
+ alt: item.product_title ?? void 0
10662
+ }
10663
+ ),
10664
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
10665
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-1", children: [
10666
+ /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: item.product_title }),
10667
+ /* @__PURE__ */ jsxs(
10668
+ Text,
10669
+ {
10670
+ size: "small",
10671
+ leading: "compact",
10672
+ className: "text-ui-fg-subtle",
10673
+ children: [
10674
+ "(",
10675
+ item.variant_title,
10676
+ ")"
10677
+ ]
10678
+ }
10679
+ )
10680
+ ] }),
10681
+ /* @__PURE__ */ jsx(
10682
+ Text,
10683
+ {
10684
+ size: "small",
10685
+ leading: "compact",
10686
+ className: "text-ui-fg-subtle",
10687
+ children: item.variant_sku
10688
+ }
10689
+ )
10690
+ ] })
10691
+ ] }),
10692
+ editing ? /* @__PURE__ */ jsx("div", { className: "w-full flex-1", children: /* @__PURE__ */ jsx(
10693
+ Form$2.Field,
10694
+ {
10695
+ control: form.control,
10696
+ name: "quantity",
10697
+ render: ({ field }) => {
10698
+ return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(NumberInput, { ...field }) }) });
10699
+ }
10700
+ }
10701
+ ) }) : /* @__PURE__ */ jsx("div", { className: "w-full flex-1", children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: item.quantity }) }),
10702
+ editing ? /* @__PURE__ */ jsx("div", { className: "w-full flex-1", children: /* @__PURE__ */ jsx(
10703
+ Form$2.Field,
10704
+ {
10705
+ control: form.control,
10706
+ name: "unit_price",
10707
+ render: ({ field: { onChange, ...field } }) => {
10708
+ return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
10709
+ CurrencyInput,
10710
+ {
10711
+ ...field,
10712
+ symbol: getNativeSymbol(currencyCode),
10713
+ code: currencyCode,
10714
+ onValueChange: (_value, _name, values) => onChange(values == null ? void 0 : values.value)
10715
+ }
10716
+ ) }) });
10717
+ }
10718
+ }
10719
+ ) }) : /* @__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) }) }),
10720
+ /* @__PURE__ */ jsx(
10721
+ IconButton,
10722
+ {
10723
+ type: "button",
10724
+ size: "small",
10725
+ onClick: editing ? onSubmit : () => {
10726
+ setEditing(true);
10727
+ },
10728
+ disabled: isPending,
10729
+ children: editing ? /* @__PURE__ */ jsx(Check, {}) : /* @__PURE__ */ jsx(PencilSquare, {})
10730
+ }
10731
+ )
10732
+ ] }) }) });
10733
+ };
10734
+ const variantItemSchema = objectType({
10735
+ quantity: numberType(),
10736
+ unit_price: unionType([numberType(), stringType()])
10737
+ });
10738
+ const CustomItem = ({ item, preview, currencyCode }) => {
10739
+ const [editing, setEditing] = useState(false);
10740
+ const { quantity, unit_price, title } = item;
10741
+ const form = useForm({
10742
+ defaultValues: {
10743
+ title,
10744
+ quantity,
10745
+ unit_price
11221
10746
  },
11222
- {
11223
- enabled: !!promoIds.length
10747
+ resolver: zodResolver(customItemSchema)
10748
+ });
10749
+ useEffect(() => {
10750
+ form.reset({
10751
+ title,
10752
+ quantity,
10753
+ unit_price
10754
+ });
10755
+ }, [form, title, quantity, unit_price]);
10756
+ const actionId = useMemo(() => {
10757
+ var _a, _b;
10758
+ return (_b = (_a = item.actions) == null ? void 0 : _a.find((a) => a.action === "ITEM_ADD")) == null ? void 0 : _b.id;
10759
+ }, [item]);
10760
+ const { mutateAsync: updateActionItem, isPending: isUpdatingActionItem } = useDraftOrderUpdateActionItem(preview.id);
10761
+ const { mutateAsync: removeActionItem, isPending: isRemovingActionItem } = useDraftOrderRemoveActionItem(preview.id);
10762
+ const { mutateAsync: updateOriginalItem, isPending: isUpdatingOriginalItem } = useDraftOrderUpdateItem(preview.id);
10763
+ const isPending = isUpdatingActionItem || isUpdatingOriginalItem;
10764
+ const onSubmit = form.handleSubmit(async (data) => {
10765
+ if (convertNumber(data.unit_price) === item.unit_price && data.quantity === item.quantity && data.title === item.title) {
10766
+ setEditing(false);
10767
+ return;
11224
10768
  }
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
10769
+ if (!actionId) {
10770
+ await updateOriginalItem(
10771
+ {
10772
+ item_id: item.id,
10773
+ quantity: data.quantity,
10774
+ unit_price: convertNumber(data.unit_price)
10775
+ },
10776
+ {
10777
+ onSuccess: () => {
10778
+ setEditing(false);
10779
+ },
10780
+ onError: (e) => {
10781
+ toast.error(e.message);
10782
+ }
11233
10783
  }
11234
- });
11235
- },
11236
- getOptions: (data) => {
11237
- return data.promotions.map((promotion) => ({
11238
- label: promotion.code,
11239
- value: promotion.code
11240
- }));
10784
+ );
10785
+ return;
11241
10786
  }
11242
- });
11243
- const add = async (value) => {
11244
- if (!value) {
10787
+ if (data.quantity === 0) {
10788
+ await removeActionItem(actionId, {
10789
+ onSuccess: () => {
10790
+ setEditing(false);
10791
+ },
10792
+ onError: (e) => {
10793
+ toast.error(e.message);
10794
+ }
10795
+ });
11245
10796
  return;
11246
10797
  }
11247
- addPromotions(
10798
+ await updateActionItem(
11248
10799
  {
11249
- promo_codes: [value]
10800
+ action_id: actionId,
10801
+ quantity: data.quantity,
10802
+ unit_price: convertNumber(data.unit_price)
11250
10803
  },
11251
10804
  {
10805
+ onSuccess: () => {
10806
+ setEditing(false);
10807
+ },
11252
10808
  onError: (e) => {
11253
10809
  toast.error(e.message);
11254
- comboboxData.onSearchValueChange("");
11255
- setComboboxValue("");
11256
- },
11257
- onSuccess: () => {
11258
- comboboxData.onSearchValueChange("");
11259
- setComboboxValue("");
11260
10810
  }
11261
10811
  }
11262
10812
  );
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
- )
11318
- ] }),
11319
- /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
11320
- /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-2", children: promotions == null ? void 0 : promotions.map((promotion) => /* @__PURE__ */ jsx(
11321
- PromotionItem,
11322
- {
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" }) }),
10813
+ });
10814
+ 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: [
10815
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-3", children: [
11332
10816
  /* @__PURE__ */ jsx(
11333
- Button,
10817
+ Thumbnail,
11334
10818
  {
11335
- size: "small",
11336
- type: "submit",
11337
- isLoading: isSubmitting || isAddingPromotions,
11338
- children: "Save"
10819
+ thumbnail: item.thumbnail,
10820
+ alt: item.title ?? void 0
11339
10821
  }
11340
- )
11341
- ] }) })
11342
- ] });
10822
+ ),
10823
+ editing ? /* @__PURE__ */ jsx(
10824
+ Form$2.Field,
10825
+ {
10826
+ control: form.control,
10827
+ name: "title",
10828
+ render: ({ field }) => {
10829
+ return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(Input, { ...field }) }) });
10830
+ }
10831
+ }
10832
+ ) : /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: item.title })
10833
+ ] }),
10834
+ editing ? /* @__PURE__ */ jsx(
10835
+ Form$2.Field,
10836
+ {
10837
+ control: form.control,
10838
+ name: "quantity",
10839
+ render: ({ field }) => {
10840
+ return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(NumberInput, { ...field }) }) });
10841
+ }
10842
+ }
10843
+ ) : /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: item.quantity }),
10844
+ editing ? /* @__PURE__ */ jsx(
10845
+ Form$2.Field,
10846
+ {
10847
+ control: form.control,
10848
+ name: "unit_price",
10849
+ render: ({ field: { onChange, ...field } }) => {
10850
+ return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
10851
+ CurrencyInput,
10852
+ {
10853
+ ...field,
10854
+ symbol: getNativeSymbol(currencyCode),
10855
+ code: currencyCode,
10856
+ onValueChange: (_value, _name, values) => onChange(values == null ? void 0 : values.value)
10857
+ }
10858
+ ) }) });
10859
+ }
10860
+ }
10861
+ ) : /* @__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) }) }),
10862
+ /* @__PURE__ */ jsx(
10863
+ IconButton,
10864
+ {
10865
+ type: "button",
10866
+ size: "small",
10867
+ onClick: editing ? onSubmit : () => {
10868
+ setEditing(true);
10869
+ },
10870
+ disabled: isPending,
10871
+ children: editing ? /* @__PURE__ */ jsx(Check, {}) : /* @__PURE__ */ jsx(PencilSquare, {})
10872
+ }
10873
+ )
10874
+ ] }) }) });
11343
10875
  };
11344
- const PromotionItem = ({
11345
- promotion,
11346
- orderId,
11347
- isLoading
10876
+ const StackedModalTrigger$1 = ({
10877
+ type,
10878
+ setModalContent
11348
10879
  }) => {
11349
- var _a;
11350
- const { mutateAsync: removePromotions, isPending } = useDraftOrderRemovePromotions(orderId);
11351
- const onRemove = async () => {
11352
- removePromotions(
10880
+ const { setIsOpen } = useStackedModal();
10881
+ const onClick = useCallback(() => {
10882
+ setModalContent(type);
10883
+ setIsOpen(STACKED_MODAL_ID, true);
10884
+ }, [setModalContent, setIsOpen, type]);
10885
+ return /* @__PURE__ */ jsx(StackedFocusModal.Trigger, { asChild: true, children: /* @__PURE__ */ jsx(DropdownMenu.Item, { onClick, children: type === "add-items" ? "Add items" : "Add custom item" }) });
10886
+ };
10887
+ const VARIANT_PREFIX = "items";
10888
+ const LIMIT = 50;
10889
+ const ExistingItemsForm = ({ orderId, items }) => {
10890
+ const { setIsOpen } = useStackedModal();
10891
+ const [rowSelection, setRowSelection] = useState(
10892
+ items.reduce((acc, item) => {
10893
+ acc[item.variant_id] = true;
10894
+ return acc;
10895
+ }, {})
10896
+ );
10897
+ useEffect(() => {
10898
+ setRowSelection(
10899
+ items.reduce((acc, item) => {
10900
+ if (item.variant_id) {
10901
+ acc[item.variant_id] = true;
10902
+ }
10903
+ return acc;
10904
+ }, {})
10905
+ );
10906
+ }, [items]);
10907
+ const { q, order, offset } = useQueryParams(
10908
+ ["q", "order", "offset"],
10909
+ VARIANT_PREFIX
10910
+ );
10911
+ const { variants, count, isPending, isError, error } = useProductVariants(
10912
+ {
10913
+ q,
10914
+ order,
10915
+ offset: offset ? parseInt(offset) : void 0,
10916
+ limit: LIMIT
10917
+ },
10918
+ {
10919
+ placeholderData: keepPreviousData
10920
+ }
10921
+ );
10922
+ const columns = useColumns();
10923
+ const { mutateAsync } = useDraftOrderAddItems(orderId);
10924
+ const onSubmit = async () => {
10925
+ const ids = Object.keys(rowSelection).filter(
10926
+ (id) => !items.find((i) => i.variant_id === id)
10927
+ );
10928
+ await mutateAsync(
11353
10929
  {
11354
- promo_codes: [promotion.code]
10930
+ items: ids.map((id) => ({
10931
+ variant_id: id,
10932
+ quantity: 1
10933
+ }))
11355
10934
  },
11356
10935
  {
10936
+ onSuccess: () => {
10937
+ setRowSelection({});
10938
+ setIsOpen(STACKED_MODAL_ID, false);
10939
+ },
11357
10940
  onError: (e) => {
11358
10941
  toast.error(e.message);
11359
10942
  }
11360
10943
  }
11361
10944
  );
11362
10945
  };
11363
- const displayValue = getDisplayValue(promotion);
10946
+ if (isError) {
10947
+ throw error;
10948
+ }
11364
10949
  return /* @__PURE__ */ jsxs(
11365
- "div",
10950
+ StackedFocusModal.Content,
11366
10951
  {
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
10952
+ onOpenAutoFocus: (e) => {
10953
+ e.preventDefault();
10954
+ const searchInput = document.querySelector(
10955
+ "[data-modal-id='modal-search-input']"
10956
+ );
10957
+ if (searchInput) {
10958
+ searchInput.focus();
11371
10959
  }
11372
- ),
10960
+ },
11373
10961
  children: [
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
- ] })
10962
+ /* @__PURE__ */ jsxs(StackedFocusModal.Header, { children: [
10963
+ /* @__PURE__ */ jsx(StackedFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Product Variants" }) }),
10964
+ /* @__PURE__ */ jsx(StackedFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Choose product variants to add to the order." }) })
11383
10965
  ] }),
11384
- /* @__PURE__ */ jsx(
11385
- IconButton,
10966
+ /* @__PURE__ */ jsx(StackedFocusModal.Body, { className: "flex-1 overflow-hidden", children: /* @__PURE__ */ jsx(
10967
+ DataTable,
11386
10968
  {
11387
- size: "small",
11388
- type: "button",
11389
- variant: "transparent",
11390
- onClick: onRemove,
11391
- isLoading: isPending || isLoading,
11392
- children: /* @__PURE__ */ jsx(XMark, {})
10969
+ data: variants,
10970
+ columns,
10971
+ isLoading: isPending,
10972
+ getRowId: (row) => row.id,
10973
+ rowCount: count,
10974
+ prefix: VARIANT_PREFIX,
10975
+ layout: "fill",
10976
+ rowSelection: {
10977
+ state: rowSelection,
10978
+ onRowSelectionChange: setRowSelection,
10979
+ enableRowSelection: (row) => {
10980
+ return !items.find((i) => i.variant_id === row.original.id);
10981
+ }
10982
+ },
10983
+ autoFocusSearch: true
11393
10984
  }
11394
- )
10985
+ ) }),
10986
+ /* @__PURE__ */ jsx(StackedFocusModal.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
10987
+ /* @__PURE__ */ jsx(StackedFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
10988
+ /* @__PURE__ */ jsx(Button, { size: "small", type: "button", onClick: onSubmit, children: "Update items" })
10989
+ ] }) })
11395
10990
  ]
11396
- },
11397
- promotion.id
10991
+ }
11398
10992
  );
11399
10993
  };
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
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);
10994
+ const columnHelper = createDataTableColumnHelper();
10995
+ const useColumns = () => {
10996
+ return useMemo(() => {
10997
+ return [
10998
+ columnHelper.select(),
10999
+ columnHelper.accessor("product.title", {
11000
+ header: "Product",
11001
+ cell: ({ row }) => {
11002
+ var _a, _b, _c;
11003
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-2", children: [
11004
+ /* @__PURE__ */ jsx(
11005
+ Thumbnail,
11006
+ {
11007
+ thumbnail: (_a = row.original.product) == null ? void 0 : _a.thumbnail,
11008
+ alt: (_b = row.original.product) == null ? void 0 : _b.title
11009
+ }
11010
+ ),
11011
+ /* @__PURE__ */ jsx("span", { children: (_c = row.original.product) == null ? void 0 : _c.title })
11012
+ ] });
11013
+ },
11014
+ enableSorting: true
11015
+ }),
11016
+ columnHelper.accessor("title", {
11017
+ header: "Variant",
11018
+ enableSorting: true
11019
+ }),
11020
+ columnHelper.accessor("sku", {
11021
+ header: "SKU",
11022
+ cell: ({ getValue }) => {
11023
+ return getValue() ?? "-";
11024
+ },
11025
+ enableSorting: true
11026
+ }),
11027
+ columnHelper.accessor("updated_at", {
11028
+ header: "Updated",
11029
+ cell: ({ getValue }) => {
11030
+ return /* @__PURE__ */ jsx(
11031
+ Tooltip,
11032
+ {
11033
+ content: getFullDate({ date: getValue(), includeTime: true }),
11034
+ children: /* @__PURE__ */ jsx("span", { children: getFullDate({ date: getValue() }) })
11035
+ }
11036
+ );
11037
+ },
11038
+ enableSorting: true,
11039
+ sortAscLabel: "Oldest first",
11040
+ sortDescLabel: "Newest first"
11041
+ }),
11042
+ columnHelper.accessor("created_at", {
11043
+ header: "Created",
11044
+ cell: ({ getValue }) => {
11045
+ return /* @__PURE__ */ jsx(
11046
+ Tooltip,
11047
+ {
11048
+ content: getFullDate({ date: getValue(), includeTime: true }),
11049
+ children: /* @__PURE__ */ jsx("span", { children: getFullDate({ date: getValue() }) })
11050
+ }
11051
+ );
11052
+ },
11053
+ enableSorting: true,
11054
+ sortAscLabel: "Oldest first",
11055
+ sortDescLabel: "Newest first"
11056
+ })
11057
+ ];
11058
+ }, []);
11427
11059
  };
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);
11060
+ const CustomItemForm = ({ orderId, currencyCode }) => {
11061
+ const { setIsOpen } = useStackedModal();
11062
+ const { mutateAsync: addItems } = useDraftOrderAddItems(orderId);
11063
+ const form = useForm({
11064
+ defaultValues: {
11065
+ title: "",
11066
+ quantity: 1,
11067
+ unit_price: ""
11068
+ },
11069
+ resolver: zodResolver(customItemSchema)
11070
+ });
11071
+ const onSubmit = form.handleSubmit(async (data) => {
11072
+ await addItems(
11073
+ {
11074
+ items: [
11075
+ {
11076
+ title: data.title,
11077
+ quantity: data.quantity,
11078
+ unit_price: convertNumber(data.unit_price)
11079
+ }
11080
+ ]
11081
+ },
11082
+ {
11083
+ onSuccess: () => {
11084
+ setIsOpen(STACKED_MODAL_ID, false);
11085
+ },
11086
+ onError: (e) => {
11087
+ toast.error(e.message);
11088
+ }
11089
+ }
11090
+ );
11091
+ });
11092
+ return /* @__PURE__ */ jsx(Form$2, { ...form, children: /* @__PURE__ */ jsx(KeyboundForm, { onSubmit, children: /* @__PURE__ */ jsxs(StackedFocusModal.Content, { children: [
11093
+ /* @__PURE__ */ jsx(StackedFocusModal.Header, {}),
11094
+ /* @__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: [
11095
+ /* @__PURE__ */ jsxs("div", { children: [
11096
+ /* @__PURE__ */ jsx(StackedFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Add custom item" }) }),
11097
+ /* @__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." }) })
11098
+ ] }),
11099
+ /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
11100
+ /* @__PURE__ */ jsx(
11101
+ Form$2.Field,
11102
+ {
11103
+ control: form.control,
11104
+ name: "title",
11105
+ render: ({ field }) => /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
11106
+ /* @__PURE__ */ jsxs("div", { children: [
11107
+ /* @__PURE__ */ jsx(Form$2.Label, { children: "Title" }),
11108
+ /* @__PURE__ */ jsx(Form$2.Hint, { children: "Enter the title of the item" })
11109
+ ] }),
11110
+ /* @__PURE__ */ jsxs("div", { children: [
11111
+ /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(Input, { ...field }) }),
11112
+ /* @__PURE__ */ jsx(Form$2.ErrorMessage, {})
11113
+ ] })
11114
+ ] }) })
11435
11115
  }
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);
11116
+ ),
11117
+ /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
11118
+ /* @__PURE__ */ jsx(
11119
+ Form$2.Field,
11120
+ {
11121
+ control: form.control,
11122
+ name: "unit_price",
11123
+ render: ({ field: { onChange, ...field } }) => /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
11124
+ /* @__PURE__ */ jsxs("div", { children: [
11125
+ /* @__PURE__ */ jsx(Form$2.Label, { children: "Unit price" }),
11126
+ /* @__PURE__ */ jsx(Form$2.Hint, { children: "Enter the unit price of the item" })
11127
+ ] }),
11128
+ /* @__PURE__ */ jsxs("div", { children: [
11129
+ /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
11130
+ CurrencyInput,
11131
+ {
11132
+ symbol: getNativeSymbol(currencyCode),
11133
+ code: currencyCode,
11134
+ onValueChange: (_value, _name, values) => onChange(values == null ? void 0 : values.value),
11135
+ ...field
11136
+ }
11137
+ ) }),
11138
+ /* @__PURE__ */ jsx(Form$2.ErrorMessage, {})
11139
+ ] })
11140
+ ] }) })
11444
11141
  }
11445
- }
11446
- }
11447
- }
11448
- return Array.from(promotionIds);
11449
- }
11142
+ ),
11143
+ /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
11144
+ /* @__PURE__ */ jsx(
11145
+ Form$2.Field,
11146
+ {
11147
+ control: form.control,
11148
+ name: "quantity",
11149
+ render: ({ field }) => /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
11150
+ /* @__PURE__ */ jsxs("div", { children: [
11151
+ /* @__PURE__ */ jsx(Form$2.Label, { children: "Quantity" }),
11152
+ /* @__PURE__ */ jsx(Form$2.Hint, { children: "Enter the quantity of the item" })
11153
+ ] }),
11154
+ /* @__PURE__ */ jsxs("div", { className: "w-full flex-1", children: [
11155
+ /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx("div", { className: "w-full flex-1", children: /* @__PURE__ */ jsx(NumberInput, { ...field, className: "w-full" }) }) }),
11156
+ /* @__PURE__ */ jsx(Form$2.ErrorMessage, {})
11157
+ ] })
11158
+ ] }) })
11159
+ }
11160
+ )
11161
+ ] }) }) }),
11162
+ /* @__PURE__ */ jsx(StackedFocusModal.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
11163
+ /* @__PURE__ */ jsx(StackedFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
11164
+ /* @__PURE__ */ jsx(Button, { size: "small", type: "button", onClick: onSubmit, children: "Add item" })
11165
+ ] }) })
11166
+ ] }) }) });
11167
+ };
11168
+ const customItemSchema = objectType({
11169
+ title: stringType().min(1),
11170
+ quantity: numberType(),
11171
+ unit_price: unionType([numberType(), stringType()])
11172
+ });
11450
11173
  const SalesChannel = () => {
11451
11174
  const { id } = useParams();
11452
11175
  const { draft_order, isPending, isError, error } = useDraftOrder(
@@ -12959,86 +12682,363 @@ const Illustration = () => {
12959
12682
  /* @__PURE__ */ jsx("g", { clipPath: "url(#clip4_20915_38670)", children: /* @__PURE__ */ jsx(
12960
12683
  "path",
12961
12684
  {
12962
- d: "M136.504 95.1945L129.12 95.1519L129.095 99.3617",
12963
- stroke: "#A1A1AA",
12964
- strokeWidth: "1.5",
12965
- strokeLinecap: "round",
12966
- strokeLinejoin: "round"
12685
+ d: "M136.504 95.1945L129.12 95.1519L129.095 99.3617",
12686
+ stroke: "#A1A1AA",
12687
+ strokeWidth: "1.5",
12688
+ strokeLinecap: "round",
12689
+ strokeLinejoin: "round"
12690
+ }
12691
+ ) }),
12692
+ /* @__PURE__ */ jsx("g", { clipPath: "url(#clip5_20915_38670)", children: /* @__PURE__ */ jsx(
12693
+ "path",
12694
+ {
12695
+ d: "M146.894 101.198L139.51 101.155L139.486 105.365",
12696
+ stroke: "#A1A1AA",
12697
+ strokeWidth: "1.5",
12698
+ strokeLinecap: "round",
12699
+ strokeLinejoin: "round"
12700
+ }
12701
+ ) }),
12702
+ /* @__PURE__ */ jsxs("defs", { children: [
12703
+ /* @__PURE__ */ jsx("clipPath", { id: "clip0_20915_38670", children: /* @__PURE__ */ jsx(
12704
+ "rect",
12705
+ {
12706
+ width: "12",
12707
+ height: "12",
12708
+ fill: "white",
12709
+ transform: "matrix(0.865865 0.500278 -0.871576 0.490261 138.36 74.6508)"
12710
+ }
12711
+ ) }),
12712
+ /* @__PURE__ */ jsx("clipPath", { id: "clip1_20915_38670", children: /* @__PURE__ */ jsx(
12713
+ "rect",
12714
+ {
12715
+ width: "12",
12716
+ height: "12",
12717
+ fill: "white",
12718
+ transform: "matrix(0.865865 0.500278 -0.871576 0.490261 148.75 80.6541)"
12719
+ }
12720
+ ) }),
12721
+ /* @__PURE__ */ jsx("clipPath", { id: "clip2_20915_38670", children: /* @__PURE__ */ jsx(
12722
+ "rect",
12723
+ {
12724
+ width: "12",
12725
+ height: "12",
12726
+ fill: "white",
12727
+ transform: "matrix(0.865865 0.500278 -0.871576 0.490261 159.141 86.6575)"
12728
+ }
12729
+ ) }),
12730
+ /* @__PURE__ */ jsx("clipPath", { id: "clip3_20915_38670", children: /* @__PURE__ */ jsx(
12731
+ "rect",
12732
+ {
12733
+ width: "12",
12734
+ height: "12",
12735
+ fill: "white",
12736
+ transform: "matrix(0.865865 0.500278 -0.871576 0.490261 120.928 84.4561)"
12737
+ }
12738
+ ) }),
12739
+ /* @__PURE__ */ jsx("clipPath", { id: "clip4_20915_38670", children: /* @__PURE__ */ jsx(
12740
+ "rect",
12741
+ {
12742
+ width: "12",
12743
+ height: "12",
12744
+ fill: "white",
12745
+ transform: "matrix(0.865865 0.500278 -0.871576 0.490261 131.318 90.4594)"
12746
+ }
12747
+ ) }),
12748
+ /* @__PURE__ */ jsx("clipPath", { id: "clip5_20915_38670", children: /* @__PURE__ */ jsx(
12749
+ "rect",
12750
+ {
12751
+ width: "12",
12752
+ height: "12",
12753
+ fill: "white",
12754
+ transform: "matrix(0.865865 0.500278 -0.871576 0.490261 141.709 96.4627)"
12755
+ }
12756
+ ) })
12757
+ ] })
12758
+ ]
12759
+ }
12760
+ );
12761
+ };
12762
+ const schema = objectType({
12763
+ customer_id: stringType().min(1)
12764
+ });
12765
+ const PROMOTION_QUERY_KEY = "promotions";
12766
+ const promotionsQueryKeys = {
12767
+ list: (query2) => [
12768
+ PROMOTION_QUERY_KEY,
12769
+ query2 ? query2 : void 0
12770
+ ],
12771
+ detail: (id, query2) => [
12772
+ PROMOTION_QUERY_KEY,
12773
+ id,
12774
+ query2 ? query2 : void 0
12775
+ ]
12776
+ };
12777
+ const usePromotions = (query2, options) => {
12778
+ const { data, ...rest } = useQuery({
12779
+ queryKey: promotionsQueryKeys.list(query2),
12780
+ queryFn: async () => sdk.admin.promotion.list(query2),
12781
+ ...options
12782
+ });
12783
+ return { ...data, ...rest };
12784
+ };
12785
+ const Promotions = () => {
12786
+ const { id } = useParams();
12787
+ const {
12788
+ order: preview,
12789
+ isError: isPreviewError,
12790
+ error: previewError
12791
+ } = useOrderPreview(id, void 0);
12792
+ useInitiateOrderEdit({ preview });
12793
+ const { onCancel } = useCancelOrderEdit({ preview });
12794
+ if (isPreviewError) {
12795
+ throw previewError;
12796
+ }
12797
+ const isReady = !!preview;
12798
+ return /* @__PURE__ */ jsxs(RouteDrawer, { onClose: onCancel, children: [
12799
+ /* @__PURE__ */ jsx(RouteDrawer.Header, { children: /* @__PURE__ */ jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Edit Promotions" }) }) }),
12800
+ isReady && /* @__PURE__ */ jsx(PromotionForm, { preview })
12801
+ ] });
12802
+ };
12803
+ const PromotionForm = ({ preview }) => {
12804
+ const { items, shipping_methods } = preview;
12805
+ const [isSubmitting, setIsSubmitting] = useState(false);
12806
+ const [comboboxValue, setComboboxValue] = useState("");
12807
+ const { handleSuccess } = useRouteModal();
12808
+ const { mutateAsync: addPromotions, isPending: isAddingPromotions } = useDraftOrderAddPromotions(preview.id);
12809
+ const promoIds = getPromotionIds(items, shipping_methods);
12810
+ const { promotions, isPending, isError, error } = usePromotions(
12811
+ {
12812
+ id: promoIds
12813
+ },
12814
+ {
12815
+ enabled: !!promoIds.length
12816
+ }
12817
+ );
12818
+ const comboboxData = useComboboxData({
12819
+ queryKey: ["promotions", "combobox", promoIds],
12820
+ queryFn: async (params) => {
12821
+ return await sdk.admin.promotion.list({
12822
+ ...params,
12823
+ id: {
12824
+ $nin: promoIds
12825
+ }
12826
+ });
12827
+ },
12828
+ getOptions: (data) => {
12829
+ return data.promotions.map((promotion) => ({
12830
+ label: promotion.code,
12831
+ value: promotion.code
12832
+ }));
12833
+ }
12834
+ });
12835
+ const add = async (value) => {
12836
+ if (!value) {
12837
+ return;
12838
+ }
12839
+ addPromotions(
12840
+ {
12841
+ promo_codes: [value]
12842
+ },
12843
+ {
12844
+ onError: (e) => {
12845
+ toast.error(e.message);
12846
+ comboboxData.onSearchValueChange("");
12847
+ setComboboxValue("");
12848
+ },
12849
+ onSuccess: () => {
12850
+ comboboxData.onSearchValueChange("");
12851
+ setComboboxValue("");
12852
+ }
12853
+ }
12854
+ );
12855
+ };
12856
+ const { mutateAsync: confirmOrderEdit } = useDraftOrderConfirmEdit(preview.id);
12857
+ const { mutateAsync: requestOrderEdit } = useOrderEditRequest(preview.id);
12858
+ const onSubmit = async () => {
12859
+ setIsSubmitting(true);
12860
+ let requestSucceeded = false;
12861
+ await requestOrderEdit(void 0, {
12862
+ onError: (e) => {
12863
+ toast.error(e.message);
12864
+ },
12865
+ onSuccess: () => {
12866
+ requestSucceeded = true;
12867
+ }
12868
+ });
12869
+ if (!requestSucceeded) {
12870
+ setIsSubmitting(false);
12871
+ return;
12872
+ }
12873
+ await confirmOrderEdit(void 0, {
12874
+ onError: (e) => {
12875
+ toast.error(e.message);
12876
+ },
12877
+ onSuccess: () => {
12878
+ handleSuccess();
12879
+ },
12880
+ onSettled: () => {
12881
+ setIsSubmitting(false);
12882
+ }
12883
+ });
12884
+ };
12885
+ if (isError) {
12886
+ throw error;
12887
+ }
12888
+ return /* @__PURE__ */ jsxs(KeyboundForm, { className: "flex flex-1 flex-col", onSubmit, children: [
12889
+ /* @__PURE__ */ jsx(RouteDrawer.Body, { children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
12890
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
12891
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
12892
+ /* @__PURE__ */ jsx(Label$1, { size: "small", weight: "plus", htmlFor: "promotion-combobox", children: "Apply promotions" }),
12893
+ /* @__PURE__ */ jsx(Hint$1, { id: "promotion-combobox-hint", children: "Manage promotions that should be applied to the order." })
12894
+ ] }),
12895
+ /* @__PURE__ */ jsx(
12896
+ Combobox,
12897
+ {
12898
+ id: "promotion-combobox",
12899
+ "aria-describedby": "promotion-combobox-hint",
12900
+ isFetchingNextPage: comboboxData.isFetchingNextPage,
12901
+ fetchNextPage: comboboxData.fetchNextPage,
12902
+ options: comboboxData.options,
12903
+ onSearchValueChange: comboboxData.onSearchValueChange,
12904
+ searchValue: comboboxData.searchValue,
12905
+ disabled: comboboxData.disabled || isAddingPromotions,
12906
+ onChange: add,
12907
+ value: comboboxValue
12967
12908
  }
12968
- ) }),
12969
- /* @__PURE__ */ jsx("g", { clipPath: "url(#clip5_20915_38670)", children: /* @__PURE__ */ jsx(
12970
- "path",
12909
+ )
12910
+ ] }),
12911
+ /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
12912
+ /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-2", children: promotions == null ? void 0 : promotions.map((promotion) => /* @__PURE__ */ jsx(
12913
+ PromotionItem,
12914
+ {
12915
+ promotion,
12916
+ orderId: preview.id,
12917
+ isLoading: isPending
12918
+ },
12919
+ promotion.id
12920
+ )) })
12921
+ ] }) }),
12922
+ /* @__PURE__ */ jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
12923
+ /* @__PURE__ */ jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
12924
+ /* @__PURE__ */ jsx(
12925
+ Button,
12926
+ {
12927
+ size: "small",
12928
+ type: "submit",
12929
+ isLoading: isSubmitting || isAddingPromotions,
12930
+ children: "Save"
12931
+ }
12932
+ )
12933
+ ] }) })
12934
+ ] });
12935
+ };
12936
+ const PromotionItem = ({
12937
+ promotion,
12938
+ orderId,
12939
+ isLoading
12940
+ }) => {
12941
+ var _a;
12942
+ const { mutateAsync: removePromotions, isPending } = useDraftOrderRemovePromotions(orderId);
12943
+ const onRemove = async () => {
12944
+ removePromotions(
12945
+ {
12946
+ promo_codes: [promotion.code]
12947
+ },
12948
+ {
12949
+ onError: (e) => {
12950
+ toast.error(e.message);
12951
+ }
12952
+ }
12953
+ );
12954
+ };
12955
+ const displayValue = getDisplayValue(promotion);
12956
+ return /* @__PURE__ */ jsxs(
12957
+ "div",
12958
+ {
12959
+ className: clx(
12960
+ "bg-ui-bg-component shadow-elevation-card-rest flex items-center justify-between rounded-lg px-3 py-2",
12961
+ {
12962
+ "animate-pulse": isLoading
12963
+ }
12964
+ ),
12965
+ children: [
12966
+ /* @__PURE__ */ jsxs("div", { children: [
12967
+ /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: promotion.code }),
12968
+ /* @__PURE__ */ jsxs("div", { className: "text-ui-fg-subtle flex items-center gap-1.5", children: [
12969
+ displayValue && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
12970
+ /* @__PURE__ */ jsx(Text, { size: "small", leading: "compact", children: displayValue }),
12971
+ /* @__PURE__ */ jsx(Text, { size: "small", leading: "compact", children: "·" })
12972
+ ] }),
12973
+ /* @__PURE__ */ jsx(Text, { size: "small", leading: "compact", className: "capitalize", children: (_a = promotion.application_method) == null ? void 0 : _a.allocation })
12974
+ ] })
12975
+ ] }),
12976
+ /* @__PURE__ */ jsx(
12977
+ IconButton,
12971
12978
  {
12972
- d: "M146.894 101.198L139.51 101.155L139.486 105.365",
12973
- stroke: "#A1A1AA",
12974
- strokeWidth: "1.5",
12975
- strokeLinecap: "round",
12976
- strokeLinejoin: "round"
12979
+ size: "small",
12980
+ type: "button",
12981
+ variant: "transparent",
12982
+ onClick: onRemove,
12983
+ isLoading: isPending || isLoading,
12984
+ children: /* @__PURE__ */ jsx(XMark, {})
12977
12985
  }
12978
- ) }),
12979
- /* @__PURE__ */ jsxs("defs", { children: [
12980
- /* @__PURE__ */ jsx("clipPath", { id: "clip0_20915_38670", children: /* @__PURE__ */ jsx(
12981
- "rect",
12982
- {
12983
- width: "12",
12984
- height: "12",
12985
- fill: "white",
12986
- transform: "matrix(0.865865 0.500278 -0.871576 0.490261 138.36 74.6508)"
12987
- }
12988
- ) }),
12989
- /* @__PURE__ */ jsx("clipPath", { id: "clip1_20915_38670", children: /* @__PURE__ */ jsx(
12990
- "rect",
12991
- {
12992
- width: "12",
12993
- height: "12",
12994
- fill: "white",
12995
- transform: "matrix(0.865865 0.500278 -0.871576 0.490261 148.75 80.6541)"
12996
- }
12997
- ) }),
12998
- /* @__PURE__ */ jsx("clipPath", { id: "clip2_20915_38670", children: /* @__PURE__ */ jsx(
12999
- "rect",
13000
- {
13001
- width: "12",
13002
- height: "12",
13003
- fill: "white",
13004
- transform: "matrix(0.865865 0.500278 -0.871576 0.490261 159.141 86.6575)"
13005
- }
13006
- ) }),
13007
- /* @__PURE__ */ jsx("clipPath", { id: "clip3_20915_38670", children: /* @__PURE__ */ jsx(
13008
- "rect",
13009
- {
13010
- width: "12",
13011
- height: "12",
13012
- fill: "white",
13013
- transform: "matrix(0.865865 0.500278 -0.871576 0.490261 120.928 84.4561)"
13014
- }
13015
- ) }),
13016
- /* @__PURE__ */ jsx("clipPath", { id: "clip4_20915_38670", children: /* @__PURE__ */ jsx(
13017
- "rect",
13018
- {
13019
- width: "12",
13020
- height: "12",
13021
- fill: "white",
13022
- transform: "matrix(0.865865 0.500278 -0.871576 0.490261 131.318 90.4594)"
13023
- }
13024
- ) }),
13025
- /* @__PURE__ */ jsx("clipPath", { id: "clip5_20915_38670", children: /* @__PURE__ */ jsx(
13026
- "rect",
13027
- {
13028
- width: "12",
13029
- height: "12",
13030
- fill: "white",
13031
- transform: "matrix(0.865865 0.500278 -0.871576 0.490261 141.709 96.4627)"
13032
- }
13033
- ) })
13034
- ] })
12986
+ )
13035
12987
  ]
13036
- }
12988
+ },
12989
+ promotion.id
13037
12990
  );
13038
12991
  };
13039
- const schema = objectType({
13040
- customer_id: stringType().min(1)
12992
+ function getDisplayValue(promotion) {
12993
+ var _a, _b, _c, _d;
12994
+ const value = (_a = promotion.application_method) == null ? void 0 : _a.value;
12995
+ if (!value) {
12996
+ return null;
12997
+ }
12998
+ if (((_b = promotion.application_method) == null ? void 0 : _b.type) === "fixed") {
12999
+ const currency = (_c = promotion.application_method) == null ? void 0 : _c.currency_code;
13000
+ if (!currency) {
13001
+ return null;
13002
+ }
13003
+ return getLocaleAmount(value, currency);
13004
+ } else if (((_d = promotion.application_method) == null ? void 0 : _d.type) === "percentage") {
13005
+ return formatPercentage(value);
13006
+ }
13007
+ return null;
13008
+ }
13009
+ const formatter = new Intl.NumberFormat([], {
13010
+ style: "percent",
13011
+ minimumFractionDigits: 2
13041
13012
  });
13013
+ const formatPercentage = (value, isPercentageValue = false) => {
13014
+ let val = value || 0;
13015
+ if (!isPercentageValue) {
13016
+ val = val / 100;
13017
+ }
13018
+ return formatter.format(val);
13019
+ };
13020
+ function getPromotionIds(items, shippingMethods) {
13021
+ const promotionIds = /* @__PURE__ */ new Set();
13022
+ for (const item of items) {
13023
+ if (item.adjustments) {
13024
+ for (const adjustment of item.adjustments) {
13025
+ if (adjustment.promotion_id) {
13026
+ promotionIds.add(adjustment.promotion_id);
13027
+ }
13028
+ }
13029
+ }
13030
+ }
13031
+ for (const shippingMethod of shippingMethods) {
13032
+ if (shippingMethod.adjustments) {
13033
+ for (const adjustment of shippingMethod.adjustments) {
13034
+ if (adjustment.promotion_id) {
13035
+ promotionIds.add(adjustment.promotion_id);
13036
+ }
13037
+ }
13038
+ }
13039
+ }
13040
+ return Array.from(promotionIds);
13041
+ }
13042
13042
  const widgetModule = { widgets: [] };
13043
13043
  const routeModule = {
13044
13044
  routes: [
@@ -13067,10 +13067,6 @@ const routeModule = {
13067
13067
  Component: Email,
13068
13068
  path: "/draft-orders/:id/email"
13069
13069
  },
13070
- {
13071
- Component: Items,
13072
- path: "/draft-orders/:id/items"
13073
- },
13074
13070
  {
13075
13071
  Component: CustomItems,
13076
13072
  path: "/draft-orders/:id/custom-items"
@@ -13080,8 +13076,8 @@ const routeModule = {
13080
13076
  path: "/draft-orders/:id/metadata"
13081
13077
  },
13082
13078
  {
13083
- Component: Promotions,
13084
- path: "/draft-orders/:id/promotions"
13079
+ Component: Items,
13080
+ path: "/draft-orders/:id/items"
13085
13081
  },
13086
13082
  {
13087
13083
  Component: SalesChannel,
@@ -13098,6 +13094,10 @@ const routeModule = {
13098
13094
  {
13099
13095
  Component: TransferOwnership,
13100
13096
  path: "/draft-orders/:id/transfer-ownership"
13097
+ },
13098
+ {
13099
+ Component: Promotions,
13100
+ path: "/draft-orders/:id/promotions"
13101
13101
  }
13102
13102
  ]
13103
13103
  }