@medusajs/draft-order 2.10.1-snapshot-20250828200335 → 2.10.1-snapshot-20250828204656

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