@medusajs/draft-order 2.11.0-snapshot-20251017130454 → 2.11.0-snapshot-20251017170018

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,7 +4,7 @@ import { Tooltip, DropdownMenu, clx, IconButton, useDataTable, DataTable as Data
4
4
  import { useQuery, useQueryClient, useMutation, keepPreviousData, useInfiniteQuery } from "@tanstack/react-query";
5
5
  import React, { useState, useCallback, useMemo, Fragment, createContext, forwardRef, useId, useContext, useTransition, useRef, useImperativeHandle, useDeferredValue, useEffect, Suspense } from "react";
6
6
  import { useSearchParams, Link, useNavigate, Outlet, useBlocker, useLocation, useParams } from "react-router-dom";
7
- import { EllipsisHorizontal, XMark, InformationCircleSolid, XMarkMini, TrianglesMini, CheckMini, EllipseMiniSolid, PlusMini, ExclamationCircleSolid, ArrowPath, FlyingBox, CurrencyDollar, Envelope, Channels, Trash, ArrowUpRightOnBox, TriangleDownMini, Check, SquareTwoStack, Photo, TriangleRightMini, Shopping, Buildings, TruckFast, Plus, ReceiptPercent, Minus, PencilSquare, EllipsisVertical, ArrowUpMini, ArrowDownMini } from "@medusajs/icons";
7
+ import { EllipsisHorizontal, XMark, InformationCircleSolid, XMarkMini, TrianglesMini, CheckMini, EllipseMiniSolid, PlusMini, ExclamationCircleSolid, ArrowPath, FlyingBox, CurrencyDollar, Envelope, Channels, Trash, ArrowUpRightOnBox, TriangleDownMini, Check, SquareTwoStack, Photo, TriangleRightMini, Shopping, Buildings, TruckFast, Plus, ReceiptPercent, EllipsisVertical, ArrowUpMini, ArrowDownMini, Minus, PencilSquare } from "@medusajs/icons";
8
8
  import Medusa from "@medusajs/js-sdk";
9
9
  import { format, formatDistance, sub, subDays, subMonths } from "date-fns";
10
10
  import { enUS } from "date-fns/locale";
@@ -9567,6 +9567,95 @@ const ID = () => {
9567
9567
  /* @__PURE__ */ jsx(Outlet, {})
9568
9568
  ] });
9569
9569
  };
9570
+ const CustomItems = () => {
9571
+ return /* @__PURE__ */ jsxs(RouteDrawer, { children: [
9572
+ /* @__PURE__ */ jsx(RouteDrawer.Header, { children: /* @__PURE__ */ jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Edit Custom Items" }) }) }),
9573
+ /* @__PURE__ */ jsx(CustomItemsForm, {})
9574
+ ] });
9575
+ };
9576
+ const CustomItemsForm = () => {
9577
+ const form = useForm({
9578
+ resolver: zodResolver(schema$5)
9579
+ });
9580
+ return /* @__PURE__ */ jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxs(KeyboundForm, { className: "flex flex-1 flex-col", children: [
9581
+ /* @__PURE__ */ jsx(RouteDrawer.Body, {}),
9582
+ /* @__PURE__ */ jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
9583
+ /* @__PURE__ */ jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
9584
+ /* @__PURE__ */ jsx(Button, { size: "small", type: "submit", children: "Save" })
9585
+ ] }) })
9586
+ ] }) });
9587
+ };
9588
+ const schema$5 = objectType({
9589
+ email: stringType().email()
9590
+ });
9591
+ const Email = () => {
9592
+ const { id } = useParams();
9593
+ const { order, isPending, isError, error } = useOrder(id, {
9594
+ fields: "+email"
9595
+ });
9596
+ if (isError) {
9597
+ throw error;
9598
+ }
9599
+ const isReady = !isPending && !!order;
9600
+ return /* @__PURE__ */ jsxs(RouteDrawer, { children: [
9601
+ /* @__PURE__ */ jsxs(RouteDrawer.Header, { children: [
9602
+ /* @__PURE__ */ jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Edit Email" }) }),
9603
+ /* @__PURE__ */ jsx(RouteDrawer.Description, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Edit the email for the draft order" }) })
9604
+ ] }),
9605
+ isReady && /* @__PURE__ */ jsx(EmailForm, { order })
9606
+ ] });
9607
+ };
9608
+ const EmailForm = ({ order }) => {
9609
+ const form = useForm({
9610
+ defaultValues: {
9611
+ email: order.email ?? ""
9612
+ },
9613
+ resolver: zodResolver(schema$4)
9614
+ });
9615
+ const { mutateAsync, isPending } = useUpdateDraftOrder(order.id);
9616
+ const { handleSuccess } = useRouteModal();
9617
+ const onSubmit = form.handleSubmit(async (data) => {
9618
+ await mutateAsync(
9619
+ { email: data.email },
9620
+ {
9621
+ onSuccess: () => {
9622
+ handleSuccess();
9623
+ },
9624
+ onError: (error) => {
9625
+ toast.error(error.message);
9626
+ }
9627
+ }
9628
+ );
9629
+ });
9630
+ return /* @__PURE__ */ jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxs(
9631
+ KeyboundForm,
9632
+ {
9633
+ className: "flex flex-1 flex-col overflow-hidden",
9634
+ onSubmit,
9635
+ children: [
9636
+ /* @__PURE__ */ jsx(RouteDrawer.Body, { className: "flex flex-col gap-y-6 overflow-y-auto", children: /* @__PURE__ */ jsx(
9637
+ Form$2.Field,
9638
+ {
9639
+ control: form.control,
9640
+ name: "email",
9641
+ render: ({ field }) => /* @__PURE__ */ jsxs(Form$2.Item, { children: [
9642
+ /* @__PURE__ */ jsx(Form$2.Label, { children: "Email" }),
9643
+ /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(Input, { ...field }) }),
9644
+ /* @__PURE__ */ jsx(Form$2.ErrorMessage, {})
9645
+ ] })
9646
+ }
9647
+ ) }),
9648
+ /* @__PURE__ */ jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
9649
+ /* @__PURE__ */ jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
9650
+ /* @__PURE__ */ jsx(Button, { size: "small", type: "submit", isLoading: isPending, children: "Save" })
9651
+ ] }) })
9652
+ ]
9653
+ }
9654
+ ) });
9655
+ };
9656
+ const schema$4 = objectType({
9657
+ email: stringType().email()
9658
+ });
9570
9659
  const BillingAddress = () => {
9571
9660
  const { id } = useParams();
9572
9661
  const { order, isPending, isError, error } = useOrder(id, {
@@ -9599,7 +9688,7 @@ const BillingAddressForm = ({ order }) => {
9599
9688
  postal_code: ((_i = order.billing_address) == null ? void 0 : _i.postal_code) ?? "",
9600
9689
  phone: ((_j = order.billing_address) == null ? void 0 : _j.phone) ?? ""
9601
9690
  },
9602
- resolver: zodResolver(schema$5)
9691
+ resolver: zodResolver(schema$3)
9603
9692
  });
9604
9693
  const { mutateAsync, isPending } = useUpdateDraftOrder(order.id);
9605
9694
  const { handleSuccess } = useRouteModal();
@@ -9756,32 +9845,55 @@ const BillingAddressForm = ({ order }) => {
9756
9845
  }
9757
9846
  ) });
9758
9847
  };
9759
- const schema$5 = addressSchema;
9760
- const CustomItems = () => {
9761
- return /* @__PURE__ */ jsxs(RouteDrawer, { children: [
9762
- /* @__PURE__ */ jsx(RouteDrawer.Header, { children: /* @__PURE__ */ jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Edit Custom Items" }) }) }),
9763
- /* @__PURE__ */ jsx(CustomItemsForm, {})
9764
- ] });
9765
- };
9766
- const CustomItemsForm = () => {
9767
- const form = useForm({
9768
- resolver: zodResolver(schema$4)
9769
- });
9770
- return /* @__PURE__ */ jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxs(KeyboundForm, { className: "flex flex-1 flex-col", children: [
9771
- /* @__PURE__ */ jsx(RouteDrawer.Body, {}),
9772
- /* @__PURE__ */ jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
9773
- /* @__PURE__ */ jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
9774
- /* @__PURE__ */ jsx(Button, { size: "small", type: "submit", children: "Save" })
9775
- ] }) })
9776
- ] }) });
9777
- };
9778
- const schema$4 = objectType({
9779
- email: stringType().email()
9848
+ const schema$3 = addressSchema;
9849
+ const InlineTip = forwardRef(
9850
+ ({ variant = "tip", label, className, children, ...props }, ref) => {
9851
+ const labelValue = label || (variant === "warning" ? "Warning" : "Tip");
9852
+ return /* @__PURE__ */ jsxs(
9853
+ "div",
9854
+ {
9855
+ ref,
9856
+ className: clx(
9857
+ "bg-ui-bg-component txt-small text-ui-fg-subtle grid grid-cols-[4px_1fr] items-start gap-3 rounded-lg border p-3",
9858
+ className
9859
+ ),
9860
+ ...props,
9861
+ children: [
9862
+ /* @__PURE__ */ jsx(
9863
+ "div",
9864
+ {
9865
+ role: "presentation",
9866
+ className: clx("w-4px bg-ui-tag-neutral-icon h-full rounded-full", {
9867
+ "bg-ui-tag-orange-icon": variant === "warning"
9868
+ })
9869
+ }
9870
+ ),
9871
+ /* @__PURE__ */ jsxs("div", { className: "text-pretty", children: [
9872
+ /* @__PURE__ */ jsxs("strong", { className: "txt-small-plus text-ui-fg-base", children: [
9873
+ labelValue,
9874
+ ":"
9875
+ ] }),
9876
+ " ",
9877
+ children
9878
+ ] })
9879
+ ]
9880
+ }
9881
+ );
9882
+ }
9883
+ );
9884
+ InlineTip.displayName = "InlineTip";
9885
+ const MetadataFieldSchema = objectType({
9886
+ key: stringType(),
9887
+ disabled: booleanType().optional(),
9888
+ value: anyType()
9780
9889
  });
9781
- const Email = () => {
9890
+ const MetadataSchema = objectType({
9891
+ metadata: arrayType(MetadataFieldSchema)
9892
+ });
9893
+ const Metadata = () => {
9782
9894
  const { id } = useParams();
9783
9895
  const { order, isPending, isError, error } = useOrder(id, {
9784
- fields: "+email"
9896
+ fields: "metadata"
9785
9897
  });
9786
9898
  if (isError) {
9787
9899
  throw error;
@@ -9789,26 +9901,33 @@ const Email = () => {
9789
9901
  const isReady = !isPending && !!order;
9790
9902
  return /* @__PURE__ */ jsxs(RouteDrawer, { children: [
9791
9903
  /* @__PURE__ */ jsxs(RouteDrawer.Header, { children: [
9792
- /* @__PURE__ */ jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Edit Email" }) }),
9793
- /* @__PURE__ */ jsx(RouteDrawer.Description, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Edit the email for the draft order" }) })
9904
+ /* @__PURE__ */ jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Metadata" }) }),
9905
+ /* @__PURE__ */ jsx(RouteDrawer.Description, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Add metadata to the draft order." }) })
9794
9906
  ] }),
9795
- isReady && /* @__PURE__ */ jsx(EmailForm, { order })
9907
+ !isReady ? /* @__PURE__ */ jsx(PlaceholderInner, {}) : /* @__PURE__ */ jsx(MetadataForm, { orderId: id, metadata: order == null ? void 0 : order.metadata })
9796
9908
  ] });
9797
9909
  };
9798
- const EmailForm = ({ order }) => {
9910
+ const METADATA_KEY_LABEL_ID = "metadata-form-key-label";
9911
+ const METADATA_VALUE_LABEL_ID = "metadata-form-value-label";
9912
+ const MetadataForm = ({ orderId, metadata }) => {
9913
+ const { handleSuccess } = useRouteModal();
9914
+ const hasUneditableRows = getHasUneditableRows(metadata);
9915
+ const { mutateAsync, isPending } = useUpdateDraftOrder(orderId);
9799
9916
  const form = useForm({
9800
9917
  defaultValues: {
9801
- email: order.email ?? ""
9918
+ metadata: getDefaultValues(metadata)
9802
9919
  },
9803
- resolver: zodResolver(schema$3)
9920
+ resolver: zodResolver(MetadataSchema)
9804
9921
  });
9805
- const { mutateAsync, isPending } = useUpdateDraftOrder(order.id);
9806
- const { handleSuccess } = useRouteModal();
9807
- const onSubmit = form.handleSubmit(async (data) => {
9922
+ const handleSubmit = form.handleSubmit(async (data) => {
9923
+ const parsedData = parseValues(data);
9808
9924
  await mutateAsync(
9809
- { email: data.email },
9925
+ {
9926
+ metadata: parsedData
9927
+ },
9810
9928
  {
9811
9929
  onSuccess: () => {
9930
+ toast.success("Metadata updated");
9812
9931
  handleSuccess();
9813
9932
  },
9814
9933
  onError: (error) => {
@@ -9817,62 +9936,293 @@ const EmailForm = ({ order }) => {
9817
9936
  }
9818
9937
  );
9819
9938
  });
9939
+ const { fields, insert, remove } = useFieldArray({
9940
+ control: form.control,
9941
+ name: "metadata"
9942
+ });
9943
+ function deleteRow(index) {
9944
+ remove(index);
9945
+ if (fields.length === 1) {
9946
+ insert(0, {
9947
+ key: "",
9948
+ value: "",
9949
+ disabled: false
9950
+ });
9951
+ }
9952
+ }
9953
+ function insertRow(index, position) {
9954
+ insert(index + (position === "above" ? 0 : 1), {
9955
+ key: "",
9956
+ value: "",
9957
+ disabled: false
9958
+ });
9959
+ }
9820
9960
  return /* @__PURE__ */ jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxs(
9821
9961
  KeyboundForm,
9822
9962
  {
9963
+ onSubmit: handleSubmit,
9823
9964
  className: "flex flex-1 flex-col overflow-hidden",
9824
- onSubmit,
9825
9965
  children: [
9826
- /* @__PURE__ */ jsx(RouteDrawer.Body, { className: "flex flex-col gap-y-6 overflow-y-auto", children: /* @__PURE__ */ jsx(
9827
- Form$2.Field,
9828
- {
9829
- control: form.control,
9830
- name: "email",
9831
- render: ({ field }) => /* @__PURE__ */ jsxs(Form$2.Item, { children: [
9832
- /* @__PURE__ */ jsx(Form$2.Label, { children: "Email" }),
9833
- /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(Input, { ...field }) }),
9834
- /* @__PURE__ */ jsx(Form$2.ErrorMessage, {})
9835
- ] })
9836
- }
9837
- ) }),
9838
- /* @__PURE__ */ jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
9839
- /* @__PURE__ */ jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
9840
- /* @__PURE__ */ jsx(Button, { size: "small", type: "submit", isLoading: isPending, children: "Save" })
9841
- ] }) })
9842
- ]
9843
- }
9844
- ) });
9845
- };
9846
- const schema$3 = objectType({
9847
- email: stringType().email()
9848
- });
9849
- const NumberInput = forwardRef(
9850
- ({
9851
- value,
9852
- onChange,
9853
- size = "base",
9854
- min = 0,
9855
- max = 100,
9856
- step = 1,
9857
- className,
9858
- disabled,
9859
- ...props
9860
- }, ref) => {
9861
- const handleChange = (event) => {
9862
- const newValue = event.target.value === "" ? min : Number(event.target.value);
9863
- if (!isNaN(newValue) && (max === void 0 || newValue <= max) && (min === void 0 || newValue >= min)) {
9864
- onChange(newValue);
9865
- }
9866
- };
9867
- const handleIncrement = () => {
9868
- const newValue = value + step;
9869
- if (max === void 0 || newValue <= max) {
9870
- onChange(newValue);
9871
- }
9872
- };
9873
- const handleDecrement = () => {
9874
- const newValue = value - step;
9875
- if (min === void 0 || newValue >= min) {
9966
+ /* @__PURE__ */ jsxs(RouteDrawer.Body, { className: "flex flex-1 flex-col gap-y-8 overflow-y-auto", children: [
9967
+ /* @__PURE__ */ jsxs("div", { className: "bg-ui-bg-base shadow-elevation-card-rest grid grid-cols-1 divide-y rounded-lg", children: [
9968
+ /* @__PURE__ */ jsxs("div", { className: "bg-ui-bg-subtle grid grid-cols-2 divide-x rounded-t-lg", children: [
9969
+ /* @__PURE__ */ jsx("div", { className: "txt-compact-small-plus text-ui-fg-subtle px-2 py-1.5", children: /* @__PURE__ */ jsx("label", { id: METADATA_KEY_LABEL_ID, children: "Key" }) }),
9970
+ /* @__PURE__ */ jsx("div", { className: "txt-compact-small-plus text-ui-fg-subtle px-2 py-1.5", children: /* @__PURE__ */ jsx("label", { id: METADATA_VALUE_LABEL_ID, children: "Value" }) })
9971
+ ] }),
9972
+ fields.map((field, index) => {
9973
+ const isDisabled = field.disabled || false;
9974
+ let placeholder = "-";
9975
+ if (typeof field.value === "object") {
9976
+ placeholder = "{ ... }";
9977
+ }
9978
+ if (Array.isArray(field.value)) {
9979
+ placeholder = "[ ... ]";
9980
+ }
9981
+ return /* @__PURE__ */ jsx(
9982
+ ConditionalTooltip,
9983
+ {
9984
+ showTooltip: isDisabled,
9985
+ content: "This row is disabled because it contains non-primitive data.",
9986
+ children: /* @__PURE__ */ jsxs("div", { className: "group/table relative", children: [
9987
+ /* @__PURE__ */ jsxs(
9988
+ "div",
9989
+ {
9990
+ className: clx("grid grid-cols-2 divide-x", {
9991
+ "overflow-hidden rounded-b-lg": index === fields.length - 1
9992
+ }),
9993
+ children: [
9994
+ /* @__PURE__ */ jsx(
9995
+ Form$2.Field,
9996
+ {
9997
+ control: form.control,
9998
+ name: `metadata.${index}.key`,
9999
+ render: ({ field: field2 }) => {
10000
+ return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
10001
+ GridInput,
10002
+ {
10003
+ "aria-labelledby": METADATA_KEY_LABEL_ID,
10004
+ ...field2,
10005
+ disabled: isDisabled,
10006
+ placeholder: "Key"
10007
+ }
10008
+ ) }) });
10009
+ }
10010
+ }
10011
+ ),
10012
+ /* @__PURE__ */ jsx(
10013
+ Form$2.Field,
10014
+ {
10015
+ control: form.control,
10016
+ name: `metadata.${index}.value`,
10017
+ render: ({ field: { value, ...field2 } }) => {
10018
+ return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
10019
+ GridInput,
10020
+ {
10021
+ "aria-labelledby": METADATA_VALUE_LABEL_ID,
10022
+ ...field2,
10023
+ value: isDisabled ? placeholder : value,
10024
+ disabled: isDisabled,
10025
+ placeholder: "Value"
10026
+ }
10027
+ ) }) });
10028
+ }
10029
+ }
10030
+ )
10031
+ ]
10032
+ }
10033
+ ),
10034
+ /* @__PURE__ */ jsxs(DropdownMenu, { children: [
10035
+ /* @__PURE__ */ jsx(
10036
+ DropdownMenu.Trigger,
10037
+ {
10038
+ className: clx(
10039
+ "invisible absolute inset-y-0 -right-2.5 my-auto group-hover/table:visible data-[state='open']:visible",
10040
+ {
10041
+ hidden: isDisabled
10042
+ }
10043
+ ),
10044
+ disabled: isDisabled,
10045
+ asChild: true,
10046
+ children: /* @__PURE__ */ jsx(IconButton, { size: "2xsmall", children: /* @__PURE__ */ jsx(EllipsisVertical, {}) })
10047
+ }
10048
+ ),
10049
+ /* @__PURE__ */ jsxs(DropdownMenu.Content, { children: [
10050
+ /* @__PURE__ */ jsxs(
10051
+ DropdownMenu.Item,
10052
+ {
10053
+ className: "gap-x-2",
10054
+ onClick: () => insertRow(index, "above"),
10055
+ children: [
10056
+ /* @__PURE__ */ jsx(ArrowUpMini, { className: "text-ui-fg-subtle" }),
10057
+ "Insert row above"
10058
+ ]
10059
+ }
10060
+ ),
10061
+ /* @__PURE__ */ jsxs(
10062
+ DropdownMenu.Item,
10063
+ {
10064
+ className: "gap-x-2",
10065
+ onClick: () => insertRow(index, "below"),
10066
+ children: [
10067
+ /* @__PURE__ */ jsx(ArrowDownMini, { className: "text-ui-fg-subtle" }),
10068
+ "Insert row below"
10069
+ ]
10070
+ }
10071
+ ),
10072
+ /* @__PURE__ */ jsx(DropdownMenu.Separator, {}),
10073
+ /* @__PURE__ */ jsxs(
10074
+ DropdownMenu.Item,
10075
+ {
10076
+ className: "gap-x-2",
10077
+ onClick: () => deleteRow(index),
10078
+ children: [
10079
+ /* @__PURE__ */ jsx(Trash, { className: "text-ui-fg-subtle" }),
10080
+ "Delete row"
10081
+ ]
10082
+ }
10083
+ )
10084
+ ] })
10085
+ ] })
10086
+ ] })
10087
+ },
10088
+ field.id
10089
+ );
10090
+ })
10091
+ ] }),
10092
+ hasUneditableRows && /* @__PURE__ */ jsx(InlineTip, { variant: "warning", label: "Some rows are disabled", children: "This object contains non-primitive metadata, such as arrays or objects, that can't be edited here. To edit the disabled rows, use the API directly." })
10093
+ ] }),
10094
+ /* @__PURE__ */ jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
10095
+ /* @__PURE__ */ jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
10096
+ /* @__PURE__ */ jsx(Button, { size: "small", type: "submit", isLoading: isPending, children: "Save" })
10097
+ ] }) })
10098
+ ]
10099
+ }
10100
+ ) });
10101
+ };
10102
+ const GridInput = forwardRef(({ className, ...props }, ref) => {
10103
+ return /* @__PURE__ */ jsx(
10104
+ "input",
10105
+ {
10106
+ ref,
10107
+ ...props,
10108
+ autoComplete: "off",
10109
+ className: clx(
10110
+ "txt-compact-small text-ui-fg-base placeholder:text-ui-fg-muted disabled:text-ui-fg-disabled disabled:bg-ui-bg-base bg-transparent px-2 py-1.5 outline-none",
10111
+ className
10112
+ )
10113
+ }
10114
+ );
10115
+ });
10116
+ GridInput.displayName = "MetadataForm.GridInput";
10117
+ const PlaceholderInner = () => {
10118
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col overflow-hidden", children: [
10119
+ /* @__PURE__ */ jsx(RouteDrawer.Body, { children: /* @__PURE__ */ jsx(Skeleton, { className: "h-[148ox] w-full rounded-lg" }) }),
10120
+ /* @__PURE__ */ jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
10121
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-7 w-12 rounded-md" }),
10122
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-7 w-12 rounded-md" })
10123
+ ] }) })
10124
+ ] });
10125
+ };
10126
+ const EDITABLE_TYPES = ["string", "number", "boolean"];
10127
+ function getDefaultValues(metadata) {
10128
+ if (!metadata || !Object.keys(metadata).length) {
10129
+ return [
10130
+ {
10131
+ key: "",
10132
+ value: "",
10133
+ disabled: false
10134
+ }
10135
+ ];
10136
+ }
10137
+ return Object.entries(metadata).map(([key, value]) => {
10138
+ if (!EDITABLE_TYPES.includes(typeof value)) {
10139
+ return {
10140
+ key,
10141
+ value,
10142
+ disabled: true
10143
+ };
10144
+ }
10145
+ let stringValue = value;
10146
+ if (typeof value !== "string") {
10147
+ stringValue = JSON.stringify(value);
10148
+ }
10149
+ return {
10150
+ key,
10151
+ value: stringValue,
10152
+ original_key: key
10153
+ };
10154
+ });
10155
+ }
10156
+ function parseValues(values) {
10157
+ const metadata = values.metadata;
10158
+ const isEmpty = !metadata.length || metadata.length === 1 && !metadata[0].key && !metadata[0].value;
10159
+ if (isEmpty) {
10160
+ return null;
10161
+ }
10162
+ const update = {};
10163
+ metadata.forEach((field) => {
10164
+ let key = field.key;
10165
+ let value = field.value;
10166
+ const disabled = field.disabled;
10167
+ if (!key || !value) {
10168
+ return;
10169
+ }
10170
+ if (disabled) {
10171
+ update[key] = value;
10172
+ return;
10173
+ }
10174
+ key = key.trim();
10175
+ value = value.trim();
10176
+ if (value === "true") {
10177
+ update[key] = true;
10178
+ } else if (value === "false") {
10179
+ update[key] = false;
10180
+ } else {
10181
+ const parsedNumber = parseFloat(value);
10182
+ if (!isNaN(parsedNumber)) {
10183
+ update[key] = parsedNumber;
10184
+ } else {
10185
+ update[key] = value;
10186
+ }
10187
+ }
10188
+ });
10189
+ return update;
10190
+ }
10191
+ function getHasUneditableRows(metadata) {
10192
+ if (!metadata) {
10193
+ return false;
10194
+ }
10195
+ return Object.values(metadata).some(
10196
+ (value) => !EDITABLE_TYPES.includes(typeof value)
10197
+ );
10198
+ }
10199
+ const NumberInput = forwardRef(
10200
+ ({
10201
+ value,
10202
+ onChange,
10203
+ size = "base",
10204
+ min = 0,
10205
+ max = 100,
10206
+ step = 1,
10207
+ className,
10208
+ disabled,
10209
+ ...props
10210
+ }, ref) => {
10211
+ const handleChange = (event) => {
10212
+ const newValue = event.target.value === "" ? min : Number(event.target.value);
10213
+ if (!isNaN(newValue) && (max === void 0 || newValue <= max) && (min === void 0 || newValue >= min)) {
10214
+ onChange(newValue);
10215
+ }
10216
+ };
10217
+ const handleIncrement = () => {
10218
+ const newValue = value + step;
10219
+ if (max === void 0 || newValue <= max) {
10220
+ onChange(newValue);
10221
+ }
10222
+ };
10223
+ const handleDecrement = () => {
10224
+ const newValue = value - step;
10225
+ if (min === void 0 || newValue >= min) {
9876
10226
  onChange(newValue);
9877
10227
  }
9878
10228
  };
@@ -10315,173 +10665,31 @@ const VariantItem = ({ item, preview, currencyCode }) => {
10315
10665
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-1", children: [
10316
10666
  /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: item.product_title }),
10317
10667
  /* @__PURE__ */ jsxs(
10318
- Text,
10319
- {
10320
- size: "small",
10321
- leading: "compact",
10322
- className: "text-ui-fg-subtle",
10323
- children: [
10324
- "(",
10325
- item.variant_title,
10326
- ")"
10327
- ]
10328
- }
10329
- )
10330
- ] }),
10331
- /* @__PURE__ */ jsx(
10332
- Text,
10333
- {
10334
- size: "small",
10335
- leading: "compact",
10336
- className: "text-ui-fg-subtle",
10337
- children: item.variant_sku
10338
- }
10339
- )
10340
- ] })
10341
- ] }),
10342
- editing ? /* @__PURE__ */ jsx("div", { className: "w-full flex-1", children: /* @__PURE__ */ jsx(
10343
- Form$2.Field,
10344
- {
10345
- control: form.control,
10346
- name: "quantity",
10347
- render: ({ field }) => {
10348
- return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(NumberInput, { ...field }) }) });
10349
- }
10350
- }
10351
- ) }) : /* @__PURE__ */ jsx("div", { className: "w-full flex-1", children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: item.quantity }) }),
10352
- editing ? /* @__PURE__ */ jsx("div", { className: "w-full flex-1", children: /* @__PURE__ */ jsx(
10353
- Form$2.Field,
10354
- {
10355
- control: form.control,
10356
- name: "unit_price",
10357
- render: ({ field: { onChange, ...field } }) => {
10358
- return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
10359
- CurrencyInput,
10360
- {
10361
- ...field,
10362
- symbol: getNativeSymbol(currencyCode),
10363
- code: currencyCode,
10364
- onValueChange: (_value, _name, values) => onChange(values == null ? void 0 : values.value)
10365
- }
10366
- ) }) });
10367
- }
10368
- }
10369
- ) }) : /* @__PURE__ */ jsx("div", { className: "flex w-full flex-1 items-center justify-end", children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: getLocaleAmount(item.unit_price, currencyCode) }) }),
10370
- /* @__PURE__ */ jsx(
10371
- IconButton,
10372
- {
10373
- type: "button",
10374
- size: "small",
10375
- onClick: editing ? onSubmit : () => {
10376
- setEditing(true);
10377
- },
10378
- disabled: isPending,
10379
- children: editing ? /* @__PURE__ */ jsx(Check, {}) : /* @__PURE__ */ jsx(PencilSquare, {})
10380
- }
10381
- )
10382
- ] }) }) });
10383
- };
10384
- const variantItemSchema = objectType({
10385
- quantity: numberType(),
10386
- unit_price: unionType([numberType(), stringType()])
10387
- });
10388
- const CustomItem = ({ item, preview, currencyCode }) => {
10389
- const [editing, setEditing] = useState(false);
10390
- const { quantity, unit_price, title } = item;
10391
- const form = useForm({
10392
- defaultValues: {
10393
- title,
10394
- quantity,
10395
- unit_price
10396
- },
10397
- resolver: zodResolver(customItemSchema)
10398
- });
10399
- useEffect(() => {
10400
- form.reset({
10401
- title,
10402
- quantity,
10403
- unit_price
10404
- });
10405
- }, [form, title, quantity, unit_price]);
10406
- const actionId = useMemo(() => {
10407
- var _a, _b;
10408
- return (_b = (_a = item.actions) == null ? void 0 : _a.find((a) => a.action === "ITEM_ADD")) == null ? void 0 : _b.id;
10409
- }, [item]);
10410
- const { mutateAsync: updateActionItem, isPending: isUpdatingActionItem } = useDraftOrderUpdateActionItem(preview.id);
10411
- const { mutateAsync: removeActionItem, isPending: isRemovingActionItem } = useDraftOrderRemoveActionItem(preview.id);
10412
- const { mutateAsync: updateOriginalItem, isPending: isUpdatingOriginalItem } = useDraftOrderUpdateItem(preview.id);
10413
- const isPending = isUpdatingActionItem || isUpdatingOriginalItem;
10414
- const onSubmit = form.handleSubmit(async (data) => {
10415
- if (convertNumber(data.unit_price) === item.unit_price && data.quantity === item.quantity && data.title === item.title) {
10416
- setEditing(false);
10417
- return;
10418
- }
10419
- if (!actionId) {
10420
- await updateOriginalItem(
10421
- {
10422
- item_id: item.id,
10423
- quantity: data.quantity,
10424
- unit_price: convertNumber(data.unit_price)
10425
- },
10426
- {
10427
- onSuccess: () => {
10428
- setEditing(false);
10429
- },
10430
- onError: (e) => {
10431
- toast.error(e.message);
10432
- }
10433
- }
10434
- );
10435
- return;
10436
- }
10437
- if (data.quantity === 0) {
10438
- await removeActionItem(actionId, {
10439
- onSuccess: () => {
10440
- setEditing(false);
10441
- },
10442
- onError: (e) => {
10443
- toast.error(e.message);
10444
- }
10445
- });
10446
- return;
10447
- }
10448
- await updateActionItem(
10449
- {
10450
- action_id: actionId,
10451
- quantity: data.quantity,
10452
- unit_price: convertNumber(data.unit_price)
10453
- },
10454
- {
10455
- onSuccess: () => {
10456
- setEditing(false);
10457
- },
10458
- onError: (e) => {
10459
- toast.error(e.message);
10460
- }
10461
- }
10462
- );
10463
- });
10464
- return /* @__PURE__ */ jsx(Form$2, { ...form, children: /* @__PURE__ */ jsx("form", { onSubmit, children: /* @__PURE__ */ jsxs("div", { className: "bg-ui-bg-base shadow-elevation-card-rest grid grid-cols-[minmax(0,2fr)_minmax(0,1fr)_minmax(0,2fr)_28px] items-center gap-3 rounded-lg px-4 py-2", children: [
10465
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-3", children: [
10466
- /* @__PURE__ */ jsx(
10467
- Thumbnail,
10468
- {
10469
- thumbnail: item.thumbnail,
10470
- alt: item.title ?? void 0
10471
- }
10472
- ),
10473
- editing ? /* @__PURE__ */ jsx(
10474
- Form$2.Field,
10475
- {
10476
- control: form.control,
10477
- name: "title",
10478
- render: ({ field }) => {
10479
- return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(Input, { ...field }) }) });
10668
+ Text,
10669
+ {
10670
+ size: "small",
10671
+ leading: "compact",
10672
+ className: "text-ui-fg-subtle",
10673
+ children: [
10674
+ "(",
10675
+ item.variant_title,
10676
+ ")"
10677
+ ]
10678
+ }
10679
+ )
10680
+ ] }),
10681
+ /* @__PURE__ */ jsx(
10682
+ Text,
10683
+ {
10684
+ size: "small",
10685
+ leading: "compact",
10686
+ className: "text-ui-fg-subtle",
10687
+ children: item.variant_sku
10480
10688
  }
10481
- }
10482
- ) : /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: item.title })
10689
+ )
10690
+ ] })
10483
10691
  ] }),
10484
- editing ? /* @__PURE__ */ jsx(
10692
+ editing ? /* @__PURE__ */ jsx("div", { className: "w-full flex-1", children: /* @__PURE__ */ jsx(
10485
10693
  Form$2.Field,
10486
10694
  {
10487
10695
  control: form.control,
@@ -10490,8 +10698,8 @@ const CustomItem = ({ item, preview, currencyCode }) => {
10490
10698
  return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(NumberInput, { ...field }) }) });
10491
10699
  }
10492
10700
  }
10493
- ) : /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: item.quantity }),
10494
- editing ? /* @__PURE__ */ jsx(
10701
+ ) }) : /* @__PURE__ */ jsx("div", { className: "w-full flex-1", children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: item.quantity }) }),
10702
+ editing ? /* @__PURE__ */ jsx("div", { className: "w-full flex-1", children: /* @__PURE__ */ jsx(
10495
10703
  Form$2.Field,
10496
10704
  {
10497
10705
  control: form.control,
@@ -10508,7 +10716,7 @@ const CustomItem = ({ item, preview, currencyCode }) => {
10508
10716
  ) }) });
10509
10717
  }
10510
10718
  }
10511
- ) : /* @__PURE__ */ jsx("div", { className: "flex flex-1 items-center justify-end", children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: getLocaleAmount(item.unit_price, currencyCode) }) }),
10719
+ ) }) : /* @__PURE__ */ jsx("div", { className: "flex w-full flex-1 items-center justify-end", children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: getLocaleAmount(item.unit_price, currencyCode) }) }),
10512
10720
  /* @__PURE__ */ jsx(
10513
10721
  IconButton,
10514
10722
  {
@@ -10523,215 +10731,79 @@ const CustomItem = ({ item, preview, currencyCode }) => {
10523
10731
  )
10524
10732
  ] }) }) });
10525
10733
  };
10526
- const StackedModalTrigger$1 = ({
10527
- type,
10528
- setModalContent
10529
- }) => {
10530
- const { setIsOpen } = useStackedModal();
10531
- const onClick = useCallback(() => {
10532
- setModalContent(type);
10533
- setIsOpen(STACKED_MODAL_ID, true);
10534
- }, [setModalContent, setIsOpen, type]);
10535
- return /* @__PURE__ */ jsx(StackedFocusModal.Trigger, { asChild: true, children: /* @__PURE__ */ jsx(DropdownMenu.Item, { onClick, children: type === "add-items" ? "Add items" : "Add custom item" }) });
10536
- };
10537
- const VARIANT_PREFIX = "items";
10538
- const LIMIT = 50;
10539
- const ExistingItemsForm = ({ orderId, items }) => {
10540
- const { setIsOpen } = useStackedModal();
10541
- const [rowSelection, setRowSelection] = useState(
10542
- items.reduce((acc, item) => {
10543
- acc[item.variant_id] = true;
10544
- return acc;
10545
- }, {})
10546
- );
10547
- useEffect(() => {
10548
- setRowSelection(
10549
- items.reduce((acc, item) => {
10550
- if (item.variant_id) {
10551
- acc[item.variant_id] = true;
10552
- }
10553
- return acc;
10554
- }, {})
10555
- );
10556
- }, [items]);
10557
- const { q, order, offset } = useQueryParams(
10558
- ["q", "order", "offset"],
10559
- VARIANT_PREFIX
10560
- );
10561
- const { variants, count, isPending, isError, error } = useProductVariants(
10562
- {
10563
- q,
10564
- order,
10565
- offset: offset ? parseInt(offset) : void 0,
10566
- limit: LIMIT
10567
- },
10568
- {
10569
- placeholderData: keepPreviousData
10570
- }
10571
- );
10572
- const columns = useColumns();
10573
- const { mutateAsync } = useDraftOrderAddItems(orderId);
10574
- const onSubmit = async () => {
10575
- const ids = Object.keys(rowSelection).filter(
10576
- (id) => !items.find((i) => i.variant_id === id)
10577
- );
10578
- await mutateAsync(
10579
- {
10580
- items: ids.map((id) => ({
10581
- variant_id: id,
10582
- quantity: 1
10583
- }))
10584
- },
10585
- {
10586
- onSuccess: () => {
10587
- setRowSelection({});
10588
- setIsOpen(STACKED_MODAL_ID, false);
10589
- },
10590
- onError: (e) => {
10591
- toast.error(e.message);
10592
- }
10593
- }
10594
- );
10595
- };
10596
- if (isError) {
10597
- throw error;
10598
- }
10599
- return /* @__PURE__ */ jsxs(
10600
- StackedFocusModal.Content,
10601
- {
10602
- onOpenAutoFocus: (e) => {
10603
- e.preventDefault();
10604
- const searchInput = document.querySelector(
10605
- "[data-modal-id='modal-search-input']"
10606
- );
10607
- if (searchInput) {
10608
- searchInput.focus();
10609
- }
10610
- },
10611
- children: [
10612
- /* @__PURE__ */ jsxs(StackedFocusModal.Header, { children: [
10613
- /* @__PURE__ */ jsx(StackedFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Product Variants" }) }),
10614
- /* @__PURE__ */ jsx(StackedFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Choose product variants to add to the order." }) })
10615
- ] }),
10616
- /* @__PURE__ */ jsx(StackedFocusModal.Body, { className: "flex-1 overflow-hidden", children: /* @__PURE__ */ jsx(
10617
- DataTable,
10618
- {
10619
- data: variants,
10620
- columns,
10621
- isLoading: isPending,
10622
- getRowId: (row) => row.id,
10623
- rowCount: count,
10624
- prefix: VARIANT_PREFIX,
10625
- layout: "fill",
10626
- rowSelection: {
10627
- state: rowSelection,
10628
- onRowSelectionChange: setRowSelection,
10629
- enableRowSelection: (row) => {
10630
- return !items.find((i) => i.variant_id === row.original.id);
10631
- }
10632
- },
10633
- autoFocusSearch: true
10634
- }
10635
- ) }),
10636
- /* @__PURE__ */ jsx(StackedFocusModal.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
10637
- /* @__PURE__ */ jsx(StackedFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
10638
- /* @__PURE__ */ jsx(Button, { size: "small", type: "button", onClick: onSubmit, children: "Update items" })
10639
- ] }) })
10640
- ]
10641
- }
10642
- );
10643
- };
10644
- const columnHelper = createDataTableColumnHelper();
10645
- const useColumns = () => {
10646
- return useMemo(() => {
10647
- return [
10648
- columnHelper.select(),
10649
- columnHelper.accessor("product.title", {
10650
- header: "Product",
10651
- cell: ({ row }) => {
10652
- var _a, _b, _c;
10653
- return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-2", children: [
10654
- /* @__PURE__ */ jsx(
10655
- Thumbnail,
10656
- {
10657
- thumbnail: (_a = row.original.product) == null ? void 0 : _a.thumbnail,
10658
- alt: (_b = row.original.product) == null ? void 0 : _b.title
10659
- }
10660
- ),
10661
- /* @__PURE__ */ jsx("span", { children: (_c = row.original.product) == null ? void 0 : _c.title })
10662
- ] });
10663
- },
10664
- enableSorting: true
10665
- }),
10666
- columnHelper.accessor("title", {
10667
- header: "Variant",
10668
- enableSorting: true
10669
- }),
10670
- columnHelper.accessor("sku", {
10671
- header: "SKU",
10672
- cell: ({ getValue }) => {
10673
- return getValue() ?? "-";
10674
- },
10675
- enableSorting: true
10676
- }),
10677
- columnHelper.accessor("updated_at", {
10678
- header: "Updated",
10679
- cell: ({ getValue }) => {
10680
- return /* @__PURE__ */ jsx(
10681
- Tooltip,
10682
- {
10683
- content: getFullDate({ date: getValue(), includeTime: true }),
10684
- children: /* @__PURE__ */ jsx("span", { children: getFullDate({ date: getValue() }) })
10685
- }
10686
- );
10687
- },
10688
- enableSorting: true,
10689
- sortAscLabel: "Oldest first",
10690
- sortDescLabel: "Newest first"
10691
- }),
10692
- columnHelper.accessor("created_at", {
10693
- header: "Created",
10694
- cell: ({ getValue }) => {
10695
- return /* @__PURE__ */ jsx(
10696
- Tooltip,
10697
- {
10698
- content: getFullDate({ date: getValue(), includeTime: true }),
10699
- children: /* @__PURE__ */ jsx("span", { children: getFullDate({ date: getValue() }) })
10700
- }
10701
- );
10702
- },
10703
- enableSorting: true,
10704
- sortAscLabel: "Oldest first",
10705
- sortDescLabel: "Newest first"
10706
- })
10707
- ];
10708
- }, []);
10709
- };
10710
- const CustomItemForm = ({ orderId, currencyCode }) => {
10711
- const { setIsOpen } = useStackedModal();
10712
- const { mutateAsync: addItems } = useDraftOrderAddItems(orderId);
10734
+ const variantItemSchema = objectType({
10735
+ quantity: numberType(),
10736
+ unit_price: unionType([numberType(), stringType()])
10737
+ });
10738
+ const CustomItem = ({ item, preview, currencyCode }) => {
10739
+ const [editing, setEditing] = useState(false);
10740
+ const { quantity, unit_price, title } = item;
10713
10741
  const form = useForm({
10714
10742
  defaultValues: {
10715
- title: "",
10716
- quantity: 1,
10717
- unit_price: ""
10743
+ title,
10744
+ quantity,
10745
+ unit_price
10718
10746
  },
10719
10747
  resolver: zodResolver(customItemSchema)
10720
10748
  });
10749
+ useEffect(() => {
10750
+ form.reset({
10751
+ title,
10752
+ quantity,
10753
+ unit_price
10754
+ });
10755
+ }, [form, title, quantity, unit_price]);
10756
+ const actionId = useMemo(() => {
10757
+ var _a, _b;
10758
+ return (_b = (_a = item.actions) == null ? void 0 : _a.find((a) => a.action === "ITEM_ADD")) == null ? void 0 : _b.id;
10759
+ }, [item]);
10760
+ const { mutateAsync: updateActionItem, isPending: isUpdatingActionItem } = useDraftOrderUpdateActionItem(preview.id);
10761
+ const { mutateAsync: removeActionItem, isPending: isRemovingActionItem } = useDraftOrderRemoveActionItem(preview.id);
10762
+ const { mutateAsync: updateOriginalItem, isPending: isUpdatingOriginalItem } = useDraftOrderUpdateItem(preview.id);
10763
+ const isPending = isUpdatingActionItem || isUpdatingOriginalItem;
10721
10764
  const onSubmit = form.handleSubmit(async (data) => {
10722
- await addItems(
10723
- {
10724
- items: [
10725
- {
10726
- title: data.title,
10727
- quantity: data.quantity,
10728
- unit_price: convertNumber(data.unit_price)
10765
+ if (convertNumber(data.unit_price) === item.unit_price && data.quantity === item.quantity && data.title === item.title) {
10766
+ setEditing(false);
10767
+ return;
10768
+ }
10769
+ if (!actionId) {
10770
+ await updateOriginalItem(
10771
+ {
10772
+ item_id: item.id,
10773
+ quantity: data.quantity,
10774
+ unit_price: convertNumber(data.unit_price)
10775
+ },
10776
+ {
10777
+ onSuccess: () => {
10778
+ setEditing(false);
10779
+ },
10780
+ onError: (e) => {
10781
+ toast.error(e.message);
10729
10782
  }
10730
- ]
10783
+ }
10784
+ );
10785
+ return;
10786
+ }
10787
+ if (data.quantity === 0) {
10788
+ await removeActionItem(actionId, {
10789
+ onSuccess: () => {
10790
+ setEditing(false);
10791
+ },
10792
+ onError: (e) => {
10793
+ toast.error(e.message);
10794
+ }
10795
+ });
10796
+ return;
10797
+ }
10798
+ await updateActionItem(
10799
+ {
10800
+ action_id: actionId,
10801
+ quantity: data.quantity,
10802
+ unit_price: convertNumber(data.unit_price)
10731
10803
  },
10732
10804
  {
10733
10805
  onSuccess: () => {
10734
- setIsOpen(STACKED_MODAL_ID, false);
10806
+ setEditing(false);
10735
10807
  },
10736
10808
  onError: (e) => {
10737
10809
  toast.error(e.message);
@@ -10739,437 +10811,365 @@ const CustomItemForm = ({ orderId, currencyCode }) => {
10739
10811
  }
10740
10812
  );
10741
10813
  });
10742
- return /* @__PURE__ */ jsx(Form$2, { ...form, children: /* @__PURE__ */ jsx(KeyboundForm, { onSubmit, children: /* @__PURE__ */ jsxs(StackedFocusModal.Content, { children: [
10743
- /* @__PURE__ */ jsx(StackedFocusModal.Header, {}),
10744
- /* @__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: [
10745
- /* @__PURE__ */ jsxs("div", { children: [
10746
- /* @__PURE__ */ jsx(StackedFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Add custom item" }) }),
10747
- /* @__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." }) })
10748
- ] }),
10749
- /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
10814
+ return /* @__PURE__ */ jsx(Form$2, { ...form, children: /* @__PURE__ */ jsx("form", { onSubmit, children: /* @__PURE__ */ jsxs("div", { className: "bg-ui-bg-base shadow-elevation-card-rest grid grid-cols-[minmax(0,2fr)_minmax(0,1fr)_minmax(0,2fr)_28px] items-center gap-3 rounded-lg px-4 py-2", children: [
10815
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-3", children: [
10750
10816
  /* @__PURE__ */ jsx(
10751
- Form$2.Field,
10817
+ Thumbnail,
10752
10818
  {
10753
- control: form.control,
10754
- name: "title",
10755
- render: ({ field }) => /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
10756
- /* @__PURE__ */ jsxs("div", { children: [
10757
- /* @__PURE__ */ jsx(Form$2.Label, { children: "Title" }),
10758
- /* @__PURE__ */ jsx(Form$2.Hint, { children: "Enter the title of the item" })
10759
- ] }),
10760
- /* @__PURE__ */ jsxs("div", { children: [
10761
- /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(Input, { ...field }) }),
10762
- /* @__PURE__ */ jsx(Form$2.ErrorMessage, {})
10763
- ] })
10764
- ] }) })
10819
+ thumbnail: item.thumbnail,
10820
+ alt: item.title ?? void 0
10765
10821
  }
10766
10822
  ),
10767
- /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
10768
- /* @__PURE__ */ jsx(
10823
+ editing ? /* @__PURE__ */ jsx(
10769
10824
  Form$2.Field,
10770
10825
  {
10771
10826
  control: form.control,
10772
- name: "unit_price",
10773
- render: ({ field: { onChange, ...field } }) => /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
10774
- /* @__PURE__ */ jsxs("div", { children: [
10775
- /* @__PURE__ */ jsx(Form$2.Label, { children: "Unit price" }),
10776
- /* @__PURE__ */ jsx(Form$2.Hint, { children: "Enter the unit price of the item" })
10777
- ] }),
10778
- /* @__PURE__ */ jsxs("div", { children: [
10779
- /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
10780
- CurrencyInput,
10781
- {
10782
- symbol: getNativeSymbol(currencyCode),
10783
- code: currencyCode,
10784
- onValueChange: (_value, _name, values) => onChange(values == null ? void 0 : values.value),
10785
- ...field
10786
- }
10787
- ) }),
10788
- /* @__PURE__ */ jsx(Form$2.ErrorMessage, {})
10789
- ] })
10790
- ] }) })
10827
+ name: "title",
10828
+ render: ({ field }) => {
10829
+ return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(Input, { ...field }) }) });
10830
+ }
10791
10831
  }
10792
- ),
10793
- /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
10794
- /* @__PURE__ */ jsx(
10795
- Form$2.Field,
10796
- {
10797
- control: form.control,
10798
- name: "quantity",
10799
- render: ({ field }) => /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
10800
- /* @__PURE__ */ jsxs("div", { children: [
10801
- /* @__PURE__ */ jsx(Form$2.Label, { children: "Quantity" }),
10802
- /* @__PURE__ */ jsx(Form$2.Hint, { children: "Enter the quantity of the item" })
10803
- ] }),
10804
- /* @__PURE__ */ jsxs("div", { className: "w-full flex-1", children: [
10805
- /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx("div", { className: "w-full flex-1", children: /* @__PURE__ */ jsx(NumberInput, { ...field, className: "w-full" }) }) }),
10806
- /* @__PURE__ */ jsx(Form$2.ErrorMessage, {})
10807
- ] })
10808
- ] }) })
10832
+ ) : /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: item.title })
10833
+ ] }),
10834
+ editing ? /* @__PURE__ */ jsx(
10835
+ Form$2.Field,
10836
+ {
10837
+ control: form.control,
10838
+ name: "quantity",
10839
+ render: ({ field }) => {
10840
+ return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(NumberInput, { ...field }) }) });
10809
10841
  }
10810
- )
10811
- ] }) }) }),
10812
- /* @__PURE__ */ jsx(StackedFocusModal.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
10813
- /* @__PURE__ */ jsx(StackedFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
10814
- /* @__PURE__ */ jsx(Button, { size: "small", type: "button", onClick: onSubmit, children: "Add item" })
10815
- ] }) })
10816
- ] }) }) });
10817
- };
10818
- const customItemSchema = objectType({
10819
- title: stringType().min(1),
10820
- quantity: numberType(),
10821
- unit_price: unionType([numberType(), stringType()])
10822
- });
10823
- const InlineTip = forwardRef(
10824
- ({ variant = "tip", label, className, children, ...props }, ref) => {
10825
- const labelValue = label || (variant === "warning" ? "Warning" : "Tip");
10826
- return /* @__PURE__ */ jsxs(
10827
- "div",
10842
+ }
10843
+ ) : /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: item.quantity }),
10844
+ editing ? /* @__PURE__ */ jsx(
10845
+ Form$2.Field,
10828
10846
  {
10829
- ref,
10830
- className: clx(
10831
- "bg-ui-bg-component txt-small text-ui-fg-subtle grid grid-cols-[4px_1fr] items-start gap-3 rounded-lg border p-3",
10832
- className
10833
- ),
10834
- ...props,
10835
- children: [
10836
- /* @__PURE__ */ jsx(
10837
- "div",
10847
+ control: form.control,
10848
+ name: "unit_price",
10849
+ render: ({ field: { onChange, ...field } }) => {
10850
+ return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
10851
+ CurrencyInput,
10838
10852
  {
10839
- role: "presentation",
10840
- className: clx("w-4px bg-ui-tag-neutral-icon h-full rounded-full", {
10841
- "bg-ui-tag-orange-icon": variant === "warning"
10842
- })
10853
+ ...field,
10854
+ symbol: getNativeSymbol(currencyCode),
10855
+ code: currencyCode,
10856
+ onValueChange: (_value, _name, values) => onChange(values == null ? void 0 : values.value)
10843
10857
  }
10844
- ),
10845
- /* @__PURE__ */ jsxs("div", { className: "text-pretty", children: [
10846
- /* @__PURE__ */ jsxs("strong", { className: "txt-small-plus text-ui-fg-base", children: [
10847
- labelValue,
10848
- ":"
10849
- ] }),
10850
- " ",
10851
- children
10852
- ] })
10853
- ]
10858
+ ) }) });
10859
+ }
10854
10860
  }
10855
- );
10856
- }
10857
- );
10858
- InlineTip.displayName = "InlineTip";
10859
- const MetadataFieldSchema = objectType({
10860
- key: stringType(),
10861
- disabled: booleanType().optional(),
10862
- value: anyType()
10863
- });
10864
- const MetadataSchema = objectType({
10865
- metadata: arrayType(MetadataFieldSchema)
10866
- });
10867
- const Metadata = () => {
10868
- const { id } = useParams();
10869
- const { order, isPending, isError, error } = useOrder(id, {
10870
- fields: "metadata"
10871
- });
10872
- if (isError) {
10873
- throw error;
10874
- }
10875
- const isReady = !isPending && !!order;
10876
- return /* @__PURE__ */ jsxs(RouteDrawer, { children: [
10877
- /* @__PURE__ */ jsxs(RouteDrawer.Header, { children: [
10878
- /* @__PURE__ */ jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Metadata" }) }),
10879
- /* @__PURE__ */ jsx(RouteDrawer.Description, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Add metadata to the draft order." }) })
10880
- ] }),
10881
- !isReady ? /* @__PURE__ */ jsx(PlaceholderInner, {}) : /* @__PURE__ */ jsx(MetadataForm, { orderId: id, metadata: order == null ? void 0 : order.metadata })
10882
- ] });
10861
+ ) : /* @__PURE__ */ jsx("div", { className: "flex flex-1 items-center justify-end", children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: getLocaleAmount(item.unit_price, currencyCode) }) }),
10862
+ /* @__PURE__ */ jsx(
10863
+ IconButton,
10864
+ {
10865
+ type: "button",
10866
+ size: "small",
10867
+ onClick: editing ? onSubmit : () => {
10868
+ setEditing(true);
10869
+ },
10870
+ disabled: isPending,
10871
+ children: editing ? /* @__PURE__ */ jsx(Check, {}) : /* @__PURE__ */ jsx(PencilSquare, {})
10872
+ }
10873
+ )
10874
+ ] }) }) });
10883
10875
  };
10884
- const METADATA_KEY_LABEL_ID = "metadata-form-key-label";
10885
- const METADATA_VALUE_LABEL_ID = "metadata-form-value-label";
10886
- const MetadataForm = ({ orderId, metadata }) => {
10887
- const { handleSuccess } = useRouteModal();
10888
- const hasUneditableRows = getHasUneditableRows(metadata);
10889
- const { mutateAsync, isPending } = useUpdateDraftOrder(orderId);
10890
- const form = useForm({
10891
- defaultValues: {
10892
- metadata: getDefaultValues(metadata)
10876
+ const StackedModalTrigger$1 = ({
10877
+ type,
10878
+ setModalContent
10879
+ }) => {
10880
+ const { setIsOpen } = useStackedModal();
10881
+ const onClick = useCallback(() => {
10882
+ setModalContent(type);
10883
+ setIsOpen(STACKED_MODAL_ID, true);
10884
+ }, [setModalContent, setIsOpen, type]);
10885
+ return /* @__PURE__ */ jsx(StackedFocusModal.Trigger, { asChild: true, children: /* @__PURE__ */ jsx(DropdownMenu.Item, { onClick, children: type === "add-items" ? "Add items" : "Add custom item" }) });
10886
+ };
10887
+ const VARIANT_PREFIX = "items";
10888
+ const LIMIT = 50;
10889
+ const ExistingItemsForm = ({ orderId, items }) => {
10890
+ const { setIsOpen } = useStackedModal();
10891
+ const [rowSelection, setRowSelection] = useState(
10892
+ items.reduce((acc, item) => {
10893
+ acc[item.variant_id] = true;
10894
+ return acc;
10895
+ }, {})
10896
+ );
10897
+ useEffect(() => {
10898
+ setRowSelection(
10899
+ items.reduce((acc, item) => {
10900
+ if (item.variant_id) {
10901
+ acc[item.variant_id] = true;
10902
+ }
10903
+ return acc;
10904
+ }, {})
10905
+ );
10906
+ }, [items]);
10907
+ const { q, order, offset } = useQueryParams(
10908
+ ["q", "order", "offset"],
10909
+ VARIANT_PREFIX
10910
+ );
10911
+ const { variants, count, isPending, isError, error } = useProductVariants(
10912
+ {
10913
+ q,
10914
+ order,
10915
+ offset: offset ? parseInt(offset) : void 0,
10916
+ limit: LIMIT
10893
10917
  },
10894
- resolver: zodResolver(MetadataSchema)
10895
- });
10896
- const handleSubmit = form.handleSubmit(async (data) => {
10897
- const parsedData = parseValues(data);
10918
+ {
10919
+ placeholderData: keepPreviousData
10920
+ }
10921
+ );
10922
+ const columns = useColumns();
10923
+ const { mutateAsync } = useDraftOrderAddItems(orderId);
10924
+ const onSubmit = async () => {
10925
+ const ids = Object.keys(rowSelection).filter(
10926
+ (id) => !items.find((i) => i.variant_id === id)
10927
+ );
10898
10928
  await mutateAsync(
10899
10929
  {
10900
- metadata: parsedData
10930
+ items: ids.map((id) => ({
10931
+ variant_id: id,
10932
+ quantity: 1
10933
+ }))
10901
10934
  },
10902
10935
  {
10903
10936
  onSuccess: () => {
10904
- toast.success("Metadata updated");
10905
- handleSuccess();
10937
+ setRowSelection({});
10938
+ setIsOpen(STACKED_MODAL_ID, false);
10906
10939
  },
10907
- onError: (error) => {
10908
- toast.error(error.message);
10940
+ onError: (e) => {
10941
+ toast.error(e.message);
10909
10942
  }
10910
10943
  }
10911
10944
  );
10912
- });
10913
- const { fields, insert, remove } = useFieldArray({
10914
- control: form.control,
10915
- name: "metadata"
10916
- });
10917
- function deleteRow(index) {
10918
- remove(index);
10919
- if (fields.length === 1) {
10920
- insert(0, {
10921
- key: "",
10922
- value: "",
10923
- disabled: false
10924
- });
10925
- }
10926
- }
10927
- function insertRow(index, position) {
10928
- insert(index + (position === "above" ? 0 : 1), {
10929
- key: "",
10930
- value: "",
10931
- disabled: false
10932
- });
10945
+ };
10946
+ if (isError) {
10947
+ throw error;
10933
10948
  }
10934
- return /* @__PURE__ */ jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxs(
10935
- KeyboundForm,
10949
+ return /* @__PURE__ */ jsxs(
10950
+ StackedFocusModal.Content,
10936
10951
  {
10937
- onSubmit: handleSubmit,
10938
- className: "flex flex-1 flex-col overflow-hidden",
10952
+ onOpenAutoFocus: (e) => {
10953
+ e.preventDefault();
10954
+ const searchInput = document.querySelector(
10955
+ "[data-modal-id='modal-search-input']"
10956
+ );
10957
+ if (searchInput) {
10958
+ searchInput.focus();
10959
+ }
10960
+ },
10939
10961
  children: [
10940
- /* @__PURE__ */ jsxs(RouteDrawer.Body, { className: "flex flex-1 flex-col gap-y-8 overflow-y-auto", children: [
10941
- /* @__PURE__ */ jsxs("div", { className: "bg-ui-bg-base shadow-elevation-card-rest grid grid-cols-1 divide-y rounded-lg", children: [
10942
- /* @__PURE__ */ jsxs("div", { className: "bg-ui-bg-subtle grid grid-cols-2 divide-x rounded-t-lg", children: [
10943
- /* @__PURE__ */ jsx("div", { className: "txt-compact-small-plus text-ui-fg-subtle px-2 py-1.5", children: /* @__PURE__ */ jsx("label", { id: METADATA_KEY_LABEL_ID, children: "Key" }) }),
10944
- /* @__PURE__ */ jsx("div", { className: "txt-compact-small-plus text-ui-fg-subtle px-2 py-1.5", children: /* @__PURE__ */ jsx("label", { id: METADATA_VALUE_LABEL_ID, children: "Value" }) })
10945
- ] }),
10946
- fields.map((field, index) => {
10947
- const isDisabled = field.disabled || false;
10948
- let placeholder = "-";
10949
- if (typeof field.value === "object") {
10950
- placeholder = "{ ... }";
10951
- }
10952
- if (Array.isArray(field.value)) {
10953
- placeholder = "[ ... ]";
10954
- }
10955
- return /* @__PURE__ */ jsx(
10956
- ConditionalTooltip,
10957
- {
10958
- showTooltip: isDisabled,
10959
- content: "This row is disabled because it contains non-primitive data.",
10960
- children: /* @__PURE__ */ jsxs("div", { className: "group/table relative", children: [
10961
- /* @__PURE__ */ jsxs(
10962
- "div",
10963
- {
10964
- className: clx("grid grid-cols-2 divide-x", {
10965
- "overflow-hidden rounded-b-lg": index === fields.length - 1
10966
- }),
10967
- children: [
10968
- /* @__PURE__ */ jsx(
10969
- Form$2.Field,
10970
- {
10971
- control: form.control,
10972
- name: `metadata.${index}.key`,
10973
- render: ({ field: field2 }) => {
10974
- return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
10975
- GridInput,
10976
- {
10977
- "aria-labelledby": METADATA_KEY_LABEL_ID,
10978
- ...field2,
10979
- disabled: isDisabled,
10980
- placeholder: "Key"
10981
- }
10982
- ) }) });
10983
- }
10984
- }
10985
- ),
10986
- /* @__PURE__ */ jsx(
10987
- Form$2.Field,
10988
- {
10989
- control: form.control,
10990
- name: `metadata.${index}.value`,
10991
- render: ({ field: { value, ...field2 } }) => {
10992
- return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
10993
- GridInput,
10994
- {
10995
- "aria-labelledby": METADATA_VALUE_LABEL_ID,
10996
- ...field2,
10997
- value: isDisabled ? placeholder : value,
10998
- disabled: isDisabled,
10999
- placeholder: "Value"
11000
- }
11001
- ) }) });
11002
- }
11003
- }
11004
- )
11005
- ]
11006
- }
11007
- ),
11008
- /* @__PURE__ */ jsxs(DropdownMenu, { children: [
11009
- /* @__PURE__ */ jsx(
11010
- DropdownMenu.Trigger,
11011
- {
11012
- className: clx(
11013
- "invisible absolute inset-y-0 -right-2.5 my-auto group-hover/table:visible data-[state='open']:visible",
11014
- {
11015
- hidden: isDisabled
11016
- }
11017
- ),
11018
- disabled: isDisabled,
11019
- asChild: true,
11020
- children: /* @__PURE__ */ jsx(IconButton, { size: "2xsmall", children: /* @__PURE__ */ jsx(EllipsisVertical, {}) })
11021
- }
11022
- ),
11023
- /* @__PURE__ */ jsxs(DropdownMenu.Content, { children: [
11024
- /* @__PURE__ */ jsxs(
11025
- DropdownMenu.Item,
11026
- {
11027
- className: "gap-x-2",
11028
- onClick: () => insertRow(index, "above"),
11029
- children: [
11030
- /* @__PURE__ */ jsx(ArrowUpMini, { className: "text-ui-fg-subtle" }),
11031
- "Insert row above"
11032
- ]
11033
- }
11034
- ),
11035
- /* @__PURE__ */ jsxs(
11036
- DropdownMenu.Item,
11037
- {
11038
- className: "gap-x-2",
11039
- onClick: () => insertRow(index, "below"),
11040
- children: [
11041
- /* @__PURE__ */ jsx(ArrowDownMini, { className: "text-ui-fg-subtle" }),
11042
- "Insert row below"
11043
- ]
11044
- }
11045
- ),
11046
- /* @__PURE__ */ jsx(DropdownMenu.Separator, {}),
11047
- /* @__PURE__ */ jsxs(
11048
- DropdownMenu.Item,
11049
- {
11050
- className: "gap-x-2",
11051
- onClick: () => deleteRow(index),
11052
- children: [
11053
- /* @__PURE__ */ jsx(Trash, { className: "text-ui-fg-subtle" }),
11054
- "Delete row"
11055
- ]
11056
- }
11057
- )
11058
- ] })
11059
- ] })
11060
- ] })
11061
- },
11062
- field.id
11063
- );
11064
- })
11065
- ] }),
11066
- hasUneditableRows && /* @__PURE__ */ jsx(InlineTip, { variant: "warning", label: "Some rows are disabled", children: "This object contains non-primitive metadata, such as arrays or objects, that can't be edited here. To edit the disabled rows, use the API directly." })
10962
+ /* @__PURE__ */ jsxs(StackedFocusModal.Header, { children: [
10963
+ /* @__PURE__ */ jsx(StackedFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Product Variants" }) }),
10964
+ /* @__PURE__ */ jsx(StackedFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Choose product variants to add to the order." }) })
11067
10965
  ] }),
11068
- /* @__PURE__ */ jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
11069
- /* @__PURE__ */ jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
11070
- /* @__PURE__ */ jsx(Button, { size: "small", type: "submit", isLoading: isPending, children: "Save" })
10966
+ /* @__PURE__ */ jsx(StackedFocusModal.Body, { className: "flex-1 overflow-hidden", children: /* @__PURE__ */ jsx(
10967
+ DataTable,
10968
+ {
10969
+ data: variants,
10970
+ columns,
10971
+ isLoading: isPending,
10972
+ getRowId: (row) => row.id,
10973
+ rowCount: count,
10974
+ prefix: VARIANT_PREFIX,
10975
+ layout: "fill",
10976
+ rowSelection: {
10977
+ state: rowSelection,
10978
+ onRowSelectionChange: setRowSelection,
10979
+ enableRowSelection: (row) => {
10980
+ return !items.find((i) => i.variant_id === row.original.id);
10981
+ }
10982
+ },
10983
+ autoFocusSearch: true
10984
+ }
10985
+ ) }),
10986
+ /* @__PURE__ */ jsx(StackedFocusModal.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
10987
+ /* @__PURE__ */ jsx(StackedFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
10988
+ /* @__PURE__ */ jsx(Button, { size: "small", type: "button", onClick: onSubmit, children: "Update items" })
11071
10989
  ] }) })
11072
10990
  ]
11073
- }
11074
- ) });
11075
- };
11076
- const GridInput = forwardRef(({ className, ...props }, ref) => {
11077
- return /* @__PURE__ */ jsx(
11078
- "input",
11079
- {
11080
- ref,
11081
- ...props,
11082
- autoComplete: "off",
11083
- className: clx(
11084
- "txt-compact-small text-ui-fg-base placeholder:text-ui-fg-muted disabled:text-ui-fg-disabled disabled:bg-ui-bg-base bg-transparent px-2 py-1.5 outline-none",
11085
- className
11086
- )
11087
- }
11088
- );
11089
- });
11090
- GridInput.displayName = "MetadataForm.GridInput";
11091
- const PlaceholderInner = () => {
11092
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col overflow-hidden", children: [
11093
- /* @__PURE__ */ jsx(RouteDrawer.Body, { children: /* @__PURE__ */ jsx(Skeleton, { className: "h-[148ox] w-full rounded-lg" }) }),
11094
- /* @__PURE__ */ jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
11095
- /* @__PURE__ */ jsx(Skeleton, { className: "h-7 w-12 rounded-md" }),
11096
- /* @__PURE__ */ jsx(Skeleton, { className: "h-7 w-12 rounded-md" })
11097
- ] }) })
11098
- ] });
10991
+ }
10992
+ );
11099
10993
  };
11100
- const EDITABLE_TYPES = ["string", "number", "boolean"];
11101
- function getDefaultValues(metadata) {
11102
- if (!metadata || !Object.keys(metadata).length) {
10994
+ const columnHelper = createDataTableColumnHelper();
10995
+ const useColumns = () => {
10996
+ return useMemo(() => {
11103
10997
  return [
11104
- {
11105
- key: "",
11106
- value: "",
11107
- disabled: false
11108
- }
10998
+ columnHelper.select(),
10999
+ columnHelper.accessor("product.title", {
11000
+ header: "Product",
11001
+ cell: ({ row }) => {
11002
+ var _a, _b, _c;
11003
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-2", children: [
11004
+ /* @__PURE__ */ jsx(
11005
+ Thumbnail,
11006
+ {
11007
+ thumbnail: (_a = row.original.product) == null ? void 0 : _a.thumbnail,
11008
+ alt: (_b = row.original.product) == null ? void 0 : _b.title
11009
+ }
11010
+ ),
11011
+ /* @__PURE__ */ jsx("span", { children: (_c = row.original.product) == null ? void 0 : _c.title })
11012
+ ] });
11013
+ },
11014
+ enableSorting: true
11015
+ }),
11016
+ columnHelper.accessor("title", {
11017
+ header: "Variant",
11018
+ enableSorting: true
11019
+ }),
11020
+ columnHelper.accessor("sku", {
11021
+ header: "SKU",
11022
+ cell: ({ getValue }) => {
11023
+ return getValue() ?? "-";
11024
+ },
11025
+ enableSorting: true
11026
+ }),
11027
+ columnHelper.accessor("updated_at", {
11028
+ header: "Updated",
11029
+ cell: ({ getValue }) => {
11030
+ return /* @__PURE__ */ jsx(
11031
+ Tooltip,
11032
+ {
11033
+ content: getFullDate({ date: getValue(), includeTime: true }),
11034
+ children: /* @__PURE__ */ jsx("span", { children: getFullDate({ date: getValue() }) })
11035
+ }
11036
+ );
11037
+ },
11038
+ enableSorting: true,
11039
+ sortAscLabel: "Oldest first",
11040
+ sortDescLabel: "Newest first"
11041
+ }),
11042
+ columnHelper.accessor("created_at", {
11043
+ header: "Created",
11044
+ cell: ({ getValue }) => {
11045
+ return /* @__PURE__ */ jsx(
11046
+ Tooltip,
11047
+ {
11048
+ content: getFullDate({ date: getValue(), includeTime: true }),
11049
+ children: /* @__PURE__ */ jsx("span", { children: getFullDate({ date: getValue() }) })
11050
+ }
11051
+ );
11052
+ },
11053
+ enableSorting: true,
11054
+ sortAscLabel: "Oldest first",
11055
+ sortDescLabel: "Newest first"
11056
+ })
11109
11057
  ];
11110
- }
11111
- return Object.entries(metadata).map(([key, value]) => {
11112
- if (!EDITABLE_TYPES.includes(typeof value)) {
11113
- return {
11114
- key,
11115
- value,
11116
- disabled: true
11117
- };
11118
- }
11119
- let stringValue = value;
11120
- if (typeof value !== "string") {
11121
- stringValue = JSON.stringify(value);
11122
- }
11123
- return {
11124
- key,
11125
- value: stringValue,
11126
- original_key: key
11127
- };
11058
+ }, []);
11059
+ };
11060
+ const CustomItemForm = ({ orderId, currencyCode }) => {
11061
+ const { setIsOpen } = useStackedModal();
11062
+ const { mutateAsync: addItems } = useDraftOrderAddItems(orderId);
11063
+ const form = useForm({
11064
+ defaultValues: {
11065
+ title: "",
11066
+ quantity: 1,
11067
+ unit_price: ""
11068
+ },
11069
+ resolver: zodResolver(customItemSchema)
11128
11070
  });
11129
- }
11130
- function parseValues(values) {
11131
- const metadata = values.metadata;
11132
- const isEmpty = !metadata.length || metadata.length === 1 && !metadata[0].key && !metadata[0].value;
11133
- if (isEmpty) {
11134
- return null;
11135
- }
11136
- const update = {};
11137
- metadata.forEach((field) => {
11138
- let key = field.key;
11139
- let value = field.value;
11140
- const disabled = field.disabled;
11141
- if (!key || !value) {
11142
- return;
11143
- }
11144
- if (disabled) {
11145
- update[key] = value;
11146
- return;
11147
- }
11148
- key = key.trim();
11149
- value = value.trim();
11150
- if (value === "true") {
11151
- update[key] = true;
11152
- } else if (value === "false") {
11153
- update[key] = false;
11154
- } else {
11155
- const parsedNumber = parseFloat(value);
11156
- if (!isNaN(parsedNumber)) {
11157
- update[key] = parsedNumber;
11158
- } else {
11159
- update[key] = value;
11071
+ const onSubmit = form.handleSubmit(async (data) => {
11072
+ await addItems(
11073
+ {
11074
+ items: [
11075
+ {
11076
+ title: data.title,
11077
+ quantity: data.quantity,
11078
+ unit_price: convertNumber(data.unit_price)
11079
+ }
11080
+ ]
11081
+ },
11082
+ {
11083
+ onSuccess: () => {
11084
+ setIsOpen(STACKED_MODAL_ID, false);
11085
+ },
11086
+ onError: (e) => {
11087
+ toast.error(e.message);
11088
+ }
11160
11089
  }
11161
- }
11090
+ );
11162
11091
  });
11163
- return update;
11164
- }
11165
- function getHasUneditableRows(metadata) {
11166
- if (!metadata) {
11167
- return false;
11168
- }
11169
- return Object.values(metadata).some(
11170
- (value) => !EDITABLE_TYPES.includes(typeof value)
11171
- );
11172
- }
11092
+ return /* @__PURE__ */ jsx(Form$2, { ...form, children: /* @__PURE__ */ jsx(KeyboundForm, { onSubmit, children: /* @__PURE__ */ jsxs(StackedFocusModal.Content, { children: [
11093
+ /* @__PURE__ */ jsx(StackedFocusModal.Header, {}),
11094
+ /* @__PURE__ */ jsx(StackedFocusModal.Body, { className: "flex flex-1 flex-col overflow-hidden", children: /* @__PURE__ */ jsx("div", { className: "flex flex-1 flex-col items-center overflow-y-auto", children: /* @__PURE__ */ jsxs("div", { className: "flex w-full max-w-[720px] flex-col gap-y-6 px-2 py-16", children: [
11095
+ /* @__PURE__ */ jsxs("div", { children: [
11096
+ /* @__PURE__ */ jsx(StackedFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Add custom item" }) }),
11097
+ /* @__PURE__ */ jsx(StackedFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Add a custom item to the order. This will add a new line item that is not associated with an existing product." }) })
11098
+ ] }),
11099
+ /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
11100
+ /* @__PURE__ */ jsx(
11101
+ Form$2.Field,
11102
+ {
11103
+ control: form.control,
11104
+ name: "title",
11105
+ render: ({ field }) => /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
11106
+ /* @__PURE__ */ jsxs("div", { children: [
11107
+ /* @__PURE__ */ jsx(Form$2.Label, { children: "Title" }),
11108
+ /* @__PURE__ */ jsx(Form$2.Hint, { children: "Enter the title of the item" })
11109
+ ] }),
11110
+ /* @__PURE__ */ jsxs("div", { children: [
11111
+ /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(Input, { ...field }) }),
11112
+ /* @__PURE__ */ jsx(Form$2.ErrorMessage, {})
11113
+ ] })
11114
+ ] }) })
11115
+ }
11116
+ ),
11117
+ /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
11118
+ /* @__PURE__ */ jsx(
11119
+ Form$2.Field,
11120
+ {
11121
+ control: form.control,
11122
+ name: "unit_price",
11123
+ render: ({ field: { onChange, ...field } }) => /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
11124
+ /* @__PURE__ */ jsxs("div", { children: [
11125
+ /* @__PURE__ */ jsx(Form$2.Label, { children: "Unit price" }),
11126
+ /* @__PURE__ */ jsx(Form$2.Hint, { children: "Enter the unit price of the item" })
11127
+ ] }),
11128
+ /* @__PURE__ */ jsxs("div", { children: [
11129
+ /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
11130
+ CurrencyInput,
11131
+ {
11132
+ symbol: getNativeSymbol(currencyCode),
11133
+ code: currencyCode,
11134
+ onValueChange: (_value, _name, values) => onChange(values == null ? void 0 : values.value),
11135
+ ...field
11136
+ }
11137
+ ) }),
11138
+ /* @__PURE__ */ jsx(Form$2.ErrorMessage, {})
11139
+ ] })
11140
+ ] }) })
11141
+ }
11142
+ ),
11143
+ /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
11144
+ /* @__PURE__ */ jsx(
11145
+ Form$2.Field,
11146
+ {
11147
+ control: form.control,
11148
+ name: "quantity",
11149
+ render: ({ field }) => /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
11150
+ /* @__PURE__ */ jsxs("div", { children: [
11151
+ /* @__PURE__ */ jsx(Form$2.Label, { children: "Quantity" }),
11152
+ /* @__PURE__ */ jsx(Form$2.Hint, { children: "Enter the quantity of the item" })
11153
+ ] }),
11154
+ /* @__PURE__ */ jsxs("div", { className: "w-full flex-1", children: [
11155
+ /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx("div", { className: "w-full flex-1", children: /* @__PURE__ */ jsx(NumberInput, { ...field, className: "w-full" }) }) }),
11156
+ /* @__PURE__ */ jsx(Form$2.ErrorMessage, {})
11157
+ ] })
11158
+ ] }) })
11159
+ }
11160
+ )
11161
+ ] }) }) }),
11162
+ /* @__PURE__ */ jsx(StackedFocusModal.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
11163
+ /* @__PURE__ */ jsx(StackedFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
11164
+ /* @__PURE__ */ jsx(Button, { size: "small", type: "button", onClick: onSubmit, children: "Add item" })
11165
+ ] }) })
11166
+ ] }) }) });
11167
+ };
11168
+ const customItemSchema = objectType({
11169
+ title: stringType().min(1),
11170
+ quantity: numberType(),
11171
+ unit_price: unionType([numberType(), stringType()])
11172
+ });
11173
11173
  const PROMOTION_QUERY_KEY = "promotions";
11174
11174
  const promotionsQueryKeys = {
11175
11175
  list: (query2) => [
@@ -13059,10 +13059,6 @@ const routeModule = {
13059
13059
  handle,
13060
13060
  loader,
13061
13061
  children: [
13062
- {
13063
- Component: BillingAddress,
13064
- path: "/draft-orders/:id/billing-address"
13065
- },
13066
13062
  {
13067
13063
  Component: CustomItems,
13068
13064
  path: "/draft-orders/:id/custom-items"
@@ -13072,13 +13068,17 @@ const routeModule = {
13072
13068
  path: "/draft-orders/:id/email"
13073
13069
  },
13074
13070
  {
13075
- Component: Items,
13076
- path: "/draft-orders/:id/items"
13071
+ Component: BillingAddress,
13072
+ path: "/draft-orders/:id/billing-address"
13077
13073
  },
13078
13074
  {
13079
13075
  Component: Metadata,
13080
13076
  path: "/draft-orders/:id/metadata"
13081
13077
  },
13078
+ {
13079
+ Component: Items,
13080
+ path: "/draft-orders/:id/items"
13081
+ },
13082
13082
  {
13083
13083
  Component: Promotions,
13084
13084
  path: "/draft-orders/:id/promotions"