@medusajs/draft-order 2.11.0-preview-20251020090157 → 2.11.0-preview-20251020141229

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