@medusajs/draft-order 2.11.1-snapshot-20251021090705 → 2.11.1-snapshot-20251021112110

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