@medusajs/draft-order 2.11.1-snapshot-20251021083840 → 2.11.1-snapshot-20251021090705

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