@medusajs/draft-order 2.10.0-snapshot-20250828112236 → 2.10.0-snapshot-20250828112445

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.
@@ -9771,243 +9771,593 @@ const CustomItemsForm = () => {
9771
9771
  const schema$4 = objectType({
9772
9772
  email: stringType().email()
9773
9773
  });
9774
- const NumberInput = React.forwardRef(
9775
- ({
9776
- value,
9777
- onChange,
9778
- size = "base",
9779
- min = 0,
9780
- max = 100,
9781
- step = 1,
9782
- className,
9783
- disabled,
9784
- ...props
9785
- }, ref) => {
9786
- const handleChange = (event) => {
9787
- const newValue = event.target.value === "" ? min : Number(event.target.value);
9788
- if (!isNaN(newValue) && (max === void 0 || newValue <= max) && (min === void 0 || newValue >= min)) {
9789
- onChange(newValue);
9790
- }
9791
- };
9792
- const handleIncrement = () => {
9793
- const newValue = value + step;
9794
- if (max === void 0 || newValue <= max) {
9795
- onChange(newValue);
9796
- }
9797
- };
9798
- const handleDecrement = () => {
9799
- const newValue = value - step;
9800
- if (min === void 0 || newValue >= min) {
9801
- onChange(newValue);
9802
- }
9803
- };
9774
+ const InlineTip = React.forwardRef(
9775
+ ({ variant = "tip", label, className, children, ...props }, ref) => {
9776
+ const labelValue = label || (variant === "warning" ? "Warning" : "Tip");
9804
9777
  return /* @__PURE__ */ jsxRuntime.jsxs(
9805
9778
  "div",
9806
9779
  {
9780
+ ref,
9807
9781
  className: ui.clx(
9808
- "inline-flex rounded-md bg-ui-bg-field shadow-borders-base overflow-hidden divide-x transition-fg",
9809
- "[&:has(input:focus)]:shadow-borders-interactive-with-active",
9810
- {
9811
- "h-7": size === "small",
9812
- "h-8": size === "base"
9813
- },
9782
+ "bg-ui-bg-component txt-small text-ui-fg-subtle grid grid-cols-[4px_1fr] items-start gap-3 rounded-lg border p-3",
9814
9783
  className
9815
9784
  ),
9785
+ ...props,
9816
9786
  children: [
9817
9787
  /* @__PURE__ */ jsxRuntime.jsx(
9818
- "input",
9819
- {
9820
- ref,
9821
- type: "number",
9822
- value,
9823
- onChange: handleChange,
9824
- min,
9825
- max,
9826
- step,
9827
- className: ui.clx(
9828
- "flex-1 px-2 py-1 bg-transparent txt-compact-small text-ui-fg-base outline-none [appearance:textfield]",
9829
- "[&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none",
9830
- "placeholder:text-ui-fg-muted"
9831
- ),
9832
- ...props
9833
- }
9834
- ),
9835
- /* @__PURE__ */ jsxRuntime.jsxs(
9836
- "button",
9788
+ "div",
9837
9789
  {
9838
- className: ui.clx(
9839
- "flex items-center justify-center outline-none transition-fg",
9840
- "disabled:cursor-not-allowed disabled:text-ui-fg-muted",
9841
- "focus:bg-ui-bg-field-component-hover",
9842
- "hover:bg-ui-bg-field-component-hover",
9843
- {
9844
- "size-7": size === "small",
9845
- "size-8": size === "base"
9846
- }
9847
- ),
9848
- type: "button",
9849
- onClick: handleDecrement,
9850
- disabled: min !== void 0 && value <= min || disabled,
9851
- children: [
9852
- /* @__PURE__ */ jsxRuntime.jsx(icons.Minus, {}),
9853
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: `Decrease by ${step}` })
9854
- ]
9790
+ role: "presentation",
9791
+ className: ui.clx("w-4px bg-ui-tag-neutral-icon h-full rounded-full", {
9792
+ "bg-ui-tag-orange-icon": variant === "warning"
9793
+ })
9855
9794
  }
9856
9795
  ),
9857
- /* @__PURE__ */ jsxRuntime.jsxs(
9858
- "button",
9859
- {
9860
- className: ui.clx(
9861
- "flex items-center justify-center outline-none transition-fg",
9862
- "disabled:cursor-not-allowed disabled:text-ui-fg-muted",
9863
- "focus:bg-ui-bg-field-hover",
9864
- "hover:bg-ui-bg-field-hover",
9865
- {
9866
- "size-7": size === "small",
9867
- "size-8": size === "base"
9868
- }
9869
- ),
9870
- type: "button",
9871
- onClick: handleIncrement,
9872
- disabled: max !== void 0 && value >= max || disabled,
9873
- children: [
9874
- /* @__PURE__ */ jsxRuntime.jsx(icons.Plus, {}),
9875
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: `Increase by ${step}` })
9876
- ]
9877
- }
9878
- )
9796
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-pretty", children: [
9797
+ /* @__PURE__ */ jsxRuntime.jsxs("strong", { className: "txt-small-plus text-ui-fg-base", children: [
9798
+ labelValue,
9799
+ ":"
9800
+ ] }),
9801
+ " ",
9802
+ children
9803
+ ] })
9879
9804
  ]
9880
9805
  }
9881
9806
  );
9882
9807
  }
9883
9808
  );
9884
- const PRODUCT_VARIANTS_QUERY_KEY = "product-variants";
9885
- const productVariantsQueryKeys = {
9886
- list: (query2) => [
9887
- PRODUCT_VARIANTS_QUERY_KEY,
9888
- query2 ? query2 : void 0
9889
- ]
9890
- };
9891
- const useProductVariants = (query2, options) => {
9892
- const { data, ...rest } = reactQuery.useQuery({
9893
- queryKey: productVariantsQueryKeys.list(query2),
9894
- queryFn: async () => await sdk.admin.productVariant.list(query2),
9895
- ...options
9896
- });
9897
- return { ...data, ...rest };
9898
- };
9899
- const useCancelOrderEdit = ({ preview }) => {
9900
- const { mutateAsync: cancelOrderEdit } = useDraftOrderCancelEdit(preview == null ? void 0 : preview.id);
9901
- const onCancel = React.useCallback(async () => {
9902
- if (!preview) {
9903
- return true;
9904
- }
9905
- let res = false;
9906
- await cancelOrderEdit(void 0, {
9907
- onError: (e) => {
9908
- ui.toast.error(e.message);
9909
- },
9910
- onSuccess: () => {
9911
- res = true;
9912
- }
9913
- });
9914
- return res;
9915
- }, [preview, cancelOrderEdit]);
9916
- return { onCancel };
9917
- };
9918
- let IS_REQUEST_RUNNING = false;
9919
- const useInitiateOrderEdit = ({
9920
- preview
9921
- }) => {
9922
- const navigate = reactRouterDom.useNavigate();
9923
- const { mutateAsync } = useDraftOrderBeginEdit(preview == null ? void 0 : preview.id);
9924
- React.useEffect(() => {
9925
- async function run() {
9926
- if (IS_REQUEST_RUNNING || !preview) {
9927
- return;
9928
- }
9929
- if (preview.order_change) {
9930
- return;
9931
- }
9932
- IS_REQUEST_RUNNING = true;
9933
- await mutateAsync(void 0, {
9934
- onError: (e) => {
9935
- ui.toast.error(e.message);
9936
- navigate(`/draft-orders/${preview.id}`, { replace: true });
9937
- return;
9938
- }
9939
- });
9940
- IS_REQUEST_RUNNING = false;
9941
- }
9942
- run();
9943
- }, [preview, navigate, mutateAsync]);
9944
- };
9945
- function convertNumber(value) {
9946
- return typeof value === "string" ? Number(value.replace(",", ".")) : value;
9947
- }
9948
- const STACKED_MODAL_ID = "items_stacked_modal";
9949
- const Items = () => {
9809
+ InlineTip.displayName = "InlineTip";
9810
+ const MetadataFieldSchema = objectType({
9811
+ key: stringType(),
9812
+ disabled: booleanType().optional(),
9813
+ value: anyType()
9814
+ });
9815
+ const MetadataSchema = objectType({
9816
+ metadata: arrayType(MetadataFieldSchema)
9817
+ });
9818
+ const Metadata = () => {
9950
9819
  const { id } = reactRouterDom.useParams();
9951
- const {
9952
- order: preview,
9953
- isPending: isPreviewPending,
9954
- isError: isPreviewError,
9955
- error: previewError
9956
- } = useOrderPreview(id, void 0, {
9957
- placeholderData: reactQuery.keepPreviousData
9820
+ const { order, isPending, isError, error } = useOrder(id, {
9821
+ fields: "metadata"
9958
9822
  });
9959
- useInitiateOrderEdit({ preview });
9960
- const { draft_order, isPending, isError, error } = useDraftOrder(
9961
- id,
9962
- {
9963
- fields: "currency_code"
9964
- },
9965
- {
9966
- enabled: !!id
9967
- }
9968
- );
9969
- const { onCancel } = useCancelOrderEdit({ preview });
9970
9823
  if (isError) {
9971
9824
  throw error;
9972
9825
  }
9973
- if (isPreviewError) {
9974
- throw previewError;
9975
- }
9976
- const ready = !!preview && !isPreviewPending && !!draft_order && !isPending;
9977
- return /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal, { onClose: onCancel, children: ready ? /* @__PURE__ */ jsxRuntime.jsx(ItemsForm, { preview, currencyCode: draft_order.currency_code }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
9978
- /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Edit Items" }) }),
9979
- /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Loading data for the draft order, please wait..." }) })
9980
- ] }) });
9826
+ const isReady = !isPending && !!order;
9827
+ return /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer, { children: [
9828
+ /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer.Header, { children: [
9829
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Metadata" }) }),
9830
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Description, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Add metadata to the draft order." }) })
9831
+ ] }),
9832
+ !isReady ? /* @__PURE__ */ jsxRuntime.jsx(PlaceholderInner, {}) : /* @__PURE__ */ jsxRuntime.jsx(MetadataForm, { orderId: id, metadata: order == null ? void 0 : order.metadata })
9833
+ ] });
9981
9834
  };
9982
- const ItemsForm = ({ preview, currencyCode }) => {
9983
- var _a;
9984
- const [isSubmitting, setIsSubmitting] = React.useState(false);
9985
- const [modalContent, setModalContent] = React.useState(
9986
- null
9987
- );
9835
+ const METADATA_KEY_LABEL_ID = "metadata-form-key-label";
9836
+ const METADATA_VALUE_LABEL_ID = "metadata-form-value-label";
9837
+ const MetadataForm = ({ orderId, metadata }) => {
9988
9838
  const { handleSuccess } = useRouteModal();
9989
- const { searchValue, onSearchValueChange, query: query2 } = useDebouncedSearch();
9990
- const { mutateAsync: confirmOrderEdit } = useDraftOrderConfirmEdit(preview.id);
9991
- const { mutateAsync: requestOrderEdit } = useDraftOrderRequestEdit(preview.id);
9992
- const itemCount = ((_a = preview.items) == null ? void 0 : _a.reduce((acc, item) => acc + item.quantity, 0)) || 0;
9993
- const matches = React.useMemo(() => {
9994
- return matchSorter.matchSorter(preview.items, query2, {
9995
- keys: ["product_title", "variant_title", "variant_sku", "title"]
9996
- });
9997
- }, [preview.items, query2]);
9998
- const onSubmit = async () => {
9999
- setIsSubmitting(true);
10000
- let requestSucceeded = false;
10001
- await requestOrderEdit(void 0, {
10002
- onError: (e) => {
10003
- ui.toast.error(`Failed to request order edit: ${e.message}`);
10004
- },
10005
- onSuccess: () => {
10006
- requestSucceeded = true;
10007
- }
10008
- });
10009
- if (!requestSucceeded) {
10010
- setIsSubmitting(false);
9839
+ const hasUneditableRows = getHasUneditableRows(metadata);
9840
+ const { mutateAsync, isPending } = useUpdateDraftOrder(orderId);
9841
+ const form = reactHookForm.useForm({
9842
+ defaultValues: {
9843
+ metadata: getDefaultValues(metadata)
9844
+ },
9845
+ resolver: zod.zodResolver(MetadataSchema)
9846
+ });
9847
+ const handleSubmit = form.handleSubmit(async (data) => {
9848
+ const parsedData = parseValues(data);
9849
+ await mutateAsync(
9850
+ {
9851
+ metadata: parsedData
9852
+ },
9853
+ {
9854
+ onSuccess: () => {
9855
+ ui.toast.success("Metadata updated");
9856
+ handleSuccess();
9857
+ },
9858
+ onError: (error) => {
9859
+ ui.toast.error(error.message);
9860
+ }
9861
+ }
9862
+ );
9863
+ });
9864
+ const { fields, insert, remove } = reactHookForm.useFieldArray({
9865
+ control: form.control,
9866
+ name: "metadata"
9867
+ });
9868
+ function deleteRow(index) {
9869
+ remove(index);
9870
+ if (fields.length === 1) {
9871
+ insert(0, {
9872
+ key: "",
9873
+ value: "",
9874
+ disabled: false
9875
+ });
9876
+ }
9877
+ }
9878
+ function insertRow(index, position) {
9879
+ insert(index + (position === "above" ? 0 : 1), {
9880
+ key: "",
9881
+ value: "",
9882
+ disabled: false
9883
+ });
9884
+ }
9885
+ return /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxRuntime.jsxs(
9886
+ KeyboundForm,
9887
+ {
9888
+ onSubmit: handleSubmit,
9889
+ className: "flex flex-1 flex-col overflow-hidden",
9890
+ children: [
9891
+ /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer.Body, { className: "flex flex-1 flex-col gap-y-8 overflow-y-auto", children: [
9892
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-base shadow-elevation-card-rest grid grid-cols-1 divide-y rounded-lg", children: [
9893
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-subtle grid grid-cols-2 divide-x rounded-t-lg", children: [
9894
+ /* @__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" }) }),
9895
+ /* @__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" }) })
9896
+ ] }),
9897
+ fields.map((field, index) => {
9898
+ const isDisabled = field.disabled || false;
9899
+ let placeholder = "-";
9900
+ if (typeof field.value === "object") {
9901
+ placeholder = "{ ... }";
9902
+ }
9903
+ if (Array.isArray(field.value)) {
9904
+ placeholder = "[ ... ]";
9905
+ }
9906
+ return /* @__PURE__ */ jsxRuntime.jsx(
9907
+ ConditionalTooltip,
9908
+ {
9909
+ showTooltip: isDisabled,
9910
+ content: "This row is disabled because it contains non-primitive data.",
9911
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "group/table relative", children: [
9912
+ /* @__PURE__ */ jsxRuntime.jsxs(
9913
+ "div",
9914
+ {
9915
+ className: ui.clx("grid grid-cols-2 divide-x", {
9916
+ "overflow-hidden rounded-b-lg": index === fields.length - 1
9917
+ }),
9918
+ children: [
9919
+ /* @__PURE__ */ jsxRuntime.jsx(
9920
+ Form$2.Field,
9921
+ {
9922
+ control: form.control,
9923
+ name: `metadata.${index}.key`,
9924
+ render: ({ field: field2 }) => {
9925
+ return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
9926
+ GridInput,
9927
+ {
9928
+ "aria-labelledby": METADATA_KEY_LABEL_ID,
9929
+ ...field2,
9930
+ disabled: isDisabled,
9931
+ placeholder: "Key"
9932
+ }
9933
+ ) }) });
9934
+ }
9935
+ }
9936
+ ),
9937
+ /* @__PURE__ */ jsxRuntime.jsx(
9938
+ Form$2.Field,
9939
+ {
9940
+ control: form.control,
9941
+ name: `metadata.${index}.value`,
9942
+ render: ({ field: { value, ...field2 } }) => {
9943
+ return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
9944
+ GridInput,
9945
+ {
9946
+ "aria-labelledby": METADATA_VALUE_LABEL_ID,
9947
+ ...field2,
9948
+ value: isDisabled ? placeholder : value,
9949
+ disabled: isDisabled,
9950
+ placeholder: "Value"
9951
+ }
9952
+ ) }) });
9953
+ }
9954
+ }
9955
+ )
9956
+ ]
9957
+ }
9958
+ ),
9959
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu, { children: [
9960
+ /* @__PURE__ */ jsxRuntime.jsx(
9961
+ ui.DropdownMenu.Trigger,
9962
+ {
9963
+ className: ui.clx(
9964
+ "invisible absolute inset-y-0 -right-2.5 my-auto group-hover/table:visible data-[state='open']:visible",
9965
+ {
9966
+ hidden: isDisabled
9967
+ }
9968
+ ),
9969
+ disabled: isDisabled,
9970
+ asChild: true,
9971
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { size: "2xsmall", children: /* @__PURE__ */ jsxRuntime.jsx(icons.EllipsisVertical, {}) })
9972
+ }
9973
+ ),
9974
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu.Content, { children: [
9975
+ /* @__PURE__ */ jsxRuntime.jsxs(
9976
+ ui.DropdownMenu.Item,
9977
+ {
9978
+ className: "gap-x-2",
9979
+ onClick: () => insertRow(index, "above"),
9980
+ children: [
9981
+ /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowUpMini, { className: "text-ui-fg-subtle" }),
9982
+ "Insert row above"
9983
+ ]
9984
+ }
9985
+ ),
9986
+ /* @__PURE__ */ jsxRuntime.jsxs(
9987
+ ui.DropdownMenu.Item,
9988
+ {
9989
+ className: "gap-x-2",
9990
+ onClick: () => insertRow(index, "below"),
9991
+ children: [
9992
+ /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowDownMini, { className: "text-ui-fg-subtle" }),
9993
+ "Insert row below"
9994
+ ]
9995
+ }
9996
+ ),
9997
+ /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenu.Separator, {}),
9998
+ /* @__PURE__ */ jsxRuntime.jsxs(
9999
+ ui.DropdownMenu.Item,
10000
+ {
10001
+ className: "gap-x-2",
10002
+ onClick: () => deleteRow(index),
10003
+ children: [
10004
+ /* @__PURE__ */ jsxRuntime.jsx(icons.Trash, { className: "text-ui-fg-subtle" }),
10005
+ "Delete row"
10006
+ ]
10007
+ }
10008
+ )
10009
+ ] })
10010
+ ] })
10011
+ ] })
10012
+ },
10013
+ field.id
10014
+ );
10015
+ })
10016
+ ] }),
10017
+ 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." })
10018
+ ] }),
10019
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
10020
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
10021
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", type: "submit", isLoading: isPending, children: "Save" })
10022
+ ] }) })
10023
+ ]
10024
+ }
10025
+ ) });
10026
+ };
10027
+ const GridInput = React.forwardRef(({ className, ...props }, ref) => {
10028
+ return /* @__PURE__ */ jsxRuntime.jsx(
10029
+ "input",
10030
+ {
10031
+ ref,
10032
+ ...props,
10033
+ autoComplete: "off",
10034
+ className: ui.clx(
10035
+ "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",
10036
+ className
10037
+ )
10038
+ }
10039
+ );
10040
+ });
10041
+ GridInput.displayName = "MetadataForm.GridInput";
10042
+ const PlaceholderInner = () => {
10043
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col overflow-hidden", children: [
10044
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Body, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: "h-[148ox] w-full rounded-lg" }) }),
10045
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
10046
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: "h-7 w-12 rounded-md" }),
10047
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: "h-7 w-12 rounded-md" })
10048
+ ] }) })
10049
+ ] });
10050
+ };
10051
+ const EDITABLE_TYPES = ["string", "number", "boolean"];
10052
+ function getDefaultValues(metadata) {
10053
+ if (!metadata || !Object.keys(metadata).length) {
10054
+ return [
10055
+ {
10056
+ key: "",
10057
+ value: "",
10058
+ disabled: false
10059
+ }
10060
+ ];
10061
+ }
10062
+ return Object.entries(metadata).map(([key, value]) => {
10063
+ if (!EDITABLE_TYPES.includes(typeof value)) {
10064
+ return {
10065
+ key,
10066
+ value,
10067
+ disabled: true
10068
+ };
10069
+ }
10070
+ let stringValue = value;
10071
+ if (typeof value !== "string") {
10072
+ stringValue = JSON.stringify(value);
10073
+ }
10074
+ return {
10075
+ key,
10076
+ value: stringValue,
10077
+ original_key: key
10078
+ };
10079
+ });
10080
+ }
10081
+ function parseValues(values) {
10082
+ const metadata = values.metadata;
10083
+ const isEmpty = !metadata.length || metadata.length === 1 && !metadata[0].key && !metadata[0].value;
10084
+ if (isEmpty) {
10085
+ return null;
10086
+ }
10087
+ const update = {};
10088
+ metadata.forEach((field) => {
10089
+ let key = field.key;
10090
+ let value = field.value;
10091
+ const disabled = field.disabled;
10092
+ if (!key || !value) {
10093
+ return;
10094
+ }
10095
+ if (disabled) {
10096
+ update[key] = value;
10097
+ return;
10098
+ }
10099
+ key = key.trim();
10100
+ value = value.trim();
10101
+ if (value === "true") {
10102
+ update[key] = true;
10103
+ } else if (value === "false") {
10104
+ update[key] = false;
10105
+ } else {
10106
+ const parsedNumber = parseFloat(value);
10107
+ if (!isNaN(parsedNumber)) {
10108
+ update[key] = parsedNumber;
10109
+ } else {
10110
+ update[key] = value;
10111
+ }
10112
+ }
10113
+ });
10114
+ return update;
10115
+ }
10116
+ function getHasUneditableRows(metadata) {
10117
+ if (!metadata) {
10118
+ return false;
10119
+ }
10120
+ return Object.values(metadata).some(
10121
+ (value) => !EDITABLE_TYPES.includes(typeof value)
10122
+ );
10123
+ }
10124
+ const NumberInput = React.forwardRef(
10125
+ ({
10126
+ value,
10127
+ onChange,
10128
+ size = "base",
10129
+ min = 0,
10130
+ max = 100,
10131
+ step = 1,
10132
+ className,
10133
+ disabled,
10134
+ ...props
10135
+ }, ref) => {
10136
+ const handleChange = (event) => {
10137
+ const newValue = event.target.value === "" ? min : Number(event.target.value);
10138
+ if (!isNaN(newValue) && (max === void 0 || newValue <= max) && (min === void 0 || newValue >= min)) {
10139
+ onChange(newValue);
10140
+ }
10141
+ };
10142
+ const handleIncrement = () => {
10143
+ const newValue = value + step;
10144
+ if (max === void 0 || newValue <= max) {
10145
+ onChange(newValue);
10146
+ }
10147
+ };
10148
+ const handleDecrement = () => {
10149
+ const newValue = value - step;
10150
+ if (min === void 0 || newValue >= min) {
10151
+ onChange(newValue);
10152
+ }
10153
+ };
10154
+ return /* @__PURE__ */ jsxRuntime.jsxs(
10155
+ "div",
10156
+ {
10157
+ className: ui.clx(
10158
+ "inline-flex rounded-md bg-ui-bg-field shadow-borders-base overflow-hidden divide-x transition-fg",
10159
+ "[&:has(input:focus)]:shadow-borders-interactive-with-active",
10160
+ {
10161
+ "h-7": size === "small",
10162
+ "h-8": size === "base"
10163
+ },
10164
+ className
10165
+ ),
10166
+ children: [
10167
+ /* @__PURE__ */ jsxRuntime.jsx(
10168
+ "input",
10169
+ {
10170
+ ref,
10171
+ type: "number",
10172
+ value,
10173
+ onChange: handleChange,
10174
+ min,
10175
+ max,
10176
+ step,
10177
+ className: ui.clx(
10178
+ "flex-1 px-2 py-1 bg-transparent txt-compact-small text-ui-fg-base outline-none [appearance:textfield]",
10179
+ "[&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none",
10180
+ "placeholder:text-ui-fg-muted"
10181
+ ),
10182
+ ...props
10183
+ }
10184
+ ),
10185
+ /* @__PURE__ */ jsxRuntime.jsxs(
10186
+ "button",
10187
+ {
10188
+ className: ui.clx(
10189
+ "flex items-center justify-center outline-none transition-fg",
10190
+ "disabled:cursor-not-allowed disabled:text-ui-fg-muted",
10191
+ "focus:bg-ui-bg-field-component-hover",
10192
+ "hover:bg-ui-bg-field-component-hover",
10193
+ {
10194
+ "size-7": size === "small",
10195
+ "size-8": size === "base"
10196
+ }
10197
+ ),
10198
+ type: "button",
10199
+ onClick: handleDecrement,
10200
+ disabled: min !== void 0 && value <= min || disabled,
10201
+ children: [
10202
+ /* @__PURE__ */ jsxRuntime.jsx(icons.Minus, {}),
10203
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: `Decrease by ${step}` })
10204
+ ]
10205
+ }
10206
+ ),
10207
+ /* @__PURE__ */ jsxRuntime.jsxs(
10208
+ "button",
10209
+ {
10210
+ className: ui.clx(
10211
+ "flex items-center justify-center outline-none transition-fg",
10212
+ "disabled:cursor-not-allowed disabled:text-ui-fg-muted",
10213
+ "focus:bg-ui-bg-field-hover",
10214
+ "hover:bg-ui-bg-field-hover",
10215
+ {
10216
+ "size-7": size === "small",
10217
+ "size-8": size === "base"
10218
+ }
10219
+ ),
10220
+ type: "button",
10221
+ onClick: handleIncrement,
10222
+ disabled: max !== void 0 && value >= max || disabled,
10223
+ children: [
10224
+ /* @__PURE__ */ jsxRuntime.jsx(icons.Plus, {}),
10225
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: `Increase by ${step}` })
10226
+ ]
10227
+ }
10228
+ )
10229
+ ]
10230
+ }
10231
+ );
10232
+ }
10233
+ );
10234
+ const PRODUCT_VARIANTS_QUERY_KEY = "product-variants";
10235
+ const productVariantsQueryKeys = {
10236
+ list: (query2) => [
10237
+ PRODUCT_VARIANTS_QUERY_KEY,
10238
+ query2 ? query2 : void 0
10239
+ ]
10240
+ };
10241
+ const useProductVariants = (query2, options) => {
10242
+ const { data, ...rest } = reactQuery.useQuery({
10243
+ queryKey: productVariantsQueryKeys.list(query2),
10244
+ queryFn: async () => await sdk.admin.productVariant.list(query2),
10245
+ ...options
10246
+ });
10247
+ return { ...data, ...rest };
10248
+ };
10249
+ const useCancelOrderEdit = ({ preview }) => {
10250
+ const { mutateAsync: cancelOrderEdit } = useDraftOrderCancelEdit(preview == null ? void 0 : preview.id);
10251
+ const onCancel = React.useCallback(async () => {
10252
+ if (!preview) {
10253
+ return true;
10254
+ }
10255
+ let res = false;
10256
+ await cancelOrderEdit(void 0, {
10257
+ onError: (e) => {
10258
+ ui.toast.error(e.message);
10259
+ },
10260
+ onSuccess: () => {
10261
+ res = true;
10262
+ }
10263
+ });
10264
+ return res;
10265
+ }, [preview, cancelOrderEdit]);
10266
+ return { onCancel };
10267
+ };
10268
+ let IS_REQUEST_RUNNING = false;
10269
+ const useInitiateOrderEdit = ({
10270
+ preview
10271
+ }) => {
10272
+ const navigate = reactRouterDom.useNavigate();
10273
+ const { mutateAsync } = useDraftOrderBeginEdit(preview == null ? void 0 : preview.id);
10274
+ React.useEffect(() => {
10275
+ async function run() {
10276
+ if (IS_REQUEST_RUNNING || !preview) {
10277
+ return;
10278
+ }
10279
+ if (preview.order_change) {
10280
+ return;
10281
+ }
10282
+ IS_REQUEST_RUNNING = true;
10283
+ await mutateAsync(void 0, {
10284
+ onError: (e) => {
10285
+ ui.toast.error(e.message);
10286
+ navigate(`/draft-orders/${preview.id}`, { replace: true });
10287
+ return;
10288
+ }
10289
+ });
10290
+ IS_REQUEST_RUNNING = false;
10291
+ }
10292
+ run();
10293
+ }, [preview, navigate, mutateAsync]);
10294
+ };
10295
+ function convertNumber(value) {
10296
+ return typeof value === "string" ? Number(value.replace(",", ".")) : value;
10297
+ }
10298
+ const STACKED_MODAL_ID = "items_stacked_modal";
10299
+ const Items = () => {
10300
+ const { id } = reactRouterDom.useParams();
10301
+ const {
10302
+ order: preview,
10303
+ isPending: isPreviewPending,
10304
+ isError: isPreviewError,
10305
+ error: previewError
10306
+ } = useOrderPreview(id, void 0, {
10307
+ placeholderData: reactQuery.keepPreviousData
10308
+ });
10309
+ useInitiateOrderEdit({ preview });
10310
+ const { draft_order, isPending, isError, error } = useDraftOrder(
10311
+ id,
10312
+ {
10313
+ fields: "currency_code"
10314
+ },
10315
+ {
10316
+ enabled: !!id
10317
+ }
10318
+ );
10319
+ const { onCancel } = useCancelOrderEdit({ preview });
10320
+ if (isError) {
10321
+ throw error;
10322
+ }
10323
+ if (isPreviewError) {
10324
+ throw previewError;
10325
+ }
10326
+ const ready = !!preview && !isPreviewPending && !!draft_order && !isPending;
10327
+ return /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal, { onClose: onCancel, children: ready ? /* @__PURE__ */ jsxRuntime.jsx(ItemsForm, { preview, currencyCode: draft_order.currency_code }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
10328
+ /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Edit Items" }) }),
10329
+ /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Loading data for the draft order, please wait..." }) })
10330
+ ] }) });
10331
+ };
10332
+ const ItemsForm = ({ preview, currencyCode }) => {
10333
+ var _a;
10334
+ const [isSubmitting, setIsSubmitting] = React.useState(false);
10335
+ const [modalContent, setModalContent] = React.useState(
10336
+ null
10337
+ );
10338
+ const { handleSuccess } = useRouteModal();
10339
+ const { searchValue, onSearchValueChange, query: query2 } = useDebouncedSearch();
10340
+ const { mutateAsync: confirmOrderEdit } = useDraftOrderConfirmEdit(preview.id);
10341
+ const { mutateAsync: requestOrderEdit } = useDraftOrderRequestEdit(preview.id);
10342
+ const itemCount = ((_a = preview.items) == null ? void 0 : _a.reduce((acc, item) => acc + item.quantity, 0)) || 0;
10343
+ const matches = React.useMemo(() => {
10344
+ return matchSorter.matchSorter(preview.items, query2, {
10345
+ keys: ["product_title", "variant_title", "variant_sku", "title"]
10346
+ });
10347
+ }, [preview.items, query2]);
10348
+ const onSubmit = async () => {
10349
+ setIsSubmitting(true);
10350
+ let requestSucceeded = false;
10351
+ await requestOrderEdit(void 0, {
10352
+ onError: (e) => {
10353
+ ui.toast.error(`Failed to request order edit: ${e.message}`);
10354
+ },
10355
+ onSuccess: () => {
10356
+ requestSucceeded = true;
10357
+ }
10358
+ });
10359
+ if (!requestSucceeded) {
10360
+ setIsSubmitting(false);
10011
10361
  return;
10012
10362
  }
10013
10363
  await confirmOrderEdit(void 0, {
@@ -10637,532 +10987,114 @@ const CustomItemForm = ({ orderId, currencyCode }) => {
10637
10987
  const { mutateAsync: addItems } = useDraftOrderAddItems(orderId);
10638
10988
  const form = reactHookForm.useForm({
10639
10989
  defaultValues: {
10640
- title: "",
10641
- quantity: 1,
10642
- unit_price: ""
10643
- },
10644
- resolver: zod.zodResolver(customItemSchema)
10645
- });
10646
- const onSubmit = form.handleSubmit(async (data) => {
10647
- await addItems(
10648
- {
10649
- items: [
10650
- {
10651
- title: data.title,
10652
- quantity: data.quantity,
10653
- unit_price: convertNumber(data.unit_price)
10654
- }
10655
- ]
10656
- },
10657
- {
10658
- onSuccess: () => {
10659
- setIsOpen(STACKED_MODAL_ID, false);
10660
- },
10661
- onError: (e) => {
10662
- ui.toast.error(e.message);
10663
- }
10664
- }
10665
- );
10666
- });
10667
- return /* @__PURE__ */ jsxRuntime.jsx(Form$2, { ...form, children: /* @__PURE__ */ jsxRuntime.jsx(KeyboundForm, { onSubmit, children: /* @__PURE__ */ jsxRuntime.jsxs(StackedFocusModal.Content, { children: [
10668
- /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Header, {}),
10669
- /* @__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: [
10670
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
10671
- /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Add custom item" }) }),
10672
- /* @__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." }) })
10673
- ] }),
10674
- /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { variant: "dashed" }),
10675
- /* @__PURE__ */ jsxRuntime.jsx(
10676
- Form$2.Field,
10677
- {
10678
- control: form.control,
10679
- name: "title",
10680
- render: ({ field }) => /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
10681
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
10682
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.Label, { children: "Title" }),
10683
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.Hint, { children: "Enter the title of the item" })
10684
- ] }),
10685
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
10686
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Input, { ...field }) }),
10687
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.ErrorMessage, {})
10688
- ] })
10689
- ] }) })
10690
- }
10691
- ),
10692
- /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { variant: "dashed" }),
10693
- /* @__PURE__ */ jsxRuntime.jsx(
10694
- Form$2.Field,
10695
- {
10696
- control: form.control,
10697
- name: "unit_price",
10698
- render: ({ field: { onChange, ...field } }) => /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
10699
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
10700
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.Label, { children: "Unit price" }),
10701
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.Hint, { children: "Enter the unit price of the item" })
10702
- ] }),
10703
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
10704
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
10705
- ui.CurrencyInput,
10706
- {
10707
- symbol: getNativeSymbol(currencyCode),
10708
- code: currencyCode,
10709
- onValueChange: (_value, _name, values) => onChange(values == null ? void 0 : values.value),
10710
- ...field
10711
- }
10712
- ) }),
10713
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.ErrorMessage, {})
10714
- ] })
10715
- ] }) })
10716
- }
10717
- ),
10718
- /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { variant: "dashed" }),
10719
- /* @__PURE__ */ jsxRuntime.jsx(
10720
- Form$2.Field,
10721
- {
10722
- control: form.control,
10723
- name: "quantity",
10724
- render: ({ field }) => /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
10725
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
10726
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.Label, { children: "Quantity" }),
10727
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.Hint, { children: "Enter the quantity of the item" })
10728
- ] }),
10729
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 w-full", children: [
10730
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 w-full", children: /* @__PURE__ */ jsxRuntime.jsx(NumberInput, { ...field, className: "w-full" }) }) }),
10731
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.ErrorMessage, {})
10732
- ] })
10733
- ] }) })
10734
- }
10735
- )
10736
- ] }) }) }),
10737
- /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-x-2 justify-end", children: [
10738
- /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
10739
- /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", type: "button", onClick: onSubmit, children: "Add item" })
10740
- ] }) })
10741
- ] }) }) });
10742
- };
10743
- const customItemSchema = objectType({
10744
- title: stringType().min(1),
10745
- quantity: numberType(),
10746
- unit_price: unionType([numberType(), stringType()])
10747
- });
10748
- const Email = () => {
10749
- const { id } = reactRouterDom.useParams();
10750
- const { order, isPending, isError, error } = useOrder(id, {
10751
- fields: "+email"
10752
- });
10753
- if (isError) {
10754
- throw error;
10755
- }
10756
- const isReady = !isPending && !!order;
10757
- return /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer, { children: [
10758
- /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer.Header, { children: [
10759
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Edit Email" }) }),
10760
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Description, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Edit the email for the draft order" }) })
10761
- ] }),
10762
- isReady && /* @__PURE__ */ jsxRuntime.jsx(EmailForm, { order })
10763
- ] });
10764
- };
10765
- const EmailForm = ({ order }) => {
10766
- const form = reactHookForm.useForm({
10767
- defaultValues: {
10768
- email: order.email ?? ""
10769
- },
10770
- resolver: zod.zodResolver(schema$3)
10771
- });
10772
- const { mutateAsync, isPending } = useUpdateDraftOrder(order.id);
10773
- const { handleSuccess } = useRouteModal();
10774
- const onSubmit = form.handleSubmit(async (data) => {
10775
- await mutateAsync(
10776
- { email: data.email },
10777
- {
10778
- onSuccess: () => {
10779
- handleSuccess();
10780
- },
10781
- onError: (error) => {
10782
- ui.toast.error(error.message);
10783
- }
10784
- }
10785
- );
10786
- });
10787
- return /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxRuntime.jsxs(
10788
- KeyboundForm,
10789
- {
10790
- className: "flex flex-1 flex-col overflow-hidden",
10791
- onSubmit,
10792
- children: [
10793
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Body, { className: "flex flex-col gap-y-6 overflow-y-auto", children: /* @__PURE__ */ jsxRuntime.jsx(
10794
- Form$2.Field,
10795
- {
10796
- control: form.control,
10797
- name: "email",
10798
- render: ({ field }) => /* @__PURE__ */ jsxRuntime.jsxs(Form$2.Item, { children: [
10799
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.Label, { children: "Email" }),
10800
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Input, { ...field }) }),
10801
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.ErrorMessage, {})
10802
- ] })
10803
- }
10804
- ) }),
10805
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-2", children: [
10806
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
10807
- /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", type: "submit", isLoading: isPending, children: "Save" })
10808
- ] }) })
10809
- ]
10810
- }
10811
- ) });
10812
- };
10813
- const schema$3 = objectType({
10814
- email: stringType().email()
10815
- });
10816
- const InlineTip = React.forwardRef(
10817
- ({ variant = "tip", label, className, children, ...props }, ref) => {
10818
- const labelValue = label || (variant === "warning" ? "Warning" : "Tip");
10819
- return /* @__PURE__ */ jsxRuntime.jsxs(
10820
- "div",
10821
- {
10822
- ref,
10823
- className: ui.clx(
10824
- "bg-ui-bg-component txt-small text-ui-fg-subtle grid grid-cols-[4px_1fr] items-start gap-3 rounded-lg border p-3",
10825
- className
10826
- ),
10827
- ...props,
10828
- children: [
10829
- /* @__PURE__ */ jsxRuntime.jsx(
10830
- "div",
10831
- {
10832
- role: "presentation",
10833
- className: ui.clx("w-4px bg-ui-tag-neutral-icon h-full rounded-full", {
10834
- "bg-ui-tag-orange-icon": variant === "warning"
10835
- })
10836
- }
10837
- ),
10838
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-pretty", children: [
10839
- /* @__PURE__ */ jsxRuntime.jsxs("strong", { className: "txt-small-plus text-ui-fg-base", children: [
10840
- labelValue,
10841
- ":"
10842
- ] }),
10843
- " ",
10844
- children
10845
- ] })
10846
- ]
10847
- }
10848
- );
10849
- }
10850
- );
10851
- InlineTip.displayName = "InlineTip";
10852
- const MetadataFieldSchema = objectType({
10853
- key: stringType(),
10854
- disabled: booleanType().optional(),
10855
- value: anyType()
10856
- });
10857
- const MetadataSchema = objectType({
10858
- metadata: arrayType(MetadataFieldSchema)
10859
- });
10860
- const Metadata = () => {
10861
- const { id } = reactRouterDom.useParams();
10862
- const { order, isPending, isError, error } = useOrder(id, {
10863
- fields: "metadata"
10864
- });
10865
- if (isError) {
10866
- throw error;
10867
- }
10868
- const isReady = !isPending && !!order;
10869
- return /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer, { children: [
10870
- /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer.Header, { children: [
10871
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Metadata" }) }),
10872
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Description, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Add metadata to the draft order." }) })
10873
- ] }),
10874
- !isReady ? /* @__PURE__ */ jsxRuntime.jsx(PlaceholderInner, {}) : /* @__PURE__ */ jsxRuntime.jsx(MetadataForm, { orderId: id, metadata: order == null ? void 0 : order.metadata })
10875
- ] });
10876
- };
10877
- const METADATA_KEY_LABEL_ID = "metadata-form-key-label";
10878
- const METADATA_VALUE_LABEL_ID = "metadata-form-value-label";
10879
- const MetadataForm = ({ orderId, metadata }) => {
10880
- const { handleSuccess } = useRouteModal();
10881
- const hasUneditableRows = getHasUneditableRows(metadata);
10882
- const { mutateAsync, isPending } = useUpdateDraftOrder(orderId);
10883
- const form = reactHookForm.useForm({
10884
- defaultValues: {
10885
- metadata: getDefaultValues(metadata)
10990
+ title: "",
10991
+ quantity: 1,
10992
+ unit_price: ""
10886
10993
  },
10887
- resolver: zod.zodResolver(MetadataSchema)
10994
+ resolver: zod.zodResolver(customItemSchema)
10888
10995
  });
10889
- const handleSubmit = form.handleSubmit(async (data) => {
10890
- const parsedData = parseValues(data);
10891
- await mutateAsync(
10996
+ const onSubmit = form.handleSubmit(async (data) => {
10997
+ await addItems(
10892
10998
  {
10893
- metadata: parsedData
10999
+ items: [
11000
+ {
11001
+ title: data.title,
11002
+ quantity: data.quantity,
11003
+ unit_price: convertNumber(data.unit_price)
11004
+ }
11005
+ ]
10894
11006
  },
10895
11007
  {
10896
11008
  onSuccess: () => {
10897
- ui.toast.success("Metadata updated");
10898
- handleSuccess();
11009
+ setIsOpen(STACKED_MODAL_ID, false);
10899
11010
  },
10900
- onError: (error) => {
10901
- ui.toast.error(error.message);
11011
+ onError: (e) => {
11012
+ ui.toast.error(e.message);
10902
11013
  }
10903
11014
  }
10904
11015
  );
10905
11016
  });
10906
- const { fields, insert, remove } = reactHookForm.useFieldArray({
10907
- control: form.control,
10908
- name: "metadata"
10909
- });
10910
- function deleteRow(index) {
10911
- remove(index);
10912
- if (fields.length === 1) {
10913
- insert(0, {
10914
- key: "",
10915
- value: "",
10916
- disabled: false
10917
- });
10918
- }
10919
- }
10920
- function insertRow(index, position) {
10921
- insert(index + (position === "above" ? 0 : 1), {
10922
- key: "",
10923
- value: "",
10924
- disabled: false
10925
- });
10926
- }
10927
- return /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxRuntime.jsxs(
10928
- KeyboundForm,
10929
- {
10930
- onSubmit: handleSubmit,
10931
- className: "flex flex-1 flex-col overflow-hidden",
10932
- children: [
10933
- /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer.Body, { className: "flex flex-1 flex-col gap-y-8 overflow-y-auto", children: [
10934
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-base shadow-elevation-card-rest grid grid-cols-1 divide-y rounded-lg", children: [
10935
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-subtle grid grid-cols-2 divide-x rounded-t-lg", children: [
10936
- /* @__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" }) }),
10937
- /* @__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" }) })
11017
+ return /* @__PURE__ */ jsxRuntime.jsx(Form$2, { ...form, children: /* @__PURE__ */ jsxRuntime.jsx(KeyboundForm, { onSubmit, children: /* @__PURE__ */ jsxRuntime.jsxs(StackedFocusModal.Content, { children: [
11018
+ /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Header, {}),
11019
+ /* @__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: [
11020
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
11021
+ /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Add custom item" }) }),
11022
+ /* @__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." }) })
11023
+ ] }),
11024
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { variant: "dashed" }),
11025
+ /* @__PURE__ */ jsxRuntime.jsx(
11026
+ Form$2.Field,
11027
+ {
11028
+ control: form.control,
11029
+ name: "title",
11030
+ render: ({ field }) => /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
11031
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
11032
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.Label, { children: "Title" }),
11033
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.Hint, { children: "Enter the title of the item" })
10938
11034
  ] }),
10939
- fields.map((field, index) => {
10940
- const isDisabled = field.disabled || false;
10941
- let placeholder = "-";
10942
- if (typeof field.value === "object") {
10943
- placeholder = "{ ... }";
10944
- }
10945
- if (Array.isArray(field.value)) {
10946
- placeholder = "[ ... ]";
10947
- }
10948
- return /* @__PURE__ */ jsxRuntime.jsx(
10949
- ConditionalTooltip,
11035
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
11036
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Input, { ...field }) }),
11037
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.ErrorMessage, {})
11038
+ ] })
11039
+ ] }) })
11040
+ }
11041
+ ),
11042
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { variant: "dashed" }),
11043
+ /* @__PURE__ */ jsxRuntime.jsx(
11044
+ Form$2.Field,
11045
+ {
11046
+ control: form.control,
11047
+ name: "unit_price",
11048
+ render: ({ field: { onChange, ...field } }) => /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
11049
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
11050
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.Label, { children: "Unit price" }),
11051
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.Hint, { children: "Enter the unit price of the item" })
11052
+ ] }),
11053
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
11054
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
11055
+ ui.CurrencyInput,
10950
11056
  {
10951
- showTooltip: isDisabled,
10952
- content: "This row is disabled because it contains non-primitive data.",
10953
- children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "group/table relative", children: [
10954
- /* @__PURE__ */ jsxRuntime.jsxs(
10955
- "div",
10956
- {
10957
- className: ui.clx("grid grid-cols-2 divide-x", {
10958
- "overflow-hidden rounded-b-lg": index === fields.length - 1
10959
- }),
10960
- children: [
10961
- /* @__PURE__ */ jsxRuntime.jsx(
10962
- Form$2.Field,
10963
- {
10964
- control: form.control,
10965
- name: `metadata.${index}.key`,
10966
- render: ({ field: field2 }) => {
10967
- return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
10968
- GridInput,
10969
- {
10970
- "aria-labelledby": METADATA_KEY_LABEL_ID,
10971
- ...field2,
10972
- disabled: isDisabled,
10973
- placeholder: "Key"
10974
- }
10975
- ) }) });
10976
- }
10977
- }
10978
- ),
10979
- /* @__PURE__ */ jsxRuntime.jsx(
10980
- Form$2.Field,
10981
- {
10982
- control: form.control,
10983
- name: `metadata.${index}.value`,
10984
- render: ({ field: { value, ...field2 } }) => {
10985
- return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
10986
- GridInput,
10987
- {
10988
- "aria-labelledby": METADATA_VALUE_LABEL_ID,
10989
- ...field2,
10990
- value: isDisabled ? placeholder : value,
10991
- disabled: isDisabled,
10992
- placeholder: "Value"
10993
- }
10994
- ) }) });
10995
- }
10996
- }
10997
- )
10998
- ]
10999
- }
11000
- ),
11001
- /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu, { children: [
11002
- /* @__PURE__ */ jsxRuntime.jsx(
11003
- ui.DropdownMenu.Trigger,
11004
- {
11005
- className: ui.clx(
11006
- "invisible absolute inset-y-0 -right-2.5 my-auto group-hover/table:visible data-[state='open']:visible",
11007
- {
11008
- hidden: isDisabled
11009
- }
11010
- ),
11011
- disabled: isDisabled,
11012
- asChild: true,
11013
- children: /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { size: "2xsmall", children: /* @__PURE__ */ jsxRuntime.jsx(icons.EllipsisVertical, {}) })
11014
- }
11015
- ),
11016
- /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu.Content, { children: [
11017
- /* @__PURE__ */ jsxRuntime.jsxs(
11018
- ui.DropdownMenu.Item,
11019
- {
11020
- className: "gap-x-2",
11021
- onClick: () => insertRow(index, "above"),
11022
- children: [
11023
- /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowUpMini, { className: "text-ui-fg-subtle" }),
11024
- "Insert row above"
11025
- ]
11026
- }
11027
- ),
11028
- /* @__PURE__ */ jsxRuntime.jsxs(
11029
- ui.DropdownMenu.Item,
11030
- {
11031
- className: "gap-x-2",
11032
- onClick: () => insertRow(index, "below"),
11033
- children: [
11034
- /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowDownMini, { className: "text-ui-fg-subtle" }),
11035
- "Insert row below"
11036
- ]
11037
- }
11038
- ),
11039
- /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenu.Separator, {}),
11040
- /* @__PURE__ */ jsxRuntime.jsxs(
11041
- ui.DropdownMenu.Item,
11042
- {
11043
- className: "gap-x-2",
11044
- onClick: () => deleteRow(index),
11045
- children: [
11046
- /* @__PURE__ */ jsxRuntime.jsx(icons.Trash, { className: "text-ui-fg-subtle" }),
11047
- "Delete row"
11048
- ]
11049
- }
11050
- )
11051
- ] })
11052
- ] })
11053
- ] })
11054
- },
11055
- field.id
11056
- );
11057
- })
11058
- ] }),
11059
- 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." })
11060
- ] }),
11061
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
11062
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
11063
- /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", type: "submit", isLoading: isPending, children: "Save" })
11064
- ] }) })
11065
- ]
11066
- }
11067
- ) });
11068
- };
11069
- const GridInput = React.forwardRef(({ className, ...props }, ref) => {
11070
- return /* @__PURE__ */ jsxRuntime.jsx(
11071
- "input",
11072
- {
11073
- ref,
11074
- ...props,
11075
- autoComplete: "off",
11076
- className: ui.clx(
11077
- "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",
11078
- className
11057
+ symbol: getNativeSymbol(currencyCode),
11058
+ code: currencyCode,
11059
+ onValueChange: (_value, _name, values) => onChange(values == null ? void 0 : values.value),
11060
+ ...field
11061
+ }
11062
+ ) }),
11063
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.ErrorMessage, {})
11064
+ ] })
11065
+ ] }) })
11066
+ }
11067
+ ),
11068
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { variant: "dashed" }),
11069
+ /* @__PURE__ */ jsxRuntime.jsx(
11070
+ Form$2.Field,
11071
+ {
11072
+ control: form.control,
11073
+ name: "quantity",
11074
+ render: ({ field }) => /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
11075
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
11076
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.Label, { children: "Quantity" }),
11077
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.Hint, { children: "Enter the quantity of the item" })
11078
+ ] }),
11079
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 w-full", children: [
11080
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 w-full", children: /* @__PURE__ */ jsxRuntime.jsx(NumberInput, { ...field, className: "w-full" }) }) }),
11081
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.ErrorMessage, {})
11082
+ ] })
11083
+ ] }) })
11084
+ }
11079
11085
  )
11080
- }
11081
- );
11082
- });
11083
- GridInput.displayName = "MetadataForm.GridInput";
11084
- const PlaceholderInner = () => {
11085
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col overflow-hidden", children: [
11086
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Body, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: "h-[148ox] w-full rounded-lg" }) }),
11087
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
11088
- /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: "h-7 w-12 rounded-md" }),
11089
- /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: "h-7 w-12 rounded-md" })
11086
+ ] }) }) }),
11087
+ /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-x-2 justify-end", children: [
11088
+ /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
11089
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", type: "button", onClick: onSubmit, children: "Add item" })
11090
11090
  ] }) })
11091
- ] });
11091
+ ] }) }) });
11092
11092
  };
11093
- const EDITABLE_TYPES = ["string", "number", "boolean"];
11094
- function getDefaultValues(metadata) {
11095
- if (!metadata || !Object.keys(metadata).length) {
11096
- return [
11097
- {
11098
- key: "",
11099
- value: "",
11100
- disabled: false
11101
- }
11102
- ];
11103
- }
11104
- return Object.entries(metadata).map(([key, value]) => {
11105
- if (!EDITABLE_TYPES.includes(typeof value)) {
11106
- return {
11107
- key,
11108
- value,
11109
- disabled: true
11110
- };
11111
- }
11112
- let stringValue = value;
11113
- if (typeof value !== "string") {
11114
- stringValue = JSON.stringify(value);
11115
- }
11116
- return {
11117
- key,
11118
- value: stringValue,
11119
- original_key: key
11120
- };
11121
- });
11122
- }
11123
- function parseValues(values) {
11124
- const metadata = values.metadata;
11125
- const isEmpty = !metadata.length || metadata.length === 1 && !metadata[0].key && !metadata[0].value;
11126
- if (isEmpty) {
11127
- return null;
11128
- }
11129
- const update = {};
11130
- metadata.forEach((field) => {
11131
- let key = field.key;
11132
- let value = field.value;
11133
- const disabled = field.disabled;
11134
- if (!key || !value) {
11135
- return;
11136
- }
11137
- if (disabled) {
11138
- update[key] = value;
11139
- return;
11140
- }
11141
- key = key.trim();
11142
- value = value.trim();
11143
- if (value === "true") {
11144
- update[key] = true;
11145
- } else if (value === "false") {
11146
- update[key] = false;
11147
- } else {
11148
- const parsedNumber = parseFloat(value);
11149
- if (!isNaN(parsedNumber)) {
11150
- update[key] = parsedNumber;
11151
- } else {
11152
- update[key] = value;
11153
- }
11154
- }
11155
- });
11156
- return update;
11157
- }
11158
- function getHasUneditableRows(metadata) {
11159
- if (!metadata) {
11160
- return false;
11161
- }
11162
- return Object.values(metadata).some(
11163
- (value) => !EDITABLE_TYPES.includes(typeof value)
11164
- );
11165
- }
11093
+ const customItemSchema = objectType({
11094
+ title: stringType().min(1),
11095
+ quantity: numberType(),
11096
+ unit_price: unionType([numberType(), stringType()])
11097
+ });
11166
11098
  const PROMOTION_QUERY_KEY = "promotions";
11167
11099
  const promotionsQueryKeys = {
11168
11100
  list: (query2) => [
@@ -11386,166 +11318,60 @@ const PromotionItem = ({
11386
11318
  }
11387
11319
  )
11388
11320
  ]
11389
- },
11390
- promotion.id
11391
- );
11392
- };
11393
- function getDisplayValue(promotion) {
11394
- var _a, _b, _c, _d;
11395
- const value = (_a = promotion.application_method) == null ? void 0 : _a.value;
11396
- if (!value) {
11397
- return null;
11398
- }
11399
- if (((_b = promotion.application_method) == null ? void 0 : _b.type) === "fixed") {
11400
- const currency = (_c = promotion.application_method) == null ? void 0 : _c.currency_code;
11401
- if (!currency) {
11402
- return null;
11403
- }
11404
- return getLocaleAmount(value, currency);
11405
- } else if (((_d = promotion.application_method) == null ? void 0 : _d.type) === "percentage") {
11406
- return formatPercentage(value);
11407
- }
11408
- return null;
11409
- }
11410
- const formatter = new Intl.NumberFormat([], {
11411
- style: "percent",
11412
- minimumFractionDigits: 2
11413
- });
11414
- const formatPercentage = (value, isPercentageValue = false) => {
11415
- let val = value || 0;
11416
- if (!isPercentageValue) {
11417
- val = val / 100;
11418
- }
11419
- return formatter.format(val);
11420
- };
11421
- function getPromotionCodes(items, shippingMethods) {
11422
- const codes = /* @__PURE__ */ new Set();
11423
- for (const item of items) {
11424
- if (item.adjustments) {
11425
- for (const adjustment of item.adjustments) {
11426
- if (adjustment.code) {
11427
- codes.add(adjustment.code);
11428
- }
11429
- }
11430
- }
11431
- }
11432
- for (const shippingMethod of shippingMethods) {
11433
- if (shippingMethod.adjustments) {
11434
- for (const adjustment of shippingMethod.adjustments) {
11435
- if (adjustment.code) {
11436
- codes.add(adjustment.code);
11437
- }
11438
- }
11439
- }
11440
- }
11441
- return Array.from(codes);
11442
- }
11443
- const SalesChannel = () => {
11444
- const { id } = reactRouterDom.useParams();
11445
- const { draft_order, isPending, isError, error } = useDraftOrder(
11446
- id,
11447
- {
11448
- fields: "+sales_channel_id"
11449
- },
11450
- {
11451
- enabled: !!id
11452
- }
11453
- );
11454
- if (isError) {
11455
- throw error;
11456
- }
11457
- const ISrEADY = !!draft_order && !isPending;
11458
- return /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer, { children: [
11459
- /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer.Header, { children: [
11460
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Edit Sales Channel" }) }),
11461
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Description, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Update which sales channel the draft order is associated with" }) })
11462
- ] }),
11463
- ISrEADY && /* @__PURE__ */ jsxRuntime.jsx(SalesChannelForm, { order: draft_order })
11464
- ] });
11465
- };
11466
- const SalesChannelForm = ({ order }) => {
11467
- const form = reactHookForm.useForm({
11468
- defaultValues: {
11469
- sales_channel_id: order.sales_channel_id || ""
11470
- },
11471
- resolver: zod.zodResolver(schema$2)
11472
- });
11473
- const { mutateAsync, isPending } = useUpdateDraftOrder(order.id);
11474
- const { handleSuccess } = useRouteModal();
11475
- const onSubmit = form.handleSubmit(async (data) => {
11476
- await mutateAsync(
11477
- {
11478
- sales_channel_id: data.sales_channel_id
11479
- },
11480
- {
11481
- onSuccess: () => {
11482
- ui.toast.success("Sales channel updated");
11483
- handleSuccess();
11484
- },
11485
- onError: (error) => {
11486
- ui.toast.error(error.message);
11487
- }
11488
- }
11489
- );
11490
- });
11491
- return /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxRuntime.jsxs(
11492
- KeyboundForm,
11493
- {
11494
- className: "flex flex-1 flex-col overflow-hidden",
11495
- onSubmit,
11496
- children: [
11497
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Body, { className: "flex flex-col gap-y-6 overflow-y-auto", children: /* @__PURE__ */ jsxRuntime.jsx(SalesChannelField, { control: form.control, order }) }),
11498
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-2", children: [
11499
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
11500
- /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", type: "submit", isLoading: isPending, children: "Save" })
11501
- ] }) })
11502
- ]
11503
- }
11504
- ) });
11505
- };
11506
- const SalesChannelField = ({ control, order }) => {
11507
- const salesChannels = useComboboxData({
11508
- queryFn: async (params) => {
11509
- return await sdk.admin.salesChannel.list(params);
11510
- },
11511
- queryKey: ["sales-channels"],
11512
- getOptions: (data) => {
11513
- return data.sales_channels.map((salesChannel) => ({
11514
- label: salesChannel.name,
11515
- value: salesChannel.id
11516
- }));
11517
- },
11518
- defaultValue: order.sales_channel_id || void 0
11519
- });
11520
- return /* @__PURE__ */ jsxRuntime.jsx(
11521
- Form$2.Field,
11522
- {
11523
- control,
11524
- name: "sales_channel_id",
11525
- render: ({ field }) => {
11526
- return /* @__PURE__ */ jsxRuntime.jsxs(Form$2.Item, { children: [
11527
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.Label, { children: "Sales Channel" }),
11528
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
11529
- Combobox,
11530
- {
11531
- options: salesChannels.options,
11532
- fetchNextPage: salesChannels.fetchNextPage,
11533
- isFetchingNextPage: salesChannels.isFetchingNextPage,
11534
- searchValue: salesChannels.searchValue,
11535
- onSearchValueChange: salesChannels.onSearchValueChange,
11536
- placeholder: "Select sales channel",
11537
- ...field
11538
- }
11539
- ) }),
11540
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.ErrorMessage, {})
11541
- ] });
11542
- }
11543
- }
11321
+ },
11322
+ promotion.id
11544
11323
  );
11545
11324
  };
11546
- const schema$2 = objectType({
11547
- sales_channel_id: stringType().min(1)
11325
+ function getDisplayValue(promotion) {
11326
+ var _a, _b, _c, _d;
11327
+ const value = (_a = promotion.application_method) == null ? void 0 : _a.value;
11328
+ if (!value) {
11329
+ return null;
11330
+ }
11331
+ if (((_b = promotion.application_method) == null ? void 0 : _b.type) === "fixed") {
11332
+ const currency = (_c = promotion.application_method) == null ? void 0 : _c.currency_code;
11333
+ if (!currency) {
11334
+ return null;
11335
+ }
11336
+ return getLocaleAmount(value, currency);
11337
+ } else if (((_d = promotion.application_method) == null ? void 0 : _d.type) === "percentage") {
11338
+ return formatPercentage(value);
11339
+ }
11340
+ return null;
11341
+ }
11342
+ const formatter = new Intl.NumberFormat([], {
11343
+ style: "percent",
11344
+ minimumFractionDigits: 2
11548
11345
  });
11346
+ const formatPercentage = (value, isPercentageValue = false) => {
11347
+ let val = value || 0;
11348
+ if (!isPercentageValue) {
11349
+ val = val / 100;
11350
+ }
11351
+ return formatter.format(val);
11352
+ };
11353
+ function getPromotionCodes(items, shippingMethods) {
11354
+ const codes = /* @__PURE__ */ new Set();
11355
+ for (const item of items) {
11356
+ if (item.adjustments) {
11357
+ for (const adjustment of item.adjustments) {
11358
+ if (adjustment.code) {
11359
+ codes.add(adjustment.code);
11360
+ }
11361
+ }
11362
+ }
11363
+ }
11364
+ for (const shippingMethod of shippingMethods) {
11365
+ if (shippingMethod.adjustments) {
11366
+ for (const adjustment of shippingMethod.adjustments) {
11367
+ if (adjustment.code) {
11368
+ codes.add(adjustment.code);
11369
+ }
11370
+ }
11371
+ }
11372
+ }
11373
+ return Array.from(codes);
11374
+ }
11549
11375
  const STACKED_FOCUS_MODAL_ID = "shipping-form";
11550
11376
  const Shipping = () => {
11551
11377
  var _a;
@@ -12385,7 +12211,7 @@ const ShippingAddressForm = ({ order }) => {
12385
12211
  postal_code: ((_i = order.shipping_address) == null ? void 0 : _i.postal_code) ?? "",
12386
12212
  phone: ((_j = order.shipping_address) == null ? void 0 : _j.phone) ?? ""
12387
12213
  },
12388
- resolver: zod.zodResolver(schema$1)
12214
+ resolver: zod.zodResolver(schema$3)
12389
12215
  });
12390
12216
  const { mutateAsync, isPending } = useUpdateDraftOrder(order.id);
12391
12217
  const { handleSuccess } = useRouteModal();
@@ -12555,7 +12381,7 @@ const ShippingAddressForm = ({ order }) => {
12555
12381
  }
12556
12382
  ) });
12557
12383
  };
12558
- const schema$1 = addressSchema;
12384
+ const schema$3 = addressSchema;
12559
12385
  const TransferOwnership = () => {
12560
12386
  const { id } = reactRouterDom.useParams();
12561
12387
  const { draft_order, isPending, isError, error } = useDraftOrder(id, {
@@ -12579,7 +12405,7 @@ const TransferOwnershipForm = ({ order }) => {
12579
12405
  defaultValues: {
12580
12406
  customer_id: order.customer_id || ""
12581
12407
  },
12582
- resolver: zod.zodResolver(schema)
12408
+ resolver: zod.zodResolver(schema$2)
12583
12409
  });
12584
12410
  const { mutateAsync, isPending } = useUpdateDraftOrder(order.id);
12585
12411
  const { handleSuccess } = useRouteModal();
@@ -13029,9 +12855,183 @@ const Illustration = () => {
13029
12855
  }
13030
12856
  );
13031
12857
  };
13032
- const schema = objectType({
12858
+ const schema$2 = objectType({
13033
12859
  customer_id: stringType().min(1)
13034
12860
  });
12861
+ const SalesChannel = () => {
12862
+ const { id } = reactRouterDom.useParams();
12863
+ const { draft_order, isPending, isError, error } = useDraftOrder(
12864
+ id,
12865
+ {
12866
+ fields: "+sales_channel_id"
12867
+ },
12868
+ {
12869
+ enabled: !!id
12870
+ }
12871
+ );
12872
+ if (isError) {
12873
+ throw error;
12874
+ }
12875
+ const ISrEADY = !!draft_order && !isPending;
12876
+ return /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer, { children: [
12877
+ /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer.Header, { children: [
12878
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Edit Sales Channel" }) }),
12879
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Description, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Update which sales channel the draft order is associated with" }) })
12880
+ ] }),
12881
+ ISrEADY && /* @__PURE__ */ jsxRuntime.jsx(SalesChannelForm, { order: draft_order })
12882
+ ] });
12883
+ };
12884
+ const SalesChannelForm = ({ order }) => {
12885
+ const form = reactHookForm.useForm({
12886
+ defaultValues: {
12887
+ sales_channel_id: order.sales_channel_id || ""
12888
+ },
12889
+ resolver: zod.zodResolver(schema$1)
12890
+ });
12891
+ const { mutateAsync, isPending } = useUpdateDraftOrder(order.id);
12892
+ const { handleSuccess } = useRouteModal();
12893
+ const onSubmit = form.handleSubmit(async (data) => {
12894
+ await mutateAsync(
12895
+ {
12896
+ sales_channel_id: data.sales_channel_id
12897
+ },
12898
+ {
12899
+ onSuccess: () => {
12900
+ ui.toast.success("Sales channel updated");
12901
+ handleSuccess();
12902
+ },
12903
+ onError: (error) => {
12904
+ ui.toast.error(error.message);
12905
+ }
12906
+ }
12907
+ );
12908
+ });
12909
+ return /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxRuntime.jsxs(
12910
+ KeyboundForm,
12911
+ {
12912
+ className: "flex flex-1 flex-col overflow-hidden",
12913
+ onSubmit,
12914
+ children: [
12915
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Body, { className: "flex flex-col gap-y-6 overflow-y-auto", children: /* @__PURE__ */ jsxRuntime.jsx(SalesChannelField, { control: form.control, order }) }),
12916
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-2", children: [
12917
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
12918
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", type: "submit", isLoading: isPending, children: "Save" })
12919
+ ] }) })
12920
+ ]
12921
+ }
12922
+ ) });
12923
+ };
12924
+ const SalesChannelField = ({ control, order }) => {
12925
+ const salesChannels = useComboboxData({
12926
+ queryFn: async (params) => {
12927
+ return await sdk.admin.salesChannel.list(params);
12928
+ },
12929
+ queryKey: ["sales-channels"],
12930
+ getOptions: (data) => {
12931
+ return data.sales_channels.map((salesChannel) => ({
12932
+ label: salesChannel.name,
12933
+ value: salesChannel.id
12934
+ }));
12935
+ },
12936
+ defaultValue: order.sales_channel_id || void 0
12937
+ });
12938
+ return /* @__PURE__ */ jsxRuntime.jsx(
12939
+ Form$2.Field,
12940
+ {
12941
+ control,
12942
+ name: "sales_channel_id",
12943
+ render: ({ field }) => {
12944
+ return /* @__PURE__ */ jsxRuntime.jsxs(Form$2.Item, { children: [
12945
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.Label, { children: "Sales Channel" }),
12946
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
12947
+ Combobox,
12948
+ {
12949
+ options: salesChannels.options,
12950
+ fetchNextPage: salesChannels.fetchNextPage,
12951
+ isFetchingNextPage: salesChannels.isFetchingNextPage,
12952
+ searchValue: salesChannels.searchValue,
12953
+ onSearchValueChange: salesChannels.onSearchValueChange,
12954
+ placeholder: "Select sales channel",
12955
+ ...field
12956
+ }
12957
+ ) }),
12958
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.ErrorMessage, {})
12959
+ ] });
12960
+ }
12961
+ }
12962
+ );
12963
+ };
12964
+ const schema$1 = objectType({
12965
+ sales_channel_id: stringType().min(1)
12966
+ });
12967
+ const Email = () => {
12968
+ const { id } = reactRouterDom.useParams();
12969
+ const { order, isPending, isError, error } = useOrder(id, {
12970
+ fields: "+email"
12971
+ });
12972
+ if (isError) {
12973
+ throw error;
12974
+ }
12975
+ const isReady = !isPending && !!order;
12976
+ return /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer, { children: [
12977
+ /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer.Header, { children: [
12978
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Edit Email" }) }),
12979
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Description, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Edit the email for the draft order" }) })
12980
+ ] }),
12981
+ isReady && /* @__PURE__ */ jsxRuntime.jsx(EmailForm, { order })
12982
+ ] });
12983
+ };
12984
+ const EmailForm = ({ order }) => {
12985
+ const form = reactHookForm.useForm({
12986
+ defaultValues: {
12987
+ email: order.email ?? ""
12988
+ },
12989
+ resolver: zod.zodResolver(schema)
12990
+ });
12991
+ const { mutateAsync, isPending } = useUpdateDraftOrder(order.id);
12992
+ const { handleSuccess } = useRouteModal();
12993
+ const onSubmit = form.handleSubmit(async (data) => {
12994
+ await mutateAsync(
12995
+ { email: data.email },
12996
+ {
12997
+ onSuccess: () => {
12998
+ handleSuccess();
12999
+ },
13000
+ onError: (error) => {
13001
+ ui.toast.error(error.message);
13002
+ }
13003
+ }
13004
+ );
13005
+ });
13006
+ return /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxRuntime.jsxs(
13007
+ KeyboundForm,
13008
+ {
13009
+ className: "flex flex-1 flex-col overflow-hidden",
13010
+ onSubmit,
13011
+ children: [
13012
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Body, { className: "flex flex-col gap-y-6 overflow-y-auto", children: /* @__PURE__ */ jsxRuntime.jsx(
13013
+ Form$2.Field,
13014
+ {
13015
+ control: form.control,
13016
+ name: "email",
13017
+ render: ({ field }) => /* @__PURE__ */ jsxRuntime.jsxs(Form$2.Item, { children: [
13018
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.Label, { children: "Email" }),
13019
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Input, { ...field }) }),
13020
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.ErrorMessage, {})
13021
+ ] })
13022
+ }
13023
+ ) }),
13024
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-2", children: [
13025
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
13026
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", type: "submit", isLoading: isPending, children: "Save" })
13027
+ ] }) })
13028
+ ]
13029
+ }
13030
+ ) });
13031
+ };
13032
+ const schema = objectType({
13033
+ email: stringType().email()
13034
+ });
13035
13035
  const widgetModule = { widgets: [] };
13036
13036
  const routeModule = {
13037
13037
  routes: [
@@ -13060,25 +13060,17 @@ const routeModule = {
13060
13060
  Component: CustomItems,
13061
13061
  path: "/draft-orders/:id/custom-items"
13062
13062
  },
13063
- {
13064
- Component: Items,
13065
- path: "/draft-orders/:id/items"
13066
- },
13067
- {
13068
- Component: Email,
13069
- path: "/draft-orders/:id/email"
13070
- },
13071
13063
  {
13072
13064
  Component: Metadata,
13073
13065
  path: "/draft-orders/:id/metadata"
13074
13066
  },
13075
13067
  {
13076
- Component: Promotions,
13077
- path: "/draft-orders/:id/promotions"
13068
+ Component: Items,
13069
+ path: "/draft-orders/:id/items"
13078
13070
  },
13079
13071
  {
13080
- Component: SalesChannel,
13081
- path: "/draft-orders/:id/sales-channel"
13072
+ Component: Promotions,
13073
+ path: "/draft-orders/:id/promotions"
13082
13074
  },
13083
13075
  {
13084
13076
  Component: Shipping,
@@ -13091,6 +13083,14 @@ const routeModule = {
13091
13083
  {
13092
13084
  Component: TransferOwnership,
13093
13085
  path: "/draft-orders/:id/transfer-ownership"
13086
+ },
13087
+ {
13088
+ Component: SalesChannel,
13089
+ path: "/draft-orders/:id/sales-channel"
13090
+ },
13091
+ {
13092
+ Component: Email,
13093
+ path: "/draft-orders/:id/email"
13094
13094
  }
13095
13095
  ]
13096
13096
  }