@medusajs/draft-order 2.11.4-preview-20251106090134 → 2.11.4-preview-20251106150143

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