@medusajs/draft-order 2.13.3 → 2.13.4-preview-20260301000326

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