@medusajs/draft-order 2.10.4-snapshot-20250918173105 → 2.10.4-snapshot-20250922062130

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