@medusajs/draft-order 3.0.0-preview-20251214150138 → 3.0.0-preview-20251214180138

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