@medusajs/draft-order 2.11.4-preview-20251122000259 → 2.11.4-preview-20251122060134

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