@medusajs/draft-order 2.11.4-snapshot-20251106121614 → 2.11.4-snapshot-20251106130942

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