@medusajs/draft-order 0.0.8 → 0.0.10

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";
@@ -9706,95 +9706,6 @@ const ID = () => {
9706
9706
  /* @__PURE__ */ jsx(Outlet, {})
9707
9707
  ] });
9708
9708
  };
9709
- const CustomItems = () => {
9710
- return /* @__PURE__ */ jsxs(RouteDrawer, { children: [
9711
- /* @__PURE__ */ jsx(RouteDrawer.Header, { children: /* @__PURE__ */ jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Edit Custom Items" }) }) }),
9712
- /* @__PURE__ */ jsx(CustomItemsForm, {})
9713
- ] });
9714
- };
9715
- const CustomItemsForm = () => {
9716
- const form = useForm({
9717
- resolver: zodResolver(schema$5)
9718
- });
9719
- return /* @__PURE__ */ jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxs(KeyboundForm, { className: "flex flex-1 flex-col", children: [
9720
- /* @__PURE__ */ jsx(RouteDrawer.Body, {}),
9721
- /* @__PURE__ */ jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
9722
- /* @__PURE__ */ jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
9723
- /* @__PURE__ */ jsx(Button, { size: "small", type: "submit", children: "Save" })
9724
- ] }) })
9725
- ] }) });
9726
- };
9727
- const schema$5 = z.object({
9728
- email: z.string().email()
9729
- });
9730
- const Email = () => {
9731
- const { id } = useParams();
9732
- const { order, isPending, isError, error } = useOrder(id, {
9733
- fields: "+email"
9734
- });
9735
- if (isError) {
9736
- throw error;
9737
- }
9738
- const isReady = !isPending && !!order;
9739
- return /* @__PURE__ */ jsxs(RouteDrawer, { children: [
9740
- /* @__PURE__ */ jsxs(RouteDrawer.Header, { children: [
9741
- /* @__PURE__ */ jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Edit Email" }) }),
9742
- /* @__PURE__ */ jsx(RouteDrawer.Description, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Edit the email for the draft order" }) })
9743
- ] }),
9744
- isReady && /* @__PURE__ */ jsx(EmailForm, { order })
9745
- ] });
9746
- };
9747
- const EmailForm = ({ order }) => {
9748
- const form = useForm({
9749
- defaultValues: {
9750
- email: order.email ?? ""
9751
- },
9752
- resolver: zodResolver(schema$4)
9753
- });
9754
- const { mutateAsync, isPending } = useUpdateDraftOrder(order.id);
9755
- const { handleSuccess } = useRouteModal();
9756
- const onSubmit = form.handleSubmit(async (data) => {
9757
- await mutateAsync(
9758
- { email: data.email },
9759
- {
9760
- onSuccess: () => {
9761
- handleSuccess();
9762
- },
9763
- onError: (error) => {
9764
- toast.error(error.message);
9765
- }
9766
- }
9767
- );
9768
- });
9769
- return /* @__PURE__ */ jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxs(
9770
- KeyboundForm,
9771
- {
9772
- className: "flex flex-1 flex-col overflow-hidden",
9773
- onSubmit,
9774
- children: [
9775
- /* @__PURE__ */ jsx(RouteDrawer.Body, { className: "flex flex-col gap-y-6 overflow-y-auto", children: /* @__PURE__ */ jsx(
9776
- Form$2.Field,
9777
- {
9778
- control: form.control,
9779
- name: "email",
9780
- render: ({ field }) => /* @__PURE__ */ jsxs(Form$2.Item, { children: [
9781
- /* @__PURE__ */ jsx(Form$2.Label, { children: "Email" }),
9782
- /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(Input, { ...field }) }),
9783
- /* @__PURE__ */ jsx(Form$2.ErrorMessage, {})
9784
- ] })
9785
- }
9786
- ) }),
9787
- /* @__PURE__ */ jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
9788
- /* @__PURE__ */ jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
9789
- /* @__PURE__ */ jsx(Button, { size: "small", type: "submit", isLoading: isPending, children: "Save" })
9790
- ] }) })
9791
- ]
9792
- }
9793
- ) });
9794
- };
9795
- const schema$4 = z.object({
9796
- email: z.string().email()
9797
- });
9798
9709
  const BillingAddress = () => {
9799
9710
  const { id } = useParams();
9800
9711
  const { order, isPending, isError, error } = useOrder(id, {
@@ -9827,7 +9738,7 @@ const BillingAddressForm = ({ order }) => {
9827
9738
  postal_code: ((_i = order.billing_address) == null ? void 0 : _i.postal_code) ?? "",
9828
9739
  phone: ((_j = order.billing_address) == null ? void 0 : _j.phone) ?? ""
9829
9740
  },
9830
- resolver: zodResolver(schema$3)
9741
+ resolver: zodResolver(schema$5)
9831
9742
  });
9832
9743
  const { mutateAsync, isPending } = useUpdateDraftOrder(order.id);
9833
9744
  const { handleSuccess } = useRouteModal();
@@ -9984,514 +9895,523 @@ const BillingAddressForm = ({ order }) => {
9984
9895
  }
9985
9896
  ) });
9986
9897
  };
9987
- const schema$3 = addressSchema;
9988
- const PROMOTION_QUERY_KEY = "promotions";
9989
- const promotionsQueryKeys = {
9990
- list: (query2) => [
9991
- PROMOTION_QUERY_KEY,
9992
- query2 ? query2 : void 0
9993
- ],
9994
- detail: (id, query2) => [
9995
- PROMOTION_QUERY_KEY,
9996
- id,
9997
- query2 ? query2 : void 0
9998
- ]
9898
+ const schema$5 = addressSchema;
9899
+ const CustomItems = () => {
9900
+ return /* @__PURE__ */ jsxs(RouteDrawer, { children: [
9901
+ /* @__PURE__ */ jsx(RouteDrawer.Header, { children: /* @__PURE__ */ jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Edit Custom Items" }) }) }),
9902
+ /* @__PURE__ */ jsx(CustomItemsForm, {})
9903
+ ] });
9999
9904
  };
10000
- const usePromotions = (query2, options) => {
10001
- const { data, ...rest } = useQuery({
10002
- queryKey: promotionsQueryKeys.list(query2),
10003
- queryFn: async () => sdk.admin.promotion.list(query2),
10004
- ...options
9905
+ const CustomItemsForm = () => {
9906
+ const form = useForm({
9907
+ resolver: zodResolver(schema$4)
10005
9908
  });
10006
- return { ...data, ...rest };
10007
- };
10008
- const useCancelOrderEdit = ({ preview }) => {
10009
- const { mutateAsync: cancelOrderEdit } = useDraftOrderCancelEdit(preview == null ? void 0 : preview.id);
10010
- const onCancel = useCallback(async () => {
10011
- if (!preview) {
10012
- return true;
10013
- }
10014
- let res = false;
10015
- await cancelOrderEdit(void 0, {
10016
- onError: (e) => {
10017
- toast.error(e.message);
10018
- },
10019
- onSuccess: () => {
10020
- res = true;
10021
- }
10022
- });
10023
- return res;
10024
- }, [preview, cancelOrderEdit]);
10025
- return { onCancel };
9909
+ return /* @__PURE__ */ jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxs(KeyboundForm, { className: "flex flex-1 flex-col", children: [
9910
+ /* @__PURE__ */ jsx(RouteDrawer.Body, {}),
9911
+ /* @__PURE__ */ jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
9912
+ /* @__PURE__ */ jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
9913
+ /* @__PURE__ */ jsx(Button, { size: "small", type: "submit", children: "Save" })
9914
+ ] }) })
9915
+ ] }) });
10026
9916
  };
10027
- let IS_REQUEST_RUNNING = false;
10028
- const useInitiateOrderEdit = ({
10029
- preview
10030
- }) => {
10031
- const navigate = useNavigate();
10032
- const { mutateAsync } = useDraftOrderBeginEdit(preview == null ? void 0 : preview.id);
10033
- useEffect(() => {
10034
- async function run() {
10035
- if (IS_REQUEST_RUNNING || !preview) {
10036
- return;
10037
- }
10038
- if (preview.order_change) {
10039
- return;
9917
+ const schema$4 = z.object({
9918
+ email: z.string().email()
9919
+ });
9920
+ const InlineTip = forwardRef(
9921
+ ({ variant = "tip", label, className, children, ...props }, ref) => {
9922
+ const labelValue = label || (variant === "warning" ? "Warning" : "Tip");
9923
+ return /* @__PURE__ */ jsxs(
9924
+ "div",
9925
+ {
9926
+ ref,
9927
+ className: clx(
9928
+ "bg-ui-bg-component txt-small text-ui-fg-subtle grid grid-cols-[4px_1fr] items-start gap-3 rounded-lg border p-3",
9929
+ className
9930
+ ),
9931
+ ...props,
9932
+ children: [
9933
+ /* @__PURE__ */ jsx(
9934
+ "div",
9935
+ {
9936
+ role: "presentation",
9937
+ className: clx("w-4px bg-ui-tag-neutral-icon h-full rounded-full", {
9938
+ "bg-ui-tag-orange-icon": variant === "warning"
9939
+ })
9940
+ }
9941
+ ),
9942
+ /* @__PURE__ */ jsxs("div", { className: "text-pretty", children: [
9943
+ /* @__PURE__ */ jsxs("strong", { className: "txt-small-plus text-ui-fg-base", children: [
9944
+ labelValue,
9945
+ ":"
9946
+ ] }),
9947
+ " ",
9948
+ children
9949
+ ] })
9950
+ ]
10040
9951
  }
10041
- IS_REQUEST_RUNNING = true;
10042
- await mutateAsync(void 0, {
10043
- onError: (e) => {
10044
- toast.error(e.message);
10045
- navigate(`/draft-orders/${preview.id}`, { replace: true });
10046
- return;
10047
- }
10048
- });
10049
- IS_REQUEST_RUNNING = false;
10050
- }
10051
- run();
10052
- }, [preview, navigate, mutateAsync]);
10053
- };
10054
- const Promotions = () => {
9952
+ );
9953
+ }
9954
+ );
9955
+ InlineTip.displayName = "InlineTip";
9956
+ const MetadataFieldSchema = z.object({
9957
+ key: z.string(),
9958
+ disabled: z.boolean().optional(),
9959
+ value: z.any()
9960
+ });
9961
+ const MetadataSchema = z.object({
9962
+ metadata: z.array(MetadataFieldSchema)
9963
+ });
9964
+ const Metadata = () => {
10055
9965
  const { id } = useParams();
10056
- const {
10057
- order: preview,
10058
- isError: isPreviewError,
10059
- error: previewError
10060
- } = useOrderPreview(id, void 0);
10061
- useInitiateOrderEdit({ preview });
10062
- const { onCancel } = useCancelOrderEdit({ preview });
10063
- if (isPreviewError) {
10064
- throw previewError;
9966
+ const { order, isPending, isError, error } = useOrder(id, {
9967
+ fields: "metadata"
9968
+ });
9969
+ if (isError) {
9970
+ throw error;
10065
9971
  }
10066
- const isReady = !!preview;
10067
- return /* @__PURE__ */ jsxs(RouteDrawer, { onClose: onCancel, children: [
10068
- /* @__PURE__ */ jsx(RouteDrawer.Header, { children: /* @__PURE__ */ jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Edit Promotions" }) }) }),
10069
- isReady && /* @__PURE__ */ jsx(PromotionForm, { preview })
9972
+ const isReady = !isPending && !!order;
9973
+ return /* @__PURE__ */ jsxs(RouteDrawer, { children: [
9974
+ /* @__PURE__ */ jsxs(RouteDrawer.Header, { children: [
9975
+ /* @__PURE__ */ jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Metadata" }) }),
9976
+ /* @__PURE__ */ jsx(RouteDrawer.Description, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Add metadata to the draft order." }) })
9977
+ ] }),
9978
+ !isReady ? /* @__PURE__ */ jsx(PlaceholderInner, {}) : /* @__PURE__ */ jsx(MetadataForm, { orderId: id, metadata: order == null ? void 0 : order.metadata })
10070
9979
  ] });
10071
9980
  };
10072
- const PromotionForm = ({ preview }) => {
10073
- const { items, shipping_methods } = preview;
10074
- const [isSubmitting, setIsSubmitting] = useState(false);
10075
- const [comboboxValue, setComboboxValue] = useState("");
9981
+ const METADATA_KEY_LABEL_ID = "metadata-form-key-label";
9982
+ const METADATA_VALUE_LABEL_ID = "metadata-form-value-label";
9983
+ const MetadataForm = ({ orderId, metadata }) => {
10076
9984
  const { handleSuccess } = useRouteModal();
10077
- const { mutateAsync: addPromotions, isPending: isAddingPromotions } = useDraftOrderAddPromotions(preview.id);
10078
- const promoCodes = getPromotionCodes(items, shipping_methods);
10079
- const { promotions, isPending, isError, error } = usePromotions(
10080
- {
10081
- code: promoCodes
10082
- },
10083
- {
10084
- enabled: !!promoCodes.length
10085
- }
10086
- );
10087
- const comboboxData = useComboboxData({
10088
- queryKey: ["promotions", "combobox", promoCodes],
10089
- queryFn: async (params) => {
10090
- return await sdk.admin.promotion.list({
10091
- ...params,
10092
- code: {
10093
- $nin: promoCodes
10094
- }
10095
- });
9985
+ const hasUneditableRows = getHasUneditableRows(metadata);
9986
+ const { mutateAsync, isPending } = useUpdateDraftOrder(orderId);
9987
+ const form = useForm({
9988
+ defaultValues: {
9989
+ metadata: getDefaultValues(metadata)
10096
9990
  },
10097
- getOptions: (data) => {
10098
- return data.promotions.map((promotion) => ({
10099
- label: promotion.code,
10100
- value: promotion.code
10101
- }));
10102
- }
9991
+ resolver: zodResolver(MetadataSchema)
10103
9992
  });
10104
- const add = async (value) => {
10105
- if (!value) {
10106
- return;
10107
- }
10108
- addPromotions(
9993
+ const handleSubmit = form.handleSubmit(async (data) => {
9994
+ const parsedData = parseValues(data);
9995
+ await mutateAsync(
10109
9996
  {
10110
- promo_codes: [value]
9997
+ metadata: parsedData
10111
9998
  },
10112
9999
  {
10113
- onError: (e) => {
10114
- toast.error(e.message);
10115
- comboboxData.onSearchValueChange("");
10116
- setComboboxValue("");
10117
- },
10118
10000
  onSuccess: () => {
10119
- comboboxData.onSearchValueChange("");
10120
- setComboboxValue("");
10001
+ toast.success("Metadata updated");
10002
+ handleSuccess();
10003
+ },
10004
+ onError: (error) => {
10005
+ toast.error(error.message);
10121
10006
  }
10122
10007
  }
10123
10008
  );
10124
- };
10125
- const { mutateAsync: confirmOrderEdit } = useDraftOrderConfirmEdit(preview.id);
10126
- const { mutateAsync: requestOrderEdit } = useOrderEditRequest(preview.id);
10127
- const onSubmit = async () => {
10128
- setIsSubmitting(true);
10129
- let requestSucceeded = false;
10130
- await requestOrderEdit(void 0, {
10131
- onError: (e) => {
10132
- toast.error(e.message);
10133
- },
10134
- onSuccess: () => {
10135
- requestSucceeded = true;
10136
- }
10137
- });
10138
- if (!requestSucceeded) {
10139
- setIsSubmitting(false);
10140
- return;
10009
+ });
10010
+ const { fields, insert, remove } = useFieldArray({
10011
+ control: form.control,
10012
+ name: "metadata"
10013
+ });
10014
+ function deleteRow(index) {
10015
+ remove(index);
10016
+ if (fields.length === 1) {
10017
+ insert(0, {
10018
+ key: "",
10019
+ value: "",
10020
+ disabled: false
10021
+ });
10141
10022
  }
10142
- await confirmOrderEdit(void 0, {
10143
- onError: (e) => {
10144
- toast.error(e.message);
10145
- },
10146
- onSuccess: () => {
10147
- handleSuccess();
10148
- },
10149
- onSettled: () => {
10150
- setIsSubmitting(false);
10151
- }
10023
+ }
10024
+ function insertRow(index, position) {
10025
+ insert(index + (position === "above" ? 0 : 1), {
10026
+ key: "",
10027
+ value: "",
10028
+ disabled: false
10152
10029
  });
10153
- };
10154
- if (isError) {
10155
- throw error;
10156
10030
  }
10157
- return /* @__PURE__ */ jsxs(KeyboundForm, { className: "flex flex-1 flex-col", onSubmit, children: [
10158
- /* @__PURE__ */ jsx(RouteDrawer.Body, { children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
10159
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
10160
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
10161
- /* @__PURE__ */ jsx(Label$1, { size: "small", weight: "plus", htmlFor: "promotion-combobox", children: "Apply promotions" }),
10162
- /* @__PURE__ */ jsx(Hint$1, { id: "promotion-combobox-hint", children: "Manage promotions that should be applied to the order." })
10163
- ] }),
10164
- /* @__PURE__ */ jsx(
10165
- Combobox,
10166
- {
10167
- id: "promotion-combobox",
10168
- "aria-describedby": "promotion-combobox-hint",
10169
- isFetchingNextPage: comboboxData.isFetchingNextPage,
10170
- fetchNextPage: comboboxData.fetchNextPage,
10171
- options: comboboxData.options,
10172
- onSearchValueChange: comboboxData.onSearchValueChange,
10173
- searchValue: comboboxData.searchValue,
10174
- disabled: comboboxData.disabled || isAddingPromotions,
10175
- onChange: add,
10176
- value: comboboxValue
10177
- }
10178
- )
10179
- ] }),
10180
- /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
10181
- /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-2", children: promotions == null ? void 0 : promotions.map((promotion) => /* @__PURE__ */ jsx(
10182
- PromotionItem,
10183
- {
10184
- promotion,
10185
- orderId: preview.id,
10186
- isLoading: isPending
10187
- },
10188
- promotion.id
10189
- )) })
10190
- ] }) }),
10191
- /* @__PURE__ */ jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
10192
- /* @__PURE__ */ jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
10193
- /* @__PURE__ */ jsx(
10194
- Button,
10195
- {
10196
- size: "small",
10197
- type: "submit",
10198
- isLoading: isSubmitting || isAddingPromotions,
10199
- children: "Save"
10200
- }
10201
- )
10202
- ] }) })
10203
- ] });
10204
- };
10205
- const PromotionItem = ({
10206
- promotion,
10207
- orderId,
10208
- isLoading
10209
- }) => {
10210
- var _a;
10211
- const { mutateAsync: removePromotions, isPending } = useDraftOrderRemovePromotions(orderId);
10212
- const onRemove = async () => {
10213
- removePromotions(
10214
- {
10215
- promo_codes: [promotion.code]
10216
- },
10217
- {
10218
- onError: (e) => {
10219
- toast.error(e.message);
10220
- }
10221
- }
10222
- );
10223
- };
10224
- const displayValue = getDisplayValue(promotion);
10225
- return /* @__PURE__ */ jsxs(
10226
- "div",
10031
+ return /* @__PURE__ */ jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxs(
10032
+ KeyboundForm,
10227
10033
  {
10228
- className: clx(
10229
- "px-3 py-2 rounded-lg bg-ui-bg-component shadow-elevation-card-rest flex items-center justify-between",
10230
- {
10231
- "animate-pulse": isLoading
10232
- }
10233
- ),
10034
+ onSubmit: handleSubmit,
10035
+ className: "flex flex-1 flex-col overflow-hidden",
10234
10036
  children: [
10235
- /* @__PURE__ */ jsxs("div", { children: [
10236
- /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: promotion.code }),
10237
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 text-ui-fg-subtle", children: [
10238
- displayValue && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
10239
- /* @__PURE__ */ jsx(Text, { size: "small", leading: "compact", children: displayValue }),
10240
- /* @__PURE__ */ jsx(Text, { size: "small", leading: "compact", children: "·" })
10037
+ /* @__PURE__ */ jsxs(RouteDrawer.Body, { className: "flex flex-1 flex-col gap-y-8 overflow-y-auto", children: [
10038
+ /* @__PURE__ */ jsxs("div", { className: "bg-ui-bg-base shadow-elevation-card-rest grid grid-cols-1 divide-y rounded-lg", children: [
10039
+ /* @__PURE__ */ jsxs("div", { className: "bg-ui-bg-subtle grid grid-cols-2 divide-x rounded-t-lg", children: [
10040
+ /* @__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" }) }),
10041
+ /* @__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" }) })
10241
10042
  ] }),
10242
- /* @__PURE__ */ jsx(Text, { size: "small", leading: "compact", className: "capitalize", children: (_a = promotion.application_method) == null ? void 0 : _a.allocation })
10243
- ] })
10244
- ] }),
10245
- /* @__PURE__ */ jsx(
10246
- IconButton,
10247
- {
10248
- size: "small",
10249
- type: "button",
10250
- variant: "transparent",
10251
- onClick: onRemove,
10252
- isLoading: isPending || isLoading,
10253
- children: /* @__PURE__ */ jsx(XMark, {})
10254
- }
10255
- )
10256
- ]
10257
- },
10258
- promotion.id
10259
- );
10260
- };
10261
- function getDisplayValue(promotion) {
10262
- var _a, _b, _c, _d;
10263
- const value = (_a = promotion.application_method) == null ? void 0 : _a.value;
10264
- if (!value) {
10265
- return null;
10266
- }
10267
- if (((_b = promotion.application_method) == null ? void 0 : _b.type) === "fixed") {
10268
- const currency = (_c = promotion.application_method) == null ? void 0 : _c.currency_code;
10269
- if (!currency) {
10270
- return null;
10271
- }
10272
- return getLocaleAmount(value, currency);
10273
- } else if (((_d = promotion.application_method) == null ? void 0 : _d.type) === "percentage") {
10274
- return formatPercentage(value);
10275
- }
10276
- return null;
10277
- }
10278
- const formatter = new Intl.NumberFormat([], {
10279
- style: "percent",
10280
- minimumFractionDigits: 2
10281
- });
10282
- const formatPercentage = (value, isPercentageValue = false) => {
10283
- let val = value || 0;
10284
- if (!isPercentageValue) {
10285
- val = val / 100;
10286
- }
10287
- return formatter.format(val);
10288
- };
10289
- function getPromotionCodes(items, shippingMethods) {
10290
- const codes = /* @__PURE__ */ new Set();
10291
- for (const item of items) {
10292
- if (item.adjustments) {
10293
- for (const adjustment of item.adjustments) {
10294
- if (adjustment.code) {
10295
- codes.add(adjustment.code);
10296
- }
10297
- }
10298
- }
10299
- }
10300
- for (const shippingMethod of shippingMethods) {
10301
- if (shippingMethod.adjustments) {
10302
- for (const adjustment of shippingMethod.adjustments) {
10303
- if (adjustment.code) {
10304
- codes.add(adjustment.code);
10305
- }
10306
- }
10307
- }
10308
- }
10309
- return Array.from(codes);
10310
- }
10311
- const NumberInput = forwardRef(
10312
- ({
10313
- value,
10314
- onChange,
10315
- size = "base",
10316
- min = 0,
10317
- max = 100,
10318
- step = 1,
10319
- className,
10320
- disabled,
10321
- ...props
10322
- }, ref) => {
10323
- const handleChange = (event) => {
10324
- const newValue = event.target.value === "" ? min : Number(event.target.value);
10325
- if (!isNaN(newValue) && (max === void 0 || newValue <= max) && (min === void 0 || newValue >= min)) {
10326
- onChange(newValue);
10327
- }
10328
- };
10329
- const handleIncrement = () => {
10330
- const newValue = value + step;
10331
- if (max === void 0 || newValue <= max) {
10332
- onChange(newValue);
10043
+ fields.map((field, index) => {
10044
+ const isDisabled = field.disabled || false;
10045
+ let placeholder = "-";
10046
+ if (typeof field.value === "object") {
10047
+ placeholder = "{ ... }";
10048
+ }
10049
+ if (Array.isArray(field.value)) {
10050
+ placeholder = "[ ... ]";
10051
+ }
10052
+ return /* @__PURE__ */ jsx(
10053
+ ConditionalTooltip,
10054
+ {
10055
+ showTooltip: isDisabled,
10056
+ content: "This row is disabled because it contains non-primitive data.",
10057
+ children: /* @__PURE__ */ jsxs("div", { className: "group/table relative", children: [
10058
+ /* @__PURE__ */ jsxs(
10059
+ "div",
10060
+ {
10061
+ className: clx("grid grid-cols-2 divide-x", {
10062
+ "overflow-hidden rounded-b-lg": index === fields.length - 1
10063
+ }),
10064
+ children: [
10065
+ /* @__PURE__ */ jsx(
10066
+ Form$2.Field,
10067
+ {
10068
+ control: form.control,
10069
+ name: `metadata.${index}.key`,
10070
+ render: ({ field: field2 }) => {
10071
+ return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
10072
+ GridInput,
10073
+ {
10074
+ "aria-labelledby": METADATA_KEY_LABEL_ID,
10075
+ ...field2,
10076
+ disabled: isDisabled,
10077
+ placeholder: "Key"
10078
+ }
10079
+ ) }) });
10080
+ }
10081
+ }
10082
+ ),
10083
+ /* @__PURE__ */ jsx(
10084
+ Form$2.Field,
10085
+ {
10086
+ control: form.control,
10087
+ name: `metadata.${index}.value`,
10088
+ render: ({ field: { value, ...field2 } }) => {
10089
+ return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
10090
+ GridInput,
10091
+ {
10092
+ "aria-labelledby": METADATA_VALUE_LABEL_ID,
10093
+ ...field2,
10094
+ value: isDisabled ? placeholder : value,
10095
+ disabled: isDisabled,
10096
+ placeholder: "Value"
10097
+ }
10098
+ ) }) });
10099
+ }
10100
+ }
10101
+ )
10102
+ ]
10103
+ }
10104
+ ),
10105
+ /* @__PURE__ */ jsxs(DropdownMenu, { children: [
10106
+ /* @__PURE__ */ jsx(
10107
+ DropdownMenu.Trigger,
10108
+ {
10109
+ className: clx(
10110
+ "invisible absolute inset-y-0 -right-2.5 my-auto group-hover/table:visible data-[state='open']:visible",
10111
+ {
10112
+ hidden: isDisabled
10113
+ }
10114
+ ),
10115
+ disabled: isDisabled,
10116
+ asChild: true,
10117
+ children: /* @__PURE__ */ jsx(IconButton, { size: "2xsmall", children: /* @__PURE__ */ jsx(EllipsisVertical, {}) })
10118
+ }
10119
+ ),
10120
+ /* @__PURE__ */ jsxs(DropdownMenu.Content, { children: [
10121
+ /* @__PURE__ */ jsxs(
10122
+ DropdownMenu.Item,
10123
+ {
10124
+ className: "gap-x-2",
10125
+ onClick: () => insertRow(index, "above"),
10126
+ children: [
10127
+ /* @__PURE__ */ jsx(ArrowUpMini, { className: "text-ui-fg-subtle" }),
10128
+ "Insert row above"
10129
+ ]
10130
+ }
10131
+ ),
10132
+ /* @__PURE__ */ jsxs(
10133
+ DropdownMenu.Item,
10134
+ {
10135
+ className: "gap-x-2",
10136
+ onClick: () => insertRow(index, "below"),
10137
+ children: [
10138
+ /* @__PURE__ */ jsx(ArrowDownMini, { className: "text-ui-fg-subtle" }),
10139
+ "Insert row below"
10140
+ ]
10141
+ }
10142
+ ),
10143
+ /* @__PURE__ */ jsx(DropdownMenu.Separator, {}),
10144
+ /* @__PURE__ */ jsxs(
10145
+ DropdownMenu.Item,
10146
+ {
10147
+ className: "gap-x-2",
10148
+ onClick: () => deleteRow(index),
10149
+ children: [
10150
+ /* @__PURE__ */ jsx(Trash, { className: "text-ui-fg-subtle" }),
10151
+ "Delete row"
10152
+ ]
10153
+ }
10154
+ )
10155
+ ] })
10156
+ ] })
10157
+ ] })
10158
+ },
10159
+ field.id
10160
+ );
10161
+ })
10162
+ ] }),
10163
+ 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." })
10164
+ ] }),
10165
+ /* @__PURE__ */ jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
10166
+ /* @__PURE__ */ jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
10167
+ /* @__PURE__ */ jsx(Button, { size: "small", type: "submit", isLoading: isPending, children: "Save" })
10168
+ ] }) })
10169
+ ]
10170
+ }
10171
+ ) });
10172
+ };
10173
+ const GridInput = forwardRef(({ className, ...props }, ref) => {
10174
+ return /* @__PURE__ */ jsx(
10175
+ "input",
10176
+ {
10177
+ ref,
10178
+ ...props,
10179
+ autoComplete: "off",
10180
+ className: clx(
10181
+ "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",
10182
+ className
10183
+ )
10184
+ }
10185
+ );
10186
+ });
10187
+ GridInput.displayName = "MetadataForm.GridInput";
10188
+ const PlaceholderInner = () => {
10189
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col overflow-hidden", children: [
10190
+ /* @__PURE__ */ jsx(RouteDrawer.Body, { children: /* @__PURE__ */ jsx(Skeleton, { className: "h-[148ox] w-full rounded-lg" }) }),
10191
+ /* @__PURE__ */ jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
10192
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-7 w-12 rounded-md" }),
10193
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-7 w-12 rounded-md" })
10194
+ ] }) })
10195
+ ] });
10196
+ };
10197
+ const EDITABLE_TYPES = ["string", "number", "boolean"];
10198
+ function getDefaultValues(metadata) {
10199
+ if (!metadata || !Object.keys(metadata).length) {
10200
+ return [
10201
+ {
10202
+ key: "",
10203
+ value: "",
10204
+ disabled: false
10333
10205
  }
10206
+ ];
10207
+ }
10208
+ return Object.entries(metadata).map(([key, value]) => {
10209
+ if (!EDITABLE_TYPES.includes(typeof value)) {
10210
+ return {
10211
+ key,
10212
+ value,
10213
+ disabled: true
10214
+ };
10215
+ }
10216
+ let stringValue = value;
10217
+ if (typeof value !== "string") {
10218
+ stringValue = JSON.stringify(value);
10219
+ }
10220
+ return {
10221
+ key,
10222
+ value: stringValue,
10223
+ original_key: key
10334
10224
  };
10335
- const handleDecrement = () => {
10336
- const newValue = value - step;
10337
- if (min === void 0 || newValue >= min) {
10338
- onChange(newValue);
10225
+ });
10226
+ }
10227
+ function parseValues(values) {
10228
+ const metadata = values.metadata;
10229
+ const isEmpty = !metadata.length || metadata.length === 1 && !metadata[0].key && !metadata[0].value;
10230
+ if (isEmpty) {
10231
+ return null;
10232
+ }
10233
+ const update = {};
10234
+ metadata.forEach((field) => {
10235
+ let key = field.key;
10236
+ let value = field.value;
10237
+ const disabled = field.disabled;
10238
+ if (!key || !value) {
10239
+ return;
10240
+ }
10241
+ if (disabled) {
10242
+ update[key] = value;
10243
+ return;
10244
+ }
10245
+ key = key.trim();
10246
+ value = value.trim();
10247
+ if (value === "true") {
10248
+ update[key] = true;
10249
+ } else if (value === "false") {
10250
+ update[key] = false;
10251
+ } else {
10252
+ const parsedNumber = parseFloat(value);
10253
+ if (!isNaN(parsedNumber)) {
10254
+ update[key] = parsedNumber;
10255
+ } else {
10256
+ update[key] = value;
10339
10257
  }
10340
- };
10341
- return /* @__PURE__ */ jsxs(
10342
- "div",
10343
- {
10344
- className: clx(
10345
- "inline-flex rounded-md bg-ui-bg-field shadow-borders-base overflow-hidden divide-x transition-fg",
10346
- "[&:has(input:focus)]:shadow-borders-interactive-with-active",
10347
- {
10348
- "h-7": size === "small",
10349
- "h-8": size === "base"
10350
- },
10351
- className
10352
- ),
10353
- children: [
10354
- /* @__PURE__ */ jsx(
10355
- "input",
10356
- {
10357
- ref,
10358
- type: "number",
10359
- value,
10360
- onChange: handleChange,
10361
- min,
10362
- max,
10363
- step,
10364
- className: clx(
10365
- "flex-1 px-2 py-1 bg-transparent txt-compact-small text-ui-fg-base outline-none [appearance:textfield]",
10366
- "[&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none",
10367
- "placeholder:text-ui-fg-muted"
10368
- ),
10369
- ...props
10370
- }
10371
- ),
10372
- /* @__PURE__ */ jsxs(
10373
- "button",
10374
- {
10375
- className: clx(
10376
- "flex items-center justify-center outline-none transition-fg",
10377
- "disabled:cursor-not-allowed disabled:text-ui-fg-muted",
10378
- "focus:bg-ui-bg-field-component-hover",
10379
- "hover:bg-ui-bg-field-component-hover",
10380
- {
10381
- "size-7": size === "small",
10382
- "size-8": size === "base"
10383
- }
10384
- ),
10385
- type: "button",
10386
- onClick: handleDecrement,
10387
- disabled: min !== void 0 && value <= min || disabled,
10388
- children: [
10389
- /* @__PURE__ */ jsx(Minus, {}),
10390
- /* @__PURE__ */ jsx("span", { className: "sr-only", children: `Decrease by ${step}` })
10391
- ]
10392
- }
10393
- ),
10394
- /* @__PURE__ */ jsxs(
10395
- "button",
10396
- {
10397
- className: clx(
10398
- "flex items-center justify-center outline-none transition-fg",
10399
- "disabled:cursor-not-allowed disabled:text-ui-fg-muted",
10400
- "focus:bg-ui-bg-field-hover",
10401
- "hover:bg-ui-bg-field-hover",
10402
- {
10403
- "size-7": size === "small",
10404
- "size-8": size === "base"
10405
- }
10406
- ),
10407
- type: "button",
10408
- onClick: handleIncrement,
10409
- disabled: max !== void 0 && value >= max || disabled,
10410
- children: [
10411
- /* @__PURE__ */ jsx(Plus, {}),
10412
- /* @__PURE__ */ jsx("span", { className: "sr-only", children: `Increase by ${step}` })
10413
- ]
10414
- }
10415
- )
10416
- ]
10417
- }
10418
- );
10258
+ }
10259
+ });
10260
+ return update;
10261
+ }
10262
+ function getHasUneditableRows(metadata) {
10263
+ if (!metadata) {
10264
+ return false;
10419
10265
  }
10420
- );
10421
- const PRODUCT_VARIANTS_QUERY_KEY = "product-variants";
10422
- const productVariantsQueryKeys = {
10266
+ return Object.values(metadata).some(
10267
+ (value) => !EDITABLE_TYPES.includes(typeof value)
10268
+ );
10269
+ }
10270
+ const PROMOTION_QUERY_KEY = "promotions";
10271
+ const promotionsQueryKeys = {
10423
10272
  list: (query2) => [
10424
- PRODUCT_VARIANTS_QUERY_KEY,
10273
+ PROMOTION_QUERY_KEY,
10274
+ query2 ? query2 : void 0
10275
+ ],
10276
+ detail: (id, query2) => [
10277
+ PROMOTION_QUERY_KEY,
10278
+ id,
10425
10279
  query2 ? query2 : void 0
10426
10280
  ]
10427
10281
  };
10428
- const useProductVariants = (query2, options) => {
10282
+ const usePromotions = (query2, options) => {
10429
10283
  const { data, ...rest } = useQuery({
10430
- queryKey: productVariantsQueryKeys.list(query2),
10431
- queryFn: async () => await sdk.admin.productVariant.list(query2),
10284
+ queryKey: promotionsQueryKeys.list(query2),
10285
+ queryFn: async () => sdk.admin.promotion.list(query2),
10432
10286
  ...options
10433
10287
  });
10434
10288
  return { ...data, ...rest };
10435
10289
  };
10436
- function convertNumber(value) {
10437
- return typeof value === "string" ? Number(value.replace(",", ".")) : value;
10438
- }
10439
- const STACKED_MODAL_ID = "items_stacked_modal";
10440
- const Items = () => {
10290
+ const useCancelOrderEdit = ({ preview }) => {
10291
+ const { mutateAsync: cancelOrderEdit } = useDraftOrderCancelEdit(preview == null ? void 0 : preview.id);
10292
+ const onCancel = useCallback(async () => {
10293
+ if (!preview) {
10294
+ return true;
10295
+ }
10296
+ let res = false;
10297
+ await cancelOrderEdit(void 0, {
10298
+ onError: (e) => {
10299
+ toast.error(e.message);
10300
+ },
10301
+ onSuccess: () => {
10302
+ res = true;
10303
+ }
10304
+ });
10305
+ return res;
10306
+ }, [preview, cancelOrderEdit]);
10307
+ return { onCancel };
10308
+ };
10309
+ let IS_REQUEST_RUNNING = false;
10310
+ const useInitiateOrderEdit = ({
10311
+ preview
10312
+ }) => {
10313
+ const navigate = useNavigate();
10314
+ const { mutateAsync } = useDraftOrderBeginEdit(preview == null ? void 0 : preview.id);
10315
+ useEffect(() => {
10316
+ async function run() {
10317
+ if (IS_REQUEST_RUNNING || !preview) {
10318
+ return;
10319
+ }
10320
+ if (preview.order_change) {
10321
+ return;
10322
+ }
10323
+ IS_REQUEST_RUNNING = true;
10324
+ await mutateAsync(void 0, {
10325
+ onError: (e) => {
10326
+ toast.error(e.message);
10327
+ navigate(`/draft-orders/${preview.id}`, { replace: true });
10328
+ return;
10329
+ }
10330
+ });
10331
+ IS_REQUEST_RUNNING = false;
10332
+ }
10333
+ run();
10334
+ }, [preview, navigate, mutateAsync]);
10335
+ };
10336
+ const Promotions = () => {
10441
10337
  const { id } = useParams();
10442
10338
  const {
10443
10339
  order: preview,
10444
- isPending: isPreviewPending,
10445
10340
  isError: isPreviewError,
10446
10341
  error: previewError
10447
- } = useOrderPreview(id, void 0, {
10448
- placeholderData: keepPreviousData
10449
- });
10342
+ } = useOrderPreview(id, void 0);
10450
10343
  useInitiateOrderEdit({ preview });
10451
- const { draft_order, isPending, isError, error } = useDraftOrder(
10452
- id,
10453
- {
10454
- fields: "currency_code"
10455
- },
10456
- {
10457
- enabled: !!id
10458
- }
10459
- );
10460
10344
  const { onCancel } = useCancelOrderEdit({ preview });
10461
- if (isError) {
10462
- throw error;
10463
- }
10464
10345
  if (isPreviewError) {
10465
10346
  throw previewError;
10466
10347
  }
10467
- const ready = !!preview && !isPreviewPending && !!draft_order && !isPending;
10468
- return /* @__PURE__ */ jsx(RouteFocusModal, { onClose: onCancel, children: ready ? /* @__PURE__ */ jsx(ItemsForm, { preview, currencyCode: draft_order.currency_code }) : /* @__PURE__ */ jsxs("div", { children: [
10469
- /* @__PURE__ */ jsx(RouteFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Edit Items" }) }),
10470
- /* @__PURE__ */ jsx(RouteFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Loading data for the draft order, please wait..." }) })
10471
- ] }) });
10348
+ const isReady = !!preview;
10349
+ return /* @__PURE__ */ jsxs(RouteDrawer, { onClose: onCancel, children: [
10350
+ /* @__PURE__ */ jsx(RouteDrawer.Header, { children: /* @__PURE__ */ jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Edit Promotions" }) }) }),
10351
+ isReady && /* @__PURE__ */ jsx(PromotionForm, { preview })
10352
+ ] });
10472
10353
  };
10473
- const ItemsForm = ({ preview, currencyCode }) => {
10474
- var _a;
10354
+ const PromotionForm = ({ preview }) => {
10355
+ const { items, shipping_methods } = preview;
10475
10356
  const [isSubmitting, setIsSubmitting] = useState(false);
10476
- const [modalContent, setModalContent] = useState(
10477
- null
10478
- );
10357
+ const [comboboxValue, setComboboxValue] = useState("");
10479
10358
  const { handleSuccess } = useRouteModal();
10480
- const { searchValue, onSearchValueChange, query: query2 } = useDebouncedSearch();
10359
+ const { mutateAsync: addPromotions, isPending: isAddingPromotions } = useDraftOrderAddPromotions(preview.id);
10360
+ const promoCodes = getPromotionCodes(items, shipping_methods);
10361
+ const { promotions, isPending, isError, error } = usePromotions(
10362
+ {
10363
+ code: promoCodes
10364
+ },
10365
+ {
10366
+ enabled: !!promoCodes.length
10367
+ }
10368
+ );
10369
+ const comboboxData = useComboboxData({
10370
+ queryKey: ["promotions", "combobox", promoCodes],
10371
+ queryFn: async (params) => {
10372
+ return await sdk.admin.promotion.list({
10373
+ ...params,
10374
+ code: {
10375
+ $nin: promoCodes
10376
+ }
10377
+ });
10378
+ },
10379
+ getOptions: (data) => {
10380
+ return data.promotions.map((promotion) => ({
10381
+ label: promotion.code,
10382
+ value: promotion.code
10383
+ }));
10384
+ }
10385
+ });
10386
+ const add = async (value) => {
10387
+ if (!value) {
10388
+ return;
10389
+ }
10390
+ addPromotions(
10391
+ {
10392
+ promo_codes: [value]
10393
+ },
10394
+ {
10395
+ onError: (e) => {
10396
+ toast.error(e.message);
10397
+ comboboxData.onSearchValueChange("");
10398
+ setComboboxValue("");
10399
+ },
10400
+ onSuccess: () => {
10401
+ comboboxData.onSearchValueChange("");
10402
+ setComboboxValue("");
10403
+ }
10404
+ }
10405
+ );
10406
+ };
10481
10407
  const { mutateAsync: confirmOrderEdit } = useDraftOrderConfirmEdit(preview.id);
10482
- const { mutateAsync: requestOrderEdit } = useDraftOrderRequestEdit(preview.id);
10483
- const itemCount = ((_a = preview.items) == null ? void 0 : _a.reduce((acc, item) => acc + item.quantity, 0)) || 0;
10484
- const matches = useMemo(() => {
10485
- return matchSorter(preview.items, query2, {
10486
- keys: ["product_title", "variant_title", "variant_sku", "title"]
10487
- });
10488
- }, [preview.items, query2]);
10408
+ const { mutateAsync: requestOrderEdit } = useOrderEditRequest(preview.id);
10489
10409
  const onSubmit = async () => {
10490
10410
  setIsSubmitting(true);
10491
10411
  let requestSucceeded = false;
10492
10412
  await requestOrderEdit(void 0, {
10493
10413
  onError: (e) => {
10494
- toast.error(`Failed to request order edit: ${e.message}`);
10414
+ toast.error(e.message);
10495
10415
  },
10496
10416
  onSuccess: () => {
10497
10417
  requestSucceeded = true;
@@ -10503,7 +10423,7 @@ const ItemsForm = ({ preview, currencyCode }) => {
10503
10423
  }
10504
10424
  await confirmOrderEdit(void 0, {
10505
10425
  onError: (e) => {
10506
- toast.error(`Failed to confirm order edit: ${e.message}`);
10426
+ toast.error(e.message);
10507
10427
  },
10508
10428
  onSuccess: () => {
10509
10429
  handleSuccess();
@@ -10513,1206 +10433,293 @@ const ItemsForm = ({ preview, currencyCode }) => {
10513
10433
  }
10514
10434
  });
10515
10435
  };
10516
- const onKeyDown = useCallback(
10517
- (e) => {
10518
- if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) {
10519
- if (modalContent || isSubmitting) {
10520
- return;
10521
- }
10522
- onSubmit();
10523
- }
10524
- },
10525
- [modalContent, isSubmitting, onSubmit]
10526
- );
10527
- useEffect(() => {
10528
- document.addEventListener("keydown", onKeyDown);
10529
- return () => {
10530
- document.removeEventListener("keydown", onKeyDown);
10531
- };
10532
- }, [onKeyDown]);
10533
- return /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-col overflow-hidden", children: [
10534
- /* @__PURE__ */ jsx(RouteFocusModal.Header, {}),
10535
- /* @__PURE__ */ jsx(RouteFocusModal.Body, { className: "flex flex-1 flex-col overflow-hidden", children: /* @__PURE__ */ jsxs(
10536
- StackedFocusModal,
10537
- {
10538
- id: STACKED_MODAL_ID,
10539
- onOpenChangeCallback: (open) => {
10540
- if (!open) {
10541
- setModalContent(null);
10436
+ if (isError) {
10437
+ throw error;
10438
+ }
10439
+ return /* @__PURE__ */ jsxs(KeyboundForm, { className: "flex flex-1 flex-col", onSubmit, children: [
10440
+ /* @__PURE__ */ jsx(RouteDrawer.Body, { children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
10441
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
10442
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
10443
+ /* @__PURE__ */ jsx(Label$1, { size: "small", weight: "plus", htmlFor: "promotion-combobox", children: "Apply promotions" }),
10444
+ /* @__PURE__ */ jsx(Hint$1, { id: "promotion-combobox-hint", children: "Manage promotions that should be applied to the order." })
10445
+ ] }),
10446
+ /* @__PURE__ */ jsx(
10447
+ Combobox,
10448
+ {
10449
+ id: "promotion-combobox",
10450
+ "aria-describedby": "promotion-combobox-hint",
10451
+ isFetchingNextPage: comboboxData.isFetchingNextPage,
10452
+ fetchNextPage: comboboxData.fetchNextPage,
10453
+ options: comboboxData.options,
10454
+ onSearchValueChange: comboboxData.onSearchValueChange,
10455
+ searchValue: comboboxData.searchValue,
10456
+ disabled: comboboxData.disabled || isAddingPromotions,
10457
+ onChange: add,
10458
+ value: comboboxValue
10542
10459
  }
10460
+ )
10461
+ ] }),
10462
+ /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
10463
+ /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-2", children: promotions == null ? void 0 : promotions.map((promotion) => /* @__PURE__ */ jsx(
10464
+ PromotionItem,
10465
+ {
10466
+ promotion,
10467
+ orderId: preview.id,
10468
+ isLoading: isPending
10543
10469
  },
10544
- children: [
10545
- /* @__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: [
10546
- /* @__PURE__ */ jsxs("div", { children: [
10547
- /* @__PURE__ */ jsx(RouteFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Edit Items" }) }),
10548
- /* @__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." }) })
10549
- ] }),
10550
- /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
10551
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-y-6", children: [
10552
- /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 items-center gap-3", children: [
10553
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
10554
- /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: "Items" }),
10555
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Choose items from the product catalog." })
10556
- ] }),
10557
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
10558
- /* @__PURE__ */ jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsx(
10559
- Input,
10560
- {
10561
- type: "search",
10562
- placeholder: "Search items",
10563
- value: searchValue,
10564
- onChange: (e) => onSearchValueChange(e.target.value)
10565
- }
10566
- ) }),
10567
- /* @__PURE__ */ jsxs(DropdownMenu, { children: [
10568
- /* @__PURE__ */ jsx(DropdownMenu.Trigger, { asChild: true, children: /* @__PURE__ */ jsx(IconButton, { type: "button", children: /* @__PURE__ */ jsx(Plus, {}) }) }),
10569
- /* @__PURE__ */ jsxs(DropdownMenu.Content, { children: [
10570
- /* @__PURE__ */ jsx(
10571
- StackedModalTrigger$1,
10572
- {
10573
- type: "add-items",
10574
- setModalContent
10575
- }
10576
- ),
10577
- /* @__PURE__ */ jsx(
10578
- StackedModalTrigger$1,
10579
- {
10580
- type: "add-custom-item",
10581
- setModalContent
10582
- }
10583
- )
10584
- ] })
10585
- ] })
10586
- ] })
10587
- ] }),
10588
- /* @__PURE__ */ jsxs("div", { className: "bg-ui-bg-subtle shadow-elevation-card-rest rounded-xl", children: [
10589
- /* @__PURE__ */ jsx("div", { className: "px-[5px]", children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-[1fr_1fr_1fr_28px] gap-3 px-4 py-2 text-ui-fg-muted", children: [
10590
- /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: "Item" }) }),
10591
- /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: "Quantity" }) }),
10592
- /* @__PURE__ */ jsx("div", { className: "text-right", children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: "Price" }) }),
10593
- /* @__PURE__ */ jsx("div", {})
10594
- ] }) }),
10595
- /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-y-1.5 px-[5px] pb-[5px]", children: itemCount <= 0 ? /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center gap-x-3 bg-ui-bg-base rounded-lg p-4 shadow-elevation-card-rest flex-col gap-1", children: [
10596
- /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: "There are no items in this order" }),
10597
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Add items to the order to get started." })
10598
- ] }) : matches.length > 0 ? matches == null ? void 0 : matches.map((item) => /* @__PURE__ */ jsx(
10599
- Item,
10600
- {
10601
- item,
10602
- preview,
10603
- currencyCode
10604
- },
10605
- item.id
10606
- )) : /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center gap-x-3 bg-ui-bg-base rounded-lg p-4 shadow-elevation-card-rest flex-col gap-1", children: [
10607
- /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: "No items found" }),
10608
- /* @__PURE__ */ jsxs(Text, { size: "small", className: "text-ui-fg-subtle", children: [
10609
- 'No items found for "',
10610
- query2,
10611
- '".'
10612
- ] })
10613
- ] }) })
10614
- ] })
10615
- ] }),
10616
- /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
10617
- /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-[1fr_0.5fr_0.5fr] gap-3", children: [
10618
- /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: "Subtotal" }) }),
10619
- /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsxs(
10620
- Text,
10621
- {
10622
- size: "small",
10623
- leading: "compact",
10624
- className: "text-ui-fg-subtle",
10625
- children: [
10626
- itemCount,
10627
- " ",
10628
- itemCount === 1 ? "item" : "items"
10629
- ]
10630
- }
10631
- ) }),
10632
- /* @__PURE__ */ jsx("div", { className: "text-right", children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: getStylizedAmount(preview.item_subtotal, currencyCode) }) })
10633
- ] })
10634
- ] }) }),
10635
- modalContent && (modalContent === "add-items" ? /* @__PURE__ */ jsx(ExistingItemsForm, { orderId: preview.id, items: preview.items }) : modalContent === "add-custom-item" ? /* @__PURE__ */ jsx(
10636
- CustomItemForm,
10637
- {
10638
- orderId: preview.id,
10639
- currencyCode
10640
- }
10641
- ) : null)
10642
- ]
10643
- }
10644
- ) }),
10645
- /* @__PURE__ */ jsx(RouteFocusModal.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-2 justify-end", children: [
10646
- /* @__PURE__ */ jsx(RouteFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
10470
+ promotion.id
10471
+ )) })
10472
+ ] }) }),
10473
+ /* @__PURE__ */ jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
10474
+ /* @__PURE__ */ jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
10647
10475
  /* @__PURE__ */ jsx(
10648
10476
  Button,
10649
10477
  {
10650
10478
  size: "small",
10651
- type: "button",
10652
- onClick: onSubmit,
10653
- isLoading: isSubmitting,
10479
+ type: "submit",
10480
+ isLoading: isSubmitting || isAddingPromotions,
10654
10481
  children: "Save"
10655
10482
  }
10656
10483
  )
10657
10484
  ] }) })
10658
10485
  ] });
10659
10486
  };
10660
- const Item = ({ item, preview, currencyCode }) => {
10661
- if (item.variant_id) {
10662
- return /* @__PURE__ */ jsx(VariantItem, { item, preview, currencyCode });
10663
- }
10664
- return /* @__PURE__ */ jsx(CustomItem, { item, preview, currencyCode });
10665
- };
10666
- const VariantItem = ({ item, preview, currencyCode }) => {
10667
- const [editing, setEditing] = useState(false);
10668
- const form = useForm({
10669
- defaultValues: {
10670
- quantity: item.quantity,
10671
- unit_price: item.unit_price
10672
- },
10673
- resolver: zodResolver(variantItemSchema)
10674
- });
10675
- const actionId = useMemo(() => {
10676
- var _a, _b;
10677
- return (_b = (_a = item.actions) == null ? void 0 : _a.find((a) => a.action === "ITEM_ADD")) == null ? void 0 : _b.id;
10678
- }, [item]);
10679
- const { mutateAsync: updateActionItem, isPending: isUpdatingActionItem } = useDraftOrderUpdateActionItem(preview.id);
10680
- const { mutateAsync: updateOriginalItem, isPending: isUpdatingOriginalItem } = useDraftOrderUpdateItem(preview.id);
10681
- const isPending = isUpdatingActionItem || isUpdatingOriginalItem;
10682
- const onSubmit = form.handleSubmit(async (data) => {
10683
- if (convertNumber(data.unit_price) === item.unit_price && data.quantity === item.quantity) {
10684
- setEditing(false);
10685
- return;
10686
- }
10687
- if (!actionId) {
10688
- await updateOriginalItem(
10689
- {
10690
- item_id: item.id,
10691
- quantity: data.quantity,
10692
- unit_price: convertNumber(data.unit_price)
10693
- },
10694
- {
10695
- onSuccess: () => {
10696
- setEditing(false);
10697
- },
10698
- onError: (e) => {
10699
- toast.error(e.message);
10700
- }
10701
- }
10702
- );
10703
- return;
10704
- }
10705
- await updateActionItem(
10487
+ const PromotionItem = ({
10488
+ promotion,
10489
+ orderId,
10490
+ isLoading
10491
+ }) => {
10492
+ var _a;
10493
+ const { mutateAsync: removePromotions, isPending } = useDraftOrderRemovePromotions(orderId);
10494
+ const onRemove = async () => {
10495
+ removePromotions(
10706
10496
  {
10707
- action_id: actionId,
10708
- quantity: data.quantity,
10709
- unit_price: convertNumber(data.unit_price)
10497
+ promo_codes: [promotion.code]
10710
10498
  },
10711
10499
  {
10712
- onSuccess: () => {
10713
- setEditing(false);
10714
- },
10715
10500
  onError: (e) => {
10716
10501
  toast.error(e.message);
10717
10502
  }
10718
10503
  }
10719
10504
  );
10720
- });
10721
- return /* @__PURE__ */ jsx(Form$2, { ...form, children: /* @__PURE__ */ jsx("form", { onSubmit, children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-[minmax(0,1fr)_minmax(0,1fr)_minmax(0,1fr)_28px] gap-3 px-4 py-2 bg-ui-bg-base shadow-elevation-card-rest rounded-lg items-center", children: [
10722
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-3 w-full", children: [
10723
- /* @__PURE__ */ jsx(
10724
- Thumbnail,
10505
+ };
10506
+ const displayValue = getDisplayValue(promotion);
10507
+ return /* @__PURE__ */ jsxs(
10508
+ "div",
10509
+ {
10510
+ className: clx(
10511
+ "px-3 py-2 rounded-lg bg-ui-bg-component shadow-elevation-card-rest flex items-center justify-between",
10725
10512
  {
10726
- thumbnail: item.thumbnail,
10727
- alt: item.product_title ?? void 0
10513
+ "animate-pulse": isLoading
10728
10514
  }
10729
10515
  ),
10730
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
10731
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-1", children: [
10732
- /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: item.product_title }),
10733
- /* @__PURE__ */ jsxs(
10734
- Text,
10735
- {
10736
- size: "small",
10737
- leading: "compact",
10738
- className: "text-ui-fg-subtle",
10739
- children: [
10740
- "(",
10741
- item.variant_title,
10742
- ")"
10743
- ]
10744
- }
10745
- )
10516
+ children: [
10517
+ /* @__PURE__ */ jsxs("div", { children: [
10518
+ /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: promotion.code }),
10519
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 text-ui-fg-subtle", children: [
10520
+ displayValue && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
10521
+ /* @__PURE__ */ jsx(Text, { size: "small", leading: "compact", children: displayValue }),
10522
+ /* @__PURE__ */ jsx(Text, { size: "small", leading: "compact", children: "·" })
10523
+ ] }),
10524
+ /* @__PURE__ */ jsx(Text, { size: "small", leading: "compact", className: "capitalize", children: (_a = promotion.application_method) == null ? void 0 : _a.allocation })
10525
+ ] })
10746
10526
  ] }),
10747
10527
  /* @__PURE__ */ jsx(
10748
- Text,
10528
+ IconButton,
10749
10529
  {
10750
10530
  size: "small",
10751
- leading: "compact",
10752
- className: "text-ui-fg-subtle",
10753
- children: item.variant_sku
10531
+ type: "button",
10532
+ variant: "transparent",
10533
+ onClick: onRemove,
10534
+ isLoading: isPending || isLoading,
10535
+ children: /* @__PURE__ */ jsx(XMark, {})
10754
10536
  }
10755
10537
  )
10756
- ] })
10757
- ] }),
10758
- editing ? /* @__PURE__ */ jsx("div", { className: "flex-1 w-full", children: /* @__PURE__ */ jsx(
10759
- Form$2.Field,
10760
- {
10761
- control: form.control,
10762
- name: "quantity",
10763
- render: ({ field }) => {
10764
- return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(NumberInput, { ...field }) }) });
10538
+ ]
10539
+ },
10540
+ promotion.id
10541
+ );
10542
+ };
10543
+ function getDisplayValue(promotion) {
10544
+ var _a, _b, _c, _d;
10545
+ const value = (_a = promotion.application_method) == null ? void 0 : _a.value;
10546
+ if (!value) {
10547
+ return null;
10548
+ }
10549
+ if (((_b = promotion.application_method) == null ? void 0 : _b.type) === "fixed") {
10550
+ const currency = (_c = promotion.application_method) == null ? void 0 : _c.currency_code;
10551
+ if (!currency) {
10552
+ return null;
10553
+ }
10554
+ return getLocaleAmount(value, currency);
10555
+ } else if (((_d = promotion.application_method) == null ? void 0 : _d.type) === "percentage") {
10556
+ return formatPercentage(value);
10557
+ }
10558
+ return null;
10559
+ }
10560
+ const formatter = new Intl.NumberFormat([], {
10561
+ style: "percent",
10562
+ minimumFractionDigits: 2
10563
+ });
10564
+ const formatPercentage = (value, isPercentageValue = false) => {
10565
+ let val = value || 0;
10566
+ if (!isPercentageValue) {
10567
+ val = val / 100;
10568
+ }
10569
+ return formatter.format(val);
10570
+ };
10571
+ function getPromotionCodes(items, shippingMethods) {
10572
+ const codes = /* @__PURE__ */ new Set();
10573
+ for (const item of items) {
10574
+ if (item.adjustments) {
10575
+ for (const adjustment of item.adjustments) {
10576
+ if (adjustment.code) {
10577
+ codes.add(adjustment.code);
10765
10578
  }
10766
10579
  }
10767
- ) }) : /* @__PURE__ */ jsx("div", { className: "flex-1 w-full", children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: item.quantity }) }),
10768
- editing ? /* @__PURE__ */ jsx("div", { className: "flex-1 w-full", children: /* @__PURE__ */ jsx(
10769
- Form$2.Field,
10770
- {
10771
- control: form.control,
10772
- name: "unit_price",
10773
- render: ({ field: { onChange, ...field } }) => {
10774
- return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
10775
- CurrencyInput,
10776
- {
10777
- ...field,
10778
- symbol: getNativeSymbol(currencyCode),
10779
- code: currencyCode,
10780
- onValueChange: (_value, _name, values) => onChange(values == null ? void 0 : values.value)
10781
- }
10782
- ) }) });
10580
+ }
10581
+ }
10582
+ for (const shippingMethod of shippingMethods) {
10583
+ if (shippingMethod.adjustments) {
10584
+ for (const adjustment of shippingMethod.adjustments) {
10585
+ if (adjustment.code) {
10586
+ codes.add(adjustment.code);
10783
10587
  }
10784
10588
  }
10785
- ) }) : /* @__PURE__ */ jsx("div", { className: "flex-1 flex items-center justify-end w-full", children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: getLocaleAmount(item.unit_price, currencyCode) }) }),
10786
- /* @__PURE__ */ jsx(
10787
- IconButton,
10788
- {
10789
- type: "button",
10790
- size: "small",
10791
- onClick: editing ? onSubmit : () => {
10792
- setEditing(true);
10793
- },
10794
- disabled: isPending,
10795
- children: editing ? /* @__PURE__ */ jsx(Check, {}) : /* @__PURE__ */ jsx(PencilSquare, {})
10796
- }
10797
- )
10798
- ] }) }) });
10589
+ }
10590
+ }
10591
+ return Array.from(codes);
10592
+ }
10593
+ function convertNumber(value) {
10594
+ return typeof value === "string" ? Number(value.replace(",", ".")) : value;
10595
+ }
10596
+ const STACKED_FOCUS_MODAL_ID = "shipping-form";
10597
+ const Shipping = () => {
10598
+ var _a;
10599
+ const { id } = useParams();
10600
+ const { order, isPending, isError, error } = useOrder(id, {
10601
+ fields: "+items.*,+items.variant.*,+items.variant.product.*,+items.variant.product.shipping_profile.*,+currency_code"
10602
+ });
10603
+ const {
10604
+ order: preview,
10605
+ isPending: isPreviewPending,
10606
+ isError: isPreviewError,
10607
+ error: previewError
10608
+ } = useOrderPreview(id);
10609
+ useInitiateOrderEdit({ preview });
10610
+ const { onCancel } = useCancelOrderEdit({ preview });
10611
+ if (isError) {
10612
+ throw error;
10613
+ }
10614
+ if (isPreviewError) {
10615
+ throw previewError;
10616
+ }
10617
+ const orderHasItems = (((_a = order == null ? void 0 : order.items) == null ? void 0 : _a.length) || 0) > 0;
10618
+ const isReady = preview && !isPreviewPending && order && !isPending;
10619
+ return /* @__PURE__ */ jsx(RouteFocusModal, { onClose: onCancel, children: !orderHasItems ? /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-col overflow-hidden ", children: [
10620
+ /* @__PURE__ */ jsx(RouteFocusModal.Header, {}),
10621
+ /* @__PURE__ */ jsx(RouteFocusModal.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 py-16 px-6", children: [
10622
+ /* @__PURE__ */ jsx(RouteFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Shipping" }) }),
10623
+ /* @__PURE__ */ jsx(RouteFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "This draft order currently has no items. Add items to the order before adding shipping." }) })
10624
+ ] }) }) }),
10625
+ /* @__PURE__ */ jsx(RouteFocusModal.Footer, { children: /* @__PURE__ */ jsx(RouteFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }) })
10626
+ ] }) : isReady ? /* @__PURE__ */ jsx(ShippingForm, { preview, order }) : /* @__PURE__ */ jsxs("div", { children: [
10627
+ /* @__PURE__ */ jsx(RouteFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Edit Shipping" }) }),
10628
+ /* @__PURE__ */ jsx(RouteFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Loading data for the draft order, please wait..." }) })
10629
+ ] }) });
10799
10630
  };
10800
- const variantItemSchema = z.object({
10801
- quantity: z.number(),
10802
- unit_price: z.union([z.number(), z.string()])
10803
- });
10804
- const CustomItem = ({ item, preview, currencyCode }) => {
10805
- const [editing, setEditing] = useState(false);
10806
- const { quantity, unit_price, title } = item;
10807
- const form = useForm({
10808
- defaultValues: {
10809
- title,
10810
- quantity,
10811
- unit_price
10631
+ const ShippingForm = ({ preview, order }) => {
10632
+ var _a;
10633
+ const { setIsOpen } = useStackedModal();
10634
+ const [isSubmitting, setIsSubmitting] = useState(false);
10635
+ const [data, setData] = useState(null);
10636
+ const appliedShippingOptionIds = (_a = preview.shipping_methods) == null ? void 0 : _a.map((method) => method.shipping_option_id).filter(Boolean);
10637
+ const { shipping_options } = useShippingOptions(
10638
+ {
10639
+ id: appliedShippingOptionIds,
10640
+ fields: "+service_zone.*,+service_zone.fulfillment_set.*,+service_zone.fulfillment_set.location.*"
10812
10641
  },
10813
- resolver: zodResolver(customItemSchema)
10814
- });
10815
- useEffect(() => {
10816
- form.reset({
10817
- title,
10818
- quantity,
10819
- unit_price
10820
- });
10821
- }, [form, title, quantity, unit_price]);
10822
- const actionId = useMemo(() => {
10823
- var _a, _b;
10824
- return (_b = (_a = item.actions) == null ? void 0 : _a.find((a) => a.action === "ITEM_ADD")) == null ? void 0 : _b.id;
10825
- }, [item]);
10826
- const { mutateAsync: updateActionItem, isPending: isUpdatingActionItem } = useDraftOrderUpdateActionItem(preview.id);
10827
- const { mutateAsync: removeActionItem, isPending: isRemovingActionItem } = useDraftOrderRemoveActionItem(preview.id);
10828
- const { mutateAsync: updateOriginalItem, isPending: isUpdatingOriginalItem } = useDraftOrderUpdateItem(preview.id);
10829
- const isPending = isUpdatingActionItem || isUpdatingOriginalItem;
10830
- const onSubmit = form.handleSubmit(async (data) => {
10831
- if (convertNumber(data.unit_price) === item.unit_price && data.quantity === item.quantity && data.title === item.title) {
10832
- setEditing(false);
10833
- return;
10834
- }
10835
- if (!actionId) {
10836
- await updateOriginalItem(
10837
- {
10838
- item_id: item.id,
10839
- quantity: data.quantity,
10840
- unit_price: convertNumber(data.unit_price)
10841
- },
10842
- {
10843
- onSuccess: () => {
10844
- setEditing(false);
10845
- },
10846
- onError: (e) => {
10847
- toast.error(e.message);
10848
- }
10849
- }
10850
- );
10851
- return;
10642
+ {
10643
+ enabled: appliedShippingOptionIds.length > 0
10852
10644
  }
10853
- if (data.quantity === 0) {
10854
- await removeActionItem(actionId, {
10855
- onSuccess: () => {
10856
- setEditing(false);
10857
- },
10858
- onError: (e) => {
10859
- toast.error(e.message);
10860
- }
10861
- });
10645
+ );
10646
+ const uniqueShippingProfiles = useMemo(() => {
10647
+ const profiles = /* @__PURE__ */ new Map();
10648
+ getUniqueShippingProfiles(order.items).forEach((profile) => {
10649
+ profiles.set(profile.id, profile);
10650
+ });
10651
+ shipping_options == null ? void 0 : shipping_options.forEach((option) => {
10652
+ profiles.set(option.shipping_profile_id, option.shipping_profile);
10653
+ });
10654
+ return Array.from(profiles.values());
10655
+ }, [order.items, shipping_options]);
10656
+ const { handleSuccess } = useRouteModal();
10657
+ const { mutateAsync: confirmOrderEdit } = useDraftOrderConfirmEdit(preview.id);
10658
+ const { mutateAsync: requestOrderEdit } = useDraftOrderRequestEdit(preview.id);
10659
+ const { mutateAsync: removeShippingMethod } = useDraftOrderRemoveShippingMethod(preview.id);
10660
+ const { mutateAsync: removeActionShippingMethod } = useDraftOrderRemoveActionShippingMethod(preview.id);
10661
+ const onSubmit = async () => {
10662
+ setIsSubmitting(true);
10663
+ let requestSucceeded = false;
10664
+ await requestOrderEdit(void 0, {
10665
+ onError: (e) => {
10666
+ toast.error(`Failed to request order edit: ${e.message}`);
10667
+ },
10668
+ onSuccess: () => {
10669
+ requestSucceeded = true;
10670
+ }
10671
+ });
10672
+ if (!requestSucceeded) {
10673
+ setIsSubmitting(false);
10862
10674
  return;
10863
10675
  }
10864
- await updateActionItem(
10865
- {
10866
- action_id: actionId,
10867
- quantity: data.quantity,
10868
- unit_price: convertNumber(data.unit_price)
10676
+ await confirmOrderEdit(void 0, {
10677
+ onError: (e) => {
10678
+ toast.error(`Failed to confirm order edit: ${e.message}`);
10869
10679
  },
10870
- {
10871
- onSuccess: () => {
10872
- setEditing(false);
10873
- },
10874
- onError: (e) => {
10875
- toast.error(e.message);
10876
- }
10680
+ onSuccess: () => {
10681
+ handleSuccess();
10682
+ },
10683
+ onSettled: () => {
10684
+ setIsSubmitting(false);
10877
10685
  }
10878
- );
10879
- });
10880
- return /* @__PURE__ */ jsx(Form$2, { ...form, children: /* @__PURE__ */ jsx("form", { onSubmit, children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-[minmax(0,1fr)_minmax(0,1fr)_minmax(0,1fr)_28px] gap-3 px-4 py-2 bg-ui-bg-base shadow-elevation-card-rest rounded-lg items-center", children: [
10881
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-3", children: [
10882
- /* @__PURE__ */ jsx(
10883
- Thumbnail,
10884
- {
10885
- thumbnail: item.thumbnail,
10886
- alt: item.title ?? void 0
10887
- }
10888
- ),
10889
- editing ? /* @__PURE__ */ jsx(
10890
- Form$2.Field,
10891
- {
10892
- control: form.control,
10893
- name: "title",
10894
- render: ({ field }) => {
10895
- return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(Input, { ...field }) }) });
10896
- }
10897
- }
10898
- ) : /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: item.title })
10899
- ] }),
10900
- editing ? /* @__PURE__ */ jsx(
10901
- Form$2.Field,
10902
- {
10903
- control: form.control,
10904
- name: "quantity",
10905
- render: ({ field }) => {
10906
- return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(NumberInput, { ...field }) }) });
10907
- }
10908
- }
10909
- ) : /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: item.quantity }),
10910
- editing ? /* @__PURE__ */ jsx(
10911
- Form$2.Field,
10912
- {
10913
- control: form.control,
10914
- name: "unit_price",
10915
- render: ({ field: { onChange, ...field } }) => {
10916
- return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
10917
- CurrencyInput,
10918
- {
10919
- ...field,
10920
- symbol: getNativeSymbol(currencyCode),
10921
- code: currencyCode,
10922
- onValueChange: (_value, _name, values) => onChange(values == null ? void 0 : values.value)
10923
- }
10924
- ) }) });
10686
+ });
10687
+ };
10688
+ const onKeydown = useCallback(
10689
+ (e) => {
10690
+ if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) {
10691
+ if (data || isSubmitting) {
10692
+ return;
10925
10693
  }
10694
+ onSubmit();
10926
10695
  }
10927
- ) : /* @__PURE__ */ jsx("div", { className: "flex-1 flex items-center justify-end", children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: getLocaleAmount(item.unit_price, currencyCode) }) }),
10928
- /* @__PURE__ */ jsx(
10929
- IconButton,
10930
- {
10931
- type: "button",
10932
- size: "small",
10933
- onClick: editing ? onSubmit : () => {
10934
- setEditing(true);
10935
- },
10936
- disabled: isPending,
10937
- children: editing ? /* @__PURE__ */ jsx(Check, {}) : /* @__PURE__ */ jsx(PencilSquare, {})
10938
- }
10939
- )
10940
- ] }) }) });
10941
- };
10942
- const StackedModalTrigger$1 = ({
10943
- type,
10944
- setModalContent
10945
- }) => {
10946
- const { setIsOpen } = useStackedModal();
10947
- const onClick = useCallback(() => {
10948
- setModalContent(type);
10949
- setIsOpen(STACKED_MODAL_ID, true);
10950
- }, [setModalContent, setIsOpen, type]);
10951
- return /* @__PURE__ */ jsx(StackedFocusModal.Trigger, { asChild: true, children: /* @__PURE__ */ jsx(DropdownMenu.Item, { onClick, children: type === "add-items" ? "Add items" : "Add custom item" }) });
10952
- };
10953
- const VARIANT_PREFIX = "items";
10954
- const LIMIT = 50;
10955
- const ExistingItemsForm = ({ orderId, items }) => {
10956
- const { setIsOpen } = useStackedModal();
10957
- const [rowSelection, setRowSelection] = useState(
10958
- items.reduce((acc, item) => {
10959
- acc[item.variant_id] = true;
10960
- return acc;
10961
- }, {})
10962
- );
10963
- useEffect(() => {
10964
- setRowSelection(
10965
- items.reduce((acc, item) => {
10966
- if (item.variant_id) {
10967
- acc[item.variant_id] = true;
10968
- }
10969
- return acc;
10970
- }, {})
10971
- );
10972
- }, [items]);
10973
- const { q, order, offset } = useQueryParams(
10974
- ["q", "order", "offset"],
10975
- VARIANT_PREFIX
10976
- );
10977
- const { variants, count, isPending, isError, error } = useProductVariants(
10978
- {
10979
- q,
10980
- order,
10981
- offset: offset ? parseInt(offset) : void 0,
10982
- limit: LIMIT
10983
10696
  },
10984
- {
10985
- placeholderData: keepPreviousData
10986
- }
10697
+ [data, isSubmitting, onSubmit]
10987
10698
  );
10988
- const columns = useColumns();
10989
- const { mutateAsync } = useDraftOrderAddItems(orderId);
10990
- const onSubmit = async () => {
10991
- const ids = Object.keys(rowSelection).filter(
10992
- (id) => !items.find((i) => i.variant_id === id)
10993
- );
10994
- await mutateAsync(
10995
- {
10996
- items: ids.map((id) => ({
10997
- variant_id: id,
10998
- quantity: 1
10999
- }))
11000
- },
11001
- {
11002
- onSuccess: () => {
11003
- setRowSelection({});
11004
- setIsOpen(STACKED_MODAL_ID, false);
11005
- },
11006
- onError: (e) => {
11007
- toast.error(e.message);
11008
- }
11009
- }
11010
- );
11011
- };
11012
- if (isError) {
11013
- throw error;
11014
- }
11015
- return /* @__PURE__ */ jsxs(
11016
- StackedFocusModal.Content,
11017
- {
11018
- onOpenAutoFocus: (e) => {
11019
- e.preventDefault();
11020
- const searchInput = document.querySelector(
11021
- "[data-modal-id='modal-search-input']"
11022
- );
11023
- if (searchInput) {
11024
- searchInput.focus();
11025
- }
11026
- },
11027
- children: [
11028
- /* @__PURE__ */ jsxs(StackedFocusModal.Header, { children: [
11029
- /* @__PURE__ */ jsx(StackedFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Product Variants" }) }),
11030
- /* @__PURE__ */ jsx(StackedFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Choose product variants to add to the order." }) })
10699
+ useEffect(() => {
10700
+ document.addEventListener("keydown", onKeydown);
10701
+ return () => {
10702
+ document.removeEventListener("keydown", onKeydown);
10703
+ };
10704
+ }, [onKeydown]);
10705
+ return /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-col overflow-hidden", children: [
10706
+ /* @__PURE__ */ jsx(RouteFocusModal.Header, {}),
10707
+ /* @__PURE__ */ jsxs(RouteFocusModal.Body, { className: "flex flex-1 flex-col overflow-hidden", children: [
10708
+ /* @__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 py-16 px-6", children: [
10709
+ /* @__PURE__ */ jsxs("div", { children: [
10710
+ /* @__PURE__ */ jsx(RouteFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Shipping" }) }),
10711
+ /* @__PURE__ */ jsx(RouteFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Choose which shipping method(s) to use for the items in the order." }) })
11031
10712
  ] }),
11032
- /* @__PURE__ */ jsx(StackedFocusModal.Body, { className: "flex-1 overflow-hidden", children: /* @__PURE__ */ jsx(
11033
- DataTable,
11034
- {
11035
- data: variants,
11036
- columns,
11037
- isLoading: isPending,
11038
- getRowId: (row) => row.id,
11039
- rowCount: count,
11040
- prefix: VARIANT_PREFIX,
11041
- layout: "fill",
11042
- rowSelection: {
11043
- state: rowSelection,
11044
- onRowSelectionChange: setRowSelection,
11045
- enableRowSelection: (row) => {
11046
- return !items.find((i) => i.variant_id === row.original.id);
11047
- }
11048
- },
11049
- autoFocusSearch: true
11050
- }
11051
- ) }),
11052
- /* @__PURE__ */ jsx(StackedFocusModal.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-2 justify-end", children: [
11053
- /* @__PURE__ */ jsx(StackedFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
11054
- /* @__PURE__ */ jsx(Button, { size: "small", type: "button", onClick: onSubmit, children: "Update items" })
11055
- ] }) })
11056
- ]
11057
- }
11058
- );
11059
- };
11060
- const columnHelper = createDataTableColumnHelper();
11061
- const useColumns = () => {
11062
- return useMemo(() => {
11063
- return [
11064
- columnHelper.select(),
11065
- columnHelper.accessor("product.title", {
11066
- header: "Product",
11067
- cell: ({ row }) => {
11068
- var _a, _b, _c;
11069
- return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-2", children: [
10713
+ /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
10714
+ /* @__PURE__ */ jsx(Accordion.Root, { type: "multiple", children: /* @__PURE__ */ jsxs("div", { className: "bg-ui-bg-subtle rounded-xl shadow-elevation-card-rest", children: [
10715
+ /* @__PURE__ */ jsxs("div", { className: "px-4 py-2 flex items-center justify-between", children: [
11070
10716
  /* @__PURE__ */ jsx(
11071
- Thumbnail,
10717
+ Text,
11072
10718
  {
11073
- thumbnail: (_a = row.original.product) == null ? void 0 : _a.thumbnail,
11074
- alt: (_b = row.original.product) == null ? void 0 : _b.title
11075
- }
11076
- ),
11077
- /* @__PURE__ */ jsx("span", { children: (_c = row.original.product) == null ? void 0 : _c.title })
11078
- ] });
11079
- },
11080
- enableSorting: true
11081
- }),
11082
- columnHelper.accessor("title", {
11083
- header: "Variant",
11084
- enableSorting: true
11085
- }),
11086
- columnHelper.accessor("sku", {
11087
- header: "SKU",
11088
- cell: ({ getValue }) => {
11089
- return getValue() ?? "-";
11090
- },
11091
- enableSorting: true
11092
- }),
11093
- columnHelper.accessor("updated_at", {
11094
- header: "Updated",
11095
- cell: ({ getValue }) => {
11096
- return /* @__PURE__ */ jsx(
11097
- Tooltip,
11098
- {
11099
- content: getFullDate({ date: getValue(), includeTime: true }),
11100
- children: /* @__PURE__ */ jsx("span", { children: getFullDate({ date: getValue() }) })
11101
- }
11102
- );
11103
- },
11104
- enableSorting: true,
11105
- sortAscLabel: "Oldest first",
11106
- sortDescLabel: "Newest first"
11107
- }),
11108
- columnHelper.accessor("created_at", {
11109
- header: "Created",
11110
- cell: ({ getValue }) => {
11111
- return /* @__PURE__ */ jsx(
11112
- Tooltip,
11113
- {
11114
- content: getFullDate({ date: getValue(), includeTime: true }),
11115
- children: /* @__PURE__ */ jsx("span", { children: getFullDate({ date: getValue() }) })
11116
- }
11117
- );
11118
- },
11119
- enableSorting: true,
11120
- sortAscLabel: "Oldest first",
11121
- sortDescLabel: "Newest first"
11122
- })
11123
- ];
11124
- }, []);
11125
- };
11126
- const CustomItemForm = ({ orderId, currencyCode }) => {
11127
- const { setIsOpen } = useStackedModal();
11128
- const { mutateAsync: addItems } = useDraftOrderAddItems(orderId);
11129
- const form = useForm({
11130
- defaultValues: {
11131
- title: "",
11132
- quantity: 1,
11133
- unit_price: ""
11134
- },
11135
- resolver: zodResolver(customItemSchema)
11136
- });
11137
- const onSubmit = form.handleSubmit(async (data) => {
11138
- await addItems(
11139
- {
11140
- items: [
11141
- {
11142
- title: data.title,
11143
- quantity: data.quantity,
11144
- unit_price: convertNumber(data.unit_price)
11145
- }
11146
- ]
11147
- },
11148
- {
11149
- onSuccess: () => {
11150
- setIsOpen(STACKED_MODAL_ID, false);
11151
- },
11152
- onError: (e) => {
11153
- toast.error(e.message);
11154
- }
11155
- }
11156
- );
11157
- });
11158
- return /* @__PURE__ */ jsx(Form$2, { ...form, children: /* @__PURE__ */ jsx(KeyboundForm, { onSubmit, children: /* @__PURE__ */ jsxs(StackedFocusModal.Content, { children: [
11159
- /* @__PURE__ */ jsx(StackedFocusModal.Header, {}),
11160
- /* @__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: [
11161
- /* @__PURE__ */ jsxs("div", { children: [
11162
- /* @__PURE__ */ jsx(StackedFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Add custom item" }) }),
11163
- /* @__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." }) })
11164
- ] }),
11165
- /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
11166
- /* @__PURE__ */ jsx(
11167
- Form$2.Field,
11168
- {
11169
- control: form.control,
11170
- name: "title",
11171
- render: ({ field }) => /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
11172
- /* @__PURE__ */ jsxs("div", { children: [
11173
- /* @__PURE__ */ jsx(Form$2.Label, { children: "Title" }),
11174
- /* @__PURE__ */ jsx(Form$2.Hint, { children: "Enter the title of the item" })
11175
- ] }),
11176
- /* @__PURE__ */ jsxs("div", { children: [
11177
- /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(Input, { ...field }) }),
11178
- /* @__PURE__ */ jsx(Form$2.ErrorMessage, {})
11179
- ] })
11180
- ] }) })
11181
- }
11182
- ),
11183
- /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
11184
- /* @__PURE__ */ jsx(
11185
- Form$2.Field,
11186
- {
11187
- control: form.control,
11188
- name: "unit_price",
11189
- render: ({ field: { onChange, ...field } }) => /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
11190
- /* @__PURE__ */ jsxs("div", { children: [
11191
- /* @__PURE__ */ jsx(Form$2.Label, { children: "Unit price" }),
11192
- /* @__PURE__ */ jsx(Form$2.Hint, { children: "Enter the unit price of the item" })
11193
- ] }),
11194
- /* @__PURE__ */ jsxs("div", { children: [
11195
- /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
11196
- CurrencyInput,
11197
- {
11198
- symbol: getNativeSymbol(currencyCode),
11199
- code: currencyCode,
11200
- onValueChange: (_value, _name, values) => onChange(values == null ? void 0 : values.value),
11201
- ...field
11202
- }
11203
- ) }),
11204
- /* @__PURE__ */ jsx(Form$2.ErrorMessage, {})
11205
- ] })
11206
- ] }) })
11207
- }
11208
- ),
11209
- /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
11210
- /* @__PURE__ */ jsx(
11211
- Form$2.Field,
11212
- {
11213
- control: form.control,
11214
- name: "quantity",
11215
- render: ({ field }) => /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
11216
- /* @__PURE__ */ jsxs("div", { children: [
11217
- /* @__PURE__ */ jsx(Form$2.Label, { children: "Quantity" }),
11218
- /* @__PURE__ */ jsx(Form$2.Hint, { children: "Enter the quantity of the item" })
11219
- ] }),
11220
- /* @__PURE__ */ jsxs("div", { className: "flex-1 w-full", children: [
11221
- /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx("div", { className: "flex-1 w-full", children: /* @__PURE__ */ jsx(NumberInput, { ...field, className: "w-full" }) }) }),
11222
- /* @__PURE__ */ jsx(Form$2.ErrorMessage, {})
11223
- ] })
11224
- ] }) })
11225
- }
11226
- )
11227
- ] }) }) }),
11228
- /* @__PURE__ */ jsx(StackedFocusModal.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-2 justify-end", children: [
11229
- /* @__PURE__ */ jsx(StackedFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
11230
- /* @__PURE__ */ jsx(Button, { size: "small", type: "button", onClick: onSubmit, children: "Add item" })
11231
- ] }) })
11232
- ] }) }) });
11233
- };
11234
- const customItemSchema = z.object({
11235
- title: z.string().min(1),
11236
- quantity: z.number(),
11237
- unit_price: z.union([z.number(), z.string()])
11238
- });
11239
- const InlineTip = forwardRef(
11240
- ({ variant = "tip", label, className, children, ...props }, ref) => {
11241
- const labelValue = label || (variant === "warning" ? "Warning" : "Tip");
11242
- return /* @__PURE__ */ jsxs(
11243
- "div",
11244
- {
11245
- ref,
11246
- className: clx(
11247
- "bg-ui-bg-component txt-small text-ui-fg-subtle grid grid-cols-[4px_1fr] items-start gap-3 rounded-lg border p-3",
11248
- className
11249
- ),
11250
- ...props,
11251
- children: [
11252
- /* @__PURE__ */ jsx(
11253
- "div",
11254
- {
11255
- role: "presentation",
11256
- className: clx("w-4px bg-ui-tag-neutral-icon h-full rounded-full", {
11257
- "bg-ui-tag-orange-icon": variant === "warning"
11258
- })
11259
- }
11260
- ),
11261
- /* @__PURE__ */ jsxs("div", { className: "text-pretty", children: [
11262
- /* @__PURE__ */ jsxs("strong", { className: "txt-small-plus text-ui-fg-base", children: [
11263
- labelValue,
11264
- ":"
11265
- ] }),
11266
- " ",
11267
- children
11268
- ] })
11269
- ]
11270
- }
11271
- );
11272
- }
11273
- );
11274
- InlineTip.displayName = "InlineTip";
11275
- const MetadataFieldSchema = z.object({
11276
- key: z.string(),
11277
- disabled: z.boolean().optional(),
11278
- value: z.any()
11279
- });
11280
- const MetadataSchema = z.object({
11281
- metadata: z.array(MetadataFieldSchema)
11282
- });
11283
- const Metadata = () => {
11284
- const { id } = useParams();
11285
- const { order, isPending, isError, error } = useOrder(id, {
11286
- fields: "metadata"
11287
- });
11288
- if (isError) {
11289
- throw error;
11290
- }
11291
- const isReady = !isPending && !!order;
11292
- return /* @__PURE__ */ jsxs(RouteDrawer, { children: [
11293
- /* @__PURE__ */ jsxs(RouteDrawer.Header, { children: [
11294
- /* @__PURE__ */ jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Metadata" }) }),
11295
- /* @__PURE__ */ jsx(RouteDrawer.Description, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Add metadata to the draft order." }) })
11296
- ] }),
11297
- !isReady ? /* @__PURE__ */ jsx(PlaceholderInner, {}) : /* @__PURE__ */ jsx(MetadataForm, { orderId: id, metadata: order == null ? void 0 : order.metadata })
11298
- ] });
11299
- };
11300
- const METADATA_KEY_LABEL_ID = "metadata-form-key-label";
11301
- const METADATA_VALUE_LABEL_ID = "metadata-form-value-label";
11302
- const MetadataForm = ({ orderId, metadata }) => {
11303
- const { handleSuccess } = useRouteModal();
11304
- const hasUneditableRows = getHasUneditableRows(metadata);
11305
- const { mutateAsync, isPending } = useUpdateDraftOrder(orderId);
11306
- const form = useForm({
11307
- defaultValues: {
11308
- metadata: getDefaultValues(metadata)
11309
- },
11310
- resolver: zodResolver(MetadataSchema)
11311
- });
11312
- const handleSubmit = form.handleSubmit(async (data) => {
11313
- const parsedData = parseValues(data);
11314
- await mutateAsync(
11315
- {
11316
- metadata: parsedData
11317
- },
11318
- {
11319
- onSuccess: () => {
11320
- toast.success("Metadata updated");
11321
- handleSuccess();
11322
- },
11323
- onError: (error) => {
11324
- toast.error(error.message);
11325
- }
11326
- }
11327
- );
11328
- });
11329
- const { fields, insert, remove } = useFieldArray({
11330
- control: form.control,
11331
- name: "metadata"
11332
- });
11333
- function deleteRow(index) {
11334
- remove(index);
11335
- if (fields.length === 1) {
11336
- insert(0, {
11337
- key: "",
11338
- value: "",
11339
- disabled: false
11340
- });
11341
- }
11342
- }
11343
- function insertRow(index, position) {
11344
- insert(index + (position === "above" ? 0 : 1), {
11345
- key: "",
11346
- value: "",
11347
- disabled: false
11348
- });
11349
- }
11350
- return /* @__PURE__ */ jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxs(
11351
- KeyboundForm,
11352
- {
11353
- onSubmit: handleSubmit,
11354
- className: "flex flex-1 flex-col overflow-hidden",
11355
- children: [
11356
- /* @__PURE__ */ jsxs(RouteDrawer.Body, { className: "flex flex-1 flex-col gap-y-8 overflow-y-auto", children: [
11357
- /* @__PURE__ */ jsxs("div", { className: "bg-ui-bg-base shadow-elevation-card-rest grid grid-cols-1 divide-y rounded-lg", children: [
11358
- /* @__PURE__ */ jsxs("div", { className: "bg-ui-bg-subtle grid grid-cols-2 divide-x rounded-t-lg", children: [
11359
- /* @__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" }) }),
11360
- /* @__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" }) })
11361
- ] }),
11362
- fields.map((field, index) => {
11363
- const isDisabled = field.disabled || false;
11364
- let placeholder = "-";
11365
- if (typeof field.value === "object") {
11366
- placeholder = "{ ... }";
11367
- }
11368
- if (Array.isArray(field.value)) {
11369
- placeholder = "[ ... ]";
11370
- }
11371
- return /* @__PURE__ */ jsx(
11372
- ConditionalTooltip,
11373
- {
11374
- showTooltip: isDisabled,
11375
- content: "This row is disabled because it contains non-primitive data.",
11376
- children: /* @__PURE__ */ jsxs("div", { className: "group/table relative", children: [
11377
- /* @__PURE__ */ jsxs(
11378
- "div",
11379
- {
11380
- className: clx("grid grid-cols-2 divide-x", {
11381
- "overflow-hidden rounded-b-lg": index === fields.length - 1
11382
- }),
11383
- children: [
11384
- /* @__PURE__ */ jsx(
11385
- Form$2.Field,
11386
- {
11387
- control: form.control,
11388
- name: `metadata.${index}.key`,
11389
- render: ({ field: field2 }) => {
11390
- return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
11391
- GridInput,
11392
- {
11393
- "aria-labelledby": METADATA_KEY_LABEL_ID,
11394
- ...field2,
11395
- disabled: isDisabled,
11396
- placeholder: "Key"
11397
- }
11398
- ) }) });
11399
- }
11400
- }
11401
- ),
11402
- /* @__PURE__ */ jsx(
11403
- Form$2.Field,
11404
- {
11405
- control: form.control,
11406
- name: `metadata.${index}.value`,
11407
- render: ({ field: { value, ...field2 } }) => {
11408
- return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
11409
- GridInput,
11410
- {
11411
- "aria-labelledby": METADATA_VALUE_LABEL_ID,
11412
- ...field2,
11413
- value: isDisabled ? placeholder : value,
11414
- disabled: isDisabled,
11415
- placeholder: "Value"
11416
- }
11417
- ) }) });
11418
- }
11419
- }
11420
- )
11421
- ]
11422
- }
11423
- ),
11424
- /* @__PURE__ */ jsxs(DropdownMenu, { children: [
11425
- /* @__PURE__ */ jsx(
11426
- DropdownMenu.Trigger,
11427
- {
11428
- className: clx(
11429
- "invisible absolute inset-y-0 -right-2.5 my-auto group-hover/table:visible data-[state='open']:visible",
11430
- {
11431
- hidden: isDisabled
11432
- }
11433
- ),
11434
- disabled: isDisabled,
11435
- asChild: true,
11436
- children: /* @__PURE__ */ jsx(IconButton, { size: "2xsmall", children: /* @__PURE__ */ jsx(EllipsisVertical, {}) })
11437
- }
11438
- ),
11439
- /* @__PURE__ */ jsxs(DropdownMenu.Content, { children: [
11440
- /* @__PURE__ */ jsxs(
11441
- DropdownMenu.Item,
11442
- {
11443
- className: "gap-x-2",
11444
- onClick: () => insertRow(index, "above"),
11445
- children: [
11446
- /* @__PURE__ */ jsx(ArrowUpMini, { className: "text-ui-fg-subtle" }),
11447
- "Insert row above"
11448
- ]
11449
- }
11450
- ),
11451
- /* @__PURE__ */ jsxs(
11452
- DropdownMenu.Item,
11453
- {
11454
- className: "gap-x-2",
11455
- onClick: () => insertRow(index, "below"),
11456
- children: [
11457
- /* @__PURE__ */ jsx(ArrowDownMini, { className: "text-ui-fg-subtle" }),
11458
- "Insert row below"
11459
- ]
11460
- }
11461
- ),
11462
- /* @__PURE__ */ jsx(DropdownMenu.Separator, {}),
11463
- /* @__PURE__ */ jsxs(
11464
- DropdownMenu.Item,
11465
- {
11466
- className: "gap-x-2",
11467
- onClick: () => deleteRow(index),
11468
- children: [
11469
- /* @__PURE__ */ jsx(Trash, { className: "text-ui-fg-subtle" }),
11470
- "Delete row"
11471
- ]
11472
- }
11473
- )
11474
- ] })
11475
- ] })
11476
- ] })
11477
- },
11478
- field.id
11479
- );
11480
- })
11481
- ] }),
11482
- 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." })
11483
- ] }),
11484
- /* @__PURE__ */ jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
11485
- /* @__PURE__ */ jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
11486
- /* @__PURE__ */ jsx(Button, { size: "small", type: "submit", isLoading: isPending, children: "Save" })
11487
- ] }) })
11488
- ]
11489
- }
11490
- ) });
11491
- };
11492
- const GridInput = forwardRef(({ className, ...props }, ref) => {
11493
- return /* @__PURE__ */ jsx(
11494
- "input",
11495
- {
11496
- ref,
11497
- ...props,
11498
- autoComplete: "off",
11499
- className: clx(
11500
- "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",
11501
- className
11502
- )
11503
- }
11504
- );
11505
- });
11506
- GridInput.displayName = "MetadataForm.GridInput";
11507
- const PlaceholderInner = () => {
11508
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col overflow-hidden", children: [
11509
- /* @__PURE__ */ jsx(RouteDrawer.Body, { children: /* @__PURE__ */ jsx(Skeleton, { className: "h-[148ox] w-full rounded-lg" }) }),
11510
- /* @__PURE__ */ jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
11511
- /* @__PURE__ */ jsx(Skeleton, { className: "h-7 w-12 rounded-md" }),
11512
- /* @__PURE__ */ jsx(Skeleton, { className: "h-7 w-12 rounded-md" })
11513
- ] }) })
11514
- ] });
11515
- };
11516
- const EDITABLE_TYPES = ["string", "number", "boolean"];
11517
- function getDefaultValues(metadata) {
11518
- if (!metadata || !Object.keys(metadata).length) {
11519
- return [
11520
- {
11521
- key: "",
11522
- value: "",
11523
- disabled: false
11524
- }
11525
- ];
11526
- }
11527
- return Object.entries(metadata).map(([key, value]) => {
11528
- if (!EDITABLE_TYPES.includes(typeof value)) {
11529
- return {
11530
- key,
11531
- value,
11532
- disabled: true
11533
- };
11534
- }
11535
- let stringValue = value;
11536
- if (typeof value !== "string") {
11537
- stringValue = JSON.stringify(value);
11538
- }
11539
- return {
11540
- key,
11541
- value: stringValue,
11542
- original_key: key
11543
- };
11544
- });
11545
- }
11546
- function parseValues(values) {
11547
- const metadata = values.metadata;
11548
- const isEmpty = !metadata.length || metadata.length === 1 && !metadata[0].key && !metadata[0].value;
11549
- if (isEmpty) {
11550
- return null;
11551
- }
11552
- const update = {};
11553
- metadata.forEach((field) => {
11554
- let key = field.key;
11555
- let value = field.value;
11556
- const disabled = field.disabled;
11557
- if (!key || !value) {
11558
- return;
11559
- }
11560
- if (disabled) {
11561
- update[key] = value;
11562
- return;
11563
- }
11564
- key = key.trim();
11565
- value = value.trim();
11566
- if (value === "true") {
11567
- update[key] = true;
11568
- } else if (value === "false") {
11569
- update[key] = false;
11570
- } else {
11571
- const parsedNumber = parseFloat(value);
11572
- if (!isNaN(parsedNumber)) {
11573
- update[key] = parsedNumber;
11574
- } else {
11575
- update[key] = value;
11576
- }
11577
- }
11578
- });
11579
- return update;
11580
- }
11581
- function getHasUneditableRows(metadata) {
11582
- if (!metadata) {
11583
- return false;
11584
- }
11585
- return Object.values(metadata).some(
11586
- (value) => !EDITABLE_TYPES.includes(typeof value)
11587
- );
11588
- }
11589
- const STACKED_FOCUS_MODAL_ID = "shipping-form";
11590
- const Shipping = () => {
11591
- var _a;
11592
- const { id } = useParams();
11593
- const { order, isPending, isError, error } = useOrder(id, {
11594
- fields: "+items.*,+items.variant.*,+items.variant.product.*,+items.variant.product.shipping_profile.*,+currency_code"
11595
- });
11596
- const {
11597
- order: preview,
11598
- isPending: isPreviewPending,
11599
- isError: isPreviewError,
11600
- error: previewError
11601
- } = useOrderPreview(id);
11602
- useInitiateOrderEdit({ preview });
11603
- const { onCancel } = useCancelOrderEdit({ preview });
11604
- if (isError) {
11605
- throw error;
11606
- }
11607
- if (isPreviewError) {
11608
- throw previewError;
11609
- }
11610
- const orderHasItems = (((_a = order == null ? void 0 : order.items) == null ? void 0 : _a.length) || 0) > 0;
11611
- const isReady = preview && !isPreviewPending && order && !isPending;
11612
- return /* @__PURE__ */ jsx(RouteFocusModal, { onClose: onCancel, children: !orderHasItems ? /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-col overflow-hidden ", children: [
11613
- /* @__PURE__ */ jsx(RouteFocusModal.Header, {}),
11614
- /* @__PURE__ */ jsx(RouteFocusModal.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 py-16 px-6", children: [
11615
- /* @__PURE__ */ jsx(RouteFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Shipping" }) }),
11616
- /* @__PURE__ */ jsx(RouteFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "This draft order currently has no items. Add items to the order before adding shipping." }) })
11617
- ] }) }) }),
11618
- /* @__PURE__ */ jsx(RouteFocusModal.Footer, { children: /* @__PURE__ */ jsx(RouteFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }) })
11619
- ] }) : isReady ? /* @__PURE__ */ jsx(ShippingForm, { preview, order }) : /* @__PURE__ */ jsxs("div", { children: [
11620
- /* @__PURE__ */ jsx(RouteFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Edit Shipping" }) }),
11621
- /* @__PURE__ */ jsx(RouteFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Loading data for the draft order, please wait..." }) })
11622
- ] }) });
11623
- };
11624
- const ShippingForm = ({ preview, order }) => {
11625
- var _a;
11626
- const { setIsOpen } = useStackedModal();
11627
- const [isSubmitting, setIsSubmitting] = useState(false);
11628
- const [data, setData] = useState(null);
11629
- const appliedShippingOptionIds = (_a = preview.shipping_methods) == null ? void 0 : _a.map((method) => method.shipping_option_id).filter(Boolean);
11630
- const { shipping_options } = useShippingOptions(
11631
- {
11632
- id: appliedShippingOptionIds,
11633
- fields: "+service_zone.*,+service_zone.fulfillment_set.*,+service_zone.fulfillment_set.location.*"
11634
- },
11635
- {
11636
- enabled: appliedShippingOptionIds.length > 0
11637
- }
11638
- );
11639
- const uniqueShippingProfiles = useMemo(() => {
11640
- const profiles = /* @__PURE__ */ new Map();
11641
- getUniqueShippingProfiles(order.items).forEach((profile) => {
11642
- profiles.set(profile.id, profile);
11643
- });
11644
- shipping_options == null ? void 0 : shipping_options.forEach((option) => {
11645
- profiles.set(option.shipping_profile_id, option.shipping_profile);
11646
- });
11647
- return Array.from(profiles.values());
11648
- }, [order.items, shipping_options]);
11649
- const { handleSuccess } = useRouteModal();
11650
- const { mutateAsync: confirmOrderEdit } = useDraftOrderConfirmEdit(preview.id);
11651
- const { mutateAsync: requestOrderEdit } = useDraftOrderRequestEdit(preview.id);
11652
- const { mutateAsync: removeShippingMethod } = useDraftOrderRemoveShippingMethod(preview.id);
11653
- const { mutateAsync: removeActionShippingMethod } = useDraftOrderRemoveActionShippingMethod(preview.id);
11654
- const onSubmit = async () => {
11655
- setIsSubmitting(true);
11656
- let requestSucceeded = false;
11657
- await requestOrderEdit(void 0, {
11658
- onError: (e) => {
11659
- toast.error(`Failed to request order edit: ${e.message}`);
11660
- },
11661
- onSuccess: () => {
11662
- requestSucceeded = true;
11663
- }
11664
- });
11665
- if (!requestSucceeded) {
11666
- setIsSubmitting(false);
11667
- return;
11668
- }
11669
- await confirmOrderEdit(void 0, {
11670
- onError: (e) => {
11671
- toast.error(`Failed to confirm order edit: ${e.message}`);
11672
- },
11673
- onSuccess: () => {
11674
- handleSuccess();
11675
- },
11676
- onSettled: () => {
11677
- setIsSubmitting(false);
11678
- }
11679
- });
11680
- };
11681
- const onKeydown = useCallback(
11682
- (e) => {
11683
- if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) {
11684
- if (data || isSubmitting) {
11685
- return;
11686
- }
11687
- onSubmit();
11688
- }
11689
- },
11690
- [data, isSubmitting, onSubmit]
11691
- );
11692
- useEffect(() => {
11693
- document.addEventListener("keydown", onKeydown);
11694
- return () => {
11695
- document.removeEventListener("keydown", onKeydown);
11696
- };
11697
- }, [onKeydown]);
11698
- return /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-col overflow-hidden", children: [
11699
- /* @__PURE__ */ jsx(RouteFocusModal.Header, {}),
11700
- /* @__PURE__ */ jsxs(RouteFocusModal.Body, { className: "flex flex-1 flex-col overflow-hidden", children: [
11701
- /* @__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 py-16 px-6", children: [
11702
- /* @__PURE__ */ jsxs("div", { children: [
11703
- /* @__PURE__ */ jsx(RouteFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Shipping" }) }),
11704
- /* @__PURE__ */ jsx(RouteFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Choose which shipping method(s) to use for the items in the order." }) })
11705
- ] }),
11706
- /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
11707
- /* @__PURE__ */ jsx(Accordion.Root, { type: "multiple", children: /* @__PURE__ */ jsxs("div", { className: "bg-ui-bg-subtle rounded-xl shadow-elevation-card-rest", children: [
11708
- /* @__PURE__ */ jsxs("div", { className: "px-4 py-2 flex items-center justify-between", children: [
11709
- /* @__PURE__ */ jsx(
11710
- Text,
11711
- {
11712
- size: "xsmall",
11713
- weight: "plus",
11714
- className: "text-ui-fg-muted",
11715
- children: "Shipping profile"
10719
+ size: "xsmall",
10720
+ weight: "plus",
10721
+ className: "text-ui-fg-muted",
10722
+ children: "Shipping profile"
11716
10723
  }
11717
10724
  ),
11718
10725
  /* @__PURE__ */ jsx(
@@ -11893,7 +10900,7 @@ const ShippingForm = ({ preview, order }) => {
11893
10900
  ]
11894
10901
  }
11895
10902
  ) : /* @__PURE__ */ jsx(
11896
- StackedModalTrigger,
10903
+ StackedModalTrigger$1,
11897
10904
  {
11898
10905
  shippingProfileId: profile.id,
11899
10906
  shippingOption,
@@ -11968,431 +10975,1462 @@ const ShippingForm = ({ preview, order }) => {
11968
10975
  ] }, item.id);
11969
10976
  })
11970
10977
  ] })
11971
- ]
11972
- },
11973
- profile.id
11974
- );
11975
- }) })
11976
- ] }) })
11977
- ] }) }),
11978
- /* @__PURE__ */ jsx(
11979
- StackedFocusModal,
11980
- {
11981
- id: STACKED_FOCUS_MODAL_ID,
11982
- onOpenChangeCallback: (open) => {
11983
- if (!open) {
11984
- setData(null);
10978
+ ]
10979
+ },
10980
+ profile.id
10981
+ );
10982
+ }) })
10983
+ ] }) })
10984
+ ] }) }),
10985
+ /* @__PURE__ */ jsx(
10986
+ StackedFocusModal,
10987
+ {
10988
+ id: STACKED_FOCUS_MODAL_ID,
10989
+ onOpenChangeCallback: (open) => {
10990
+ if (!open) {
10991
+ setData(null);
10992
+ }
10993
+ return open;
10994
+ },
10995
+ children: data && /* @__PURE__ */ jsx(ShippingProfileForm, { data, order, preview })
10996
+ }
10997
+ )
10998
+ ] }),
10999
+ /* @__PURE__ */ jsx(RouteFocusModal.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-x-2", children: [
11000
+ /* @__PURE__ */ jsx(RouteFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
11001
+ /* @__PURE__ */ jsx(
11002
+ Button,
11003
+ {
11004
+ size: "small",
11005
+ type: "button",
11006
+ isLoading: isSubmitting,
11007
+ onClick: onSubmit,
11008
+ children: "Save"
11009
+ }
11010
+ )
11011
+ ] }) })
11012
+ ] });
11013
+ };
11014
+ const StackedModalTrigger$1 = ({
11015
+ shippingProfileId,
11016
+ shippingOption,
11017
+ shippingMethod,
11018
+ setData,
11019
+ children
11020
+ }) => {
11021
+ const { setIsOpen, getIsOpen } = useStackedModal();
11022
+ const isOpen = getIsOpen(STACKED_FOCUS_MODAL_ID);
11023
+ const onToggle = () => {
11024
+ if (isOpen) {
11025
+ setIsOpen(STACKED_FOCUS_MODAL_ID, false);
11026
+ setData(null);
11027
+ } else {
11028
+ setIsOpen(STACKED_FOCUS_MODAL_ID, true);
11029
+ setData({
11030
+ shippingProfileId,
11031
+ shippingOption,
11032
+ shippingMethod
11033
+ });
11034
+ }
11035
+ };
11036
+ return /* @__PURE__ */ jsx(
11037
+ Button,
11038
+ {
11039
+ size: "small",
11040
+ variant: "secondary",
11041
+ onClick: onToggle,
11042
+ className: "text-ui-fg-primary shrink-0",
11043
+ children
11044
+ }
11045
+ );
11046
+ };
11047
+ const ShippingProfileForm = ({
11048
+ data,
11049
+ order,
11050
+ preview
11051
+ }) => {
11052
+ var _a, _b, _c, _d, _e, _f;
11053
+ const { setIsOpen } = useStackedModal();
11054
+ const form = useForm({
11055
+ resolver: zodResolver(shippingMethodSchema),
11056
+ defaultValues: {
11057
+ location_id: (_d = (_c = (_b = (_a = data.shippingOption) == null ? void 0 : _a.service_zone) == null ? void 0 : _b.fulfillment_set) == null ? void 0 : _c.location) == null ? void 0 : _d.id,
11058
+ shipping_option_id: (_e = data.shippingOption) == null ? void 0 : _e.id,
11059
+ custom_amount: (_f = data.shippingMethod) == null ? void 0 : _f.amount
11060
+ }
11061
+ });
11062
+ const { mutateAsync: addShippingMethod, isPending } = useDraftOrderAddShippingMethod(order.id);
11063
+ const {
11064
+ mutateAsync: updateShippingMethod,
11065
+ isPending: isUpdatingShippingMethod
11066
+ } = useDraftOrderUpdateShippingMethod(order.id);
11067
+ const onSubmit = form.handleSubmit(async (values) => {
11068
+ if (isEqual(values, form.formState.defaultValues)) {
11069
+ setIsOpen(STACKED_FOCUS_MODAL_ID, false);
11070
+ return;
11071
+ }
11072
+ if (data.shippingMethod) {
11073
+ await updateShippingMethod(
11074
+ {
11075
+ method_id: data.shippingMethod.id,
11076
+ shipping_option_id: values.shipping_option_id,
11077
+ custom_amount: values.custom_amount ? convertNumber(values.custom_amount) : void 0
11078
+ },
11079
+ {
11080
+ onError: (e) => {
11081
+ toast.error(e.message);
11082
+ },
11083
+ onSuccess: () => {
11084
+ setIsOpen(STACKED_FOCUS_MODAL_ID, false);
11085
+ }
11086
+ }
11087
+ );
11088
+ return;
11089
+ }
11090
+ await addShippingMethod(
11091
+ {
11092
+ shipping_option_id: values.shipping_option_id,
11093
+ custom_amount: values.custom_amount ? convertNumber(values.custom_amount) : void 0
11094
+ },
11095
+ {
11096
+ onError: (e) => {
11097
+ toast.error(e.message);
11098
+ },
11099
+ onSuccess: () => {
11100
+ setIsOpen(STACKED_FOCUS_MODAL_ID, false);
11101
+ }
11102
+ }
11103
+ );
11104
+ });
11105
+ return /* @__PURE__ */ jsx(StackedFocusModal.Content, { children: /* @__PURE__ */ jsx(Form$2, { ...form, children: /* @__PURE__ */ jsxs(
11106
+ KeyboundForm,
11107
+ {
11108
+ className: "flex h-full flex-col overflow-hidden",
11109
+ onSubmit,
11110
+ children: [
11111
+ /* @__PURE__ */ jsx(StackedFocusModal.Header, {}),
11112
+ /* @__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 py-16 px-6", children: [
11113
+ /* @__PURE__ */ jsxs("div", { children: [
11114
+ /* @__PURE__ */ jsx(RouteFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Shipping" }) }),
11115
+ /* @__PURE__ */ jsx(RouteFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Add a shipping method for the selected shipping profile. You can see the items that will be shipped using this method in the preview below." }) })
11116
+ ] }),
11117
+ /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
11118
+ /* @__PURE__ */ jsx(
11119
+ LocationField,
11120
+ {
11121
+ control: form.control,
11122
+ setValue: form.setValue
11123
+ }
11124
+ ),
11125
+ /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
11126
+ /* @__PURE__ */ jsx(
11127
+ ShippingOptionField,
11128
+ {
11129
+ shippingProfileId: data.shippingProfileId,
11130
+ preview,
11131
+ control: form.control
11132
+ }
11133
+ ),
11134
+ /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
11135
+ /* @__PURE__ */ jsx(
11136
+ CustomAmountField,
11137
+ {
11138
+ control: form.control,
11139
+ currencyCode: order.currency_code
11140
+ }
11141
+ ),
11142
+ /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
11143
+ /* @__PURE__ */ jsx(
11144
+ ItemsPreview,
11145
+ {
11146
+ order,
11147
+ shippingProfileId: data.shippingProfileId
11148
+ }
11149
+ )
11150
+ ] }) }) }),
11151
+ /* @__PURE__ */ jsx(StackedFocusModal.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-x-2", children: [
11152
+ /* @__PURE__ */ jsx(StackedFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
11153
+ /* @__PURE__ */ jsx(
11154
+ Button,
11155
+ {
11156
+ size: "small",
11157
+ type: "submit",
11158
+ isLoading: isPending || isUpdatingShippingMethod,
11159
+ children: data.shippingMethod ? "Update" : "Add"
11160
+ }
11161
+ )
11162
+ ] }) })
11163
+ ]
11164
+ }
11165
+ ) }) });
11166
+ };
11167
+ const shippingMethodSchema = z.object({
11168
+ location_id: z.string(),
11169
+ shipping_option_id: z.string(),
11170
+ custom_amount: z.union([z.number(), z.string()]).optional()
11171
+ });
11172
+ const ItemsPreview = ({ order, shippingProfileId }) => {
11173
+ const matches = order.items.filter(
11174
+ (item) => {
11175
+ var _a, _b, _c;
11176
+ return ((_c = (_b = (_a = item.variant) == null ? void 0 : _a.product) == null ? void 0 : _b.shipping_profile) == null ? void 0 : _c.id) === shippingProfileId;
11177
+ }
11178
+ );
11179
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-y-6", children: [
11180
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 items-center gap-3", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
11181
+ /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: "Items to ship" }),
11182
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Items with the selected shipping profile." })
11183
+ ] }) }),
11184
+ /* @__PURE__ */ jsxs("div", { className: "bg-ui-bg-subtle shadow-elevation-card-rest rounded-xl", children: [
11185
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-3 px-4 py-2 text-ui-fg-muted", children: [
11186
+ /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: "Item" }) }),
11187
+ /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: "Quantity" }) })
11188
+ ] }),
11189
+ /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-y-1.5 px-[5px] pb-[5px]", children: matches.length > 0 ? matches == null ? void 0 : matches.map((item) => /* @__PURE__ */ jsxs(
11190
+ "div",
11191
+ {
11192
+ className: "grid grid-cols-2 gap-3 px-4 py-2 bg-ui-bg-base shadow-elevation-card-rest rounded-lg items-center",
11193
+ children: [
11194
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-3", children: [
11195
+ /* @__PURE__ */ jsx(
11196
+ Thumbnail,
11197
+ {
11198
+ thumbnail: item.thumbnail,
11199
+ alt: item.product_title ?? void 0
11200
+ }
11201
+ ),
11202
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
11203
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-1", children: [
11204
+ /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: item.product_title }),
11205
+ /* @__PURE__ */ jsxs(
11206
+ Text,
11207
+ {
11208
+ size: "small",
11209
+ leading: "compact",
11210
+ className: "text-ui-fg-subtle",
11211
+ children: [
11212
+ "(",
11213
+ item.variant_title,
11214
+ ")"
11215
+ ]
11216
+ }
11217
+ )
11218
+ ] }),
11219
+ /* @__PURE__ */ jsx(
11220
+ Text,
11221
+ {
11222
+ size: "small",
11223
+ leading: "compact",
11224
+ className: "text-ui-fg-subtle",
11225
+ children: item.variant_sku
11226
+ }
11227
+ )
11228
+ ] })
11229
+ ] }),
11230
+ /* @__PURE__ */ jsxs(
11231
+ Text,
11232
+ {
11233
+ size: "small",
11234
+ leading: "compact",
11235
+ className: "text-ui-fg-subtle",
11236
+ children: [
11237
+ item.quantity,
11238
+ "x"
11239
+ ]
11240
+ }
11241
+ )
11242
+ ]
11243
+ },
11244
+ item.id
11245
+ )) : /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center gap-x-3 bg-ui-bg-base rounded-lg p-4 shadow-elevation-card-rest flex-col gap-1", children: [
11246
+ /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: "No items found" }),
11247
+ /* @__PURE__ */ jsxs(Text, { size: "small", className: "text-ui-fg-subtle", children: [
11248
+ 'No items found for "',
11249
+ query,
11250
+ '".'
11251
+ ] })
11252
+ ] }) })
11253
+ ] })
11254
+ ] });
11255
+ };
11256
+ const LocationField = ({ control, setValue }) => {
11257
+ const locations = useComboboxData({
11258
+ queryKey: ["locations"],
11259
+ queryFn: async (params) => {
11260
+ return await sdk.admin.stockLocation.list(params);
11261
+ },
11262
+ getOptions: (data) => {
11263
+ return data.stock_locations.map((location) => ({
11264
+ label: location.name,
11265
+ value: location.id
11266
+ }));
11267
+ }
11268
+ });
11269
+ return /* @__PURE__ */ jsx(
11270
+ Form$2.Field,
11271
+ {
11272
+ control,
11273
+ name: "location_id",
11274
+ render: ({ field: { onChange, ...field } }) => {
11275
+ return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
11276
+ /* @__PURE__ */ jsxs("div", { children: [
11277
+ /* @__PURE__ */ jsx(Form$2.Label, { children: "Location" }),
11278
+ /* @__PURE__ */ jsx(Form$2.Hint, { children: "Choose where you want to ship the items from." })
11279
+ ] }),
11280
+ /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
11281
+ Combobox,
11282
+ {
11283
+ options: locations.options,
11284
+ fetchNextPage: locations.fetchNextPage,
11285
+ isFetchingNextPage: locations.isFetchingNextPage,
11286
+ searchValue: locations.searchValue,
11287
+ onSearchValueChange: locations.onSearchValueChange,
11288
+ placeholder: "Select location",
11289
+ onChange: (value) => {
11290
+ setValue("shipping_option_id", "", {
11291
+ shouldDirty: true,
11292
+ shouldTouch: true
11293
+ });
11294
+ onChange(value);
11295
+ },
11296
+ ...field
11297
+ }
11298
+ ) })
11299
+ ] }) });
11300
+ }
11301
+ }
11302
+ );
11303
+ };
11304
+ const ShippingOptionField = ({
11305
+ shippingProfileId,
11306
+ preview,
11307
+ control
11308
+ }) => {
11309
+ var _a;
11310
+ const locationId = useWatch({ control, name: "location_id" });
11311
+ const shippingOptions = useComboboxData({
11312
+ queryKey: ["shipping_options", locationId, shippingProfileId],
11313
+ queryFn: async (params) => {
11314
+ return await sdk.admin.shippingOption.list({
11315
+ ...params,
11316
+ stock_location_id: locationId,
11317
+ shipping_profile_id: shippingProfileId
11318
+ });
11319
+ },
11320
+ getOptions: (data) => {
11321
+ return data.shipping_options.map((option) => {
11322
+ var _a2;
11323
+ if ((_a2 = option.rules) == null ? void 0 : _a2.find(
11324
+ (r) => r.attribute === "is_return" && r.value === "true"
11325
+ )) {
11326
+ return void 0;
11327
+ }
11328
+ return {
11329
+ label: option.name,
11330
+ value: option.id
11331
+ };
11332
+ }).filter(Boolean);
11333
+ },
11334
+ enabled: !!locationId && !!shippingProfileId,
11335
+ defaultValue: ((_a = preview.shipping_methods[0]) == null ? void 0 : _a.shipping_option_id) || void 0
11336
+ });
11337
+ const tooltipContent = !locationId && !shippingProfileId ? "Choose a location and shipping profile first." : !locationId ? "Choose a location first." : "Choose a shipping profile first.";
11338
+ return /* @__PURE__ */ jsx(
11339
+ Form$2.Field,
11340
+ {
11341
+ control,
11342
+ name: "shipping_option_id",
11343
+ render: ({ field }) => {
11344
+ return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
11345
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
11346
+ /* @__PURE__ */ jsx(Form$2.Label, { children: "Shipping option" }),
11347
+ /* @__PURE__ */ jsx(Form$2.Hint, { children: "Choose the shipping option to use." })
11348
+ ] }),
11349
+ /* @__PURE__ */ jsx(
11350
+ ConditionalTooltip,
11351
+ {
11352
+ content: tooltipContent,
11353
+ showTooltip: !locationId || !shippingProfileId,
11354
+ children: /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
11355
+ Combobox,
11356
+ {
11357
+ options: shippingOptions.options,
11358
+ fetchNextPage: shippingOptions.fetchNextPage,
11359
+ isFetchingNextPage: shippingOptions.isFetchingNextPage,
11360
+ searchValue: shippingOptions.searchValue,
11361
+ onSearchValueChange: shippingOptions.onSearchValueChange,
11362
+ placeholder: "Select shipping option",
11363
+ ...field,
11364
+ disabled: !locationId || !shippingProfileId
11365
+ }
11366
+ ) }) })
11367
+ }
11368
+ )
11369
+ ] }) });
11370
+ }
11371
+ }
11372
+ );
11373
+ };
11374
+ const CustomAmountField = ({
11375
+ control,
11376
+ currencyCode
11377
+ }) => {
11378
+ return /* @__PURE__ */ jsx(
11379
+ Form$2.Field,
11380
+ {
11381
+ control,
11382
+ name: "custom_amount",
11383
+ render: ({ field: { onChange, ...field } }) => {
11384
+ return /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
11385
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
11386
+ /* @__PURE__ */ jsx(Form$2.Label, { optional: true, children: "Custom amount" }),
11387
+ /* @__PURE__ */ jsx(Form$2.Hint, { children: "Set a custom amount for the shipping option." })
11388
+ ] }),
11389
+ /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
11390
+ CurrencyInput,
11391
+ {
11392
+ ...field,
11393
+ onValueChange: (value) => onChange(value),
11394
+ symbol: getNativeSymbol(currencyCode),
11395
+ code: currencyCode
11396
+ }
11397
+ ) })
11398
+ ] });
11399
+ }
11400
+ }
11401
+ );
11402
+ };
11403
+ const SalesChannel = () => {
11404
+ const { id } = useParams();
11405
+ const { draft_order, isPending, isError, error } = useDraftOrder(
11406
+ id,
11407
+ {
11408
+ fields: "+sales_channel_id"
11409
+ },
11410
+ {
11411
+ enabled: !!id
11412
+ }
11413
+ );
11414
+ if (isError) {
11415
+ throw error;
11416
+ }
11417
+ const ISrEADY = !!draft_order && !isPending;
11418
+ return /* @__PURE__ */ jsxs(RouteDrawer, { children: [
11419
+ /* @__PURE__ */ jsxs(RouteDrawer.Header, { children: [
11420
+ /* @__PURE__ */ jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Edit Sales Channel" }) }),
11421
+ /* @__PURE__ */ jsx(RouteDrawer.Description, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Update which sales channel the draft order is associated with" }) })
11422
+ ] }),
11423
+ ISrEADY && /* @__PURE__ */ jsx(SalesChannelForm, { order: draft_order })
11424
+ ] });
11425
+ };
11426
+ const SalesChannelForm = ({ order }) => {
11427
+ const form = useForm({
11428
+ defaultValues: {
11429
+ sales_channel_id: order.sales_channel_id || ""
11430
+ },
11431
+ resolver: zodResolver(schema$3)
11432
+ });
11433
+ const { mutateAsync, isPending } = useUpdateDraftOrder(order.id);
11434
+ const { handleSuccess } = useRouteModal();
11435
+ const onSubmit = form.handleSubmit(async (data) => {
11436
+ await mutateAsync(
11437
+ {
11438
+ sales_channel_id: data.sales_channel_id
11439
+ },
11440
+ {
11441
+ onSuccess: () => {
11442
+ toast.success("Sales channel updated");
11443
+ handleSuccess();
11444
+ },
11445
+ onError: (error) => {
11446
+ toast.error(error.message);
11447
+ }
11448
+ }
11449
+ );
11450
+ });
11451
+ return /* @__PURE__ */ jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxs(
11452
+ KeyboundForm,
11453
+ {
11454
+ className: "flex flex-1 flex-col overflow-hidden",
11455
+ onSubmit,
11456
+ children: [
11457
+ /* @__PURE__ */ jsx(RouteDrawer.Body, { className: "flex flex-col gap-y-6 overflow-y-auto", children: /* @__PURE__ */ jsx(SalesChannelField, { control: form.control, order }) }),
11458
+ /* @__PURE__ */ jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
11459
+ /* @__PURE__ */ jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
11460
+ /* @__PURE__ */ jsx(Button, { size: "small", type: "submit", isLoading: isPending, children: "Save" })
11461
+ ] }) })
11462
+ ]
11463
+ }
11464
+ ) });
11465
+ };
11466
+ const SalesChannelField = ({ control, order }) => {
11467
+ const salesChannels = useComboboxData({
11468
+ queryFn: async (params) => {
11469
+ return await sdk.admin.salesChannel.list(params);
11470
+ },
11471
+ queryKey: ["sales-channels"],
11472
+ getOptions: (data) => {
11473
+ return data.sales_channels.map((salesChannel) => ({
11474
+ label: salesChannel.name,
11475
+ value: salesChannel.id
11476
+ }));
11477
+ },
11478
+ defaultValue: order.sales_channel_id || void 0
11479
+ });
11480
+ return /* @__PURE__ */ jsx(
11481
+ Form$2.Field,
11482
+ {
11483
+ control,
11484
+ name: "sales_channel_id",
11485
+ render: ({ field }) => {
11486
+ return /* @__PURE__ */ jsxs(Form$2.Item, { children: [
11487
+ /* @__PURE__ */ jsx(Form$2.Label, { children: "Sales Channel" }),
11488
+ /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
11489
+ Combobox,
11490
+ {
11491
+ options: salesChannels.options,
11492
+ fetchNextPage: salesChannels.fetchNextPage,
11493
+ isFetchingNextPage: salesChannels.isFetchingNextPage,
11494
+ searchValue: salesChannels.searchValue,
11495
+ onSearchValueChange: salesChannels.onSearchValueChange,
11496
+ placeholder: "Select sales channel",
11497
+ ...field
11498
+ }
11499
+ ) }),
11500
+ /* @__PURE__ */ jsx(Form$2.ErrorMessage, {})
11501
+ ] });
11502
+ }
11503
+ }
11504
+ );
11505
+ };
11506
+ const schema$3 = z.object({
11507
+ sales_channel_id: z.string().min(1)
11508
+ });
11509
+ const NumberInput = forwardRef(
11510
+ ({
11511
+ value,
11512
+ onChange,
11513
+ size = "base",
11514
+ min = 0,
11515
+ max = 100,
11516
+ step = 1,
11517
+ className,
11518
+ disabled,
11519
+ ...props
11520
+ }, ref) => {
11521
+ const handleChange = (event) => {
11522
+ const newValue = event.target.value === "" ? min : Number(event.target.value);
11523
+ if (!isNaN(newValue) && (max === void 0 || newValue <= max) && (min === void 0 || newValue >= min)) {
11524
+ onChange(newValue);
11525
+ }
11526
+ };
11527
+ const handleIncrement = () => {
11528
+ const newValue = value + step;
11529
+ if (max === void 0 || newValue <= max) {
11530
+ onChange(newValue);
11531
+ }
11532
+ };
11533
+ const handleDecrement = () => {
11534
+ const newValue = value - step;
11535
+ if (min === void 0 || newValue >= min) {
11536
+ onChange(newValue);
11537
+ }
11538
+ };
11539
+ return /* @__PURE__ */ jsxs(
11540
+ "div",
11541
+ {
11542
+ className: clx(
11543
+ "inline-flex rounded-md bg-ui-bg-field shadow-borders-base overflow-hidden divide-x transition-fg",
11544
+ "[&:has(input:focus)]:shadow-borders-interactive-with-active",
11545
+ {
11546
+ "h-7": size === "small",
11547
+ "h-8": size === "base"
11548
+ },
11549
+ className
11550
+ ),
11551
+ children: [
11552
+ /* @__PURE__ */ jsx(
11553
+ "input",
11554
+ {
11555
+ ref,
11556
+ type: "number",
11557
+ value,
11558
+ onChange: handleChange,
11559
+ min,
11560
+ max,
11561
+ step,
11562
+ className: clx(
11563
+ "flex-1 px-2 py-1 bg-transparent txt-compact-small text-ui-fg-base outline-none [appearance:textfield]",
11564
+ "[&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none",
11565
+ "placeholder:text-ui-fg-muted"
11566
+ ),
11567
+ ...props
11568
+ }
11569
+ ),
11570
+ /* @__PURE__ */ jsxs(
11571
+ "button",
11572
+ {
11573
+ className: clx(
11574
+ "flex items-center justify-center outline-none transition-fg",
11575
+ "disabled:cursor-not-allowed disabled:text-ui-fg-muted",
11576
+ "focus:bg-ui-bg-field-component-hover",
11577
+ "hover:bg-ui-bg-field-component-hover",
11578
+ {
11579
+ "size-7": size === "small",
11580
+ "size-8": size === "base"
11581
+ }
11582
+ ),
11583
+ type: "button",
11584
+ onClick: handleDecrement,
11585
+ disabled: min !== void 0 && value <= min || disabled,
11586
+ children: [
11587
+ /* @__PURE__ */ jsx(Minus, {}),
11588
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: `Decrease by ${step}` })
11589
+ ]
11590
+ }
11591
+ ),
11592
+ /* @__PURE__ */ jsxs(
11593
+ "button",
11594
+ {
11595
+ className: clx(
11596
+ "flex items-center justify-center outline-none transition-fg",
11597
+ "disabled:cursor-not-allowed disabled:text-ui-fg-muted",
11598
+ "focus:bg-ui-bg-field-hover",
11599
+ "hover:bg-ui-bg-field-hover",
11600
+ {
11601
+ "size-7": size === "small",
11602
+ "size-8": size === "base"
11603
+ }
11604
+ ),
11605
+ type: "button",
11606
+ onClick: handleIncrement,
11607
+ disabled: max !== void 0 && value >= max || disabled,
11608
+ children: [
11609
+ /* @__PURE__ */ jsx(Plus, {}),
11610
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: `Increase by ${step}` })
11611
+ ]
11612
+ }
11613
+ )
11614
+ ]
11615
+ }
11616
+ );
11617
+ }
11618
+ );
11619
+ const PRODUCT_VARIANTS_QUERY_KEY = "product-variants";
11620
+ const productVariantsQueryKeys = {
11621
+ list: (query2) => [
11622
+ PRODUCT_VARIANTS_QUERY_KEY,
11623
+ query2 ? query2 : void 0
11624
+ ]
11625
+ };
11626
+ const useProductVariants = (query2, options) => {
11627
+ const { data, ...rest } = useQuery({
11628
+ queryKey: productVariantsQueryKeys.list(query2),
11629
+ queryFn: async () => await sdk.admin.productVariant.list(query2),
11630
+ ...options
11631
+ });
11632
+ return { ...data, ...rest };
11633
+ };
11634
+ const STACKED_MODAL_ID = "items_stacked_modal";
11635
+ const Items = () => {
11636
+ const { id } = useParams();
11637
+ const {
11638
+ order: preview,
11639
+ isPending: isPreviewPending,
11640
+ isError: isPreviewError,
11641
+ error: previewError
11642
+ } = useOrderPreview(id, void 0, {
11643
+ placeholderData: keepPreviousData
11644
+ });
11645
+ useInitiateOrderEdit({ preview });
11646
+ const { draft_order, isPending, isError, error } = useDraftOrder(
11647
+ id,
11648
+ {
11649
+ fields: "currency_code"
11650
+ },
11651
+ {
11652
+ enabled: !!id
11653
+ }
11654
+ );
11655
+ const { onCancel } = useCancelOrderEdit({ preview });
11656
+ if (isError) {
11657
+ throw error;
11658
+ }
11659
+ if (isPreviewError) {
11660
+ throw previewError;
11661
+ }
11662
+ const ready = !!preview && !isPreviewPending && !!draft_order && !isPending;
11663
+ return /* @__PURE__ */ jsx(RouteFocusModal, { onClose: onCancel, children: ready ? /* @__PURE__ */ jsx(ItemsForm, { preview, currencyCode: draft_order.currency_code }) : /* @__PURE__ */ jsxs("div", { children: [
11664
+ /* @__PURE__ */ jsx(RouteFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Edit Items" }) }),
11665
+ /* @__PURE__ */ jsx(RouteFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Loading data for the draft order, please wait..." }) })
11666
+ ] }) });
11667
+ };
11668
+ const ItemsForm = ({ preview, currencyCode }) => {
11669
+ var _a;
11670
+ const [isSubmitting, setIsSubmitting] = useState(false);
11671
+ const [modalContent, setModalContent] = useState(
11672
+ null
11673
+ );
11674
+ const { handleSuccess } = useRouteModal();
11675
+ const { searchValue, onSearchValueChange, query: query2 } = useDebouncedSearch();
11676
+ const { mutateAsync: confirmOrderEdit } = useDraftOrderConfirmEdit(preview.id);
11677
+ const { mutateAsync: requestOrderEdit } = useDraftOrderRequestEdit(preview.id);
11678
+ const itemCount = ((_a = preview.items) == null ? void 0 : _a.reduce((acc, item) => acc + item.quantity, 0)) || 0;
11679
+ const matches = useMemo(() => {
11680
+ return matchSorter(preview.items, query2, {
11681
+ keys: ["product_title", "variant_title", "variant_sku", "title"]
11682
+ });
11683
+ }, [preview.items, query2]);
11684
+ const onSubmit = async () => {
11685
+ setIsSubmitting(true);
11686
+ let requestSucceeded = false;
11687
+ await requestOrderEdit(void 0, {
11688
+ onError: (e) => {
11689
+ toast.error(`Failed to request order edit: ${e.message}`);
11690
+ },
11691
+ onSuccess: () => {
11692
+ requestSucceeded = true;
11693
+ }
11694
+ });
11695
+ if (!requestSucceeded) {
11696
+ setIsSubmitting(false);
11697
+ return;
11698
+ }
11699
+ await confirmOrderEdit(void 0, {
11700
+ onError: (e) => {
11701
+ toast.error(`Failed to confirm order edit: ${e.message}`);
11702
+ },
11703
+ onSuccess: () => {
11704
+ handleSuccess();
11705
+ },
11706
+ onSettled: () => {
11707
+ setIsSubmitting(false);
11708
+ }
11709
+ });
11710
+ };
11711
+ const onKeyDown = useCallback(
11712
+ (e) => {
11713
+ if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) {
11714
+ if (modalContent || isSubmitting) {
11715
+ return;
11716
+ }
11717
+ onSubmit();
11718
+ }
11719
+ },
11720
+ [modalContent, isSubmitting, onSubmit]
11721
+ );
11722
+ useEffect(() => {
11723
+ document.addEventListener("keydown", onKeyDown);
11724
+ return () => {
11725
+ document.removeEventListener("keydown", onKeyDown);
11726
+ };
11727
+ }, [onKeyDown]);
11728
+ return /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-col overflow-hidden", children: [
11729
+ /* @__PURE__ */ jsx(RouteFocusModal.Header, {}),
11730
+ /* @__PURE__ */ jsx(RouteFocusModal.Body, { className: "flex flex-1 flex-col overflow-hidden", children: /* @__PURE__ */ jsxs(
11731
+ StackedFocusModal,
11732
+ {
11733
+ id: STACKED_MODAL_ID,
11734
+ onOpenChangeCallback: (open) => {
11735
+ if (!open) {
11736
+ setModalContent(null);
11737
+ }
11738
+ },
11739
+ children: [
11740
+ /* @__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: [
11741
+ /* @__PURE__ */ jsxs("div", { children: [
11742
+ /* @__PURE__ */ jsx(RouteFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Edit Items" }) }),
11743
+ /* @__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." }) })
11744
+ ] }),
11745
+ /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
11746
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-y-6", children: [
11747
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 items-center gap-3", children: [
11748
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
11749
+ /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: "Items" }),
11750
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Choose items from the product catalog." })
11751
+ ] }),
11752
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
11753
+ /* @__PURE__ */ jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsx(
11754
+ Input,
11755
+ {
11756
+ type: "search",
11757
+ placeholder: "Search items",
11758
+ value: searchValue,
11759
+ onChange: (e) => onSearchValueChange(e.target.value)
11760
+ }
11761
+ ) }),
11762
+ /* @__PURE__ */ jsxs(DropdownMenu, { children: [
11763
+ /* @__PURE__ */ jsx(DropdownMenu.Trigger, { asChild: true, children: /* @__PURE__ */ jsx(IconButton, { type: "button", children: /* @__PURE__ */ jsx(Plus, {}) }) }),
11764
+ /* @__PURE__ */ jsxs(DropdownMenu.Content, { children: [
11765
+ /* @__PURE__ */ jsx(
11766
+ StackedModalTrigger,
11767
+ {
11768
+ type: "add-items",
11769
+ setModalContent
11770
+ }
11771
+ ),
11772
+ /* @__PURE__ */ jsx(
11773
+ StackedModalTrigger,
11774
+ {
11775
+ type: "add-custom-item",
11776
+ setModalContent
11777
+ }
11778
+ )
11779
+ ] })
11780
+ ] })
11781
+ ] })
11782
+ ] }),
11783
+ /* @__PURE__ */ jsxs("div", { className: "bg-ui-bg-subtle shadow-elevation-card-rest rounded-xl", children: [
11784
+ /* @__PURE__ */ jsx("div", { className: "px-[5px]", children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-[1fr_1fr_1fr_28px] gap-3 px-4 py-2 text-ui-fg-muted", children: [
11785
+ /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: "Item" }) }),
11786
+ /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: "Quantity" }) }),
11787
+ /* @__PURE__ */ jsx("div", { className: "text-right", children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: "Price" }) }),
11788
+ /* @__PURE__ */ jsx("div", {})
11789
+ ] }) }),
11790
+ /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-y-1.5 px-[5px] pb-[5px]", children: itemCount <= 0 ? /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center gap-x-3 bg-ui-bg-base rounded-lg p-4 shadow-elevation-card-rest flex-col gap-1", children: [
11791
+ /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: "There are no items in this order" }),
11792
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Add items to the order to get started." })
11793
+ ] }) : matches.length > 0 ? matches == null ? void 0 : matches.map((item) => /* @__PURE__ */ jsx(
11794
+ Item,
11795
+ {
11796
+ item,
11797
+ preview,
11798
+ currencyCode
11799
+ },
11800
+ item.id
11801
+ )) : /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center gap-x-3 bg-ui-bg-base rounded-lg p-4 shadow-elevation-card-rest flex-col gap-1", children: [
11802
+ /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: "No items found" }),
11803
+ /* @__PURE__ */ jsxs(Text, { size: "small", className: "text-ui-fg-subtle", children: [
11804
+ 'No items found for "',
11805
+ query2,
11806
+ '".'
11807
+ ] })
11808
+ ] }) })
11809
+ ] })
11810
+ ] }),
11811
+ /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
11812
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-[1fr_0.5fr_0.5fr] gap-3", children: [
11813
+ /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: "Subtotal" }) }),
11814
+ /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsxs(
11815
+ Text,
11816
+ {
11817
+ size: "small",
11818
+ leading: "compact",
11819
+ className: "text-ui-fg-subtle",
11820
+ children: [
11821
+ itemCount,
11822
+ " ",
11823
+ itemCount === 1 ? "item" : "items"
11824
+ ]
11825
+ }
11826
+ ) }),
11827
+ /* @__PURE__ */ jsx("div", { className: "text-right", children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: getStylizedAmount(preview.item_subtotal, currencyCode) }) })
11828
+ ] })
11829
+ ] }) }),
11830
+ modalContent && (modalContent === "add-items" ? /* @__PURE__ */ jsx(ExistingItemsForm, { orderId: preview.id, items: preview.items }) : modalContent === "add-custom-item" ? /* @__PURE__ */ jsx(
11831
+ CustomItemForm,
11832
+ {
11833
+ orderId: preview.id,
11834
+ currencyCode
11985
11835
  }
11986
- return open;
11987
- },
11988
- children: data && /* @__PURE__ */ jsx(ShippingProfileForm, { data, order, preview })
11989
- }
11990
- )
11991
- ] }),
11992
- /* @__PURE__ */ jsx(RouteFocusModal.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-x-2", children: [
11836
+ ) : null)
11837
+ ]
11838
+ }
11839
+ ) }),
11840
+ /* @__PURE__ */ jsx(RouteFocusModal.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-2 justify-end", children: [
11993
11841
  /* @__PURE__ */ jsx(RouteFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
11994
11842
  /* @__PURE__ */ jsx(
11995
11843
  Button,
11996
11844
  {
11997
11845
  size: "small",
11998
11846
  type: "button",
11999
- isLoading: isSubmitting,
12000
11847
  onClick: onSubmit,
11848
+ isLoading: isSubmitting,
12001
11849
  children: "Save"
12002
11850
  }
12003
11851
  )
12004
11852
  ] }) })
12005
11853
  ] });
12006
11854
  };
12007
- const StackedModalTrigger = ({
12008
- shippingProfileId,
12009
- shippingOption,
12010
- shippingMethod,
12011
- setData,
12012
- children
12013
- }) => {
12014
- const { setIsOpen, getIsOpen } = useStackedModal();
12015
- const isOpen = getIsOpen(STACKED_FOCUS_MODAL_ID);
12016
- const onToggle = () => {
12017
- if (isOpen) {
12018
- setIsOpen(STACKED_FOCUS_MODAL_ID, false);
12019
- setData(null);
12020
- } else {
12021
- setIsOpen(STACKED_FOCUS_MODAL_ID, true);
12022
- setData({
12023
- shippingProfileId,
12024
- shippingOption,
12025
- shippingMethod
12026
- });
11855
+ const Item = ({ item, preview, currencyCode }) => {
11856
+ if (item.variant_id) {
11857
+ return /* @__PURE__ */ jsx(VariantItem, { item, preview, currencyCode });
11858
+ }
11859
+ return /* @__PURE__ */ jsx(CustomItem, { item, preview, currencyCode });
11860
+ };
11861
+ const VariantItem = ({ item, preview, currencyCode }) => {
11862
+ const [editing, setEditing] = useState(false);
11863
+ const form = useForm({
11864
+ defaultValues: {
11865
+ quantity: item.quantity,
11866
+ unit_price: item.unit_price
11867
+ },
11868
+ resolver: zodResolver(variantItemSchema)
11869
+ });
11870
+ const actionId = useMemo(() => {
11871
+ var _a, _b;
11872
+ return (_b = (_a = item.actions) == null ? void 0 : _a.find((a) => a.action === "ITEM_ADD")) == null ? void 0 : _b.id;
11873
+ }, [item]);
11874
+ const { mutateAsync: updateActionItem, isPending: isUpdatingActionItem } = useDraftOrderUpdateActionItem(preview.id);
11875
+ const { mutateAsync: updateOriginalItem, isPending: isUpdatingOriginalItem } = useDraftOrderUpdateItem(preview.id);
11876
+ const isPending = isUpdatingActionItem || isUpdatingOriginalItem;
11877
+ const onSubmit = form.handleSubmit(async (data) => {
11878
+ if (convertNumber(data.unit_price) === item.unit_price && data.quantity === item.quantity) {
11879
+ setEditing(false);
11880
+ return;
12027
11881
  }
12028
- };
12029
- return /* @__PURE__ */ jsx(
12030
- Button,
12031
- {
12032
- size: "small",
12033
- variant: "secondary",
12034
- onClick: onToggle,
12035
- className: "text-ui-fg-primary shrink-0",
12036
- children
11882
+ if (!actionId) {
11883
+ await updateOriginalItem(
11884
+ {
11885
+ item_id: item.id,
11886
+ quantity: data.quantity,
11887
+ unit_price: convertNumber(data.unit_price)
11888
+ },
11889
+ {
11890
+ onSuccess: () => {
11891
+ setEditing(false);
11892
+ },
11893
+ onError: (e) => {
11894
+ toast.error(e.message);
11895
+ }
11896
+ }
11897
+ );
11898
+ return;
12037
11899
  }
12038
- );
11900
+ await updateActionItem(
11901
+ {
11902
+ action_id: actionId,
11903
+ quantity: data.quantity,
11904
+ unit_price: convertNumber(data.unit_price)
11905
+ },
11906
+ {
11907
+ onSuccess: () => {
11908
+ setEditing(false);
11909
+ },
11910
+ onError: (e) => {
11911
+ toast.error(e.message);
11912
+ }
11913
+ }
11914
+ );
11915
+ });
11916
+ return /* @__PURE__ */ jsx(Form$2, { ...form, children: /* @__PURE__ */ jsx("form", { onSubmit, children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-[minmax(0,1fr)_minmax(0,1fr)_minmax(0,1fr)_28px] gap-3 px-4 py-2 bg-ui-bg-base shadow-elevation-card-rest rounded-lg items-center", children: [
11917
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-3 w-full", children: [
11918
+ /* @__PURE__ */ jsx(
11919
+ Thumbnail,
11920
+ {
11921
+ thumbnail: item.thumbnail,
11922
+ alt: item.product_title ?? void 0
11923
+ }
11924
+ ),
11925
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
11926
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-1", children: [
11927
+ /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: item.product_title }),
11928
+ /* @__PURE__ */ jsxs(
11929
+ Text,
11930
+ {
11931
+ size: "small",
11932
+ leading: "compact",
11933
+ className: "text-ui-fg-subtle",
11934
+ children: [
11935
+ "(",
11936
+ item.variant_title,
11937
+ ")"
11938
+ ]
11939
+ }
11940
+ )
11941
+ ] }),
11942
+ /* @__PURE__ */ jsx(
11943
+ Text,
11944
+ {
11945
+ size: "small",
11946
+ leading: "compact",
11947
+ className: "text-ui-fg-subtle",
11948
+ children: item.variant_sku
11949
+ }
11950
+ )
11951
+ ] })
11952
+ ] }),
11953
+ editing ? /* @__PURE__ */ jsx("div", { className: "flex-1 w-full", children: /* @__PURE__ */ jsx(
11954
+ Form$2.Field,
11955
+ {
11956
+ control: form.control,
11957
+ name: "quantity",
11958
+ render: ({ field }) => {
11959
+ return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(NumberInput, { ...field }) }) });
11960
+ }
11961
+ }
11962
+ ) }) : /* @__PURE__ */ jsx("div", { className: "flex-1 w-full", children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: item.quantity }) }),
11963
+ editing ? /* @__PURE__ */ jsx("div", { className: "flex-1 w-full", children: /* @__PURE__ */ jsx(
11964
+ Form$2.Field,
11965
+ {
11966
+ control: form.control,
11967
+ name: "unit_price",
11968
+ render: ({ field: { onChange, ...field } }) => {
11969
+ return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
11970
+ CurrencyInput,
11971
+ {
11972
+ ...field,
11973
+ symbol: getNativeSymbol(currencyCode),
11974
+ code: currencyCode,
11975
+ onValueChange: (_value, _name, values) => onChange(values == null ? void 0 : values.value)
11976
+ }
11977
+ ) }) });
11978
+ }
11979
+ }
11980
+ ) }) : /* @__PURE__ */ jsx("div", { className: "flex-1 flex items-center justify-end w-full", children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: getLocaleAmount(item.unit_price, currencyCode) }) }),
11981
+ /* @__PURE__ */ jsx(
11982
+ IconButton,
11983
+ {
11984
+ type: "button",
11985
+ size: "small",
11986
+ onClick: editing ? onSubmit : () => {
11987
+ setEditing(true);
11988
+ },
11989
+ disabled: isPending,
11990
+ children: editing ? /* @__PURE__ */ jsx(Check, {}) : /* @__PURE__ */ jsx(PencilSquare, {})
11991
+ }
11992
+ )
11993
+ ] }) }) });
12039
11994
  };
12040
- const ShippingProfileForm = ({
12041
- data,
12042
- order,
12043
- preview
12044
- }) => {
12045
- var _a, _b, _c, _d, _e, _f;
12046
- const { setIsOpen } = useStackedModal();
11995
+ const variantItemSchema = z.object({
11996
+ quantity: z.number(),
11997
+ unit_price: z.union([z.number(), z.string()])
11998
+ });
11999
+ const CustomItem = ({ item, preview, currencyCode }) => {
12000
+ const [editing, setEditing] = useState(false);
12001
+ const { quantity, unit_price, title } = item;
12047
12002
  const form = useForm({
12048
- resolver: zodResolver(shippingMethodSchema),
12049
12003
  defaultValues: {
12050
- location_id: (_d = (_c = (_b = (_a = data.shippingOption) == null ? void 0 : _a.service_zone) == null ? void 0 : _b.fulfillment_set) == null ? void 0 : _c.location) == null ? void 0 : _d.id,
12051
- shipping_option_id: (_e = data.shippingOption) == null ? void 0 : _e.id,
12052
- custom_amount: (_f = data.shippingMethod) == null ? void 0 : _f.amount
12053
- }
12004
+ title,
12005
+ quantity,
12006
+ unit_price
12007
+ },
12008
+ resolver: zodResolver(customItemSchema)
12054
12009
  });
12055
- const { mutateAsync: addShippingMethod, isPending } = useDraftOrderAddShippingMethod(order.id);
12056
- const {
12057
- mutateAsync: updateShippingMethod,
12058
- isPending: isUpdatingShippingMethod
12059
- } = useDraftOrderUpdateShippingMethod(order.id);
12060
- const onSubmit = form.handleSubmit(async (values) => {
12061
- if (isEqual(values, form.formState.defaultValues)) {
12062
- setIsOpen(STACKED_FOCUS_MODAL_ID, false);
12010
+ useEffect(() => {
12011
+ form.reset({
12012
+ title,
12013
+ quantity,
12014
+ unit_price
12015
+ });
12016
+ }, [form, title, quantity, unit_price]);
12017
+ const actionId = useMemo(() => {
12018
+ var _a, _b;
12019
+ return (_b = (_a = item.actions) == null ? void 0 : _a.find((a) => a.action === "ITEM_ADD")) == null ? void 0 : _b.id;
12020
+ }, [item]);
12021
+ const { mutateAsync: updateActionItem, isPending: isUpdatingActionItem } = useDraftOrderUpdateActionItem(preview.id);
12022
+ const { mutateAsync: removeActionItem, isPending: isRemovingActionItem } = useDraftOrderRemoveActionItem(preview.id);
12023
+ const { mutateAsync: updateOriginalItem, isPending: isUpdatingOriginalItem } = useDraftOrderUpdateItem(preview.id);
12024
+ const isPending = isUpdatingActionItem || isUpdatingOriginalItem;
12025
+ const onSubmit = form.handleSubmit(async (data) => {
12026
+ if (convertNumber(data.unit_price) === item.unit_price && data.quantity === item.quantity && data.title === item.title) {
12027
+ setEditing(false);
12063
12028
  return;
12064
12029
  }
12065
- if (data.shippingMethod) {
12066
- await updateShippingMethod(
12030
+ if (!actionId) {
12031
+ await updateOriginalItem(
12067
12032
  {
12068
- method_id: data.shippingMethod.id,
12069
- shipping_option_id: values.shipping_option_id,
12070
- custom_amount: values.custom_amount ? convertNumber(values.custom_amount) : void 0
12033
+ item_id: item.id,
12034
+ quantity: data.quantity,
12035
+ unit_price: convertNumber(data.unit_price)
12071
12036
  },
12072
12037
  {
12038
+ onSuccess: () => {
12039
+ setEditing(false);
12040
+ },
12073
12041
  onError: (e) => {
12074
12042
  toast.error(e.message);
12075
- },
12076
- onSuccess: () => {
12077
- setIsOpen(STACKED_FOCUS_MODAL_ID, false);
12078
12043
  }
12079
12044
  }
12080
12045
  );
12081
12046
  return;
12082
12047
  }
12083
- await addShippingMethod(
12048
+ if (data.quantity === 0) {
12049
+ await removeActionItem(actionId, {
12050
+ onSuccess: () => {
12051
+ setEditing(false);
12052
+ },
12053
+ onError: (e) => {
12054
+ toast.error(e.message);
12055
+ }
12056
+ });
12057
+ return;
12058
+ }
12059
+ await updateActionItem(
12084
12060
  {
12085
- shipping_option_id: values.shipping_option_id,
12086
- custom_amount: values.custom_amount ? convertNumber(values.custom_amount) : void 0
12061
+ action_id: actionId,
12062
+ quantity: data.quantity,
12063
+ unit_price: convertNumber(data.unit_price)
12087
12064
  },
12088
12065
  {
12066
+ onSuccess: () => {
12067
+ setEditing(false);
12068
+ },
12089
12069
  onError: (e) => {
12090
12070
  toast.error(e.message);
12091
- },
12092
- onSuccess: () => {
12093
- setIsOpen(STACKED_FOCUS_MODAL_ID, false);
12094
12071
  }
12095
12072
  }
12096
12073
  );
12097
12074
  });
12098
- return /* @__PURE__ */ jsx(StackedFocusModal.Content, { children: /* @__PURE__ */ jsx(Form$2, { ...form, children: /* @__PURE__ */ jsxs(
12099
- KeyboundForm,
12100
- {
12101
- className: "flex h-full flex-col overflow-hidden",
12102
- onSubmit,
12103
- children: [
12104
- /* @__PURE__ */ jsx(StackedFocusModal.Header, {}),
12105
- /* @__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 py-16 px-6", children: [
12106
- /* @__PURE__ */ jsxs("div", { children: [
12107
- /* @__PURE__ */ jsx(RouteFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Shipping" }) }),
12108
- /* @__PURE__ */ jsx(RouteFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Add a shipping method for the selected shipping profile. You can see the items that will be shipped using this method in the preview below." }) })
12109
- ] }),
12110
- /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
12111
- /* @__PURE__ */ jsx(
12112
- LocationField,
12113
- {
12114
- control: form.control,
12115
- setValue: form.setValue
12116
- }
12117
- ),
12118
- /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
12119
- /* @__PURE__ */ jsx(
12120
- ShippingOptionField,
12121
- {
12122
- shippingProfileId: data.shippingProfileId,
12123
- preview,
12124
- control: form.control
12125
- }
12126
- ),
12127
- /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
12128
- /* @__PURE__ */ jsx(
12129
- CustomAmountField,
12130
- {
12131
- control: form.control,
12132
- currencyCode: order.currency_code
12133
- }
12134
- ),
12135
- /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
12136
- /* @__PURE__ */ jsx(
12137
- ItemsPreview,
12138
- {
12139
- order,
12140
- shippingProfileId: data.shippingProfileId
12141
- }
12142
- )
12143
- ] }) }) }),
12144
- /* @__PURE__ */ jsx(StackedFocusModal.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-x-2", children: [
12145
- /* @__PURE__ */ jsx(StackedFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
12146
- /* @__PURE__ */ jsx(
12147
- Button,
12148
- {
12149
- size: "small",
12150
- type: "submit",
12151
- isLoading: isPending || isUpdatingShippingMethod,
12152
- children: data.shippingMethod ? "Update" : "Add"
12153
- }
12154
- )
12155
- ] }) })
12156
- ]
12157
- }
12158
- ) }) });
12159
- };
12160
- const shippingMethodSchema = z.object({
12161
- location_id: z.string(),
12162
- shipping_option_id: z.string(),
12163
- custom_amount: z.union([z.number(), z.string()]).optional()
12164
- });
12165
- const ItemsPreview = ({ order, shippingProfileId }) => {
12166
- const matches = order.items.filter(
12167
- (item) => {
12168
- var _a, _b, _c;
12169
- return ((_c = (_b = (_a = item.variant) == null ? void 0 : _a.product) == null ? void 0 : _b.shipping_profile) == null ? void 0 : _c.id) === shippingProfileId;
12170
- }
12171
- );
12172
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-y-6", children: [
12173
- /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 items-center gap-3", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
12174
- /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: "Items to ship" }),
12175
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Items with the selected shipping profile." })
12176
- ] }) }),
12177
- /* @__PURE__ */ jsxs("div", { className: "bg-ui-bg-subtle shadow-elevation-card-rest rounded-xl", children: [
12178
- /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-3 px-4 py-2 text-ui-fg-muted", children: [
12179
- /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: "Item" }) }),
12180
- /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: "Quantity" }) })
12181
- ] }),
12182
- /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-y-1.5 px-[5px] pb-[5px]", children: matches.length > 0 ? matches == null ? void 0 : matches.map((item) => /* @__PURE__ */ jsxs(
12183
- "div",
12075
+ return /* @__PURE__ */ jsx(Form$2, { ...form, children: /* @__PURE__ */ jsx("form", { onSubmit, children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-[minmax(0,1fr)_minmax(0,1fr)_minmax(0,1fr)_28px] gap-3 px-4 py-2 bg-ui-bg-base shadow-elevation-card-rest rounded-lg items-center", children: [
12076
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-3", children: [
12077
+ /* @__PURE__ */ jsx(
12078
+ Thumbnail,
12184
12079
  {
12185
- className: "grid grid-cols-2 gap-3 px-4 py-2 bg-ui-bg-base shadow-elevation-card-rest rounded-lg items-center",
12186
- children: [
12187
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-3", children: [
12188
- /* @__PURE__ */ jsx(
12189
- Thumbnail,
12190
- {
12191
- thumbnail: item.thumbnail,
12192
- alt: item.product_title ?? void 0
12193
- }
12194
- ),
12195
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
12196
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-1", children: [
12197
- /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: item.product_title }),
12198
- /* @__PURE__ */ jsxs(
12199
- Text,
12200
- {
12201
- size: "small",
12202
- leading: "compact",
12203
- className: "text-ui-fg-subtle",
12204
- children: [
12205
- "(",
12206
- item.variant_title,
12207
- ")"
12208
- ]
12209
- }
12210
- )
12211
- ] }),
12212
- /* @__PURE__ */ jsx(
12213
- Text,
12214
- {
12215
- size: "small",
12216
- leading: "compact",
12217
- className: "text-ui-fg-subtle",
12218
- children: item.variant_sku
12219
- }
12220
- )
12221
- ] })
12222
- ] }),
12223
- /* @__PURE__ */ jsxs(
12224
- Text,
12225
- {
12226
- size: "small",
12227
- leading: "compact",
12228
- className: "text-ui-fg-subtle",
12229
- children: [
12230
- item.quantity,
12231
- "x"
12232
- ]
12233
- }
12234
- )
12235
- ]
12236
- },
12237
- item.id
12238
- )) : /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center gap-x-3 bg-ui-bg-base rounded-lg p-4 shadow-elevation-card-rest flex-col gap-1", children: [
12239
- /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: "No items found" }),
12240
- /* @__PURE__ */ jsxs(Text, { size: "small", className: "text-ui-fg-subtle", children: [
12241
- 'No items found for "',
12242
- query,
12243
- '".'
12244
- ] })
12245
- ] }) })
12246
- ] })
12247
- ] });
12248
- };
12249
- const LocationField = ({ control, setValue }) => {
12250
- const locations = useComboboxData({
12251
- queryKey: ["locations"],
12252
- queryFn: async (params) => {
12253
- return await sdk.admin.stockLocation.list(params);
12254
- },
12255
- getOptions: (data) => {
12256
- return data.stock_locations.map((location) => ({
12257
- label: location.name,
12258
- value: location.id
12259
- }));
12260
- }
12261
- });
12262
- return /* @__PURE__ */ jsx(
12263
- Form$2.Field,
12264
- {
12265
- control,
12266
- name: "location_id",
12267
- render: ({ field: { onChange, ...field } }) => {
12268
- return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
12269
- /* @__PURE__ */ jsxs("div", { children: [
12270
- /* @__PURE__ */ jsx(Form$2.Label, { children: "Location" }),
12271
- /* @__PURE__ */ jsx(Form$2.Hint, { children: "Choose where you want to ship the items from." })
12272
- ] }),
12273
- /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
12274
- Combobox,
12275
- {
12276
- options: locations.options,
12277
- fetchNextPage: locations.fetchNextPage,
12278
- isFetchingNextPage: locations.isFetchingNextPage,
12279
- searchValue: locations.searchValue,
12280
- onSearchValueChange: locations.onSearchValueChange,
12281
- placeholder: "Select location",
12282
- onChange: (value) => {
12283
- setValue("shipping_option_id", "", {
12284
- shouldDirty: true,
12285
- shouldTouch: true
12286
- });
12287
- onChange(value);
12288
- },
12289
- ...field
12080
+ thumbnail: item.thumbnail,
12081
+ alt: item.title ?? void 0
12082
+ }
12083
+ ),
12084
+ editing ? /* @__PURE__ */ jsx(
12085
+ Form$2.Field,
12086
+ {
12087
+ control: form.control,
12088
+ name: "title",
12089
+ render: ({ field }) => {
12090
+ return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(Input, { ...field }) }) });
12091
+ }
12092
+ }
12093
+ ) : /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: item.title })
12094
+ ] }),
12095
+ editing ? /* @__PURE__ */ jsx(
12096
+ Form$2.Field,
12097
+ {
12098
+ control: form.control,
12099
+ name: "quantity",
12100
+ render: ({ field }) => {
12101
+ return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(NumberInput, { ...field }) }) });
12102
+ }
12103
+ }
12104
+ ) : /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: item.quantity }),
12105
+ editing ? /* @__PURE__ */ jsx(
12106
+ Form$2.Field,
12107
+ {
12108
+ control: form.control,
12109
+ name: "unit_price",
12110
+ render: ({ field: { onChange, ...field } }) => {
12111
+ return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
12112
+ CurrencyInput,
12113
+ {
12114
+ ...field,
12115
+ symbol: getNativeSymbol(currencyCode),
12116
+ code: currencyCode,
12117
+ onValueChange: (_value, _name, values) => onChange(values == null ? void 0 : values.value)
12290
12118
  }
12291
- ) })
12292
- ] }) });
12119
+ ) }) });
12120
+ }
12293
12121
  }
12294
- }
12295
- );
12122
+ ) : /* @__PURE__ */ jsx("div", { className: "flex-1 flex items-center justify-end", children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: getLocaleAmount(item.unit_price, currencyCode) }) }),
12123
+ /* @__PURE__ */ jsx(
12124
+ IconButton,
12125
+ {
12126
+ type: "button",
12127
+ size: "small",
12128
+ onClick: editing ? onSubmit : () => {
12129
+ setEditing(true);
12130
+ },
12131
+ disabled: isPending,
12132
+ children: editing ? /* @__PURE__ */ jsx(Check, {}) : /* @__PURE__ */ jsx(PencilSquare, {})
12133
+ }
12134
+ )
12135
+ ] }) }) });
12296
12136
  };
12297
- const ShippingOptionField = ({
12298
- shippingProfileId,
12299
- preview,
12300
- control
12137
+ const StackedModalTrigger = ({
12138
+ type,
12139
+ setModalContent
12301
12140
  }) => {
12302
- var _a;
12303
- const locationId = useWatch({ control, name: "location_id" });
12304
- const shippingOptions = useComboboxData({
12305
- queryKey: ["shipping_options", locationId, shippingProfileId],
12306
- queryFn: async (params) => {
12307
- return await sdk.admin.shippingOption.list({
12308
- ...params,
12309
- stock_location_id: locationId,
12310
- shipping_profile_id: shippingProfileId
12311
- });
12312
- },
12313
- getOptions: (data) => {
12314
- return data.shipping_options.map((option) => {
12315
- var _a2;
12316
- if ((_a2 = option.rules) == null ? void 0 : _a2.find(
12317
- (r) => r.attribute === "is_return" && r.value === "true"
12318
- )) {
12319
- return void 0;
12141
+ const { setIsOpen } = useStackedModal();
12142
+ const onClick = useCallback(() => {
12143
+ setModalContent(type);
12144
+ setIsOpen(STACKED_MODAL_ID, true);
12145
+ }, [setModalContent, setIsOpen, type]);
12146
+ return /* @__PURE__ */ jsx(StackedFocusModal.Trigger, { asChild: true, children: /* @__PURE__ */ jsx(DropdownMenu.Item, { onClick, children: type === "add-items" ? "Add items" : "Add custom item" }) });
12147
+ };
12148
+ const VARIANT_PREFIX = "items";
12149
+ const LIMIT = 50;
12150
+ const ExistingItemsForm = ({ orderId, items }) => {
12151
+ const { setIsOpen } = useStackedModal();
12152
+ const [rowSelection, setRowSelection] = useState(
12153
+ items.reduce((acc, item) => {
12154
+ acc[item.variant_id] = true;
12155
+ return acc;
12156
+ }, {})
12157
+ );
12158
+ useEffect(() => {
12159
+ setRowSelection(
12160
+ items.reduce((acc, item) => {
12161
+ if (item.variant_id) {
12162
+ acc[item.variant_id] = true;
12320
12163
  }
12321
- return {
12322
- label: option.name,
12323
- value: option.id
12324
- };
12325
- }).filter(Boolean);
12164
+ return acc;
12165
+ }, {})
12166
+ );
12167
+ }, [items]);
12168
+ const { q, order, offset } = useQueryParams(
12169
+ ["q", "order", "offset"],
12170
+ VARIANT_PREFIX
12171
+ );
12172
+ const { variants, count, isPending, isError, error } = useProductVariants(
12173
+ {
12174
+ q,
12175
+ order,
12176
+ offset: offset ? parseInt(offset) : void 0,
12177
+ limit: LIMIT
12326
12178
  },
12327
- enabled: !!locationId && !!shippingProfileId,
12328
- defaultValue: ((_a = preview.shipping_methods[0]) == null ? void 0 : _a.shipping_option_id) || void 0
12329
- });
12330
- const tooltipContent = !locationId && !shippingProfileId ? "Choose a location and shipping profile first." : !locationId ? "Choose a location first." : "Choose a shipping profile first.";
12331
- return /* @__PURE__ */ jsx(
12332
- Form$2.Field,
12333
12179
  {
12334
- control,
12335
- name: "shipping_option_id",
12336
- render: ({ field }) => {
12337
- return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
12338
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
12339
- /* @__PURE__ */ jsx(Form$2.Label, { children: "Shipping option" }),
12340
- /* @__PURE__ */ jsx(Form$2.Hint, { children: "Choose the shipping option to use." })
12341
- ] }),
12342
- /* @__PURE__ */ jsx(
12343
- ConditionalTooltip,
12344
- {
12345
- content: tooltipContent,
12346
- showTooltip: !locationId || !shippingProfileId,
12347
- children: /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
12348
- Combobox,
12349
- {
12350
- options: shippingOptions.options,
12351
- fetchNextPage: shippingOptions.fetchNextPage,
12352
- isFetchingNextPage: shippingOptions.isFetchingNextPage,
12353
- searchValue: shippingOptions.searchValue,
12354
- onSearchValueChange: shippingOptions.onSearchValueChange,
12355
- placeholder: "Select shipping option",
12356
- ...field,
12357
- disabled: !locationId || !shippingProfileId
12358
- }
12359
- ) }) })
12360
- }
12361
- )
12362
- ] }) });
12180
+ placeholderData: keepPreviousData
12181
+ }
12182
+ );
12183
+ const columns = useColumns();
12184
+ const { mutateAsync } = useDraftOrderAddItems(orderId);
12185
+ const onSubmit = async () => {
12186
+ const ids = Object.keys(rowSelection).filter(
12187
+ (id) => !items.find((i) => i.variant_id === id)
12188
+ );
12189
+ await mutateAsync(
12190
+ {
12191
+ items: ids.map((id) => ({
12192
+ variant_id: id,
12193
+ quantity: 1
12194
+ }))
12195
+ },
12196
+ {
12197
+ onSuccess: () => {
12198
+ setRowSelection({});
12199
+ setIsOpen(STACKED_MODAL_ID, false);
12200
+ },
12201
+ onError: (e) => {
12202
+ toast.error(e.message);
12203
+ }
12363
12204
  }
12205
+ );
12206
+ };
12207
+ if (isError) {
12208
+ throw error;
12209
+ }
12210
+ return /* @__PURE__ */ jsxs(
12211
+ StackedFocusModal.Content,
12212
+ {
12213
+ onOpenAutoFocus: (e) => {
12214
+ e.preventDefault();
12215
+ const searchInput = document.querySelector(
12216
+ "[data-modal-id='modal-search-input']"
12217
+ );
12218
+ if (searchInput) {
12219
+ searchInput.focus();
12220
+ }
12221
+ },
12222
+ children: [
12223
+ /* @__PURE__ */ jsxs(StackedFocusModal.Header, { children: [
12224
+ /* @__PURE__ */ jsx(StackedFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Product Variants" }) }),
12225
+ /* @__PURE__ */ jsx(StackedFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Choose product variants to add to the order." }) })
12226
+ ] }),
12227
+ /* @__PURE__ */ jsx(StackedFocusModal.Body, { className: "flex-1 overflow-hidden", children: /* @__PURE__ */ jsx(
12228
+ DataTable,
12229
+ {
12230
+ data: variants,
12231
+ columns,
12232
+ isLoading: isPending,
12233
+ getRowId: (row) => row.id,
12234
+ rowCount: count,
12235
+ prefix: VARIANT_PREFIX,
12236
+ layout: "fill",
12237
+ rowSelection: {
12238
+ state: rowSelection,
12239
+ onRowSelectionChange: setRowSelection,
12240
+ enableRowSelection: (row) => {
12241
+ return !items.find((i) => i.variant_id === row.original.id);
12242
+ }
12243
+ },
12244
+ autoFocusSearch: true
12245
+ }
12246
+ ) }),
12247
+ /* @__PURE__ */ jsx(StackedFocusModal.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-2 justify-end", children: [
12248
+ /* @__PURE__ */ jsx(StackedFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
12249
+ /* @__PURE__ */ jsx(Button, { size: "small", type: "button", onClick: onSubmit, children: "Update items" })
12250
+ ] }) })
12251
+ ]
12364
12252
  }
12365
12253
  );
12366
12254
  };
12367
- const CustomAmountField = ({
12368
- control,
12369
- currencyCode
12370
- }) => {
12371
- return /* @__PURE__ */ jsx(
12372
- Form$2.Field,
12373
- {
12374
- control,
12375
- name: "custom_amount",
12376
- render: ({ field: { onChange, ...field } }) => {
12377
- return /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
12378
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
12379
- /* @__PURE__ */ jsx(Form$2.Label, { optional: true, children: "Custom amount" }),
12380
- /* @__PURE__ */ jsx(Form$2.Hint, { children: "Set a custom amount for the shipping option." })
12381
- ] }),
12382
- /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
12383
- CurrencyInput,
12255
+ const columnHelper = createDataTableColumnHelper();
12256
+ const useColumns = () => {
12257
+ return useMemo(() => {
12258
+ return [
12259
+ columnHelper.select(),
12260
+ columnHelper.accessor("product.title", {
12261
+ header: "Product",
12262
+ cell: ({ row }) => {
12263
+ var _a, _b, _c;
12264
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-2", children: [
12265
+ /* @__PURE__ */ jsx(
12266
+ Thumbnail,
12267
+ {
12268
+ thumbnail: (_a = row.original.product) == null ? void 0 : _a.thumbnail,
12269
+ alt: (_b = row.original.product) == null ? void 0 : _b.title
12270
+ }
12271
+ ),
12272
+ /* @__PURE__ */ jsx("span", { children: (_c = row.original.product) == null ? void 0 : _c.title })
12273
+ ] });
12274
+ },
12275
+ enableSorting: true
12276
+ }),
12277
+ columnHelper.accessor("title", {
12278
+ header: "Variant",
12279
+ enableSorting: true
12280
+ }),
12281
+ columnHelper.accessor("sku", {
12282
+ header: "SKU",
12283
+ cell: ({ getValue }) => {
12284
+ return getValue() ?? "-";
12285
+ },
12286
+ enableSorting: true
12287
+ }),
12288
+ columnHelper.accessor("updated_at", {
12289
+ header: "Updated",
12290
+ cell: ({ getValue }) => {
12291
+ return /* @__PURE__ */ jsx(
12292
+ Tooltip,
12293
+ {
12294
+ content: getFullDate({ date: getValue(), includeTime: true }),
12295
+ children: /* @__PURE__ */ jsx("span", { children: getFullDate({ date: getValue() }) })
12296
+ }
12297
+ );
12298
+ },
12299
+ enableSorting: true,
12300
+ sortAscLabel: "Oldest first",
12301
+ sortDescLabel: "Newest first"
12302
+ }),
12303
+ columnHelper.accessor("created_at", {
12304
+ header: "Created",
12305
+ cell: ({ getValue }) => {
12306
+ return /* @__PURE__ */ jsx(
12307
+ Tooltip,
12384
12308
  {
12385
- ...field,
12386
- onValueChange: (value) => onChange(value),
12387
- symbol: getNativeSymbol(currencyCode),
12388
- code: currencyCode
12309
+ content: getFullDate({ date: getValue(), includeTime: true }),
12310
+ children: /* @__PURE__ */ jsx("span", { children: getFullDate({ date: getValue() }) })
12389
12311
  }
12390
- ) })
12391
- ] });
12312
+ );
12313
+ },
12314
+ enableSorting: true,
12315
+ sortAscLabel: "Oldest first",
12316
+ sortDescLabel: "Newest first"
12317
+ })
12318
+ ];
12319
+ }, []);
12320
+ };
12321
+ const CustomItemForm = ({ orderId, currencyCode }) => {
12322
+ const { setIsOpen } = useStackedModal();
12323
+ const { mutateAsync: addItems } = useDraftOrderAddItems(orderId);
12324
+ const form = useForm({
12325
+ defaultValues: {
12326
+ title: "",
12327
+ quantity: 1,
12328
+ unit_price: ""
12329
+ },
12330
+ resolver: zodResolver(customItemSchema)
12331
+ });
12332
+ const onSubmit = form.handleSubmit(async (data) => {
12333
+ await addItems(
12334
+ {
12335
+ items: [
12336
+ {
12337
+ title: data.title,
12338
+ quantity: data.quantity,
12339
+ unit_price: convertNumber(data.unit_price)
12340
+ }
12341
+ ]
12342
+ },
12343
+ {
12344
+ onSuccess: () => {
12345
+ setIsOpen(STACKED_MODAL_ID, false);
12346
+ },
12347
+ onError: (e) => {
12348
+ toast.error(e.message);
12349
+ }
12392
12350
  }
12393
- }
12394
- );
12351
+ );
12352
+ });
12353
+ return /* @__PURE__ */ jsx(Form$2, { ...form, children: /* @__PURE__ */ jsx(KeyboundForm, { onSubmit, children: /* @__PURE__ */ jsxs(StackedFocusModal.Content, { children: [
12354
+ /* @__PURE__ */ jsx(StackedFocusModal.Header, {}),
12355
+ /* @__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: [
12356
+ /* @__PURE__ */ jsxs("div", { children: [
12357
+ /* @__PURE__ */ jsx(StackedFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Add custom item" }) }),
12358
+ /* @__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." }) })
12359
+ ] }),
12360
+ /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
12361
+ /* @__PURE__ */ jsx(
12362
+ Form$2.Field,
12363
+ {
12364
+ control: form.control,
12365
+ name: "title",
12366
+ render: ({ field }) => /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
12367
+ /* @__PURE__ */ jsxs("div", { children: [
12368
+ /* @__PURE__ */ jsx(Form$2.Label, { children: "Title" }),
12369
+ /* @__PURE__ */ jsx(Form$2.Hint, { children: "Enter the title of the item" })
12370
+ ] }),
12371
+ /* @__PURE__ */ jsxs("div", { children: [
12372
+ /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(Input, { ...field }) }),
12373
+ /* @__PURE__ */ jsx(Form$2.ErrorMessage, {})
12374
+ ] })
12375
+ ] }) })
12376
+ }
12377
+ ),
12378
+ /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
12379
+ /* @__PURE__ */ jsx(
12380
+ Form$2.Field,
12381
+ {
12382
+ control: form.control,
12383
+ name: "unit_price",
12384
+ render: ({ field: { onChange, ...field } }) => /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
12385
+ /* @__PURE__ */ jsxs("div", { children: [
12386
+ /* @__PURE__ */ jsx(Form$2.Label, { children: "Unit price" }),
12387
+ /* @__PURE__ */ jsx(Form$2.Hint, { children: "Enter the unit price of the item" })
12388
+ ] }),
12389
+ /* @__PURE__ */ jsxs("div", { children: [
12390
+ /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
12391
+ CurrencyInput,
12392
+ {
12393
+ symbol: getNativeSymbol(currencyCode),
12394
+ code: currencyCode,
12395
+ onValueChange: (_value, _name, values) => onChange(values == null ? void 0 : values.value),
12396
+ ...field
12397
+ }
12398
+ ) }),
12399
+ /* @__PURE__ */ jsx(Form$2.ErrorMessage, {})
12400
+ ] })
12401
+ ] }) })
12402
+ }
12403
+ ),
12404
+ /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
12405
+ /* @__PURE__ */ jsx(
12406
+ Form$2.Field,
12407
+ {
12408
+ control: form.control,
12409
+ name: "quantity",
12410
+ render: ({ field }) => /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
12411
+ /* @__PURE__ */ jsxs("div", { children: [
12412
+ /* @__PURE__ */ jsx(Form$2.Label, { children: "Quantity" }),
12413
+ /* @__PURE__ */ jsx(Form$2.Hint, { children: "Enter the quantity of the item" })
12414
+ ] }),
12415
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 w-full", children: [
12416
+ /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx("div", { className: "flex-1 w-full", children: /* @__PURE__ */ jsx(NumberInput, { ...field, className: "w-full" }) }) }),
12417
+ /* @__PURE__ */ jsx(Form$2.ErrorMessage, {})
12418
+ ] })
12419
+ ] }) })
12420
+ }
12421
+ )
12422
+ ] }) }) }),
12423
+ /* @__PURE__ */ jsx(StackedFocusModal.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-2 justify-end", children: [
12424
+ /* @__PURE__ */ jsx(StackedFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
12425
+ /* @__PURE__ */ jsx(Button, { size: "small", type: "button", onClick: onSubmit, children: "Add item" })
12426
+ ] }) })
12427
+ ] }) }) });
12395
12428
  };
12429
+ const customItemSchema = z.object({
12430
+ title: z.string().min(1),
12431
+ quantity: z.number(),
12432
+ unit_price: z.union([z.number(), z.string()])
12433
+ });
12396
12434
  const ShippingAddress = () => {
12397
12435
  const { id } = useParams();
12398
12436
  const { order, isPending, isError, error } = useOrder(id, {
@@ -13072,33 +13110,27 @@ const Illustration = () => {
13072
13110
  const schema$1 = z.object({
13073
13111
  customer_id: z.string().min(1)
13074
13112
  });
13075
- const SalesChannel = () => {
13113
+ const Email = () => {
13076
13114
  const { id } = useParams();
13077
- const { draft_order, isPending, isError, error } = useDraftOrder(
13078
- id,
13079
- {
13080
- fields: "+sales_channel_id"
13081
- },
13082
- {
13083
- enabled: !!id
13084
- }
13085
- );
13115
+ const { order, isPending, isError, error } = useOrder(id, {
13116
+ fields: "+email"
13117
+ });
13086
13118
  if (isError) {
13087
13119
  throw error;
13088
13120
  }
13089
- const ISrEADY = !!draft_order && !isPending;
13121
+ const isReady = !isPending && !!order;
13090
13122
  return /* @__PURE__ */ jsxs(RouteDrawer, { children: [
13091
13123
  /* @__PURE__ */ jsxs(RouteDrawer.Header, { children: [
13092
- /* @__PURE__ */ jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Edit Sales Channel" }) }),
13093
- /* @__PURE__ */ jsx(RouteDrawer.Description, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Update which sales channel the draft order is associated with" }) })
13124
+ /* @__PURE__ */ jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Edit Email" }) }),
13125
+ /* @__PURE__ */ jsx(RouteDrawer.Description, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Edit the email for the draft order" }) })
13094
13126
  ] }),
13095
- ISrEADY && /* @__PURE__ */ jsx(SalesChannelForm, { order: draft_order })
13127
+ isReady && /* @__PURE__ */ jsx(EmailForm, { order })
13096
13128
  ] });
13097
13129
  };
13098
- const SalesChannelForm = ({ order }) => {
13130
+ const EmailForm = ({ order }) => {
13099
13131
  const form = useForm({
13100
13132
  defaultValues: {
13101
- sales_channel_id: order.sales_channel_id || ""
13133
+ email: order.email ?? ""
13102
13134
  },
13103
13135
  resolver: zodResolver(schema)
13104
13136
  });
@@ -13106,12 +13138,9 @@ const SalesChannelForm = ({ order }) => {
13106
13138
  const { handleSuccess } = useRouteModal();
13107
13139
  const onSubmit = form.handleSubmit(async (data) => {
13108
13140
  await mutateAsync(
13109
- {
13110
- sales_channel_id: data.sales_channel_id
13111
- },
13141
+ { email: data.email },
13112
13142
  {
13113
13143
  onSuccess: () => {
13114
- toast.success("Sales channel updated");
13115
13144
  handleSuccess();
13116
13145
  },
13117
13146
  onError: (error) => {
@@ -13126,7 +13155,18 @@ const SalesChannelForm = ({ order }) => {
13126
13155
  className: "flex flex-1 flex-col overflow-hidden",
13127
13156
  onSubmit,
13128
13157
  children: [
13129
- /* @__PURE__ */ jsx(RouteDrawer.Body, { className: "flex flex-col gap-y-6 overflow-y-auto", children: /* @__PURE__ */ jsx(SalesChannelField, { control: form.control, order }) }),
13158
+ /* @__PURE__ */ jsx(RouteDrawer.Body, { className: "flex flex-col gap-y-6 overflow-y-auto", children: /* @__PURE__ */ jsx(
13159
+ Form$2.Field,
13160
+ {
13161
+ control: form.control,
13162
+ name: "email",
13163
+ render: ({ field }) => /* @__PURE__ */ jsxs(Form$2.Item, { children: [
13164
+ /* @__PURE__ */ jsx(Form$2.Label, { children: "Email" }),
13165
+ /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(Input, { ...field }) }),
13166
+ /* @__PURE__ */ jsx(Form$2.ErrorMessage, {})
13167
+ ] })
13168
+ }
13169
+ ) }),
13130
13170
  /* @__PURE__ */ jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
13131
13171
  /* @__PURE__ */ jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
13132
13172
  /* @__PURE__ */ jsx(Button, { size: "small", type: "submit", isLoading: isPending, children: "Save" })
@@ -13135,48 +13175,8 @@ const SalesChannelForm = ({ order }) => {
13135
13175
  }
13136
13176
  ) });
13137
13177
  };
13138
- const SalesChannelField = ({ control, order }) => {
13139
- const salesChannels = useComboboxData({
13140
- queryFn: async (params) => {
13141
- return await sdk.admin.salesChannel.list(params);
13142
- },
13143
- queryKey: ["sales-channels"],
13144
- getOptions: (data) => {
13145
- return data.sales_channels.map((salesChannel) => ({
13146
- label: salesChannel.name,
13147
- value: salesChannel.id
13148
- }));
13149
- },
13150
- defaultValue: order.sales_channel_id || void 0
13151
- });
13152
- return /* @__PURE__ */ jsx(
13153
- Form$2.Field,
13154
- {
13155
- control,
13156
- name: "sales_channel_id",
13157
- render: ({ field }) => {
13158
- return /* @__PURE__ */ jsxs(Form$2.Item, { children: [
13159
- /* @__PURE__ */ jsx(Form$2.Label, { children: "Sales Channel" }),
13160
- /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
13161
- Combobox,
13162
- {
13163
- options: salesChannels.options,
13164
- fetchNextPage: salesChannels.fetchNextPage,
13165
- isFetchingNextPage: salesChannels.isFetchingNextPage,
13166
- searchValue: salesChannels.searchValue,
13167
- onSearchValueChange: salesChannels.onSearchValueChange,
13168
- placeholder: "Select sales channel",
13169
- ...field
13170
- }
13171
- ) }),
13172
- /* @__PURE__ */ jsx(Form$2.ErrorMessage, {})
13173
- ] });
13174
- }
13175
- }
13176
- );
13177
- };
13178
13178
  const schema = z.object({
13179
- sales_channel_id: z.string().min(1)
13179
+ email: z.string().email()
13180
13180
  });
13181
13181
  const widgetModule = { widgets: [] };
13182
13182
  const routeModule = {
@@ -13199,32 +13199,32 @@ const routeModule = {
13199
13199
  loader,
13200
13200
  children: [
13201
13201
  {
13202
- Component: CustomItems,
13203
- path: "/draft-orders/:id/custom-items"
13202
+ Component: BillingAddress,
13203
+ path: "/draft-orders/:id/billing-address"
13204
13204
  },
13205
13205
  {
13206
- Component: Email,
13207
- path: "/draft-orders/:id/email"
13206
+ Component: CustomItems,
13207
+ path: "/draft-orders/:id/custom-items"
13208
13208
  },
13209
13209
  {
13210
- Component: BillingAddress,
13211
- path: "/draft-orders/:id/billing-address"
13210
+ Component: Metadata,
13211
+ path: "/draft-orders/:id/metadata"
13212
13212
  },
13213
13213
  {
13214
13214
  Component: Promotions,
13215
13215
  path: "/draft-orders/:id/promotions"
13216
13216
  },
13217
13217
  {
13218
- Component: Items,
13219
- path: "/draft-orders/:id/items"
13218
+ Component: Shipping,
13219
+ path: "/draft-orders/:id/shipping"
13220
13220
  },
13221
13221
  {
13222
- Component: Metadata,
13223
- path: "/draft-orders/:id/metadata"
13222
+ Component: SalesChannel,
13223
+ path: "/draft-orders/:id/sales-channel"
13224
13224
  },
13225
13225
  {
13226
- Component: Shipping,
13227
- path: "/draft-orders/:id/shipping"
13226
+ Component: Items,
13227
+ path: "/draft-orders/:id/items"
13228
13228
  },
13229
13229
  {
13230
13230
  Component: ShippingAddress,
@@ -13235,8 +13235,8 @@ const routeModule = {
13235
13235
  path: "/draft-orders/:id/transfer-ownership"
13236
13236
  },
13237
13237
  {
13238
- Component: SalesChannel,
13239
- path: "/draft-orders/:id/sales-channel"
13238
+ Component: Email,
13239
+ path: "/draft-orders/:id/email"
13240
13240
  }
13241
13241
  ]
13242
13242
  }