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

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.
@@ -9568,27 +9568,6 @@ const ID = () => {
9568
9568
  /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Outlet, {})
9569
9569
  ] });
9570
9570
  };
9571
- const CustomItems = () => {
9572
- return /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer, { children: [
9573
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Edit Custom Items" }) }) }),
9574
- /* @__PURE__ */ jsxRuntime.jsx(CustomItemsForm, {})
9575
- ] });
9576
- };
9577
- const CustomItemsForm = () => {
9578
- const form = reactHookForm.useForm({
9579
- resolver: zod.zodResolver(schema$5)
9580
- });
9581
- return /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxRuntime.jsxs(KeyboundForm, { className: "flex flex-1 flex-col", children: [
9582
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Body, {}),
9583
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-2", children: [
9584
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
9585
- /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", type: "submit", children: "Save" })
9586
- ] }) })
9587
- ] }) });
9588
- };
9589
- const schema$5 = objectType({
9590
- email: stringType().email()
9591
- });
9592
9571
  const BillingAddress = () => {
9593
9572
  const { id } = reactRouterDom.useParams();
9594
9573
  const { order, isPending, isError, error } = useOrder(id, {
@@ -9621,7 +9600,7 @@ const BillingAddressForm = ({ order }) => {
9621
9600
  postal_code: ((_i = order.billing_address) == null ? void 0 : _i.postal_code) ?? "",
9622
9601
  phone: ((_j = order.billing_address) == null ? void 0 : _j.phone) ?? ""
9623
9602
  },
9624
- resolver: zod.zodResolver(schema$4)
9603
+ resolver: zod.zodResolver(schema$5)
9625
9604
  });
9626
9605
  const { mutateAsync, isPending } = useUpdateDraftOrder(order.id);
9627
9606
  const { handleSuccess } = useRouteModal();
@@ -9778,7 +9757,28 @@ const BillingAddressForm = ({ order }) => {
9778
9757
  }
9779
9758
  ) });
9780
9759
  };
9781
- const schema$4 = addressSchema;
9760
+ const schema$5 = addressSchema;
9761
+ const CustomItems = () => {
9762
+ return /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer, { children: [
9763
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Edit Custom Items" }) }) }),
9764
+ /* @__PURE__ */ jsxRuntime.jsx(CustomItemsForm, {})
9765
+ ] });
9766
+ };
9767
+ const CustomItemsForm = () => {
9768
+ const form = reactHookForm.useForm({
9769
+ resolver: zod.zodResolver(schema$4)
9770
+ });
9771
+ return /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxRuntime.jsxs(KeyboundForm, { className: "flex flex-1 flex-col", children: [
9772
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Body, {}),
9773
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-2", children: [
9774
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
9775
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", type: "submit", children: "Save" })
9776
+ ] }) })
9777
+ ] }) });
9778
+ };
9779
+ const schema$4 = objectType({
9780
+ email: stringType().email()
9781
+ });
9782
9782
  const Email = () => {
9783
9783
  const { id } = reactRouterDom.useParams();
9784
9784
  const { order, isPending, isError, error } = useOrder(id, {
@@ -9847,1607 +9847,1607 @@ const EmailForm = ({ order }) => {
9847
9847
  const schema$3 = objectType({
9848
9848
  email: stringType().email()
9849
9849
  });
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
- };
9850
+ const InlineTip = React.forwardRef(
9851
+ ({ variant = "tip", label, className, children, ...props }, ref) => {
9852
+ const labelValue = label || (variant === "warning" ? "Warning" : "Tip");
9880
9853
  return /* @__PURE__ */ jsxRuntime.jsxs(
9881
9854
  "div",
9882
9855
  {
9856
+ ref,
9883
9857
  className: ui.clx(
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
- },
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",
9890
9859
  className
9891
9860
  ),
9861
+ ...props,
9892
9862
  children: [
9893
9863
  /* @__PURE__ */ jsxRuntime.jsx(
9894
- "input",
9895
- {
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
9909
- }
9910
- ),
9911
- /* @__PURE__ */ jsxRuntime.jsxs(
9912
- "button",
9864
+ "div",
9913
9865
  {
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
- ]
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
+ })
9931
9870
  }
9932
9871
  ),
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
- )
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
+ ] })
9955
9880
  ]
9956
9881
  }
9957
9882
  );
9958
9883
  }
9959
9884
  );
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 = () => {
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 = () => {
10026
9895
  const { id } = reactRouterDom.useParams();
10027
- const {
10028
- order: preview,
10029
- isPending: isPreviewPending,
10030
- isError: isPreviewError,
10031
- error: previewError
10032
- } = useOrderPreview(id, void 0, {
10033
- placeholderData: reactQuery.keepPreviousData
9896
+ const { order, isPending, isError, error } = useOrder(id, {
9897
+ fields: "metadata"
10034
9898
  });
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 });
10046
9899
  if (isError) {
10047
9900
  throw error;
10048
9901
  }
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
- ] }) });
10057
- };
10058
- const ItemsForm = ({ preview, currencyCode }) => {
10059
- var _a;
10060
- const [isSubmitting, setIsSubmitting] = React.useState(false);
10061
- const [modalContent, setModalContent] = React.useState(
10062
- null
10063
- );
10064
- const { handleSuccess } = useRouteModal();
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;
10083
- }
10084
- });
10085
- if (!requestSucceeded) {
10086
- setIsSubmitting(false);
10087
- return;
10088
- }
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
- }
10099
- });
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" }) })
10134
- ] }),
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: [
10155
- /* @__PURE__ */ jsxRuntime.jsx(
10156
- StackedModalTrigger$1,
10157
- {
10158
- type: "add-items",
10159
- setModalContent
10160
- }
10161
- ),
10162
- /* @__PURE__ */ jsxRuntime.jsx(
10163
- StackedModalTrigger$1,
10164
- {
10165
- type: "add-custom-item",
10166
- setModalContent
10167
- }
10168
- )
10169
- ] })
10170
- ] })
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
- }
10241
- )
10242
- ] }) })
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 })
10243
9909
  ] });
10244
9910
  };
10245
- const Item = ({ item, preview, currencyCode }) => {
10246
- if (item.variant_id) {
10247
- return /* @__PURE__ */ jsxRuntime.jsx(VariantItem, { item, preview, currencyCode });
10248
- }
10249
- return /* @__PURE__ */ jsxRuntime.jsx(CustomItem, { item, preview, currencyCode });
10250
- };
10251
- const VariantItem = ({ item, preview, currencyCode }) => {
10252
- const [editing, setEditing] = React.useState(false);
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 }) => {
9914
+ const { handleSuccess } = useRouteModal();
9915
+ const hasUneditableRows = getHasUneditableRows(metadata);
9916
+ const { mutateAsync, isPending } = useUpdateDraftOrder(orderId);
10253
9917
  const form = reactHookForm.useForm({
10254
9918
  defaultValues: {
10255
- quantity: item.quantity,
10256
- unit_price: item.unit_price
9919
+ metadata: getDefaultValues(metadata)
10257
9920
  },
10258
- resolver: zod.zodResolver(variantItemSchema)
9921
+ resolver: zod.zodResolver(MetadataSchema)
10259
9922
  });
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);
10270
- return;
10271
- }
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
- );
10288
- return;
10289
- }
10290
- await updateActionItem(
9923
+ const handleSubmit = form.handleSubmit(async (data) => {
9924
+ const parsedData = parseValues(data);
9925
+ await mutateAsync(
10291
9926
  {
10292
- action_id: actionId,
10293
- quantity: data.quantity,
10294
- unit_price: convertNumber(data.unit_price)
9927
+ metadata: parsedData
10295
9928
  },
10296
9929
  {
10297
9930
  onSuccess: () => {
10298
- setEditing(false);
9931
+ ui.toast.success("Metadata updated");
9932
+ handleSuccess();
10299
9933
  },
9934
+ onError: (error) => {
9935
+ ui.toast.error(error.message);
9936
+ }
9937
+ }
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
+ });
9952
+ }
9953
+ }
9954
+ function insertRow(index, position) {
9955
+ insert(index + (position === "above" ? 0 : 1), {
9956
+ key: "",
9957
+ value: "",
9958
+ disabled: false
9959
+ });
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" }) })
9972
+ ] }),
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: [
10036
+ /* @__PURE__ */ jsxRuntime.jsx(
10037
+ ui.DropdownMenu.Trigger,
10038
+ {
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, {}) })
10048
+ }
10049
+ ),
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
+ ] })
10086
+ ] })
10087
+ ] })
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
10113
+ )
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
+ ] }) })
10125
+ ] });
10126
+ };
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
+ ];
10137
+ }
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
+ };
10155
+ });
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) {
10169
+ return;
10170
+ }
10171
+ if (disabled) {
10172
+ update[key] = value;
10173
+ return;
10174
+ }
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);
10230
+ },
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, {
10255
+ onError: (e) => {
10256
+ ui.toast.error(e.message);
10257
+ navigate(`/draft-orders/${preview.id}`, { replace: true });
10258
+ return;
10259
+ }
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
+ ] });
10283
+ };
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
10294
+ },
10295
+ {
10296
+ enabled: !!promoIds.length
10297
+ }
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
10306
+ }
10307
+ });
10308
+ },
10309
+ getOptions: (data) => {
10310
+ return data.promotions.map((promotion) => ({
10311
+ label: promotion.code,
10312
+ value: promotion.code
10313
+ }));
10314
+ }
10315
+ });
10316
+ const add = async (value) => {
10317
+ if (!value) {
10318
+ return;
10319
+ }
10320
+ addPromotions(
10321
+ {
10322
+ promo_codes: [value]
10323
+ },
10324
+ {
10325
+ onError: (e) => {
10326
+ ui.toast.error(e.message);
10327
+ comboboxData.onSearchValueChange("");
10328
+ setComboboxValue("");
10329
+ },
10330
+ onSuccess: () => {
10331
+ comboboxData.onSearchValueChange("");
10332
+ setComboboxValue("");
10333
+ }
10334
+ }
10335
+ );
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;
10348
+ }
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);
10363
+ }
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
10399
+ },
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
+ ] });
10416
+ };
10417
+ const PromotionItem = ({
10418
+ promotion,
10419
+ orderId,
10420
+ isLoading
10421
+ }) => {
10422
+ var _a;
10423
+ const { mutateAsync: removePromotions, isPending } = useDraftOrderRemovePromotions(orderId);
10424
+ const onRemove = async () => {
10425
+ removePromotions(
10426
+ {
10427
+ promo_codes: [promotion.code]
10428
+ },
10429
+ {
10300
10430
  onError: (e) => {
10301
10431
  ui.toast.error(e.message);
10302
10432
  }
10303
10433
  }
10304
10434
  );
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,
10435
+ };
10436
+ const displayValue = getDisplayValue(promotion);
10437
+ return /* @__PURE__ */ jsxRuntime.jsxs(
10438
+ "div",
10439
+ {
10440
+ className: ui.clx(
10441
+ "bg-ui-bg-component shadow-elevation-card-rest flex items-center justify-between rounded-lg px-3 py-2",
10310
10442
  {
10311
- thumbnail: item.thumbnail,
10312
- alt: item.product_title ?? void 0
10443
+ "animate-pulse": isLoading
10313
10444
  }
10314
10445
  ),
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
- )
10446
+ 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
+ ] })
10331
10456
  ] }),
10332
10457
  /* @__PURE__ */ jsxRuntime.jsx(
10333
- ui.Text,
10458
+ ui.IconButton,
10334
10459
  {
10335
10460
  size: "small",
10336
- leading: "compact",
10337
- className: "text-ui-fg-subtle",
10338
- children: item.variant_sku
10461
+ type: "button",
10462
+ variant: "transparent",
10463
+ onClick: onRemove,
10464
+ isLoading: isPending || isLoading,
10465
+ children: /* @__PURE__ */ jsxRuntime.jsx(icons.XMark, {})
10339
10466
  }
10340
10467
  )
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
- ] }) }) });
10384
- };
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
10468
+ ]
10397
10469
  },
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;
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;
10419
10483
  }
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
- }
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);
10500
+ };
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);
10434
10508
  }
10435
- );
10436
- return;
10509
+ }
10437
10510
  }
10438
- if (data.quantity === 0) {
10439
- await removeActionItem(actionId, {
10440
- onSuccess: () => {
10441
- setEditing(false);
10442
- },
10443
- onError: (e) => {
10444
- ui.toast.error(e.message);
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);
10445
10517
  }
10446
- });
10447
- return;
10518
+ }
10448
10519
  }
10449
- await updateActionItem(
10450
- {
10451
- action_id: actionId,
10452
- quantity: data.quantity,
10453
- unit_price: convertNumber(data.unit_price)
10454
- },
10455
- {
10456
- onSuccess: () => {
10457
- setEditing(false);
10458
- },
10459
- onError: (e) => {
10460
- ui.toast.error(e.message);
10461
- }
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);
10462
10539
  }
10463
- );
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
- }
10540
+ };
10541
+ const handleIncrement = () => {
10542
+ const newValue = value + step;
10543
+ if (max === void 0 || newValue <= max) {
10544
+ onChange(newValue);
10493
10545
  }
10494
- ) : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: item.quantity }),
10495
- editing ? /* @__PURE__ */ jsxRuntime.jsx(
10496
- Form$2.Field,
10546
+ };
10547
+ const handleDecrement = () => {
10548
+ const newValue = value - step;
10549
+ if (min === void 0 || newValue >= min) {
10550
+ onChange(newValue);
10551
+ }
10552
+ };
10553
+ return /* @__PURE__ */ jsxRuntime.jsxs(
10554
+ "div",
10497
10555
  {
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,
10556
+ 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
+ },
10563
+ className
10564
+ ),
10565
+ children: [
10566
+ /* @__PURE__ */ jsxRuntime.jsx(
10567
+ "input",
10503
10568
  {
10504
- ...field,
10505
- symbol: getNativeSymbol(currencyCode),
10506
- code: currencyCode,
10507
- onValueChange: (_value, _name, values) => onChange(values == null ? void 0 : values.value)
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
10508
10582
  }
10509
- ) }) });
10510
- }
10511
- }
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);
10520
- },
10521
- disabled: isPending,
10522
- children: editing ? /* @__PURE__ */ jsxRuntime.jsx(icons.Check, {}) : /* @__PURE__ */ jsxRuntime.jsx(icons.PencilSquare, {})
10583
+ ),
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
+ )
10628
+ ]
10523
10629
  }
10524
- )
10525
- ] }) }) });
10526
- };
10527
- const StackedModalTrigger$1 = ({
10528
- type,
10529
- setModalContent
10530
- }) => {
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
10630
  );
10557
- }, [items]);
10558
- const { q, order, offset } = useQueryParams(
10559
- ["q", "order", "offset"],
10560
- VARIANT_PREFIX
10561
- );
10562
- const { variants, count, isPending, isError, error } = useProductVariants(
10631
+ }
10632
+ );
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 = () => {
10653
+ 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
10661
+ });
10662
+ useInitiateOrderEdit({ preview });
10663
+ const { draft_order, isPending, isError, error } = useDraftOrder(
10664
+ id,
10563
10665
  {
10564
- q,
10565
- order,
10566
- offset: offset ? parseInt(offset) : void 0,
10567
- limit: LIMIT
10666
+ fields: "currency_code"
10568
10667
  },
10569
10668
  {
10570
- placeholderData: reactQuery.keepPreviousData
10669
+ enabled: !!id
10571
10670
  }
10572
10671
  );
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(
10580
- {
10581
- items: ids.map((id) => ({
10582
- variant_id: id,
10583
- quantity: 1
10584
- }))
10585
- },
10586
- {
10587
- onSuccess: () => {
10588
- setRowSelection({});
10589
- setIsOpen(STACKED_MODAL_ID, false);
10590
- },
10591
- onError: (e) => {
10592
- ui.toast.error(e.message);
10593
- }
10594
- }
10595
- );
10596
- };
10672
+ const { onCancel } = useCancelOrderEdit({ preview });
10597
10673
  if (isError) {
10598
10674
  throw error;
10599
10675
  }
10600
- return /* @__PURE__ */ jsxRuntime.jsxs(
10601
- StackedFocusModal.Content,
10602
- {
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();
10610
- }
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
+ ] }) });
10684
+ };
10685
+ const ItemsForm = ({ preview, currencyCode }) => {
10686
+ var _a;
10687
+ const [isSubmitting, setIsSubmitting] = React.useState(false);
10688
+ const [modalContent, setModalContent] = React.useState(
10689
+ null
10690
+ );
10691
+ 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}`);
10611
10707
  },
10612
- children: [
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." }) })
10616
- ] }),
10617
- /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Body, { className: "flex-1 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
10618
- DataTable,
10619
- {
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
10635
- }
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
- ] }) })
10641
- ]
10708
+ onSuccess: () => {
10709
+ requestSucceeded = true;
10710
+ }
10711
+ });
10712
+ if (!requestSucceeded) {
10713
+ setIsSubmitting(false);
10714
+ return;
10642
10715
  }
10643
- );
10644
- };
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: ""
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
+ }
10726
+ });
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
+ }
10719
10736
  },
10720
- resolver: zod.zodResolver(customItemSchema)
10721
- });
10722
- const onSubmit = form.handleSubmit(async (data) => {
10723
- await addItems(
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,
10724
10749
  {
10725
- items: [
10726
- {
10727
- title: data.title,
10728
- quantity: data.quantity,
10729
- unit_price: convertNumber(data.unit_price)
10750
+ id: STACKED_MODAL_ID,
10751
+ onOpenChangeCallback: (open) => {
10752
+ if (!open) {
10753
+ setModalContent(null);
10730
10754
  }
10731
- ]
10732
- },
10733
- {
10734
- onSuccess: () => {
10735
- setIsOpen(STACKED_MODAL_ID, false);
10736
10755
  },
10737
- onError: (e) => {
10738
- ui.toast.error(e.message);
10739
- }
10740
- }
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: [
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: [
10757
10758
  /* @__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" })
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" }) })
10760
10761
  ] }),
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
- ] }) })
10766
- }
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" })
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: [
10782
+ /* @__PURE__ */ jsxRuntime.jsx(
10783
+ StackedModalTrigger$1,
10784
+ {
10785
+ type: "add-items",
10786
+ setModalContent
10787
+ }
10788
+ ),
10789
+ /* @__PURE__ */ jsxRuntime.jsx(
10790
+ StackedModalTrigger$1,
10791
+ {
10792
+ type: "add-custom-item",
10793
+ setModalContent
10794
+ }
10795
+ )
10796
+ ] })
10797
+ ] })
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
+ ] })
10778
10827
  ] }),
10779
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
10780
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
10781
- ui.CurrencyInput,
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,
10782
10833
  {
10783
- symbol: getNativeSymbol(currencyCode),
10784
- code: currencyCode,
10785
- onValueChange: (_value, _name, values) => onChange(values == null ? void 0 : values.value),
10786
- ...field
10834
+ size: "small",
10835
+ leading: "compact",
10836
+ className: "text-ui-fg-subtle",
10837
+ children: [
10838
+ itemCount,
10839
+ " ",
10840
+ itemCount === 1 ? "item" : "items"
10841
+ ]
10787
10842
  }
10788
10843
  ) }),
10789
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.ErrorMessage, {})
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) }) })
10790
10845
  ] })
10791
- ] }) })
10792
- }
10793
- ),
10794
- /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { variant: "dashed" }),
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" }) }),
10795
10859
  /* @__PURE__ */ jsxRuntime.jsx(
10796
- Form$2.Field,
10860
+ ui.Button,
10797
10861
  {
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
- ] }) })
10862
+ size: "small",
10863
+ type: "button",
10864
+ onClick: onSubmit,
10865
+ isLoading: isSubmitting,
10866
+ children: "Save"
10810
10867
  }
10811
10868
  )
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
10869
  ] }) })
10817
- ] }) }) });
10870
+ ] });
10818
10871
  };
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");
10827
- return /* @__PURE__ */ jsxRuntime.jsxs(
10828
- "div",
10829
- {
10830
- ref,
10831
- className: ui.clx(
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",
10833
- className
10834
- ),
10835
- ...props,
10836
- children: [
10837
- /* @__PURE__ */ jsxRuntime.jsx(
10838
- "div",
10839
- {
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
- })
10844
- }
10845
- ),
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
- ] })
10854
- ]
10855
- }
10856
- );
10857
- }
10858
- );
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 = () => {
10869
- const { id } = reactRouterDom.useParams();
10870
- const { order, isPending, isError, error } = useOrder(id, {
10871
- fields: "metadata"
10872
- });
10873
- if (isError) {
10874
- throw error;
10872
+ const Item = ({ item, preview, currencyCode }) => {
10873
+ if (item.variant_id) {
10874
+ return /* @__PURE__ */ jsxRuntime.jsx(VariantItem, { item, preview, currencyCode });
10875
10875
  }
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
- ] });
10876
+ return /* @__PURE__ */ jsxRuntime.jsx(CustomItem, { item, preview, currencyCode });
10884
10877
  };
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 }) => {
10888
- const { handleSuccess } = useRouteModal();
10889
- const hasUneditableRows = getHasUneditableRows(metadata);
10890
- const { mutateAsync, isPending } = useUpdateDraftOrder(orderId);
10878
+ const VariantItem = ({ item, preview, currencyCode }) => {
10879
+ const [editing, setEditing] = React.useState(false);
10891
10880
  const form = reactHookForm.useForm({
10892
10881
  defaultValues: {
10893
- metadata: getDefaultValues(metadata)
10882
+ quantity: item.quantity,
10883
+ unit_price: item.unit_price
10894
10884
  },
10895
- resolver: zod.zodResolver(MetadataSchema)
10885
+ resolver: zod.zodResolver(variantItemSchema)
10896
10886
  });
10897
- const handleSubmit = form.handleSubmit(async (data) => {
10898
- const parsedData = parseValues(data);
10899
- await mutateAsync(
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;
10898
+ }
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;
10916
+ }
10917
+ await updateActionItem(
10900
10918
  {
10901
- metadata: parsedData
10919
+ action_id: actionId,
10920
+ quantity: data.quantity,
10921
+ unit_price: convertNumber(data.unit_price)
10902
10922
  },
10903
10923
  {
10904
10924
  onSuccess: () => {
10905
- ui.toast.success("Metadata updated");
10906
- handleSuccess();
10925
+ setEditing(false);
10907
10926
  },
10908
- onError: (error) => {
10909
- ui.toast.error(error.message);
10927
+ onError: (e) => {
10928
+ ui.toast.error(e.message);
10910
10929
  }
10911
10930
  }
10912
10931
  );
10913
10932
  });
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
- });
10926
- }
10927
- }
10928
- function insertRow(index, position) {
10929
- insert(index + (position === "above" ? 0 : 1), {
10930
- key: "",
10931
- value: "",
10932
- disabled: false
10933
- });
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" }) })
10946
- ] }),
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: [
11010
- /* @__PURE__ */ jsxRuntime.jsx(
11011
- ui.DropdownMenu.Trigger,
11012
- {
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, {}) })
11022
- }
11023
- ),
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
- ] })
11060
- ] })
11061
- ] })
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
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" })
11098
- ] }) })
11099
- ] });
11100
- };
11101
- const EDITABLE_TYPES = ["string", "number", "boolean"];
11102
- function getDefaultValues(metadata) {
11103
- if (!metadata || !Object.keys(metadata).length) {
11104
- return [
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,
11105
10972
  {
11106
- key: "",
11107
- value: "",
11108
- disabled: false
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
+ }
11109
10978
  }
11110
- ];
11111
- }
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
- };
11119
- }
11120
- let stringValue = value;
11121
- if (typeof value !== "string") {
11122
- stringValue = JSON.stringify(value);
11123
- }
11124
- return {
11125
- key,
11126
- value: stringValue,
11127
- original_key: key
11128
- };
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)
11129
11026
  });
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) {
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);
11143
11045
  return;
11144
11046
  }
11145
- if (disabled) {
11146
- update[key] = value;
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
+ );
11147
11063
  return;
11148
11064
  }
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;
11161
- }
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
+ });
11074
+ return;
11162
11075
  }
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
+ }
11089
+ }
11090
+ );
11163
11091
  });
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
- ]
11185
- };
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 };
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
+ ] }) }) });
11193
11153
  };
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
- ] });
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" }) });
11211
11164
  };
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(
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(
11220
11190
  {
11221
- id: promoIds
11191
+ q,
11192
+ order,
11193
+ offset: offset ? parseInt(offset) : void 0,
11194
+ limit: LIMIT
11222
11195
  },
11223
11196
  {
11224
- enabled: !!promoIds.length
11197
+ placeholderData: reactQuery.keepPreviousData
11225
11198
  }
11226
11199
  );
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(
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(
11249
11207
  {
11250
- promo_codes: [value]
11208
+ items: ids.map((id) => ({
11209
+ variant_id: id,
11210
+ quantity: 1
11211
+ }))
11251
11212
  },
11252
11213
  {
11214
+ onSuccess: () => {
11215
+ setRowSelection({});
11216
+ setIsOpen(STACKED_MODAL_ID, false);
11217
+ },
11253
11218
  onError: (e) => {
11254
11219
  ui.toast.error(e.message);
11255
- comboboxData.onSearchValueChange("");
11256
- setComboboxValue("");
11257
- },
11258
- onSuccess: () => {
11259
- comboboxData.onSearchValueChange("");
11260
- setComboboxValue("");
11261
11220
  }
11262
11221
  }
11263
11222
  );
11264
11223
  };
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);
11273
- },
11274
- onSuccess: () => {
11275
- requestSucceeded = true;
11276
- }
11277
- });
11278
- if (!requestSucceeded) {
11279
- setIsSubmitting(false);
11280
- return;
11281
- }
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
11224
  if (isError) {
11295
11225
  throw error;
11296
11226
  }
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." })
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
+ }
11238
+ },
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." }) })
11303
11243
  ] }),
11304
- /* @__PURE__ */ jsxRuntime.jsx(
11305
- Combobox,
11244
+ /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Body, { className: "flex-1 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
11245
+ DataTable,
11306
11246
  {
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
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
11317
11262
  }
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
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
+ ]
11269
+ }
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
+ );
11327
11315
  },
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
- ] });
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
+ );
11330
+ },
11331
+ enableSorting: true,
11332
+ sortAscLabel: "Oldest first",
11333
+ sortDescLabel: "Newest first"
11334
+ })
11335
+ ];
11336
+ }, []);
11344
11337
  };
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(
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(
11354
11351
  {
11355
- promo_codes: [promotion.code]
11352
+ items: [
11353
+ {
11354
+ title: data.title,
11355
+ quantity: data.quantity,
11356
+ unit_price: convertNumber(data.unit_price)
11357
+ }
11358
+ ]
11356
11359
  },
11357
11360
  {
11361
+ onSuccess: () => {
11362
+ setIsOpen(STACKED_MODAL_ID, false);
11363
+ },
11358
11364
  onError: (e) => {
11359
11365
  ui.toast.error(e.message);
11360
11366
  }
11361
11367
  }
11362
11368
  );
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",
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,
11370
11380
  {
11371
- "animate-pulse": isLoading
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
+ ] }) })
11372
11393
  }
11373
11394
  ),
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: "·" })
11395
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { variant: "dashed" }),
11396
+ /* @__PURE__ */ jsxRuntime.jsx(
11397
+ Form$2.Field,
11398
+ {
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" })
11381
11405
  ] }),
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
- );
11400
- };
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
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);
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
+ ] }) })
11436
11419
  }
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);
11420
+ ),
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" })
11431
+ ] }),
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
+ ] }) })
11445
11437
  }
11446
- }
11447
- }
11448
- }
11449
- return Array.from(promotionIds);
11450
- }
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
+ ] }) }) });
11445
+ };
11446
+ const customItemSchema = objectType({
11447
+ title: stringType().min(1),
11448
+ quantity: numberType(),
11449
+ unit_price: unionType([numberType(), stringType()])
11450
+ });
11451
11451
  const SalesChannel = () => {
11452
11452
  const { id } = reactRouterDom.useParams();
11453
11453
  const { draft_order, isPending, isError, error } = useDraftOrder(
@@ -13060,21 +13060,17 @@ const routeModule = {
13060
13060
  handle,
13061
13061
  loader,
13062
13062
  children: [
13063
- {
13064
- Component: CustomItems,
13065
- path: "/draft-orders/:id/custom-items"
13066
- },
13067
13063
  {
13068
13064
  Component: BillingAddress,
13069
13065
  path: "/draft-orders/:id/billing-address"
13070
13066
  },
13071
13067
  {
13072
- Component: Email,
13073
- path: "/draft-orders/:id/email"
13068
+ Component: CustomItems,
13069
+ path: "/draft-orders/:id/custom-items"
13074
13070
  },
13075
13071
  {
13076
- Component: Items,
13077
- path: "/draft-orders/:id/items"
13072
+ Component: Email,
13073
+ path: "/draft-orders/:id/email"
13078
13074
  },
13079
13075
  {
13080
13076
  Component: Metadata,
@@ -13084,6 +13080,10 @@ const routeModule = {
13084
13080
  Component: Promotions,
13085
13081
  path: "/draft-orders/:id/promotions"
13086
13082
  },
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"