@medusajs/draft-order 2.11.1-snapshot-20251021115115 → 2.11.1-snapshot-20251021125705

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.
@@ -9761,27 +9761,6 @@ const BillingAddressForm = ({ order }) => {
9761
9761
  ) });
9762
9762
  };
9763
9763
  const schema$5 = addressSchema;
9764
- const CustomItems = () => {
9765
- return /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer, { children: [
9766
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Edit Custom Items" }) }) }),
9767
- /* @__PURE__ */ jsxRuntime.jsx(CustomItemsForm, {})
9768
- ] });
9769
- };
9770
- const CustomItemsForm = () => {
9771
- const form = reactHookForm.useForm({
9772
- resolver: zod.zodResolver(schema$4)
9773
- });
9774
- return /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxRuntime.jsxs(KeyboundForm, { className: "flex flex-1 flex-col", children: [
9775
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Body, {}),
9776
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-2", children: [
9777
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
9778
- /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", type: "submit", children: "Save" })
9779
- ] }) })
9780
- ] }) });
9781
- };
9782
- const schema$4 = objectType({
9783
- email: stringType().email()
9784
- });
9785
9764
  const Email = () => {
9786
9765
  const { id } = reactRouterDom.useParams();
9787
9766
  const { order, isPending, isError, error } = useOrder(id, {
@@ -9804,7 +9783,7 @@ const EmailForm = ({ order }) => {
9804
9783
  defaultValues: {
9805
9784
  email: order.email ?? ""
9806
9785
  },
9807
- resolver: zod.zodResolver(schema$3)
9786
+ resolver: zod.zodResolver(schema$4)
9808
9787
  });
9809
9788
  const { mutateAsync, isPending } = useUpdateDraftOrder(order.id);
9810
9789
  const { handleSuccess } = useRouteModal();
@@ -9847,1432 +9826,883 @@ const EmailForm = ({ order }) => {
9847
9826
  }
9848
9827
  ) });
9849
9828
  };
9829
+ const schema$4 = objectType({
9830
+ email: stringType().email()
9831
+ });
9832
+ const CustomItems = () => {
9833
+ return /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer, { children: [
9834
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Edit Custom Items" }) }) }),
9835
+ /* @__PURE__ */ jsxRuntime.jsx(CustomItemsForm, {})
9836
+ ] });
9837
+ };
9838
+ const CustomItemsForm = () => {
9839
+ const form = reactHookForm.useForm({
9840
+ resolver: zod.zodResolver(schema$3)
9841
+ });
9842
+ return /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxRuntime.jsxs(KeyboundForm, { className: "flex flex-1 flex-col", children: [
9843
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Body, {}),
9844
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-2", children: [
9845
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
9846
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", type: "submit", children: "Save" })
9847
+ ] }) })
9848
+ ] }) });
9849
+ };
9850
9850
  const schema$3 = objectType({
9851
9851
  email: stringType().email()
9852
9852
  });
9853
- const NumberInput = React.forwardRef(
9854
- ({
9855
- value,
9856
- onChange,
9857
- size = "base",
9858
- min = 0,
9859
- max = 100,
9860
- step = 1,
9861
- className,
9862
- disabled,
9863
- ...props
9864
- }, ref) => {
9865
- const handleChange = (event) => {
9866
- const newValue = event.target.value === "" ? min : Number(event.target.value);
9867
- if (!isNaN(newValue) && (max === void 0 || newValue <= max) && (min === void 0 || newValue >= min)) {
9868
- onChange(newValue);
9869
- }
9870
- };
9871
- const handleIncrement = () => {
9872
- const newValue = value + step;
9873
- if (max === void 0 || newValue <= max) {
9874
- onChange(newValue);
9875
- }
9876
- };
9877
- const handleDecrement = () => {
9878
- const newValue = value - step;
9879
- if (min === void 0 || newValue >= min) {
9880
- onChange(newValue);
9881
- }
9882
- };
9853
+ const InlineTip = React.forwardRef(
9854
+ ({ variant = "tip", label, className, children, ...props }, ref) => {
9855
+ const labelValue = label || (variant === "warning" ? "Warning" : "Tip");
9883
9856
  return /* @__PURE__ */ jsxRuntime.jsxs(
9884
9857
  "div",
9885
9858
  {
9859
+ ref,
9886
9860
  className: ui.clx(
9887
- "inline-flex rounded-md bg-ui-bg-field shadow-borders-base overflow-hidden divide-x transition-fg",
9888
- "[&:has(input:focus)]:shadow-borders-interactive-with-active",
9889
- {
9890
- "h-7": size === "small",
9891
- "h-8": size === "base"
9892
- },
9861
+ "bg-ui-bg-component txt-small text-ui-fg-subtle grid grid-cols-[4px_1fr] items-start gap-3 rounded-lg border p-3",
9893
9862
  className
9894
9863
  ),
9864
+ ...props,
9895
9865
  children: [
9896
9866
  /* @__PURE__ */ jsxRuntime.jsx(
9897
- "input",
9898
- {
9899
- ref,
9900
- type: "number",
9901
- value,
9902
- onChange: handleChange,
9903
- min,
9904
- max,
9905
- step,
9906
- className: ui.clx(
9907
- "flex-1 px-2 py-1 bg-transparent txt-compact-small text-ui-fg-base outline-none [appearance:textfield]",
9908
- "[&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none",
9909
- "placeholder:text-ui-fg-muted"
9910
- ),
9911
- ...props
9912
- }
9913
- ),
9914
- /* @__PURE__ */ jsxRuntime.jsxs(
9915
- "button",
9867
+ "div",
9916
9868
  {
9917
- className: ui.clx(
9918
- "flex items-center justify-center outline-none transition-fg",
9919
- "disabled:cursor-not-allowed disabled:text-ui-fg-muted",
9920
- "focus:bg-ui-bg-field-component-hover",
9921
- "hover:bg-ui-bg-field-component-hover",
9922
- {
9923
- "size-7": size === "small",
9924
- "size-8": size === "base"
9925
- }
9926
- ),
9927
- type: "button",
9928
- onClick: handleDecrement,
9929
- disabled: min !== void 0 && value <= min || disabled,
9930
- children: [
9931
- /* @__PURE__ */ jsxRuntime.jsx(icons.Minus, {}),
9932
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: `Decrease by ${step}` })
9933
- ]
9869
+ role: "presentation",
9870
+ className: ui.clx("w-4px bg-ui-tag-neutral-icon h-full rounded-full", {
9871
+ "bg-ui-tag-orange-icon": variant === "warning"
9872
+ })
9934
9873
  }
9935
9874
  ),
9936
- /* @__PURE__ */ jsxRuntime.jsxs(
9937
- "button",
9938
- {
9939
- className: ui.clx(
9940
- "flex items-center justify-center outline-none transition-fg",
9941
- "disabled:cursor-not-allowed disabled:text-ui-fg-muted",
9942
- "focus:bg-ui-bg-field-hover",
9943
- "hover:bg-ui-bg-field-hover",
9944
- {
9945
- "size-7": size === "small",
9946
- "size-8": size === "base"
9947
- }
9948
- ),
9949
- type: "button",
9950
- onClick: handleIncrement,
9951
- disabled: max !== void 0 && value >= max || disabled,
9952
- children: [
9953
- /* @__PURE__ */ jsxRuntime.jsx(icons.Plus, {}),
9954
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: `Increase by ${step}` })
9955
- ]
9956
- }
9957
- )
9875
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-pretty", children: [
9876
+ /* @__PURE__ */ jsxRuntime.jsxs("strong", { className: "txt-small-plus text-ui-fg-base", children: [
9877
+ labelValue,
9878
+ ":"
9879
+ ] }),
9880
+ " ",
9881
+ children
9882
+ ] })
9958
9883
  ]
9959
9884
  }
9960
9885
  );
9961
9886
  }
9962
9887
  );
9963
- const PRODUCT_VARIANTS_QUERY_KEY = "product-variants";
9964
- const productVariantsQueryKeys = {
9965
- list: (query2) => [
9966
- PRODUCT_VARIANTS_QUERY_KEY,
9967
- query2 ? query2 : void 0
9968
- ]
9969
- };
9970
- const useProductVariants = (query2, options) => {
9971
- const { data, ...rest } = reactQuery.useQuery({
9972
- queryKey: productVariantsQueryKeys.list(query2),
9973
- queryFn: async () => await sdk.admin.productVariant.list(query2),
9974
- ...options
9975
- });
9976
- return { ...data, ...rest };
9977
- };
9978
- const useCancelOrderEdit = ({ preview }) => {
9979
- const { mutateAsync: cancelOrderEdit } = useDraftOrderCancelEdit(preview == null ? void 0 : preview.id);
9980
- const onCancel = React.useCallback(async () => {
9981
- if (!preview) {
9982
- return true;
9983
- }
9984
- let res = false;
9985
- await cancelOrderEdit(void 0, {
9986
- onError: (e) => {
9987
- ui.toast.error(e.message);
9988
- },
9989
- onSuccess: () => {
9990
- res = true;
9991
- }
9992
- });
9993
- return res;
9994
- }, [preview, cancelOrderEdit]);
9995
- return { onCancel };
9996
- };
9997
- let IS_REQUEST_RUNNING = false;
9998
- const useInitiateOrderEdit = ({
9999
- preview
10000
- }) => {
10001
- const navigate = reactRouterDom.useNavigate();
10002
- const { mutateAsync } = useDraftOrderBeginEdit(preview == null ? void 0 : preview.id);
10003
- React.useEffect(() => {
10004
- async function run() {
10005
- if (IS_REQUEST_RUNNING || !preview) {
10006
- return;
10007
- }
10008
- if (preview.order_change) {
10009
- return;
10010
- }
10011
- IS_REQUEST_RUNNING = true;
10012
- await mutateAsync(void 0, {
10013
- onError: (e) => {
10014
- ui.toast.error(e.message);
10015
- navigate(`/draft-orders/${preview.id}`, { replace: true });
10016
- return;
10017
- }
10018
- });
10019
- IS_REQUEST_RUNNING = false;
10020
- }
10021
- run();
10022
- }, [preview, navigate, mutateAsync]);
10023
- };
10024
- function convertNumber(value) {
10025
- return typeof value === "string" ? Number(value.replace(",", ".")) : value;
10026
- }
10027
- const STACKED_MODAL_ID = "items_stacked_modal";
10028
- const Items = () => {
9888
+ InlineTip.displayName = "InlineTip";
9889
+ const MetadataFieldSchema = objectType({
9890
+ key: stringType(),
9891
+ disabled: booleanType().optional(),
9892
+ value: anyType()
9893
+ });
9894
+ const MetadataSchema = objectType({
9895
+ metadata: arrayType(MetadataFieldSchema)
9896
+ });
9897
+ const Metadata = () => {
10029
9898
  const { id } = reactRouterDom.useParams();
10030
- const {
10031
- order: preview,
10032
- isPending: isPreviewPending,
10033
- isError: isPreviewError,
10034
- error: previewError
10035
- } = useOrderPreview(id, void 0, {
10036
- placeholderData: reactQuery.keepPreviousData
9899
+ const { order, isPending, isError, error } = useOrder(id, {
9900
+ fields: "metadata"
10037
9901
  });
10038
- useInitiateOrderEdit({ preview });
10039
- const { draft_order, isPending, isError, error } = useDraftOrder(
10040
- id,
10041
- {
10042
- fields: "currency_code"
10043
- },
10044
- {
10045
- enabled: !!id
10046
- }
10047
- );
10048
- const { onCancel } = useCancelOrderEdit({ preview });
10049
9902
  if (isError) {
10050
9903
  throw error;
10051
9904
  }
10052
- if (isPreviewError) {
10053
- throw previewError;
10054
- }
10055
- const ready = !!preview && !isPreviewPending && !!draft_order && !isPending;
10056
- return /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal, { onClose: onCancel, children: ready ? /* @__PURE__ */ jsxRuntime.jsx(ItemsForm, { preview, currencyCode: draft_order.currency_code }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
10057
- /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Edit Items" }) }),
10058
- /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Loading data for the draft order, please wait..." }) })
10059
- ] }) });
10060
- };
10061
- const ItemsForm = ({ preview, currencyCode }) => {
10062
- var _a;
10063
- const [isSubmitting, setIsSubmitting] = React.useState(false);
10064
- const [modalContent, setModalContent] = React.useState(
10065
- null
10066
- );
10067
- const { handleSuccess } = useRouteModal();
10068
- const { searchValue, onSearchValueChange, query: query2 } = useDebouncedSearch();
10069
- const { mutateAsync: confirmOrderEdit } = useDraftOrderConfirmEdit(preview.id);
10070
- const { mutateAsync: requestOrderEdit } = useDraftOrderRequestEdit(preview.id);
10071
- const itemCount = ((_a = preview.items) == null ? void 0 : _a.reduce((acc, item) => acc + item.quantity, 0)) || 0;
10072
- const matches = React.useMemo(() => {
10073
- return matchSorter.matchSorter(preview.items, query2, {
10074
- keys: ["product_title", "variant_title", "variant_sku", "title"]
10075
- });
10076
- }, [preview.items, query2]);
10077
- const onSubmit = async () => {
10078
- setIsSubmitting(true);
10079
- let requestSucceeded = false;
10080
- await requestOrderEdit(void 0, {
10081
- onError: (e) => {
10082
- ui.toast.error(`Failed to request order edit: ${e.message}`);
10083
- },
10084
- onSuccess: () => {
10085
- requestSucceeded = true;
10086
- }
10087
- });
10088
- if (!requestSucceeded) {
10089
- setIsSubmitting(false);
10090
- return;
10091
- }
10092
- await confirmOrderEdit(void 0, {
10093
- onError: (e) => {
10094
- ui.toast.error(`Failed to confirm order edit: ${e.message}`);
10095
- },
10096
- onSuccess: () => {
10097
- handleSuccess();
10098
- },
10099
- onSettled: () => {
10100
- setIsSubmitting(false);
10101
- }
10102
- });
10103
- };
10104
- const onKeyDown = React.useCallback(
10105
- (e) => {
10106
- if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) {
10107
- if (modalContent || isSubmitting) {
10108
- return;
10109
- }
10110
- onSubmit();
10111
- }
10112
- },
10113
- [modalContent, isSubmitting, onSubmit]
10114
- );
10115
- React.useEffect(() => {
10116
- document.addEventListener("keydown", onKeyDown);
10117
- return () => {
10118
- document.removeEventListener("keydown", onKeyDown);
10119
- };
10120
- }, [onKeyDown]);
10121
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-full flex-col overflow-hidden", children: [
10122
- /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Header, {}),
10123
- /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Body, { className: "flex flex-1 flex-col overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsxs(
10124
- StackedFocusModal,
10125
- {
10126
- id: STACKED_MODAL_ID,
10127
- onOpenChangeCallback: (open) => {
10128
- if (!open) {
10129
- setModalContent(null);
10130
- }
10131
- },
10132
- children: [
10133
- /* @__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: [
10134
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
10135
- /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Edit Items" }) }),
10136
- /* @__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" }) })
10137
- ] }),
10138
- /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { variant: "dashed" }),
10139
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-6", children: [
10140
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 items-center gap-3", children: [
10141
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
10142
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", leading: "compact", children: "Items" }),
10143
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Choose items from the product catalog." })
10144
- ] }),
10145
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
10146
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(
10147
- ui.Input,
10148
- {
10149
- type: "search",
10150
- placeholder: "Search items",
10151
- value: searchValue,
10152
- onChange: (e) => onSearchValueChange(e.target.value)
10153
- }
10154
- ) }),
10155
- /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu, { children: [
10156
- /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenu.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { type: "button", children: /* @__PURE__ */ jsxRuntime.jsx(icons.Plus, {}) }) }),
10157
- /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu.Content, { children: [
10158
- /* @__PURE__ */ jsxRuntime.jsx(
10159
- StackedModalTrigger$1,
10160
- {
10161
- type: "add-items",
10162
- setModalContent
10163
- }
10164
- ),
10165
- /* @__PURE__ */ jsxRuntime.jsx(
10166
- StackedModalTrigger$1,
10167
- {
10168
- type: "add-custom-item",
10169
- setModalContent
10170
- }
10171
- )
10172
- ] })
10173
- ] })
10174
- ] })
10175
- ] }),
10176
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-subtle shadow-elevation-card-rest rounded-xl", children: [
10177
- /* @__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: [
10178
- /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: "Item" }) }),
10179
- /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: "Quantity" }) }),
10180
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-right", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: "Price" }) }),
10181
- /* @__PURE__ */ jsxRuntime.jsx("div", {})
10182
- ] }) }),
10183
- /* @__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: [
10184
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", leading: "compact", children: "There are no items in this order" }),
10185
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Add items to the order to get started." })
10186
- ] }) : matches.length > 0 ? matches == null ? void 0 : matches.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
10187
- Item,
10188
- {
10189
- item,
10190
- preview,
10191
- currencyCode
10192
- },
10193
- item.id
10194
- )) : /* @__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: [
10195
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", leading: "compact", children: "No items found" }),
10196
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: [
10197
- 'No items found for "',
10198
- query2,
10199
- '".'
10200
- ] })
10201
- ] }) })
10202
- ] })
10203
- ] }),
10204
- /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { variant: "dashed" }),
10205
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-[1fr_0.5fr_0.5fr] gap-3", children: [
10206
- /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", leading: "compact", children: "Subtotal" }) }),
10207
- /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsxs(
10208
- ui.Text,
10209
- {
10210
- size: "small",
10211
- leading: "compact",
10212
- className: "text-ui-fg-subtle",
10213
- children: [
10214
- itemCount,
10215
- " ",
10216
- itemCount === 1 ? "item" : "items"
10217
- ]
10218
- }
10219
- ) }),
10220
- /* @__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) }) })
10221
- ] })
10222
- ] }) }),
10223
- modalContent && (modalContent === "add-items" ? /* @__PURE__ */ jsxRuntime.jsx(ExistingItemsForm, { orderId: preview.id, items: preview.items }) : modalContent === "add-custom-item" ? /* @__PURE__ */ jsxRuntime.jsx(
10224
- CustomItemForm,
10225
- {
10226
- orderId: preview.id,
10227
- currencyCode
10228
- }
10229
- ) : null)
10230
- ]
10231
- }
10232
- ) }),
10233
- /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
10234
- /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
10235
- /* @__PURE__ */ jsxRuntime.jsx(
10236
- ui.Button,
10237
- {
10238
- size: "small",
10239
- type: "button",
10240
- onClick: onSubmit,
10241
- isLoading: isSubmitting,
10242
- children: "Save"
10243
- }
10244
- )
10245
- ] }) })
9905
+ const isReady = !isPending && !!order;
9906
+ return /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer, { children: [
9907
+ /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer.Header, { children: [
9908
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Metadata" }) }),
9909
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Description, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Add metadata to the draft order." }) })
9910
+ ] }),
9911
+ !isReady ? /* @__PURE__ */ jsxRuntime.jsx(PlaceholderInner, {}) : /* @__PURE__ */ jsxRuntime.jsx(MetadataForm, { orderId: id, metadata: order == null ? void 0 : order.metadata })
10246
9912
  ] });
10247
9913
  };
10248
- const Item = ({ item, preview, currencyCode }) => {
10249
- if (item.variant_id) {
10250
- return /* @__PURE__ */ jsxRuntime.jsx(VariantItem, { item, preview, currencyCode });
10251
- }
10252
- return /* @__PURE__ */ jsxRuntime.jsx(CustomItem, { item, preview, currencyCode });
10253
- };
10254
- const VariantItem = ({ item, preview, currencyCode }) => {
10255
- const [editing, setEditing] = React.useState(false);
9914
+ const METADATA_KEY_LABEL_ID = "metadata-form-key-label";
9915
+ const METADATA_VALUE_LABEL_ID = "metadata-form-value-label";
9916
+ const MetadataForm = ({ orderId, metadata }) => {
9917
+ const { handleSuccess } = useRouteModal();
9918
+ const hasUneditableRows = getHasUneditableRows(metadata);
9919
+ const { mutateAsync, isPending } = useUpdateDraftOrder(orderId);
10256
9920
  const form = reactHookForm.useForm({
10257
9921
  defaultValues: {
10258
- quantity: item.quantity,
10259
- unit_price: item.unit_price
9922
+ metadata: getDefaultValues(metadata)
10260
9923
  },
10261
- resolver: zod.zodResolver(variantItemSchema)
9924
+ resolver: zod.zodResolver(MetadataSchema)
10262
9925
  });
10263
- const actionId = React.useMemo(() => {
10264
- var _a, _b;
10265
- return (_b = (_a = item.actions) == null ? void 0 : _a.find((a) => a.action === "ITEM_ADD")) == null ? void 0 : _b.id;
10266
- }, [item]);
10267
- const { mutateAsync: updateActionItem, isPending: isUpdatingActionItem } = useDraftOrderUpdateActionItem(preview.id);
10268
- const { mutateAsync: updateOriginalItem, isPending: isUpdatingOriginalItem } = useDraftOrderUpdateItem(preview.id);
10269
- const isPending = isUpdatingActionItem || isUpdatingOriginalItem;
10270
- const onSubmit = form.handleSubmit(async (data) => {
10271
- if (convertNumber(data.unit_price) === item.unit_price && data.quantity === item.quantity) {
10272
- setEditing(false);
10273
- return;
10274
- }
10275
- if (!actionId) {
10276
- await updateOriginalItem(
10277
- {
10278
- item_id: item.id,
10279
- quantity: data.quantity,
10280
- unit_price: convertNumber(data.unit_price)
10281
- },
10282
- {
10283
- onSuccess: () => {
10284
- setEditing(false);
10285
- },
10286
- onError: (e) => {
10287
- ui.toast.error(e.message);
10288
- }
10289
- }
10290
- );
10291
- return;
10292
- }
10293
- await updateActionItem(
9926
+ const handleSubmit = form.handleSubmit(async (data) => {
9927
+ const parsedData = parseValues(data);
9928
+ await mutateAsync(
10294
9929
  {
10295
- action_id: actionId,
10296
- quantity: data.quantity,
10297
- unit_price: convertNumber(data.unit_price)
9930
+ metadata: parsedData
10298
9931
  },
10299
9932
  {
10300
9933
  onSuccess: () => {
10301
- setEditing(false);
9934
+ ui.toast.success("Metadata updated");
9935
+ handleSuccess();
10302
9936
  },
10303
- onError: (e) => {
10304
- ui.toast.error(e.message);
9937
+ onError: (error) => {
9938
+ ui.toast.error(error.message);
10305
9939
  }
10306
9940
  }
10307
9941
  );
10308
9942
  });
10309
- 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: [
10310
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex w-full items-center gap-x-3", children: [
10311
- /* @__PURE__ */ jsxRuntime.jsx(
10312
- Thumbnail,
10313
- {
10314
- thumbnail: item.thumbnail,
10315
- alt: item.product_title ?? void 0
10316
- }
10317
- ),
10318
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
10319
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-x-1", children: [
10320
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", leading: "compact", children: item.product_title }),
10321
- /* @__PURE__ */ jsxRuntime.jsxs(
10322
- ui.Text,
10323
- {
10324
- size: "small",
10325
- leading: "compact",
10326
- className: "text-ui-fg-subtle",
10327
- children: [
10328
- "(",
10329
- item.variant_title,
10330
- ")"
10331
- ]
10332
- }
10333
- )
10334
- ] }),
10335
- /* @__PURE__ */ jsxRuntime.jsx(
10336
- ui.Text,
10337
- {
10338
- size: "small",
10339
- leading: "compact",
10340
- className: "text-ui-fg-subtle",
10341
- children: item.variant_sku
10342
- }
10343
- )
10344
- ] })
10345
- ] }),
10346
- editing ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(
10347
- Form$2.Field,
10348
- {
10349
- control: form.control,
10350
- name: "quantity",
10351
- render: ({ field }) => {
10352
- return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(NumberInput, { ...field }) }) });
10353
- }
10354
- }
10355
- ) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: item.quantity }) }),
10356
- editing ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(
10357
- Form$2.Field,
10358
- {
10359
- control: form.control,
10360
- name: "unit_price",
10361
- render: ({ field: { onChange, ...field } }) => {
10362
- return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
10363
- ui.CurrencyInput,
10364
- {
10365
- ...field,
10366
- symbol: getNativeSymbol(currencyCode),
10367
- code: currencyCode,
10368
- onValueChange: (_value, _name, values) => onChange(values == null ? void 0 : values.value)
10369
- }
10370
- ) }) });
10371
- }
10372
- }
10373
- ) }) : /* @__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) }) }),
10374
- /* @__PURE__ */ jsxRuntime.jsx(
10375
- ui.IconButton,
10376
- {
10377
- type: "button",
10378
- size: "small",
10379
- onClick: editing ? onSubmit : () => {
10380
- setEditing(true);
10381
- },
10382
- disabled: isPending,
10383
- children: editing ? /* @__PURE__ */ jsxRuntime.jsx(icons.Check, {}) : /* @__PURE__ */ jsxRuntime.jsx(icons.PencilSquare, {})
10384
- }
10385
- )
10386
- ] }) }) });
10387
- };
10388
- const variantItemSchema = objectType({
10389
- quantity: numberType(),
10390
- unit_price: unionType([numberType(), stringType()])
10391
- });
10392
- const CustomItem = ({ item, preview, currencyCode }) => {
10393
- const [editing, setEditing] = React.useState(false);
10394
- const { quantity, unit_price, title } = item;
10395
- const form = reactHookForm.useForm({
10396
- defaultValues: {
10397
- title,
10398
- quantity,
10399
- unit_price
10400
- },
10401
- resolver: zod.zodResolver(customItemSchema)
9943
+ const { fields, insert, remove } = reactHookForm.useFieldArray({
9944
+ control: form.control,
9945
+ name: "metadata"
10402
9946
  });
10403
- React.useEffect(() => {
10404
- form.reset({
10405
- title,
10406
- quantity,
10407
- unit_price
10408
- });
10409
- }, [form, title, quantity, unit_price]);
10410
- const actionId = React.useMemo(() => {
10411
- var _a, _b;
10412
- return (_b = (_a = item.actions) == null ? void 0 : _a.find((a) => a.action === "ITEM_ADD")) == null ? void 0 : _b.id;
10413
- }, [item]);
10414
- const { mutateAsync: updateActionItem, isPending: isUpdatingActionItem } = useDraftOrderUpdateActionItem(preview.id);
10415
- const { mutateAsync: removeActionItem, isPending: isRemovingActionItem } = useDraftOrderRemoveActionItem(preview.id);
10416
- const { mutateAsync: updateOriginalItem, isPending: isUpdatingOriginalItem } = useDraftOrderUpdateItem(preview.id);
10417
- const isPending = isUpdatingActionItem || isUpdatingOriginalItem;
10418
- const onSubmit = form.handleSubmit(async (data) => {
10419
- if (convertNumber(data.unit_price) === item.unit_price && data.quantity === item.quantity && data.title === item.title) {
10420
- setEditing(false);
10421
- return;
10422
- }
10423
- if (!actionId) {
10424
- await updateOriginalItem(
10425
- {
10426
- item_id: item.id,
10427
- quantity: data.quantity,
10428
- unit_price: convertNumber(data.unit_price)
10429
- },
10430
- {
10431
- onSuccess: () => {
10432
- setEditing(false);
10433
- },
10434
- onError: (e) => {
10435
- ui.toast.error(e.message);
10436
- }
10437
- }
10438
- );
10439
- return;
10440
- }
10441
- if (data.quantity === 0) {
10442
- await removeActionItem(actionId, {
10443
- onSuccess: () => {
10444
- setEditing(false);
10445
- },
10446
- onError: (e) => {
10447
- ui.toast.error(e.message);
10448
- }
9947
+ function deleteRow(index) {
9948
+ remove(index);
9949
+ if (fields.length === 1) {
9950
+ insert(0, {
9951
+ key: "",
9952
+ value: "",
9953
+ disabled: false
10449
9954
  });
10450
- return;
10451
9955
  }
10452
- await updateActionItem(
10453
- {
10454
- action_id: actionId,
10455
- quantity: data.quantity,
10456
- unit_price: convertNumber(data.unit_price)
10457
- },
10458
- {
10459
- onSuccess: () => {
10460
- setEditing(false);
10461
- },
10462
- onError: (e) => {
10463
- ui.toast.error(e.message);
10464
- }
10465
- }
10466
- );
10467
- });
10468
- 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: [
10469
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-x-3", children: [
10470
- /* @__PURE__ */ jsxRuntime.jsx(
10471
- Thumbnail,
10472
- {
10473
- thumbnail: item.thumbnail,
10474
- alt: item.title ?? void 0
10475
- }
10476
- ),
10477
- editing ? /* @__PURE__ */ jsxRuntime.jsx(
10478
- Form$2.Field,
10479
- {
10480
- control: form.control,
10481
- name: "title",
10482
- render: ({ field }) => {
10483
- return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Input, { ...field }) }) });
10484
- }
10485
- }
10486
- ) : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: item.title })
10487
- ] }),
10488
- editing ? /* @__PURE__ */ jsxRuntime.jsx(
10489
- Form$2.Field,
10490
- {
10491
- control: form.control,
10492
- name: "quantity",
10493
- render: ({ field }) => {
10494
- return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(NumberInput, { ...field }) }) });
10495
- }
10496
- }
10497
- ) : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: item.quantity }),
10498
- editing ? /* @__PURE__ */ jsxRuntime.jsx(
10499
- Form$2.Field,
10500
- {
10501
- control: form.control,
10502
- name: "unit_price",
10503
- render: ({ field: { onChange, ...field } }) => {
10504
- return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
10505
- ui.CurrencyInput,
10506
- {
10507
- ...field,
10508
- symbol: getNativeSymbol(currencyCode),
10509
- code: currencyCode,
10510
- onValueChange: (_value, _name, values) => onChange(values == null ? void 0 : values.value)
10511
- }
10512
- ) }) });
10513
- }
10514
- }
10515
- ) : /* @__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) }) }),
10516
- /* @__PURE__ */ jsxRuntime.jsx(
10517
- ui.IconButton,
10518
- {
10519
- type: "button",
10520
- size: "small",
10521
- onClick: editing ? onSubmit : () => {
10522
- setEditing(true);
10523
- },
10524
- disabled: isPending,
10525
- children: editing ? /* @__PURE__ */ jsxRuntime.jsx(icons.Check, {}) : /* @__PURE__ */ jsxRuntime.jsx(icons.PencilSquare, {})
10526
- }
10527
- )
10528
- ] }) }) });
10529
- };
10530
- const StackedModalTrigger$1 = ({
10531
- type,
10532
- setModalContent
10533
- }) => {
10534
- const { setIsOpen } = useStackedModal();
10535
- const onClick = React.useCallback(() => {
10536
- setModalContent(type);
10537
- setIsOpen(STACKED_MODAL_ID, true);
10538
- }, [setModalContent, setIsOpen, type]);
10539
- 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" }) });
10540
- };
10541
- const VARIANT_PREFIX = "items";
10542
- const LIMIT = 50;
10543
- const ExistingItemsForm = ({ orderId, items }) => {
10544
- const { setIsOpen } = useStackedModal();
10545
- const [rowSelection, setRowSelection] = React.useState(
10546
- items.reduce((acc, item) => {
10547
- acc[item.variant_id] = true;
10548
- return acc;
10549
- }, {})
10550
- );
10551
- React.useEffect(() => {
10552
- setRowSelection(
10553
- items.reduce((acc, item) => {
10554
- if (item.variant_id) {
10555
- acc[item.variant_id] = true;
10556
- }
10557
- return acc;
10558
- }, {})
10559
- );
10560
- }, [items]);
10561
- const { q, order, offset } = useQueryParams(
10562
- ["q", "order", "offset"],
10563
- VARIANT_PREFIX
10564
- );
10565
- const { variants, count, isPending, isError, error } = useProductVariants(
10566
- {
10567
- q,
10568
- order,
10569
- offset: offset ? parseInt(offset) : void 0,
10570
- limit: LIMIT
10571
- },
10572
- {
10573
- placeholderData: reactQuery.keepPreviousData
10574
- }
10575
- );
10576
- const columns = useColumns();
10577
- const { mutateAsync } = useDraftOrderAddItems(orderId);
10578
- const onSubmit = async () => {
10579
- const ids = Object.keys(rowSelection).filter(
10580
- (id) => !items.find((i) => i.variant_id === id)
10581
- );
10582
- await mutateAsync(
10583
- {
10584
- items: ids.map((id) => ({
10585
- variant_id: id,
10586
- quantity: 1
10587
- }))
10588
- },
10589
- {
10590
- onSuccess: () => {
10591
- setRowSelection({});
10592
- setIsOpen(STACKED_MODAL_ID, false);
10593
- },
10594
- onError: (e) => {
10595
- ui.toast.error(e.message);
10596
- }
10597
- }
10598
- );
10599
- };
10600
- if (isError) {
10601
- throw error;
10602
9956
  }
10603
- return /* @__PURE__ */ jsxRuntime.jsxs(
10604
- StackedFocusModal.Content,
9957
+ function insertRow(index, position) {
9958
+ insert(index + (position === "above" ? 0 : 1), {
9959
+ key: "",
9960
+ value: "",
9961
+ disabled: false
9962
+ });
9963
+ }
9964
+ return /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxRuntime.jsxs(
9965
+ KeyboundForm,
10605
9966
  {
10606
- onOpenAutoFocus: (e) => {
10607
- e.preventDefault();
10608
- const searchInput = document.querySelector(
10609
- "[data-modal-id='modal-search-input']"
10610
- );
10611
- if (searchInput) {
10612
- searchInput.focus();
10613
- }
10614
- },
9967
+ onSubmit: handleSubmit,
9968
+ className: "flex flex-1 flex-col overflow-hidden",
10615
9969
  children: [
10616
- /* @__PURE__ */ jsxRuntime.jsxs(StackedFocusModal.Header, { children: [
10617
- /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Product Variants" }) }),
10618
- /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Choose product variants to add to the order." }) })
10619
- ] }),
10620
- /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Body, { className: "flex-1 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
10621
- DataTable,
10622
- {
10623
- data: variants,
10624
- columns,
10625
- isLoading: isPending,
10626
- getRowId: (row) => row.id,
10627
- rowCount: count,
10628
- prefix: VARIANT_PREFIX,
10629
- layout: "fill",
10630
- rowSelection: {
10631
- state: rowSelection,
10632
- onRowSelectionChange: setRowSelection,
10633
- enableRowSelection: (row) => {
10634
- return !items.find((i) => i.variant_id === row.original.id);
9970
+ /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer.Body, { className: "flex flex-1 flex-col gap-y-8 overflow-y-auto", children: [
9971
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-base shadow-elevation-card-rest grid grid-cols-1 divide-y rounded-lg", children: [
9972
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-subtle grid grid-cols-2 divide-x rounded-t-lg", children: [
9973
+ /* @__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" }) }),
9974
+ /* @__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" }) })
9975
+ ] }),
9976
+ fields.map((field, index) => {
9977
+ const isDisabled = field.disabled || false;
9978
+ let placeholder = "-";
9979
+ if (typeof field.value === "object") {
9980
+ placeholder = "{ ... }";
10635
9981
  }
10636
- },
10637
- autoFocusSearch: true
10638
- }
10639
- ) }),
10640
- /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
10641
- /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
10642
- /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", type: "button", onClick: onSubmit, children: "Update items" })
9982
+ if (Array.isArray(field.value)) {
9983
+ placeholder = "[ ... ]";
9984
+ }
9985
+ return /* @__PURE__ */ jsxRuntime.jsx(
9986
+ ConditionalTooltip,
9987
+ {
9988
+ showTooltip: isDisabled,
9989
+ content: "This row is disabled because it contains non-primitive data.",
9990
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "group/table relative", children: [
9991
+ /* @__PURE__ */ jsxRuntime.jsxs(
9992
+ "div",
9993
+ {
9994
+ className: ui.clx("grid grid-cols-2 divide-x", {
9995
+ "overflow-hidden rounded-b-lg": index === fields.length - 1
9996
+ }),
9997
+ children: [
9998
+ /* @__PURE__ */ jsxRuntime.jsx(
9999
+ Form$2.Field,
10000
+ {
10001
+ control: form.control,
10002
+ name: `metadata.${index}.key`,
10003
+ render: ({ field: field2 }) => {
10004
+ return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
10005
+ GridInput,
10006
+ {
10007
+ "aria-labelledby": METADATA_KEY_LABEL_ID,
10008
+ ...field2,
10009
+ disabled: isDisabled,
10010
+ placeholder: "Key"
10011
+ }
10012
+ ) }) });
10013
+ }
10014
+ }
10015
+ ),
10016
+ /* @__PURE__ */ jsxRuntime.jsx(
10017
+ Form$2.Field,
10018
+ {
10019
+ control: form.control,
10020
+ name: `metadata.${index}.value`,
10021
+ render: ({ field: { value, ...field2 } }) => {
10022
+ return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
10023
+ GridInput,
10024
+ {
10025
+ "aria-labelledby": METADATA_VALUE_LABEL_ID,
10026
+ ...field2,
10027
+ value: isDisabled ? placeholder : value,
10028
+ disabled: isDisabled,
10029
+ placeholder: "Value"
10030
+ }
10031
+ ) }) });
10032
+ }
10033
+ }
10034
+ )
10035
+ ]
10036
+ }
10037
+ ),
10038
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu, { children: [
10039
+ /* @__PURE__ */ jsxRuntime.jsx(
10040
+ ui.DropdownMenu.Trigger,
10041
+ {
10042
+ className: ui.clx(
10043
+ "invisible absolute inset-y-0 -right-2.5 my-auto group-hover/table:visible data-[state='open']:visible",
10044
+ {
10045
+ hidden: isDisabled
10046
+ }
10047
+ ),
10048
+ disabled: isDisabled,
10049
+ asChild: true,
10050
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { size: "2xsmall", children: /* @__PURE__ */ jsxRuntime.jsx(icons.EllipsisVertical, {}) })
10051
+ }
10052
+ ),
10053
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu.Content, { children: [
10054
+ /* @__PURE__ */ jsxRuntime.jsxs(
10055
+ ui.DropdownMenu.Item,
10056
+ {
10057
+ className: "gap-x-2",
10058
+ onClick: () => insertRow(index, "above"),
10059
+ children: [
10060
+ /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowUpMini, { className: "text-ui-fg-subtle" }),
10061
+ "Insert row above"
10062
+ ]
10063
+ }
10064
+ ),
10065
+ /* @__PURE__ */ jsxRuntime.jsxs(
10066
+ ui.DropdownMenu.Item,
10067
+ {
10068
+ className: "gap-x-2",
10069
+ onClick: () => insertRow(index, "below"),
10070
+ children: [
10071
+ /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowDownMini, { className: "text-ui-fg-subtle" }),
10072
+ "Insert row below"
10073
+ ]
10074
+ }
10075
+ ),
10076
+ /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenu.Separator, {}),
10077
+ /* @__PURE__ */ jsxRuntime.jsxs(
10078
+ ui.DropdownMenu.Item,
10079
+ {
10080
+ className: "gap-x-2",
10081
+ onClick: () => deleteRow(index),
10082
+ children: [
10083
+ /* @__PURE__ */ jsxRuntime.jsx(icons.Trash, { className: "text-ui-fg-subtle" }),
10084
+ "Delete row"
10085
+ ]
10086
+ }
10087
+ )
10088
+ ] })
10089
+ ] })
10090
+ ] })
10091
+ },
10092
+ field.id
10093
+ );
10094
+ })
10095
+ ] }),
10096
+ 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." })
10097
+ ] }),
10098
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
10099
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
10100
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", type: "submit", isLoading: isPending, children: "Save" })
10643
10101
  ] }) })
10644
10102
  ]
10645
10103
  }
10104
+ ) });
10105
+ };
10106
+ const GridInput = React.forwardRef(({ className, ...props }, ref) => {
10107
+ return /* @__PURE__ */ jsxRuntime.jsx(
10108
+ "input",
10109
+ {
10110
+ ref,
10111
+ ...props,
10112
+ autoComplete: "off",
10113
+ className: ui.clx(
10114
+ "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",
10115
+ className
10116
+ )
10117
+ }
10646
10118
  );
10119
+ });
10120
+ GridInput.displayName = "MetadataForm.GridInput";
10121
+ const PlaceholderInner = () => {
10122
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col overflow-hidden", children: [
10123
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Body, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: "h-[148ox] w-full rounded-lg" }) }),
10124
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
10125
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: "h-7 w-12 rounded-md" }),
10126
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: "h-7 w-12 rounded-md" })
10127
+ ] }) })
10128
+ ] });
10647
10129
  };
10648
- const columnHelper = ui.createDataTableColumnHelper();
10649
- const useColumns = () => {
10650
- return React.useMemo(() => {
10130
+ const EDITABLE_TYPES = ["string", "number", "boolean"];
10131
+ function getDefaultValues(metadata) {
10132
+ if (!metadata || !Object.keys(metadata).length) {
10651
10133
  return [
10652
- columnHelper.select(),
10653
- columnHelper.accessor("product.title", {
10654
- header: "Product",
10655
- cell: ({ row }) => {
10656
- var _a, _b, _c;
10657
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-x-2", children: [
10658
- /* @__PURE__ */ jsxRuntime.jsx(
10659
- Thumbnail,
10660
- {
10661
- thumbnail: (_a = row.original.product) == null ? void 0 : _a.thumbnail,
10662
- alt: (_b = row.original.product) == null ? void 0 : _b.title
10663
- }
10664
- ),
10665
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: (_c = row.original.product) == null ? void 0 : _c.title })
10666
- ] });
10667
- },
10668
- enableSorting: true
10669
- }),
10670
- columnHelper.accessor("title", {
10671
- header: "Variant",
10672
- enableSorting: true
10673
- }),
10674
- columnHelper.accessor("sku", {
10675
- header: "SKU",
10676
- cell: ({ getValue }) => {
10677
- return getValue() ?? "-";
10678
- },
10679
- enableSorting: true
10680
- }),
10681
- columnHelper.accessor("updated_at", {
10682
- header: "Updated",
10683
- cell: ({ getValue }) => {
10684
- return /* @__PURE__ */ jsxRuntime.jsx(
10685
- ui.Tooltip,
10686
- {
10687
- content: getFullDate({ date: getValue(), includeTime: true }),
10688
- children: /* @__PURE__ */ jsxRuntime.jsx("span", { children: getFullDate({ date: getValue() }) })
10689
- }
10690
- );
10691
- },
10692
- enableSorting: true,
10693
- sortAscLabel: "Oldest first",
10694
- sortDescLabel: "Newest first"
10695
- }),
10696
- columnHelper.accessor("created_at", {
10697
- header: "Created",
10698
- cell: ({ getValue }) => {
10699
- return /* @__PURE__ */ jsxRuntime.jsx(
10700
- ui.Tooltip,
10701
- {
10702
- content: getFullDate({ date: getValue(), includeTime: true }),
10703
- children: /* @__PURE__ */ jsxRuntime.jsx("span", { children: getFullDate({ date: getValue() }) })
10704
- }
10705
- );
10706
- },
10707
- enableSorting: true,
10708
- sortAscLabel: "Oldest first",
10709
- sortDescLabel: "Newest first"
10710
- })
10134
+ {
10135
+ key: "",
10136
+ value: "",
10137
+ disabled: false
10138
+ }
10711
10139
  ];
10712
- }, []);
10140
+ }
10141
+ return Object.entries(metadata).map(([key, value]) => {
10142
+ if (!EDITABLE_TYPES.includes(typeof value)) {
10143
+ return {
10144
+ key,
10145
+ value,
10146
+ disabled: true
10147
+ };
10148
+ }
10149
+ let stringValue = value;
10150
+ if (typeof value !== "string") {
10151
+ stringValue = JSON.stringify(value);
10152
+ }
10153
+ return {
10154
+ key,
10155
+ value: stringValue,
10156
+ original_key: key
10157
+ };
10158
+ });
10159
+ }
10160
+ function parseValues(values) {
10161
+ const metadata = values.metadata;
10162
+ const isEmpty = !metadata.length || metadata.length === 1 && !metadata[0].key && !metadata[0].value;
10163
+ if (isEmpty) {
10164
+ return null;
10165
+ }
10166
+ const update = {};
10167
+ metadata.forEach((field) => {
10168
+ let key = field.key;
10169
+ let value = field.value;
10170
+ const disabled = field.disabled;
10171
+ if (!key || !value) {
10172
+ return;
10173
+ }
10174
+ if (disabled) {
10175
+ update[key] = value;
10176
+ return;
10177
+ }
10178
+ key = key.trim();
10179
+ value = value.trim();
10180
+ if (value === "true") {
10181
+ update[key] = true;
10182
+ } else if (value === "false") {
10183
+ update[key] = false;
10184
+ } else {
10185
+ const parsedNumber = parseFloat(value);
10186
+ if (!isNaN(parsedNumber)) {
10187
+ update[key] = parsedNumber;
10188
+ } else {
10189
+ update[key] = value;
10190
+ }
10191
+ }
10192
+ });
10193
+ return update;
10194
+ }
10195
+ function getHasUneditableRows(metadata) {
10196
+ if (!metadata) {
10197
+ return false;
10198
+ }
10199
+ return Object.values(metadata).some(
10200
+ (value) => !EDITABLE_TYPES.includes(typeof value)
10201
+ );
10202
+ }
10203
+ const PROMOTION_QUERY_KEY = "promotions";
10204
+ const promotionsQueryKeys = {
10205
+ list: (query2) => [
10206
+ PROMOTION_QUERY_KEY,
10207
+ query2 ? query2 : void 0
10208
+ ],
10209
+ detail: (id, query2) => [
10210
+ PROMOTION_QUERY_KEY,
10211
+ id,
10212
+ query2 ? query2 : void 0
10213
+ ]
10713
10214
  };
10714
- const CustomItemForm = ({ orderId, currencyCode }) => {
10715
- const { setIsOpen } = useStackedModal();
10716
- const { mutateAsync: addItems } = useDraftOrderAddItems(orderId);
10717
- const form = reactHookForm.useForm({
10718
- defaultValues: {
10719
- title: "",
10720
- quantity: 1,
10721
- unit_price: ""
10722
- },
10723
- resolver: zod.zodResolver(customItemSchema)
10215
+ const usePromotions = (query2, options) => {
10216
+ const { data, ...rest } = reactQuery.useQuery({
10217
+ queryKey: promotionsQueryKeys.list(query2),
10218
+ queryFn: async () => sdk.admin.promotion.list(query2),
10219
+ ...options
10724
10220
  });
10725
- const onSubmit = form.handleSubmit(async (data) => {
10726
- await addItems(
10727
- {
10728
- items: [
10729
- {
10730
- title: data.title,
10731
- quantity: data.quantity,
10732
- unit_price: convertNumber(data.unit_price)
10733
- }
10734
- ]
10221
+ return { ...data, ...rest };
10222
+ };
10223
+ const useCancelOrderEdit = ({ preview }) => {
10224
+ const { mutateAsync: cancelOrderEdit } = useDraftOrderCancelEdit(preview == null ? void 0 : preview.id);
10225
+ const onCancel = React.useCallback(async () => {
10226
+ if (!preview) {
10227
+ return true;
10228
+ }
10229
+ let res = false;
10230
+ await cancelOrderEdit(void 0, {
10231
+ onError: (e) => {
10232
+ ui.toast.error(e.message);
10735
10233
  },
10736
- {
10737
- onSuccess: () => {
10738
- setIsOpen(STACKED_MODAL_ID, false);
10739
- },
10234
+ onSuccess: () => {
10235
+ res = true;
10236
+ }
10237
+ });
10238
+ return res;
10239
+ }, [preview, cancelOrderEdit]);
10240
+ return { onCancel };
10241
+ };
10242
+ let IS_REQUEST_RUNNING = false;
10243
+ const useInitiateOrderEdit = ({
10244
+ preview
10245
+ }) => {
10246
+ const navigate = reactRouterDom.useNavigate();
10247
+ const { mutateAsync } = useDraftOrderBeginEdit(preview == null ? void 0 : preview.id);
10248
+ React.useEffect(() => {
10249
+ async function run() {
10250
+ if (IS_REQUEST_RUNNING || !preview) {
10251
+ return;
10252
+ }
10253
+ if (preview.order_change) {
10254
+ return;
10255
+ }
10256
+ IS_REQUEST_RUNNING = true;
10257
+ await mutateAsync(void 0, {
10740
10258
  onError: (e) => {
10741
10259
  ui.toast.error(e.message);
10260
+ navigate(`/draft-orders/${preview.id}`, { replace: true });
10261
+ return;
10742
10262
  }
10743
- }
10744
- );
10745
- });
10746
- return /* @__PURE__ */ jsxRuntime.jsx(Form$2, { ...form, children: /* @__PURE__ */ jsxRuntime.jsx(KeyboundForm, { onSubmit, children: /* @__PURE__ */ jsxRuntime.jsxs(StackedFocusModal.Content, { children: [
10747
- /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Header, {}),
10748
- /* @__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: [
10749
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
10750
- /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Add custom item" }) }),
10751
- /* @__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." }) })
10752
- ] }),
10753
- /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { variant: "dashed" }),
10754
- /* @__PURE__ */ jsxRuntime.jsx(
10755
- Form$2.Field,
10756
- {
10757
- control: form.control,
10758
- name: "title",
10759
- render: ({ field }) => /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
10760
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
10761
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.Label, { children: "Title" }),
10762
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.Hint, { children: "Enter the title of the item" })
10763
- ] }),
10764
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
10765
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Input, { ...field }) }),
10766
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.ErrorMessage, {})
10767
- ] })
10768
- ] }) })
10769
- }
10770
- ),
10771
- /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { variant: "dashed" }),
10772
- /* @__PURE__ */ jsxRuntime.jsx(
10773
- Form$2.Field,
10774
- {
10775
- control: form.control,
10776
- name: "unit_price",
10777
- render: ({ field: { onChange, ...field } }) => /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
10778
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
10779
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.Label, { children: "Unit price" }),
10780
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.Hint, { children: "Enter the unit price of the item" })
10781
- ] }),
10782
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
10783
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
10784
- ui.CurrencyInput,
10785
- {
10786
- symbol: getNativeSymbol(currencyCode),
10787
- code: currencyCode,
10788
- onValueChange: (_value, _name, values) => onChange(values == null ? void 0 : values.value),
10789
- ...field
10790
- }
10791
- ) }),
10792
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.ErrorMessage, {})
10793
- ] })
10794
- ] }) })
10795
- }
10796
- ),
10797
- /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { variant: "dashed" }),
10798
- /* @__PURE__ */ jsxRuntime.jsx(
10799
- Form$2.Field,
10800
- {
10801
- control: form.control,
10802
- name: "quantity",
10803
- render: ({ field }) => /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
10804
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
10805
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.Label, { children: "Quantity" }),
10806
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.Hint, { children: "Enter the quantity of the item" })
10807
- ] }),
10808
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full flex-1", children: [
10809
- /* @__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" }) }) }),
10810
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.ErrorMessage, {})
10811
- ] })
10812
- ] }) })
10813
- }
10814
- )
10815
- ] }) }) }),
10816
- /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
10817
- /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
10818
- /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", type: "button", onClick: onSubmit, children: "Add item" })
10819
- ] }) })
10820
- ] }) }) });
10263
+ });
10264
+ IS_REQUEST_RUNNING = false;
10265
+ }
10266
+ run();
10267
+ }, [preview, navigate, mutateAsync]);
10821
10268
  };
10822
- const customItemSchema = objectType({
10823
- title: stringType().min(1),
10824
- quantity: numberType(),
10825
- unit_price: unionType([numberType(), stringType()])
10826
- });
10827
- const InlineTip = React.forwardRef(
10828
- ({ variant = "tip", label, className, children, ...props }, ref) => {
10829
- const labelValue = label || (variant === "warning" ? "Warning" : "Tip");
10830
- return /* @__PURE__ */ jsxRuntime.jsxs(
10831
- "div",
10832
- {
10833
- ref,
10834
- className: ui.clx(
10835
- "bg-ui-bg-component txt-small text-ui-fg-subtle grid grid-cols-[4px_1fr] items-start gap-3 rounded-lg border p-3",
10836
- className
10837
- ),
10838
- ...props,
10839
- children: [
10840
- /* @__PURE__ */ jsxRuntime.jsx(
10841
- "div",
10842
- {
10843
- role: "presentation",
10844
- className: ui.clx("w-4px bg-ui-tag-neutral-icon h-full rounded-full", {
10845
- "bg-ui-tag-orange-icon": variant === "warning"
10846
- })
10847
- }
10848
- ),
10849
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-pretty", children: [
10850
- /* @__PURE__ */ jsxRuntime.jsxs("strong", { className: "txt-small-plus text-ui-fg-base", children: [
10851
- labelValue,
10852
- ":"
10853
- ] }),
10854
- " ",
10855
- children
10856
- ] })
10857
- ]
10858
- }
10859
- );
10860
- }
10861
- );
10862
- InlineTip.displayName = "InlineTip";
10863
- const MetadataFieldSchema = objectType({
10864
- key: stringType(),
10865
- disabled: booleanType().optional(),
10866
- value: anyType()
10867
- });
10868
- const MetadataSchema = objectType({
10869
- metadata: arrayType(MetadataFieldSchema)
10870
- });
10871
- const Metadata = () => {
10269
+ const Promotions = () => {
10872
10270
  const { id } = reactRouterDom.useParams();
10873
- const { order, isPending, isError, error } = useOrder(id, {
10874
- fields: "metadata"
10875
- });
10876
- if (isError) {
10877
- throw error;
10271
+ const {
10272
+ order: preview,
10273
+ isError: isPreviewError,
10274
+ error: previewError
10275
+ } = useOrderPreview(id, void 0);
10276
+ useInitiateOrderEdit({ preview });
10277
+ const { onCancel } = useCancelOrderEdit({ preview });
10278
+ if (isPreviewError) {
10279
+ throw previewError;
10878
10280
  }
10879
- const isReady = !isPending && !!order;
10880
- return /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer, { children: [
10881
- /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer.Header, { children: [
10882
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Metadata" }) }),
10883
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Description, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Add metadata to the draft order." }) })
10884
- ] }),
10885
- !isReady ? /* @__PURE__ */ jsxRuntime.jsx(PlaceholderInner, {}) : /* @__PURE__ */ jsxRuntime.jsx(MetadataForm, { orderId: id, metadata: order == null ? void 0 : order.metadata })
10281
+ const isReady = !!preview;
10282
+ return /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer, { onClose: onCancel, children: [
10283
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Edit Promotions" }) }) }),
10284
+ isReady && /* @__PURE__ */ jsxRuntime.jsx(PromotionForm, { preview })
10886
10285
  ] });
10887
10286
  };
10888
- const METADATA_KEY_LABEL_ID = "metadata-form-key-label";
10889
- const METADATA_VALUE_LABEL_ID = "metadata-form-value-label";
10890
- const MetadataForm = ({ orderId, metadata }) => {
10287
+ const PromotionForm = ({ preview }) => {
10288
+ const { items, shipping_methods } = preview;
10289
+ const [isSubmitting, setIsSubmitting] = React.useState(false);
10290
+ const [comboboxValue, setComboboxValue] = React.useState("");
10891
10291
  const { handleSuccess } = useRouteModal();
10892
- const hasUneditableRows = getHasUneditableRows(metadata);
10893
- const { mutateAsync, isPending } = useUpdateDraftOrder(orderId);
10894
- const form = reactHookForm.useForm({
10895
- defaultValues: {
10896
- metadata: getDefaultValues(metadata)
10292
+ const { mutateAsync: addPromotions, isPending: isAddingPromotions } = useDraftOrderAddPromotions(preview.id);
10293
+ const promoIds = getPromotionIds(items, shipping_methods);
10294
+ const { promotions, isPending, isError, error } = usePromotions(
10295
+ {
10296
+ id: promoIds
10897
10297
  },
10898
- resolver: zod.zodResolver(MetadataSchema)
10298
+ {
10299
+ enabled: !!promoIds.length
10300
+ }
10301
+ );
10302
+ const comboboxData = useComboboxData({
10303
+ queryKey: ["promotions", "combobox", promoIds],
10304
+ queryFn: async (params) => {
10305
+ return await sdk.admin.promotion.list({
10306
+ ...params,
10307
+ id: {
10308
+ $nin: promoIds
10309
+ }
10310
+ });
10311
+ },
10312
+ getOptions: (data) => {
10313
+ return data.promotions.map((promotion) => ({
10314
+ label: promotion.code,
10315
+ value: promotion.code
10316
+ }));
10317
+ }
10899
10318
  });
10900
- const handleSubmit = form.handleSubmit(async (data) => {
10901
- const parsedData = parseValues(data);
10902
- await mutateAsync(
10319
+ const add = async (value) => {
10320
+ if (!value) {
10321
+ return;
10322
+ }
10323
+ addPromotions(
10903
10324
  {
10904
- metadata: parsedData
10325
+ promo_codes: [value]
10905
10326
  },
10906
10327
  {
10907
- onSuccess: () => {
10908
- ui.toast.success("Metadata updated");
10909
- handleSuccess();
10328
+ onError: (e) => {
10329
+ ui.toast.error(e.message);
10330
+ comboboxData.onSearchValueChange("");
10331
+ setComboboxValue("");
10910
10332
  },
10911
- onError: (error) => {
10912
- ui.toast.error(error.message);
10333
+ onSuccess: () => {
10334
+ comboboxData.onSearchValueChange("");
10335
+ setComboboxValue("");
10913
10336
  }
10914
10337
  }
10915
10338
  );
10916
- });
10917
- const { fields, insert, remove } = reactHookForm.useFieldArray({
10918
- control: form.control,
10919
- name: "metadata"
10920
- });
10921
- function deleteRow(index) {
10922
- remove(index);
10923
- if (fields.length === 1) {
10924
- insert(0, {
10925
- key: "",
10926
- value: "",
10927
- disabled: false
10928
- });
10339
+ };
10340
+ const { mutateAsync: confirmOrderEdit } = useDraftOrderConfirmEdit(preview.id);
10341
+ const { mutateAsync: requestOrderEdit } = useOrderEditRequest(preview.id);
10342
+ const onSubmit = async () => {
10343
+ setIsSubmitting(true);
10344
+ let requestSucceeded = false;
10345
+ await requestOrderEdit(void 0, {
10346
+ onError: (e) => {
10347
+ ui.toast.error(e.message);
10348
+ },
10349
+ onSuccess: () => {
10350
+ requestSucceeded = true;
10351
+ }
10352
+ });
10353
+ if (!requestSucceeded) {
10354
+ setIsSubmitting(false);
10355
+ return;
10929
10356
  }
10930
- }
10931
- function insertRow(index, position) {
10932
- insert(index + (position === "above" ? 0 : 1), {
10933
- key: "",
10934
- value: "",
10935
- disabled: false
10357
+ await confirmOrderEdit(void 0, {
10358
+ onError: (e) => {
10359
+ ui.toast.error(e.message);
10360
+ },
10361
+ onSuccess: () => {
10362
+ handleSuccess();
10363
+ },
10364
+ onSettled: () => {
10365
+ setIsSubmitting(false);
10366
+ }
10936
10367
  });
10368
+ };
10369
+ if (isError) {
10370
+ throw error;
10937
10371
  }
10938
- return /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxRuntime.jsxs(
10939
- KeyboundForm,
10940
- {
10941
- onSubmit: handleSubmit,
10942
- className: "flex flex-1 flex-col overflow-hidden",
10943
- children: [
10944
- /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer.Body, { className: "flex flex-1 flex-col gap-y-8 overflow-y-auto", children: [
10945
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-base shadow-elevation-card-rest grid grid-cols-1 divide-y rounded-lg", children: [
10946
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-subtle grid grid-cols-2 divide-x rounded-t-lg", children: [
10947
- /* @__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" }) }),
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_VALUE_LABEL_ID, children: "Value" }) })
10949
- ] }),
10950
- fields.map((field, index) => {
10951
- const isDisabled = field.disabled || false;
10952
- let placeholder = "-";
10953
- if (typeof field.value === "object") {
10954
- placeholder = "{ ... }";
10955
- }
10956
- if (Array.isArray(field.value)) {
10957
- placeholder = "[ ... ]";
10958
- }
10959
- return /* @__PURE__ */ jsxRuntime.jsx(
10960
- ConditionalTooltip,
10961
- {
10962
- showTooltip: isDisabled,
10963
- content: "This row is disabled because it contains non-primitive data.",
10964
- children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "group/table relative", children: [
10965
- /* @__PURE__ */ jsxRuntime.jsxs(
10966
- "div",
10967
- {
10968
- className: ui.clx("grid grid-cols-2 divide-x", {
10969
- "overflow-hidden rounded-b-lg": index === fields.length - 1
10970
- }),
10971
- children: [
10972
- /* @__PURE__ */ jsxRuntime.jsx(
10973
- Form$2.Field,
10974
- {
10975
- control: form.control,
10976
- name: `metadata.${index}.key`,
10977
- render: ({ field: field2 }) => {
10978
- return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
10979
- GridInput,
10980
- {
10981
- "aria-labelledby": METADATA_KEY_LABEL_ID,
10982
- ...field2,
10983
- disabled: isDisabled,
10984
- placeholder: "Key"
10985
- }
10986
- ) }) });
10987
- }
10988
- }
10989
- ),
10990
- /* @__PURE__ */ jsxRuntime.jsx(
10991
- Form$2.Field,
10992
- {
10993
- control: form.control,
10994
- name: `metadata.${index}.value`,
10995
- render: ({ field: { value, ...field2 } }) => {
10996
- return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
10997
- GridInput,
10998
- {
10999
- "aria-labelledby": METADATA_VALUE_LABEL_ID,
11000
- ...field2,
11001
- value: isDisabled ? placeholder : value,
11002
- disabled: isDisabled,
11003
- placeholder: "Value"
11004
- }
11005
- ) }) });
11006
- }
11007
- }
11008
- )
11009
- ]
11010
- }
11011
- ),
11012
- /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu, { children: [
11013
- /* @__PURE__ */ jsxRuntime.jsx(
11014
- ui.DropdownMenu.Trigger,
11015
- {
11016
- className: ui.clx(
11017
- "invisible absolute inset-y-0 -right-2.5 my-auto group-hover/table:visible data-[state='open']:visible",
11018
- {
11019
- hidden: isDisabled
11020
- }
11021
- ),
11022
- disabled: isDisabled,
11023
- asChild: true,
11024
- children: /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { size: "2xsmall", children: /* @__PURE__ */ jsxRuntime.jsx(icons.EllipsisVertical, {}) })
11025
- }
11026
- ),
11027
- /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu.Content, { children: [
11028
- /* @__PURE__ */ jsxRuntime.jsxs(
11029
- ui.DropdownMenu.Item,
11030
- {
11031
- className: "gap-x-2",
11032
- onClick: () => insertRow(index, "above"),
11033
- children: [
11034
- /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowUpMini, { className: "text-ui-fg-subtle" }),
11035
- "Insert row above"
11036
- ]
11037
- }
11038
- ),
11039
- /* @__PURE__ */ jsxRuntime.jsxs(
11040
- ui.DropdownMenu.Item,
11041
- {
11042
- className: "gap-x-2",
11043
- onClick: () => insertRow(index, "below"),
11044
- children: [
11045
- /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowDownMini, { className: "text-ui-fg-subtle" }),
11046
- "Insert row below"
11047
- ]
11048
- }
11049
- ),
11050
- /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenu.Separator, {}),
11051
- /* @__PURE__ */ jsxRuntime.jsxs(
11052
- ui.DropdownMenu.Item,
11053
- {
11054
- className: "gap-x-2",
11055
- onClick: () => deleteRow(index),
11056
- children: [
11057
- /* @__PURE__ */ jsxRuntime.jsx(icons.Trash, { className: "text-ui-fg-subtle" }),
11058
- "Delete row"
11059
- ]
11060
- }
11061
- )
11062
- ] })
11063
- ] })
11064
- ] })
11065
- },
11066
- field.id
11067
- );
11068
- })
11069
- ] }),
11070
- 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." })
10372
+ return /* @__PURE__ */ jsxRuntime.jsxs(KeyboundForm, { className: "flex flex-1 flex-col", onSubmit, children: [
10373
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Body, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-4", children: [
10374
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3", children: [
10375
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
10376
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: "small", weight: "plus", htmlFor: "promotion-combobox", children: "Apply promotions" }),
10377
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Hint, { id: "promotion-combobox-hint", children: "Manage promotions that should be applied to the order." })
11071
10378
  ] }),
11072
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
11073
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
11074
- /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", type: "submit", isLoading: isPending, children: "Save" })
11075
- ] }) })
11076
- ]
11077
- }
11078
- ) });
11079
- };
11080
- const GridInput = React.forwardRef(({ className, ...props }, ref) => {
11081
- return /* @__PURE__ */ jsxRuntime.jsx(
11082
- "input",
11083
- {
11084
- ref,
11085
- ...props,
11086
- autoComplete: "off",
11087
- className: ui.clx(
11088
- "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",
11089
- className
10379
+ /* @__PURE__ */ jsxRuntime.jsx(
10380
+ Combobox,
10381
+ {
10382
+ id: "promotion-combobox",
10383
+ "aria-describedby": "promotion-combobox-hint",
10384
+ isFetchingNextPage: comboboxData.isFetchingNextPage,
10385
+ fetchNextPage: comboboxData.fetchNextPage,
10386
+ options: comboboxData.options,
10387
+ onSearchValueChange: comboboxData.onSearchValueChange,
10388
+ searchValue: comboboxData.searchValue,
10389
+ disabled: comboboxData.disabled || isAddingPromotions,
10390
+ onChange: add,
10391
+ value: comboboxValue
10392
+ }
10393
+ )
10394
+ ] }),
10395
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { variant: "dashed" }),
10396
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-2", children: promotions == null ? void 0 : promotions.map((promotion) => /* @__PURE__ */ jsxRuntime.jsx(
10397
+ PromotionItem,
10398
+ {
10399
+ promotion,
10400
+ orderId: preview.id,
10401
+ isLoading: isPending
10402
+ },
10403
+ promotion.id
10404
+ )) })
10405
+ ] }) }),
10406
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-2", children: [
10407
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
10408
+ /* @__PURE__ */ jsxRuntime.jsx(
10409
+ ui.Button,
10410
+ {
10411
+ size: "small",
10412
+ type: "submit",
10413
+ isLoading: isSubmitting || isAddingPromotions,
10414
+ children: "Save"
10415
+ }
11090
10416
  )
11091
- }
11092
- );
11093
- });
11094
- GridInput.displayName = "MetadataForm.GridInput";
11095
- const PlaceholderInner = () => {
11096
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col overflow-hidden", children: [
11097
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Body, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: "h-[148ox] w-full rounded-lg" }) }),
11098
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
11099
- /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: "h-7 w-12 rounded-md" }),
11100
- /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: "h-7 w-12 rounded-md" })
11101
10417
  ] }) })
11102
10418
  ] });
11103
10419
  };
11104
- const EDITABLE_TYPES = ["string", "number", "boolean"];
11105
- function getDefaultValues(metadata) {
11106
- if (!metadata || !Object.keys(metadata).length) {
11107
- return [
10420
+ const PromotionItem = ({
10421
+ promotion,
10422
+ orderId,
10423
+ isLoading
10424
+ }) => {
10425
+ var _a;
10426
+ const { mutateAsync: removePromotions, isPending } = useDraftOrderRemovePromotions(orderId);
10427
+ const onRemove = async () => {
10428
+ removePromotions(
11108
10429
  {
11109
- key: "",
11110
- value: "",
11111
- disabled: false
10430
+ promo_codes: [promotion.code]
10431
+ },
10432
+ {
10433
+ onError: (e) => {
10434
+ ui.toast.error(e.message);
10435
+ }
11112
10436
  }
11113
- ];
11114
- }
11115
- return Object.entries(metadata).map(([key, value]) => {
11116
- if (!EDITABLE_TYPES.includes(typeof value)) {
11117
- return {
11118
- key,
11119
- value,
11120
- disabled: true
11121
- };
11122
- }
11123
- let stringValue = value;
11124
- if (typeof value !== "string") {
11125
- stringValue = JSON.stringify(value);
11126
- }
11127
- return {
11128
- key,
11129
- value: stringValue,
11130
- original_key: key
11131
- };
11132
- });
11133
- }
11134
- function parseValues(values) {
11135
- const metadata = values.metadata;
11136
- const isEmpty = !metadata.length || metadata.length === 1 && !metadata[0].key && !metadata[0].value;
11137
- if (isEmpty) {
10437
+ );
10438
+ };
10439
+ const displayValue = getDisplayValue(promotion);
10440
+ return /* @__PURE__ */ jsxRuntime.jsxs(
10441
+ "div",
10442
+ {
10443
+ className: ui.clx(
10444
+ "bg-ui-bg-component shadow-elevation-card-rest flex items-center justify-between rounded-lg px-3 py-2",
10445
+ {
10446
+ "animate-pulse": isLoading
10447
+ }
10448
+ ),
10449
+ children: [
10450
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
10451
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", leading: "compact", children: promotion.code }),
10452
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-ui-fg-subtle flex items-center gap-1.5", children: [
10453
+ displayValue && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
10454
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", leading: "compact", children: displayValue }),
10455
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", leading: "compact", children: "·" })
10456
+ ] }),
10457
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", leading: "compact", className: "capitalize", children: (_a = promotion.application_method) == null ? void 0 : _a.allocation })
10458
+ ] })
10459
+ ] }),
10460
+ /* @__PURE__ */ jsxRuntime.jsx(
10461
+ ui.IconButton,
10462
+ {
10463
+ size: "small",
10464
+ type: "button",
10465
+ variant: "transparent",
10466
+ onClick: onRemove,
10467
+ isLoading: isPending || isLoading,
10468
+ children: /* @__PURE__ */ jsxRuntime.jsx(icons.XMark, {})
10469
+ }
10470
+ )
10471
+ ]
10472
+ },
10473
+ promotion.id
10474
+ );
10475
+ };
10476
+ function getDisplayValue(promotion) {
10477
+ var _a, _b, _c, _d;
10478
+ const value = (_a = promotion.application_method) == null ? void 0 : _a.value;
10479
+ if (!value) {
11138
10480
  return null;
11139
10481
  }
11140
- const update = {};
11141
- metadata.forEach((field) => {
11142
- let key = field.key;
11143
- let value = field.value;
11144
- const disabled = field.disabled;
11145
- if (!key || !value) {
11146
- return;
10482
+ if (((_b = promotion.application_method) == null ? void 0 : _b.type) === "fixed") {
10483
+ const currency = (_c = promotion.application_method) == null ? void 0 : _c.currency_code;
10484
+ if (!currency) {
10485
+ return null;
11147
10486
  }
11148
- if (disabled) {
11149
- update[key] = value;
11150
- return;
10487
+ return getLocaleAmount(value, currency);
10488
+ } else if (((_d = promotion.application_method) == null ? void 0 : _d.type) === "percentage") {
10489
+ return formatPercentage(value);
10490
+ }
10491
+ return null;
10492
+ }
10493
+ const formatter = new Intl.NumberFormat([], {
10494
+ style: "percent",
10495
+ minimumFractionDigits: 2
10496
+ });
10497
+ const formatPercentage = (value, isPercentageValue = false) => {
10498
+ let val = value || 0;
10499
+ if (!isPercentageValue) {
10500
+ val = val / 100;
10501
+ }
10502
+ return formatter.format(val);
10503
+ };
10504
+ function getPromotionIds(items, shippingMethods) {
10505
+ const promotionIds = /* @__PURE__ */ new Set();
10506
+ for (const item of items) {
10507
+ if (item.adjustments) {
10508
+ for (const adjustment of item.adjustments) {
10509
+ if (adjustment.promotion_id) {
10510
+ promotionIds.add(adjustment.promotion_id);
10511
+ }
10512
+ }
11151
10513
  }
11152
- key = key.trim();
11153
- value = value.trim();
11154
- if (value === "true") {
11155
- update[key] = true;
11156
- } else if (value === "false") {
11157
- update[key] = false;
11158
- } else {
11159
- const parsedNumber = parseFloat(value);
11160
- if (!isNaN(parsedNumber)) {
11161
- update[key] = parsedNumber;
11162
- } else {
11163
- update[key] = value;
10514
+ }
10515
+ for (const shippingMethod of shippingMethods) {
10516
+ if (shippingMethod.adjustments) {
10517
+ for (const adjustment of shippingMethod.adjustments) {
10518
+ if (adjustment.promotion_id) {
10519
+ promotionIds.add(adjustment.promotion_id);
10520
+ }
11164
10521
  }
11165
10522
  }
11166
- });
11167
- return update;
11168
- }
11169
- function getHasUneditableRows(metadata) {
11170
- if (!metadata) {
11171
- return false;
11172
10523
  }
11173
- return Object.values(metadata).some(
11174
- (value) => !EDITABLE_TYPES.includes(typeof value)
11175
- );
10524
+ return Array.from(promotionIds);
11176
10525
  }
11177
- const PROMOTION_QUERY_KEY = "promotions";
11178
- const promotionsQueryKeys = {
11179
- list: (query2) => [
11180
- PROMOTION_QUERY_KEY,
11181
- query2 ? query2 : void 0
11182
- ],
11183
- detail: (id, query2) => [
11184
- PROMOTION_QUERY_KEY,
10526
+ const SalesChannel = () => {
10527
+ const { id } = reactRouterDom.useParams();
10528
+ const { draft_order, isPending, isError, error } = useDraftOrder(
11185
10529
  id,
11186
- query2 ? query2 : void 0
11187
- ]
10530
+ {
10531
+ fields: "+sales_channel_id"
10532
+ },
10533
+ {
10534
+ enabled: !!id
10535
+ }
10536
+ );
10537
+ if (isError) {
10538
+ throw error;
10539
+ }
10540
+ const ISrEADY = !!draft_order && !isPending;
10541
+ return /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer, { children: [
10542
+ /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer.Header, { children: [
10543
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Edit Sales Channel" }) }),
10544
+ /* @__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" }) })
10545
+ ] }),
10546
+ ISrEADY && /* @__PURE__ */ jsxRuntime.jsx(SalesChannelForm, { order: draft_order })
10547
+ ] });
11188
10548
  };
11189
- const usePromotions = (query2, options) => {
11190
- const { data, ...rest } = reactQuery.useQuery({
11191
- queryKey: promotionsQueryKeys.list(query2),
11192
- queryFn: async () => sdk.admin.promotion.list(query2),
11193
- ...options
10549
+ const SalesChannelForm = ({ order }) => {
10550
+ const form = reactHookForm.useForm({
10551
+ defaultValues: {
10552
+ sales_channel_id: order.sales_channel_id || ""
10553
+ },
10554
+ resolver: zod.zodResolver(schema$2)
11194
10555
  });
11195
- return { ...data, ...rest };
10556
+ const { mutateAsync, isPending } = useUpdateDraftOrder(order.id);
10557
+ const { handleSuccess } = useRouteModal();
10558
+ const onSubmit = form.handleSubmit(async (data) => {
10559
+ await mutateAsync(
10560
+ {
10561
+ sales_channel_id: data.sales_channel_id
10562
+ },
10563
+ {
10564
+ onSuccess: () => {
10565
+ ui.toast.success("Sales channel updated");
10566
+ handleSuccess();
10567
+ },
10568
+ onError: (error) => {
10569
+ ui.toast.error(error.message);
10570
+ }
10571
+ }
10572
+ );
10573
+ });
10574
+ return /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxRuntime.jsxs(
10575
+ KeyboundForm,
10576
+ {
10577
+ className: "flex flex-1 flex-col overflow-hidden",
10578
+ onSubmit,
10579
+ children: [
10580
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Body, { className: "flex flex-col gap-y-6 overflow-y-auto", children: /* @__PURE__ */ jsxRuntime.jsx(SalesChannelField, { control: form.control, order }) }),
10581
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-2", children: [
10582
+ /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
10583
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", type: "submit", isLoading: isPending, children: "Save" })
10584
+ ] }) })
10585
+ ]
10586
+ }
10587
+ ) });
11196
10588
  };
11197
- const Promotions = () => {
10589
+ const SalesChannelField = ({ control, order }) => {
10590
+ const salesChannels = useComboboxData({
10591
+ queryFn: async (params) => {
10592
+ return await sdk.admin.salesChannel.list(params);
10593
+ },
10594
+ queryKey: ["sales-channels"],
10595
+ getOptions: (data) => {
10596
+ return data.sales_channels.map((salesChannel) => ({
10597
+ label: salesChannel.name,
10598
+ value: salesChannel.id
10599
+ }));
10600
+ },
10601
+ defaultValue: order.sales_channel_id || void 0
10602
+ });
10603
+ return /* @__PURE__ */ jsxRuntime.jsx(
10604
+ Form$2.Field,
10605
+ {
10606
+ control,
10607
+ name: "sales_channel_id",
10608
+ render: ({ field }) => {
10609
+ return /* @__PURE__ */ jsxRuntime.jsxs(Form$2.Item, { children: [
10610
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.Label, { children: "Sales Channel" }),
10611
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
10612
+ Combobox,
10613
+ {
10614
+ options: salesChannels.options,
10615
+ fetchNextPage: salesChannels.fetchNextPage,
10616
+ isFetchingNextPage: salesChannels.isFetchingNextPage,
10617
+ searchValue: salesChannels.searchValue,
10618
+ onSearchValueChange: salesChannels.onSearchValueChange,
10619
+ placeholder: "Select sales channel",
10620
+ ...field
10621
+ }
10622
+ ) }),
10623
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.ErrorMessage, {})
10624
+ ] });
10625
+ }
10626
+ }
10627
+ );
10628
+ };
10629
+ const schema$2 = objectType({
10630
+ sales_channel_id: stringType().min(1)
10631
+ });
10632
+ function convertNumber(value) {
10633
+ return typeof value === "string" ? Number(value.replace(",", ".")) : value;
10634
+ }
10635
+ const STACKED_FOCUS_MODAL_ID = "shipping-form";
10636
+ const Shipping = () => {
10637
+ var _a;
11198
10638
  const { id } = reactRouterDom.useParams();
10639
+ const { order, isPending, isError, error } = useOrder(id, {
10640
+ fields: "+items.*,+items.variant.*,+items.variant.product.*,+items.variant.product.shipping_profile.*,+currency_code"
10641
+ });
11199
10642
  const {
11200
10643
  order: preview,
10644
+ isPending: isPreviewPending,
11201
10645
  isError: isPreviewError,
11202
10646
  error: previewError
11203
- } = useOrderPreview(id, void 0);
10647
+ } = useOrderPreview(id);
11204
10648
  useInitiateOrderEdit({ preview });
11205
10649
  const { onCancel } = useCancelOrderEdit({ preview });
10650
+ if (isError) {
10651
+ throw error;
10652
+ }
11206
10653
  if (isPreviewError) {
11207
10654
  throw previewError;
11208
10655
  }
11209
- const isReady = !!preview;
11210
- return /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer, { onClose: onCancel, children: [
11211
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Edit Promotions" }) }) }),
11212
- isReady && /* @__PURE__ */ jsxRuntime.jsx(PromotionForm, { preview })
11213
- ] });
10656
+ const orderHasItems = (((_a = order == null ? void 0 : order.items) == null ? void 0 : _a.length) || 0) > 0;
10657
+ const isReady = preview && !isPreviewPending && order && !isPending;
10658
+ return /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal, { onClose: onCancel, children: !orderHasItems ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-full flex-col overflow-hidden ", children: [
10659
+ /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Header, {}),
10660
+ /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.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 py-16 px-6", children: [
10661
+ /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Shipping" }) }),
10662
+ /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "This draft order currently has no items. Add items to the order before adding shipping." }) })
10663
+ ] }) }) }),
10664
+ /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Footer, { children: /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }) })
10665
+ ] }) : isReady ? /* @__PURE__ */ jsxRuntime.jsx(ShippingForm, { preview, order }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
10666
+ /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Edit Shipping" }) }),
10667
+ /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Loading data for the draft order, please wait..." }) })
10668
+ ] }) });
11214
10669
  };
11215
- const PromotionForm = ({ preview }) => {
11216
- const { items, shipping_methods } = preview;
10670
+ const ShippingForm = ({ preview, order }) => {
10671
+ var _a;
10672
+ const { setIsOpen } = useStackedModal();
11217
10673
  const [isSubmitting, setIsSubmitting] = React.useState(false);
11218
- const [comboboxValue, setComboboxValue] = React.useState("");
11219
- const { handleSuccess } = useRouteModal();
11220
- const { mutateAsync: addPromotions, isPending: isAddingPromotions } = useDraftOrderAddPromotions(preview.id);
11221
- const promoIds = getPromotionIds(items, shipping_methods);
11222
- const { promotions, isPending, isError, error } = usePromotions(
10674
+ const [data, setData] = React.useState(null);
10675
+ const appliedShippingOptionIds = (_a = preview.shipping_methods) == null ? void 0 : _a.map((method) => method.shipping_option_id).filter(Boolean);
10676
+ const { shipping_options } = useShippingOptions(
11223
10677
  {
11224
- id: promoIds
10678
+ id: appliedShippingOptionIds,
10679
+ fields: "+service_zone.*,+service_zone.fulfillment_set.*,+service_zone.fulfillment_set.location.*"
11225
10680
  },
11226
10681
  {
11227
- enabled: !!promoIds.length
10682
+ enabled: appliedShippingOptionIds.length > 0
11228
10683
  }
11229
10684
  );
11230
- const comboboxData = useComboboxData({
11231
- queryKey: ["promotions", "combobox", promoIds],
11232
- queryFn: async (params) => {
11233
- return await sdk.admin.promotion.list({
11234
- ...params,
11235
- id: {
11236
- $nin: promoIds
11237
- }
11238
- });
11239
- },
11240
- getOptions: (data) => {
11241
- return data.promotions.map((promotion) => ({
11242
- label: promotion.code,
11243
- value: promotion.code
11244
- }));
11245
- }
11246
- });
11247
- const add = async (value) => {
11248
- if (!value) {
11249
- return;
11250
- }
11251
- addPromotions(
11252
- {
11253
- promo_codes: [value]
11254
- },
11255
- {
11256
- onError: (e) => {
11257
- ui.toast.error(e.message);
11258
- comboboxData.onSearchValueChange("");
11259
- setComboboxValue("");
11260
- },
11261
- onSuccess: () => {
11262
- comboboxData.onSearchValueChange("");
11263
- setComboboxValue("");
11264
- }
11265
- }
11266
- );
11267
- };
10685
+ const uniqueShippingProfiles = React.useMemo(() => {
10686
+ const profiles = /* @__PURE__ */ new Map();
10687
+ getUniqueShippingProfiles(order.items).forEach((profile) => {
10688
+ profiles.set(profile.id, profile);
10689
+ });
10690
+ shipping_options == null ? void 0 : shipping_options.forEach((option) => {
10691
+ profiles.set(option.shipping_profile_id, option.shipping_profile);
10692
+ });
10693
+ return Array.from(profiles.values());
10694
+ }, [order.items, shipping_options]);
10695
+ const { handleSuccess } = useRouteModal();
11268
10696
  const { mutateAsync: confirmOrderEdit } = useDraftOrderConfirmEdit(preview.id);
11269
- const { mutateAsync: requestOrderEdit } = useOrderEditRequest(preview.id);
10697
+ const { mutateAsync: requestOrderEdit } = useDraftOrderRequestEdit(preview.id);
10698
+ const { mutateAsync: removeShippingMethod } = useDraftOrderRemoveShippingMethod(preview.id);
10699
+ const { mutateAsync: removeActionShippingMethod } = useDraftOrderRemoveActionShippingMethod(preview.id);
11270
10700
  const onSubmit = async () => {
11271
10701
  setIsSubmitting(true);
11272
10702
  let requestSucceeded = false;
11273
10703
  await requestOrderEdit(void 0, {
11274
10704
  onError: (e) => {
11275
- ui.toast.error(e.message);
10705
+ ui.toast.error(`Failed to request order edit: ${e.message}`);
11276
10706
  },
11277
10707
  onSuccess: () => {
11278
10708
  requestSucceeded = true;
@@ -11284,7 +10714,7 @@ const PromotionForm = ({ preview }) => {
11284
10714
  }
11285
10715
  await confirmOrderEdit(void 0, {
11286
10716
  onError: (e) => {
11287
- ui.toast.error(e.message);
10717
+ ui.toast.error(`Failed to confirm order edit: ${e.message}`);
11288
10718
  },
11289
10719
  onSuccess: () => {
11290
10720
  handleSuccess();
@@ -11294,371 +10724,16 @@ const PromotionForm = ({ preview }) => {
11294
10724
  }
11295
10725
  });
11296
10726
  };
11297
- if (isError) {
11298
- throw error;
11299
- }
11300
- return /* @__PURE__ */ jsxRuntime.jsxs(KeyboundForm, { className: "flex flex-1 flex-col", onSubmit, children: [
11301
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Body, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-4", children: [
11302
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3", children: [
11303
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
11304
- /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: "small", weight: "plus", htmlFor: "promotion-combobox", children: "Apply promotions" }),
11305
- /* @__PURE__ */ jsxRuntime.jsx(ui.Hint, { id: "promotion-combobox-hint", children: "Manage promotions that should be applied to the order." })
11306
- ] }),
11307
- /* @__PURE__ */ jsxRuntime.jsx(
11308
- Combobox,
11309
- {
11310
- id: "promotion-combobox",
11311
- "aria-describedby": "promotion-combobox-hint",
11312
- isFetchingNextPage: comboboxData.isFetchingNextPage,
11313
- fetchNextPage: comboboxData.fetchNextPage,
11314
- options: comboboxData.options,
11315
- onSearchValueChange: comboboxData.onSearchValueChange,
11316
- searchValue: comboboxData.searchValue,
11317
- disabled: comboboxData.disabled || isAddingPromotions,
11318
- onChange: add,
11319
- value: comboboxValue
11320
- }
11321
- )
11322
- ] }),
11323
- /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { variant: "dashed" }),
11324
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-2", children: promotions == null ? void 0 : promotions.map((promotion) => /* @__PURE__ */ jsxRuntime.jsx(
11325
- PromotionItem,
11326
- {
11327
- promotion,
11328
- orderId: preview.id,
11329
- isLoading: isPending
11330
- },
11331
- promotion.id
11332
- )) })
11333
- ] }) }),
11334
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-2", children: [
11335
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
11336
- /* @__PURE__ */ jsxRuntime.jsx(
11337
- ui.Button,
11338
- {
11339
- size: "small",
11340
- type: "submit",
11341
- isLoading: isSubmitting || isAddingPromotions,
11342
- children: "Save"
11343
- }
11344
- )
11345
- ] }) })
11346
- ] });
11347
- };
11348
- const PromotionItem = ({
11349
- promotion,
11350
- orderId,
11351
- isLoading
11352
- }) => {
11353
- var _a;
11354
- const { mutateAsync: removePromotions, isPending } = useDraftOrderRemovePromotions(orderId);
11355
- const onRemove = async () => {
11356
- removePromotions(
11357
- {
11358
- promo_codes: [promotion.code]
11359
- },
11360
- {
11361
- onError: (e) => {
11362
- ui.toast.error(e.message);
11363
- }
11364
- }
11365
- );
11366
- };
11367
- const displayValue = getDisplayValue(promotion);
11368
- return /* @__PURE__ */ jsxRuntime.jsxs(
11369
- "div",
11370
- {
11371
- className: ui.clx(
11372
- "bg-ui-bg-component shadow-elevation-card-rest flex items-center justify-between rounded-lg px-3 py-2",
11373
- {
11374
- "animate-pulse": isLoading
11375
- }
11376
- ),
11377
- children: [
11378
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
11379
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", leading: "compact", children: promotion.code }),
11380
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-ui-fg-subtle flex items-center gap-1.5", children: [
11381
- displayValue && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
11382
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", leading: "compact", children: displayValue }),
11383
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", leading: "compact", children: "·" })
11384
- ] }),
11385
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", leading: "compact", className: "capitalize", children: (_a = promotion.application_method) == null ? void 0 : _a.allocation })
11386
- ] })
11387
- ] }),
11388
- /* @__PURE__ */ jsxRuntime.jsx(
11389
- ui.IconButton,
11390
- {
11391
- size: "small",
11392
- type: "button",
11393
- variant: "transparent",
11394
- onClick: onRemove,
11395
- isLoading: isPending || isLoading,
11396
- children: /* @__PURE__ */ jsxRuntime.jsx(icons.XMark, {})
11397
- }
11398
- )
11399
- ]
11400
- },
11401
- promotion.id
11402
- );
11403
- };
11404
- function getDisplayValue(promotion) {
11405
- var _a, _b, _c, _d;
11406
- const value = (_a = promotion.application_method) == null ? void 0 : _a.value;
11407
- if (!value) {
11408
- return null;
11409
- }
11410
- if (((_b = promotion.application_method) == null ? void 0 : _b.type) === "fixed") {
11411
- const currency = (_c = promotion.application_method) == null ? void 0 : _c.currency_code;
11412
- if (!currency) {
11413
- return null;
11414
- }
11415
- return getLocaleAmount(value, currency);
11416
- } else if (((_d = promotion.application_method) == null ? void 0 : _d.type) === "percentage") {
11417
- return formatPercentage(value);
11418
- }
11419
- return null;
11420
- }
11421
- const formatter = new Intl.NumberFormat([], {
11422
- style: "percent",
11423
- minimumFractionDigits: 2
11424
- });
11425
- const formatPercentage = (value, isPercentageValue = false) => {
11426
- let val = value || 0;
11427
- if (!isPercentageValue) {
11428
- val = val / 100;
11429
- }
11430
- return formatter.format(val);
11431
- };
11432
- function getPromotionIds(items, shippingMethods) {
11433
- const promotionIds = /* @__PURE__ */ new Set();
11434
- for (const item of items) {
11435
- if (item.adjustments) {
11436
- for (const adjustment of item.adjustments) {
11437
- if (adjustment.promotion_id) {
11438
- promotionIds.add(adjustment.promotion_id);
11439
- }
11440
- }
11441
- }
11442
- }
11443
- for (const shippingMethod of shippingMethods) {
11444
- if (shippingMethod.adjustments) {
11445
- for (const adjustment of shippingMethod.adjustments) {
11446
- if (adjustment.promotion_id) {
11447
- promotionIds.add(adjustment.promotion_id);
10727
+ const onKeydown = React.useCallback(
10728
+ (e) => {
10729
+ if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) {
10730
+ if (data || isSubmitting) {
10731
+ return;
11448
10732
  }
10733
+ onSubmit();
11449
10734
  }
11450
- }
11451
- }
11452
- return Array.from(promotionIds);
11453
- }
11454
- const SalesChannel = () => {
11455
- const { id } = reactRouterDom.useParams();
11456
- const { draft_order, isPending, isError, error } = useDraftOrder(
11457
- id,
11458
- {
11459
- fields: "+sales_channel_id"
11460
10735
  },
11461
- {
11462
- enabled: !!id
11463
- }
11464
- );
11465
- if (isError) {
11466
- throw error;
11467
- }
11468
- const ISrEADY = !!draft_order && !isPending;
11469
- return /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer, { children: [
11470
- /* @__PURE__ */ jsxRuntime.jsxs(RouteDrawer.Header, { children: [
11471
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Edit Sales Channel" }) }),
11472
- /* @__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" }) })
11473
- ] }),
11474
- ISrEADY && /* @__PURE__ */ jsxRuntime.jsx(SalesChannelForm, { order: draft_order })
11475
- ] });
11476
- };
11477
- const SalesChannelForm = ({ order }) => {
11478
- const form = reactHookForm.useForm({
11479
- defaultValues: {
11480
- sales_channel_id: order.sales_channel_id || ""
11481
- },
11482
- resolver: zod.zodResolver(schema$2)
11483
- });
11484
- const { mutateAsync, isPending } = useUpdateDraftOrder(order.id);
11485
- const { handleSuccess } = useRouteModal();
11486
- const onSubmit = form.handleSubmit(async (data) => {
11487
- await mutateAsync(
11488
- {
11489
- sales_channel_id: data.sales_channel_id
11490
- },
11491
- {
11492
- onSuccess: () => {
11493
- ui.toast.success("Sales channel updated");
11494
- handleSuccess();
11495
- },
11496
- onError: (error) => {
11497
- ui.toast.error(error.message);
11498
- }
11499
- }
11500
- );
11501
- });
11502
- return /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxRuntime.jsxs(
11503
- KeyboundForm,
11504
- {
11505
- className: "flex flex-1 flex-col overflow-hidden",
11506
- onSubmit,
11507
- children: [
11508
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Body, { className: "flex flex-col gap-y-6 overflow-y-auto", children: /* @__PURE__ */ jsxRuntime.jsx(SalesChannelField, { control: form.control, order }) }),
11509
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-2", children: [
11510
- /* @__PURE__ */ jsxRuntime.jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
11511
- /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", type: "submit", isLoading: isPending, children: "Save" })
11512
- ] }) })
11513
- ]
11514
- }
11515
- ) });
11516
- };
11517
- const SalesChannelField = ({ control, order }) => {
11518
- const salesChannels = useComboboxData({
11519
- queryFn: async (params) => {
11520
- return await sdk.admin.salesChannel.list(params);
11521
- },
11522
- queryKey: ["sales-channels"],
11523
- getOptions: (data) => {
11524
- return data.sales_channels.map((salesChannel) => ({
11525
- label: salesChannel.name,
11526
- value: salesChannel.id
11527
- }));
11528
- },
11529
- defaultValue: order.sales_channel_id || void 0
11530
- });
11531
- return /* @__PURE__ */ jsxRuntime.jsx(
11532
- Form$2.Field,
11533
- {
11534
- control,
11535
- name: "sales_channel_id",
11536
- render: ({ field }) => {
11537
- return /* @__PURE__ */ jsxRuntime.jsxs(Form$2.Item, { children: [
11538
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.Label, { children: "Sales Channel" }),
11539
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
11540
- Combobox,
11541
- {
11542
- options: salesChannels.options,
11543
- fetchNextPage: salesChannels.fetchNextPage,
11544
- isFetchingNextPage: salesChannels.isFetchingNextPage,
11545
- searchValue: salesChannels.searchValue,
11546
- onSearchValueChange: salesChannels.onSearchValueChange,
11547
- placeholder: "Select sales channel",
11548
- ...field
11549
- }
11550
- ) }),
11551
- /* @__PURE__ */ jsxRuntime.jsx(Form$2.ErrorMessage, {})
11552
- ] });
11553
- }
11554
- }
11555
- );
11556
- };
11557
- const schema$2 = objectType({
11558
- sales_channel_id: stringType().min(1)
11559
- });
11560
- const STACKED_FOCUS_MODAL_ID = "shipping-form";
11561
- const Shipping = () => {
11562
- var _a;
11563
- const { id } = reactRouterDom.useParams();
11564
- const { order, isPending, isError, error } = useOrder(id, {
11565
- fields: "+items.*,+items.variant.*,+items.variant.product.*,+items.variant.product.shipping_profile.*,+currency_code"
11566
- });
11567
- const {
11568
- order: preview,
11569
- isPending: isPreviewPending,
11570
- isError: isPreviewError,
11571
- error: previewError
11572
- } = useOrderPreview(id);
11573
- useInitiateOrderEdit({ preview });
11574
- const { onCancel } = useCancelOrderEdit({ preview });
11575
- if (isError) {
11576
- throw error;
11577
- }
11578
- if (isPreviewError) {
11579
- throw previewError;
11580
- }
11581
- const orderHasItems = (((_a = order == null ? void 0 : order.items) == null ? void 0 : _a.length) || 0) > 0;
11582
- const isReady = preview && !isPreviewPending && order && !isPending;
11583
- return /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal, { onClose: onCancel, children: !orderHasItems ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-full flex-col overflow-hidden ", children: [
11584
- /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Header, {}),
11585
- /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.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 py-16 px-6", children: [
11586
- /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Shipping" }) }),
11587
- /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "This draft order currently has no items. Add items to the order before adding shipping." }) })
11588
- ] }) }) }),
11589
- /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Footer, { children: /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }) })
11590
- ] }) : isReady ? /* @__PURE__ */ jsxRuntime.jsx(ShippingForm, { preview, order }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
11591
- /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Edit Shipping" }) }),
11592
- /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Loading data for the draft order, please wait..." }) })
11593
- ] }) });
11594
- };
11595
- const ShippingForm = ({ preview, order }) => {
11596
- var _a;
11597
- const { setIsOpen } = useStackedModal();
11598
- const [isSubmitting, setIsSubmitting] = React.useState(false);
11599
- const [data, setData] = React.useState(null);
11600
- const appliedShippingOptionIds = (_a = preview.shipping_methods) == null ? void 0 : _a.map((method) => method.shipping_option_id).filter(Boolean);
11601
- const { shipping_options } = useShippingOptions(
11602
- {
11603
- id: appliedShippingOptionIds,
11604
- fields: "+service_zone.*,+service_zone.fulfillment_set.*,+service_zone.fulfillment_set.location.*"
11605
- },
11606
- {
11607
- enabled: appliedShippingOptionIds.length > 0
11608
- }
11609
- );
11610
- const uniqueShippingProfiles = React.useMemo(() => {
11611
- const profiles = /* @__PURE__ */ new Map();
11612
- getUniqueShippingProfiles(order.items).forEach((profile) => {
11613
- profiles.set(profile.id, profile);
11614
- });
11615
- shipping_options == null ? void 0 : shipping_options.forEach((option) => {
11616
- profiles.set(option.shipping_profile_id, option.shipping_profile);
11617
- });
11618
- return Array.from(profiles.values());
11619
- }, [order.items, shipping_options]);
11620
- const { handleSuccess } = useRouteModal();
11621
- const { mutateAsync: confirmOrderEdit } = useDraftOrderConfirmEdit(preview.id);
11622
- const { mutateAsync: requestOrderEdit } = useDraftOrderRequestEdit(preview.id);
11623
- const { mutateAsync: removeShippingMethod } = useDraftOrderRemoveShippingMethod(preview.id);
11624
- const { mutateAsync: removeActionShippingMethod } = useDraftOrderRemoveActionShippingMethod(preview.id);
11625
- const onSubmit = async () => {
11626
- setIsSubmitting(true);
11627
- let requestSucceeded = false;
11628
- await requestOrderEdit(void 0, {
11629
- onError: (e) => {
11630
- ui.toast.error(`Failed to request order edit: ${e.message}`);
11631
- },
11632
- onSuccess: () => {
11633
- requestSucceeded = true;
11634
- }
11635
- });
11636
- if (!requestSucceeded) {
11637
- setIsSubmitting(false);
11638
- return;
11639
- }
11640
- await confirmOrderEdit(void 0, {
11641
- onError: (e) => {
11642
- ui.toast.error(`Failed to confirm order edit: ${e.message}`);
11643
- },
11644
- onSuccess: () => {
11645
- handleSuccess();
11646
- },
11647
- onSettled: () => {
11648
- setIsSubmitting(false);
11649
- }
11650
- });
11651
- };
11652
- const onKeydown = React.useCallback(
11653
- (e) => {
11654
- if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) {
11655
- if (data || isSubmitting) {
11656
- return;
11657
- }
11658
- onSubmit();
11659
- }
11660
- },
11661
- [data, isSubmitting, onSubmit]
10736
+ [data, isSubmitting, onSubmit]
11662
10737
  );
11663
10738
  React.useEffect(() => {
11664
10739
  document.addEventListener("keydown", onKeydown);
@@ -11864,7 +10939,7 @@ const ShippingForm = ({ preview, order }) => {
11864
10939
  ]
11865
10940
  }
11866
10941
  ) : /* @__PURE__ */ jsxRuntime.jsx(
11867
- StackedModalTrigger,
10942
+ StackedModalTrigger$1,
11868
10943
  {
11869
10944
  shippingProfileId: profile.id,
11870
10945
  shippingOption,
@@ -11975,7 +11050,7 @@ const ShippingForm = ({ preview, order }) => {
11975
11050
  ] }) })
11976
11051
  ] });
11977
11052
  };
11978
- const StackedModalTrigger = ({
11053
+ const StackedModalTrigger$1 = ({
11979
11054
  shippingProfileId,
11980
11055
  shippingOption,
11981
11056
  shippingMethod,
@@ -12980,68 +12055,993 @@ const Illustration = () => {
12980
12055
  strokeLinejoin: "round"
12981
12056
  }
12982
12057
  ) }),
12983
- /* @__PURE__ */ jsxRuntime.jsxs("defs", { children: [
12984
- /* @__PURE__ */ jsxRuntime.jsx("clipPath", { id: "clip0_20915_38670", children: /* @__PURE__ */ jsxRuntime.jsx(
12985
- "rect",
12986
- {
12987
- width: "12",
12988
- height: "12",
12989
- fill: "white",
12990
- transform: "matrix(0.865865 0.500278 -0.871576 0.490261 138.36 74.6508)"
12991
- }
12992
- ) }),
12993
- /* @__PURE__ */ jsxRuntime.jsx("clipPath", { id: "clip1_20915_38670", children: /* @__PURE__ */ jsxRuntime.jsx(
12994
- "rect",
12995
- {
12996
- width: "12",
12997
- height: "12",
12998
- fill: "white",
12999
- transform: "matrix(0.865865 0.500278 -0.871576 0.490261 148.75 80.6541)"
13000
- }
13001
- ) }),
13002
- /* @__PURE__ */ jsxRuntime.jsx("clipPath", { id: "clip2_20915_38670", children: /* @__PURE__ */ jsxRuntime.jsx(
13003
- "rect",
13004
- {
13005
- width: "12",
13006
- height: "12",
13007
- fill: "white",
13008
- transform: "matrix(0.865865 0.500278 -0.871576 0.490261 159.141 86.6575)"
13009
- }
13010
- ) }),
13011
- /* @__PURE__ */ jsxRuntime.jsx("clipPath", { id: "clip3_20915_38670", children: /* @__PURE__ */ jsxRuntime.jsx(
13012
- "rect",
13013
- {
13014
- width: "12",
13015
- height: "12",
13016
- fill: "white",
13017
- transform: "matrix(0.865865 0.500278 -0.871576 0.490261 120.928 84.4561)"
13018
- }
13019
- ) }),
13020
- /* @__PURE__ */ jsxRuntime.jsx("clipPath", { id: "clip4_20915_38670", children: /* @__PURE__ */ jsxRuntime.jsx(
13021
- "rect",
12058
+ /* @__PURE__ */ jsxRuntime.jsxs("defs", { children: [
12059
+ /* @__PURE__ */ jsxRuntime.jsx("clipPath", { id: "clip0_20915_38670", children: /* @__PURE__ */ jsxRuntime.jsx(
12060
+ "rect",
12061
+ {
12062
+ width: "12",
12063
+ height: "12",
12064
+ fill: "white",
12065
+ transform: "matrix(0.865865 0.500278 -0.871576 0.490261 138.36 74.6508)"
12066
+ }
12067
+ ) }),
12068
+ /* @__PURE__ */ jsxRuntime.jsx("clipPath", { id: "clip1_20915_38670", children: /* @__PURE__ */ jsxRuntime.jsx(
12069
+ "rect",
12070
+ {
12071
+ width: "12",
12072
+ height: "12",
12073
+ fill: "white",
12074
+ transform: "matrix(0.865865 0.500278 -0.871576 0.490261 148.75 80.6541)"
12075
+ }
12076
+ ) }),
12077
+ /* @__PURE__ */ jsxRuntime.jsx("clipPath", { id: "clip2_20915_38670", children: /* @__PURE__ */ jsxRuntime.jsx(
12078
+ "rect",
12079
+ {
12080
+ width: "12",
12081
+ height: "12",
12082
+ fill: "white",
12083
+ transform: "matrix(0.865865 0.500278 -0.871576 0.490261 159.141 86.6575)"
12084
+ }
12085
+ ) }),
12086
+ /* @__PURE__ */ jsxRuntime.jsx("clipPath", { id: "clip3_20915_38670", children: /* @__PURE__ */ jsxRuntime.jsx(
12087
+ "rect",
12088
+ {
12089
+ width: "12",
12090
+ height: "12",
12091
+ fill: "white",
12092
+ transform: "matrix(0.865865 0.500278 -0.871576 0.490261 120.928 84.4561)"
12093
+ }
12094
+ ) }),
12095
+ /* @__PURE__ */ jsxRuntime.jsx("clipPath", { id: "clip4_20915_38670", children: /* @__PURE__ */ jsxRuntime.jsx(
12096
+ "rect",
12097
+ {
12098
+ width: "12",
12099
+ height: "12",
12100
+ fill: "white",
12101
+ transform: "matrix(0.865865 0.500278 -0.871576 0.490261 131.318 90.4594)"
12102
+ }
12103
+ ) }),
12104
+ /* @__PURE__ */ jsxRuntime.jsx("clipPath", { id: "clip5_20915_38670", children: /* @__PURE__ */ jsxRuntime.jsx(
12105
+ "rect",
12106
+ {
12107
+ width: "12",
12108
+ height: "12",
12109
+ fill: "white",
12110
+ transform: "matrix(0.865865 0.500278 -0.871576 0.490261 141.709 96.4627)"
12111
+ }
12112
+ ) })
12113
+ ] })
12114
+ ]
12115
+ }
12116
+ );
12117
+ };
12118
+ const schema = objectType({
12119
+ customer_id: stringType().min(1)
12120
+ });
12121
+ const NumberInput = React.forwardRef(
12122
+ ({
12123
+ value,
12124
+ onChange,
12125
+ size = "base",
12126
+ min = 0,
12127
+ max = 100,
12128
+ step = 1,
12129
+ className,
12130
+ disabled,
12131
+ ...props
12132
+ }, ref) => {
12133
+ const handleChange = (event) => {
12134
+ const newValue = event.target.value === "" ? min : Number(event.target.value);
12135
+ if (!isNaN(newValue) && (max === void 0 || newValue <= max) && (min === void 0 || newValue >= min)) {
12136
+ onChange(newValue);
12137
+ }
12138
+ };
12139
+ const handleIncrement = () => {
12140
+ const newValue = value + step;
12141
+ if (max === void 0 || newValue <= max) {
12142
+ onChange(newValue);
12143
+ }
12144
+ };
12145
+ const handleDecrement = () => {
12146
+ const newValue = value - step;
12147
+ if (min === void 0 || newValue >= min) {
12148
+ onChange(newValue);
12149
+ }
12150
+ };
12151
+ return /* @__PURE__ */ jsxRuntime.jsxs(
12152
+ "div",
12153
+ {
12154
+ className: ui.clx(
12155
+ "inline-flex rounded-md bg-ui-bg-field shadow-borders-base overflow-hidden divide-x transition-fg",
12156
+ "[&:has(input:focus)]:shadow-borders-interactive-with-active",
12157
+ {
12158
+ "h-7": size === "small",
12159
+ "h-8": size === "base"
12160
+ },
12161
+ className
12162
+ ),
12163
+ children: [
12164
+ /* @__PURE__ */ jsxRuntime.jsx(
12165
+ "input",
12166
+ {
12167
+ ref,
12168
+ type: "number",
12169
+ value,
12170
+ onChange: handleChange,
12171
+ min,
12172
+ max,
12173
+ step,
12174
+ className: ui.clx(
12175
+ "flex-1 px-2 py-1 bg-transparent txt-compact-small text-ui-fg-base outline-none [appearance:textfield]",
12176
+ "[&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none",
12177
+ "placeholder:text-ui-fg-muted"
12178
+ ),
12179
+ ...props
12180
+ }
12181
+ ),
12182
+ /* @__PURE__ */ jsxRuntime.jsxs(
12183
+ "button",
12184
+ {
12185
+ className: ui.clx(
12186
+ "flex items-center justify-center outline-none transition-fg",
12187
+ "disabled:cursor-not-allowed disabled:text-ui-fg-muted",
12188
+ "focus:bg-ui-bg-field-component-hover",
12189
+ "hover:bg-ui-bg-field-component-hover",
12190
+ {
12191
+ "size-7": size === "small",
12192
+ "size-8": size === "base"
12193
+ }
12194
+ ),
12195
+ type: "button",
12196
+ onClick: handleDecrement,
12197
+ disabled: min !== void 0 && value <= min || disabled,
12198
+ children: [
12199
+ /* @__PURE__ */ jsxRuntime.jsx(icons.Minus, {}),
12200
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: `Decrease by ${step}` })
12201
+ ]
12202
+ }
12203
+ ),
12204
+ /* @__PURE__ */ jsxRuntime.jsxs(
12205
+ "button",
12206
+ {
12207
+ className: ui.clx(
12208
+ "flex items-center justify-center outline-none transition-fg",
12209
+ "disabled:cursor-not-allowed disabled:text-ui-fg-muted",
12210
+ "focus:bg-ui-bg-field-hover",
12211
+ "hover:bg-ui-bg-field-hover",
12212
+ {
12213
+ "size-7": size === "small",
12214
+ "size-8": size === "base"
12215
+ }
12216
+ ),
12217
+ type: "button",
12218
+ onClick: handleIncrement,
12219
+ disabled: max !== void 0 && value >= max || disabled,
12220
+ children: [
12221
+ /* @__PURE__ */ jsxRuntime.jsx(icons.Plus, {}),
12222
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: `Increase by ${step}` })
12223
+ ]
12224
+ }
12225
+ )
12226
+ ]
12227
+ }
12228
+ );
12229
+ }
12230
+ );
12231
+ const PRODUCT_VARIANTS_QUERY_KEY = "product-variants";
12232
+ const productVariantsQueryKeys = {
12233
+ list: (query2) => [
12234
+ PRODUCT_VARIANTS_QUERY_KEY,
12235
+ query2 ? query2 : void 0
12236
+ ]
12237
+ };
12238
+ const useProductVariants = (query2, options) => {
12239
+ const { data, ...rest } = reactQuery.useQuery({
12240
+ queryKey: productVariantsQueryKeys.list(query2),
12241
+ queryFn: async () => await sdk.admin.productVariant.list(query2),
12242
+ ...options
12243
+ });
12244
+ return { ...data, ...rest };
12245
+ };
12246
+ const STACKED_MODAL_ID = "items_stacked_modal";
12247
+ const Items = () => {
12248
+ const { id } = reactRouterDom.useParams();
12249
+ const {
12250
+ order: preview,
12251
+ isPending: isPreviewPending,
12252
+ isError: isPreviewError,
12253
+ error: previewError
12254
+ } = useOrderPreview(id, void 0, {
12255
+ placeholderData: reactQuery.keepPreviousData
12256
+ });
12257
+ useInitiateOrderEdit({ preview });
12258
+ const { draft_order, isPending, isError, error } = useDraftOrder(
12259
+ id,
12260
+ {
12261
+ fields: "currency_code"
12262
+ },
12263
+ {
12264
+ enabled: !!id
12265
+ }
12266
+ );
12267
+ const { onCancel } = useCancelOrderEdit({ preview });
12268
+ if (isError) {
12269
+ throw error;
12270
+ }
12271
+ if (isPreviewError) {
12272
+ throw previewError;
12273
+ }
12274
+ const ready = !!preview && !isPreviewPending && !!draft_order && !isPending;
12275
+ return /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal, { onClose: onCancel, children: ready ? /* @__PURE__ */ jsxRuntime.jsx(ItemsForm, { preview, currencyCode: draft_order.currency_code }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
12276
+ /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Edit Items" }) }),
12277
+ /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Loading data for the draft order, please wait..." }) })
12278
+ ] }) });
12279
+ };
12280
+ const ItemsForm = ({ preview, currencyCode }) => {
12281
+ var _a;
12282
+ const [isSubmitting, setIsSubmitting] = React.useState(false);
12283
+ const [modalContent, setModalContent] = React.useState(
12284
+ null
12285
+ );
12286
+ const { handleSuccess } = useRouteModal();
12287
+ const { searchValue, onSearchValueChange, query: query2 } = useDebouncedSearch();
12288
+ const { mutateAsync: confirmOrderEdit } = useDraftOrderConfirmEdit(preview.id);
12289
+ const { mutateAsync: requestOrderEdit } = useDraftOrderRequestEdit(preview.id);
12290
+ const itemCount = ((_a = preview.items) == null ? void 0 : _a.reduce((acc, item) => acc + item.quantity, 0)) || 0;
12291
+ const matches = React.useMemo(() => {
12292
+ return matchSorter.matchSorter(preview.items, query2, {
12293
+ keys: ["product_title", "variant_title", "variant_sku", "title"]
12294
+ });
12295
+ }, [preview.items, query2]);
12296
+ const onSubmit = async () => {
12297
+ setIsSubmitting(true);
12298
+ let requestSucceeded = false;
12299
+ await requestOrderEdit(void 0, {
12300
+ onError: (e) => {
12301
+ ui.toast.error(`Failed to request order edit: ${e.message}`);
12302
+ },
12303
+ onSuccess: () => {
12304
+ requestSucceeded = true;
12305
+ }
12306
+ });
12307
+ if (!requestSucceeded) {
12308
+ setIsSubmitting(false);
12309
+ return;
12310
+ }
12311
+ await confirmOrderEdit(void 0, {
12312
+ onError: (e) => {
12313
+ ui.toast.error(`Failed to confirm order edit: ${e.message}`);
12314
+ },
12315
+ onSuccess: () => {
12316
+ handleSuccess();
12317
+ },
12318
+ onSettled: () => {
12319
+ setIsSubmitting(false);
12320
+ }
12321
+ });
12322
+ };
12323
+ const onKeyDown = React.useCallback(
12324
+ (e) => {
12325
+ if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) {
12326
+ if (modalContent || isSubmitting) {
12327
+ return;
12328
+ }
12329
+ onSubmit();
12330
+ }
12331
+ },
12332
+ [modalContent, isSubmitting, onSubmit]
12333
+ );
12334
+ React.useEffect(() => {
12335
+ document.addEventListener("keydown", onKeyDown);
12336
+ return () => {
12337
+ document.removeEventListener("keydown", onKeyDown);
12338
+ };
12339
+ }, [onKeyDown]);
12340
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-full flex-col overflow-hidden", children: [
12341
+ /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Header, {}),
12342
+ /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Body, { className: "flex flex-1 flex-col overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsxs(
12343
+ StackedFocusModal,
12344
+ {
12345
+ id: STACKED_MODAL_ID,
12346
+ onOpenChangeCallback: (open) => {
12347
+ if (!open) {
12348
+ setModalContent(null);
12349
+ }
12350
+ },
12351
+ children: [
12352
+ /* @__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: [
12353
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
12354
+ /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Edit Items" }) }),
12355
+ /* @__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" }) })
12356
+ ] }),
12357
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { variant: "dashed" }),
12358
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-6", children: [
12359
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 items-center gap-3", children: [
12360
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
12361
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", leading: "compact", children: "Items" }),
12362
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Choose items from the product catalog." })
12363
+ ] }),
12364
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
12365
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(
12366
+ ui.Input,
12367
+ {
12368
+ type: "search",
12369
+ placeholder: "Search items",
12370
+ value: searchValue,
12371
+ onChange: (e) => onSearchValueChange(e.target.value)
12372
+ }
12373
+ ) }),
12374
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu, { children: [
12375
+ /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenu.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { type: "button", children: /* @__PURE__ */ jsxRuntime.jsx(icons.Plus, {}) }) }),
12376
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu.Content, { children: [
12377
+ /* @__PURE__ */ jsxRuntime.jsx(
12378
+ StackedModalTrigger,
12379
+ {
12380
+ type: "add-items",
12381
+ setModalContent
12382
+ }
12383
+ ),
12384
+ /* @__PURE__ */ jsxRuntime.jsx(
12385
+ StackedModalTrigger,
12386
+ {
12387
+ type: "add-custom-item",
12388
+ setModalContent
12389
+ }
12390
+ )
12391
+ ] })
12392
+ ] })
12393
+ ] })
12394
+ ] }),
12395
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-subtle shadow-elevation-card-rest rounded-xl", children: [
12396
+ /* @__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: [
12397
+ /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: "Item" }) }),
12398
+ /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: "Quantity" }) }),
12399
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-right", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: "Price" }) }),
12400
+ /* @__PURE__ */ jsxRuntime.jsx("div", {})
12401
+ ] }) }),
12402
+ /* @__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: [
12403
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", leading: "compact", children: "There are no items in this order" }),
12404
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: "Add items to the order to get started." })
12405
+ ] }) : matches.length > 0 ? matches == null ? void 0 : matches.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
12406
+ Item,
12407
+ {
12408
+ item,
12409
+ preview,
12410
+ currencyCode
12411
+ },
12412
+ item.id
12413
+ )) : /* @__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: [
12414
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", leading: "compact", children: "No items found" }),
12415
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: [
12416
+ 'No items found for "',
12417
+ query2,
12418
+ '".'
12419
+ ] })
12420
+ ] }) })
12421
+ ] })
12422
+ ] }),
12423
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { variant: "dashed" }),
12424
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-[1fr_0.5fr_0.5fr] gap-3", children: [
12425
+ /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", leading: "compact", children: "Subtotal" }) }),
12426
+ /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsxs(
12427
+ ui.Text,
12428
+ {
12429
+ size: "small",
12430
+ leading: "compact",
12431
+ className: "text-ui-fg-subtle",
12432
+ children: [
12433
+ itemCount,
12434
+ " ",
12435
+ itemCount === 1 ? "item" : "items"
12436
+ ]
12437
+ }
12438
+ ) }),
12439
+ /* @__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) }) })
12440
+ ] })
12441
+ ] }) }),
12442
+ modalContent && (modalContent === "add-items" ? /* @__PURE__ */ jsxRuntime.jsx(ExistingItemsForm, { orderId: preview.id, items: preview.items }) : modalContent === "add-custom-item" ? /* @__PURE__ */ jsxRuntime.jsx(
12443
+ CustomItemForm,
12444
+ {
12445
+ orderId: preview.id,
12446
+ currencyCode
12447
+ }
12448
+ ) : null)
12449
+ ]
12450
+ }
12451
+ ) }),
12452
+ /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
12453
+ /* @__PURE__ */ jsxRuntime.jsx(RouteFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
12454
+ /* @__PURE__ */ jsxRuntime.jsx(
12455
+ ui.Button,
12456
+ {
12457
+ size: "small",
12458
+ type: "button",
12459
+ onClick: onSubmit,
12460
+ isLoading: isSubmitting,
12461
+ children: "Save"
12462
+ }
12463
+ )
12464
+ ] }) })
12465
+ ] });
12466
+ };
12467
+ const Item = ({ item, preview, currencyCode }) => {
12468
+ if (item.variant_id) {
12469
+ return /* @__PURE__ */ jsxRuntime.jsx(VariantItem, { item, preview, currencyCode });
12470
+ }
12471
+ return /* @__PURE__ */ jsxRuntime.jsx(CustomItem, { item, preview, currencyCode });
12472
+ };
12473
+ const VariantItem = ({ item, preview, currencyCode }) => {
12474
+ const [editing, setEditing] = React.useState(false);
12475
+ const form = reactHookForm.useForm({
12476
+ defaultValues: {
12477
+ quantity: item.quantity,
12478
+ unit_price: item.unit_price
12479
+ },
12480
+ resolver: zod.zodResolver(variantItemSchema)
12481
+ });
12482
+ const actionId = React.useMemo(() => {
12483
+ var _a, _b;
12484
+ return (_b = (_a = item.actions) == null ? void 0 : _a.find((a) => a.action === "ITEM_ADD")) == null ? void 0 : _b.id;
12485
+ }, [item]);
12486
+ const { mutateAsync: updateActionItem, isPending: isUpdatingActionItem } = useDraftOrderUpdateActionItem(preview.id);
12487
+ const { mutateAsync: updateOriginalItem, isPending: isUpdatingOriginalItem } = useDraftOrderUpdateItem(preview.id);
12488
+ const isPending = isUpdatingActionItem || isUpdatingOriginalItem;
12489
+ const onSubmit = form.handleSubmit(async (data) => {
12490
+ if (convertNumber(data.unit_price) === item.unit_price && data.quantity === item.quantity) {
12491
+ setEditing(false);
12492
+ return;
12493
+ }
12494
+ if (!actionId) {
12495
+ await updateOriginalItem(
12496
+ {
12497
+ item_id: item.id,
12498
+ quantity: data.quantity,
12499
+ unit_price: convertNumber(data.unit_price)
12500
+ },
12501
+ {
12502
+ onSuccess: () => {
12503
+ setEditing(false);
12504
+ },
12505
+ onError: (e) => {
12506
+ ui.toast.error(e.message);
12507
+ }
12508
+ }
12509
+ );
12510
+ return;
12511
+ }
12512
+ await updateActionItem(
12513
+ {
12514
+ action_id: actionId,
12515
+ quantity: data.quantity,
12516
+ unit_price: convertNumber(data.unit_price)
12517
+ },
12518
+ {
12519
+ onSuccess: () => {
12520
+ setEditing(false);
12521
+ },
12522
+ onError: (e) => {
12523
+ ui.toast.error(e.message);
12524
+ }
12525
+ }
12526
+ );
12527
+ });
12528
+ 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: [
12529
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex w-full items-center gap-x-3", children: [
12530
+ /* @__PURE__ */ jsxRuntime.jsx(
12531
+ Thumbnail,
12532
+ {
12533
+ thumbnail: item.thumbnail,
12534
+ alt: item.product_title ?? void 0
12535
+ }
12536
+ ),
12537
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
12538
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-x-1", children: [
12539
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", leading: "compact", children: item.product_title }),
12540
+ /* @__PURE__ */ jsxRuntime.jsxs(
12541
+ ui.Text,
12542
+ {
12543
+ size: "small",
12544
+ leading: "compact",
12545
+ className: "text-ui-fg-subtle",
12546
+ children: [
12547
+ "(",
12548
+ item.variant_title,
12549
+ ")"
12550
+ ]
12551
+ }
12552
+ )
12553
+ ] }),
12554
+ /* @__PURE__ */ jsxRuntime.jsx(
12555
+ ui.Text,
12556
+ {
12557
+ size: "small",
12558
+ leading: "compact",
12559
+ className: "text-ui-fg-subtle",
12560
+ children: item.variant_sku
12561
+ }
12562
+ )
12563
+ ] })
12564
+ ] }),
12565
+ editing ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(
12566
+ Form$2.Field,
12567
+ {
12568
+ control: form.control,
12569
+ name: "quantity",
12570
+ render: ({ field }) => {
12571
+ return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(NumberInput, { ...field }) }) });
12572
+ }
12573
+ }
12574
+ ) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: item.quantity }) }),
12575
+ editing ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(
12576
+ Form$2.Field,
12577
+ {
12578
+ control: form.control,
12579
+ name: "unit_price",
12580
+ render: ({ field: { onChange, ...field } }) => {
12581
+ return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
12582
+ ui.CurrencyInput,
12583
+ {
12584
+ ...field,
12585
+ symbol: getNativeSymbol(currencyCode),
12586
+ code: currencyCode,
12587
+ onValueChange: (_value, _name, values) => onChange(values == null ? void 0 : values.value)
12588
+ }
12589
+ ) }) });
12590
+ }
12591
+ }
12592
+ ) }) : /* @__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) }) }),
12593
+ /* @__PURE__ */ jsxRuntime.jsx(
12594
+ ui.IconButton,
12595
+ {
12596
+ type: "button",
12597
+ size: "small",
12598
+ onClick: editing ? onSubmit : () => {
12599
+ setEditing(true);
12600
+ },
12601
+ disabled: isPending,
12602
+ children: editing ? /* @__PURE__ */ jsxRuntime.jsx(icons.Check, {}) : /* @__PURE__ */ jsxRuntime.jsx(icons.PencilSquare, {})
12603
+ }
12604
+ )
12605
+ ] }) }) });
12606
+ };
12607
+ const variantItemSchema = objectType({
12608
+ quantity: numberType(),
12609
+ unit_price: unionType([numberType(), stringType()])
12610
+ });
12611
+ const CustomItem = ({ item, preview, currencyCode }) => {
12612
+ const [editing, setEditing] = React.useState(false);
12613
+ const { quantity, unit_price, title } = item;
12614
+ const form = reactHookForm.useForm({
12615
+ defaultValues: {
12616
+ title,
12617
+ quantity,
12618
+ unit_price
12619
+ },
12620
+ resolver: zod.zodResolver(customItemSchema)
12621
+ });
12622
+ React.useEffect(() => {
12623
+ form.reset({
12624
+ title,
12625
+ quantity,
12626
+ unit_price
12627
+ });
12628
+ }, [form, title, quantity, unit_price]);
12629
+ const actionId = React.useMemo(() => {
12630
+ var _a, _b;
12631
+ return (_b = (_a = item.actions) == null ? void 0 : _a.find((a) => a.action === "ITEM_ADD")) == null ? void 0 : _b.id;
12632
+ }, [item]);
12633
+ const { mutateAsync: updateActionItem, isPending: isUpdatingActionItem } = useDraftOrderUpdateActionItem(preview.id);
12634
+ const { mutateAsync: removeActionItem, isPending: isRemovingActionItem } = useDraftOrderRemoveActionItem(preview.id);
12635
+ const { mutateAsync: updateOriginalItem, isPending: isUpdatingOriginalItem } = useDraftOrderUpdateItem(preview.id);
12636
+ const isPending = isUpdatingActionItem || isUpdatingOriginalItem;
12637
+ const onSubmit = form.handleSubmit(async (data) => {
12638
+ if (convertNumber(data.unit_price) === item.unit_price && data.quantity === item.quantity && data.title === item.title) {
12639
+ setEditing(false);
12640
+ return;
12641
+ }
12642
+ if (!actionId) {
12643
+ await updateOriginalItem(
12644
+ {
12645
+ item_id: item.id,
12646
+ quantity: data.quantity,
12647
+ unit_price: convertNumber(data.unit_price)
12648
+ },
12649
+ {
12650
+ onSuccess: () => {
12651
+ setEditing(false);
12652
+ },
12653
+ onError: (e) => {
12654
+ ui.toast.error(e.message);
12655
+ }
12656
+ }
12657
+ );
12658
+ return;
12659
+ }
12660
+ if (data.quantity === 0) {
12661
+ await removeActionItem(actionId, {
12662
+ onSuccess: () => {
12663
+ setEditing(false);
12664
+ },
12665
+ onError: (e) => {
12666
+ ui.toast.error(e.message);
12667
+ }
12668
+ });
12669
+ return;
12670
+ }
12671
+ await updateActionItem(
12672
+ {
12673
+ action_id: actionId,
12674
+ quantity: data.quantity,
12675
+ unit_price: convertNumber(data.unit_price)
12676
+ },
12677
+ {
12678
+ onSuccess: () => {
12679
+ setEditing(false);
12680
+ },
12681
+ onError: (e) => {
12682
+ ui.toast.error(e.message);
12683
+ }
12684
+ }
12685
+ );
12686
+ });
12687
+ 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: [
12688
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-x-3", children: [
12689
+ /* @__PURE__ */ jsxRuntime.jsx(
12690
+ Thumbnail,
12691
+ {
12692
+ thumbnail: item.thumbnail,
12693
+ alt: item.title ?? void 0
12694
+ }
12695
+ ),
12696
+ editing ? /* @__PURE__ */ jsxRuntime.jsx(
12697
+ Form$2.Field,
12698
+ {
12699
+ control: form.control,
12700
+ name: "title",
12701
+ render: ({ field }) => {
12702
+ return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Input, { ...field }) }) });
12703
+ }
12704
+ }
12705
+ ) : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: item.title })
12706
+ ] }),
12707
+ editing ? /* @__PURE__ */ jsxRuntime.jsx(
12708
+ Form$2.Field,
12709
+ {
12710
+ control: form.control,
12711
+ name: "quantity",
12712
+ render: ({ field }) => {
12713
+ return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(NumberInput, { ...field }) }) });
12714
+ }
12715
+ }
12716
+ ) : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: item.quantity }),
12717
+ editing ? /* @__PURE__ */ jsxRuntime.jsx(
12718
+ Form$2.Field,
12719
+ {
12720
+ control: form.control,
12721
+ name: "unit_price",
12722
+ render: ({ field: { onChange, ...field } }) => {
12723
+ return /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
12724
+ ui.CurrencyInput,
12725
+ {
12726
+ ...field,
12727
+ symbol: getNativeSymbol(currencyCode),
12728
+ code: currencyCode,
12729
+ onValueChange: (_value, _name, values) => onChange(values == null ? void 0 : values.value)
12730
+ }
12731
+ ) }) });
12732
+ }
12733
+ }
12734
+ ) : /* @__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) }) }),
12735
+ /* @__PURE__ */ jsxRuntime.jsx(
12736
+ ui.IconButton,
12737
+ {
12738
+ type: "button",
12739
+ size: "small",
12740
+ onClick: editing ? onSubmit : () => {
12741
+ setEditing(true);
12742
+ },
12743
+ disabled: isPending,
12744
+ children: editing ? /* @__PURE__ */ jsxRuntime.jsx(icons.Check, {}) : /* @__PURE__ */ jsxRuntime.jsx(icons.PencilSquare, {})
12745
+ }
12746
+ )
12747
+ ] }) }) });
12748
+ };
12749
+ const StackedModalTrigger = ({
12750
+ type,
12751
+ setModalContent
12752
+ }) => {
12753
+ const { setIsOpen } = useStackedModal();
12754
+ const onClick = React.useCallback(() => {
12755
+ setModalContent(type);
12756
+ setIsOpen(STACKED_MODAL_ID, true);
12757
+ }, [setModalContent, setIsOpen, type]);
12758
+ 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" }) });
12759
+ };
12760
+ const VARIANT_PREFIX = "items";
12761
+ const LIMIT = 50;
12762
+ const ExistingItemsForm = ({ orderId, items }) => {
12763
+ const { setIsOpen } = useStackedModal();
12764
+ const [rowSelection, setRowSelection] = React.useState(
12765
+ items.reduce((acc, item) => {
12766
+ acc[item.variant_id] = true;
12767
+ return acc;
12768
+ }, {})
12769
+ );
12770
+ React.useEffect(() => {
12771
+ setRowSelection(
12772
+ items.reduce((acc, item) => {
12773
+ if (item.variant_id) {
12774
+ acc[item.variant_id] = true;
12775
+ }
12776
+ return acc;
12777
+ }, {})
12778
+ );
12779
+ }, [items]);
12780
+ const { q, order, offset } = useQueryParams(
12781
+ ["q", "order", "offset"],
12782
+ VARIANT_PREFIX
12783
+ );
12784
+ const { variants, count, isPending, isError, error } = useProductVariants(
12785
+ {
12786
+ q,
12787
+ order,
12788
+ offset: offset ? parseInt(offset) : void 0,
12789
+ limit: LIMIT
12790
+ },
12791
+ {
12792
+ placeholderData: reactQuery.keepPreviousData
12793
+ }
12794
+ );
12795
+ const columns = useColumns();
12796
+ const { mutateAsync } = useDraftOrderAddItems(orderId);
12797
+ const onSubmit = async () => {
12798
+ const ids = Object.keys(rowSelection).filter(
12799
+ (id) => !items.find((i) => i.variant_id === id)
12800
+ );
12801
+ await mutateAsync(
12802
+ {
12803
+ items: ids.map((id) => ({
12804
+ variant_id: id,
12805
+ quantity: 1
12806
+ }))
12807
+ },
12808
+ {
12809
+ onSuccess: () => {
12810
+ setRowSelection({});
12811
+ setIsOpen(STACKED_MODAL_ID, false);
12812
+ },
12813
+ onError: (e) => {
12814
+ ui.toast.error(e.message);
12815
+ }
12816
+ }
12817
+ );
12818
+ };
12819
+ if (isError) {
12820
+ throw error;
12821
+ }
12822
+ return /* @__PURE__ */ jsxRuntime.jsxs(
12823
+ StackedFocusModal.Content,
12824
+ {
12825
+ onOpenAutoFocus: (e) => {
12826
+ e.preventDefault();
12827
+ const searchInput = document.querySelector(
12828
+ "[data-modal-id='modal-search-input']"
12829
+ );
12830
+ if (searchInput) {
12831
+ searchInput.focus();
12832
+ }
12833
+ },
12834
+ children: [
12835
+ /* @__PURE__ */ jsxRuntime.jsxs(StackedFocusModal.Header, { children: [
12836
+ /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Product Variants" }) }),
12837
+ /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Choose product variants to add to the order." }) })
12838
+ ] }),
12839
+ /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Body, { className: "flex-1 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
12840
+ DataTable,
12841
+ {
12842
+ data: variants,
12843
+ columns,
12844
+ isLoading: isPending,
12845
+ getRowId: (row) => row.id,
12846
+ rowCount: count,
12847
+ prefix: VARIANT_PREFIX,
12848
+ layout: "fill",
12849
+ rowSelection: {
12850
+ state: rowSelection,
12851
+ onRowSelectionChange: setRowSelection,
12852
+ enableRowSelection: (row) => {
12853
+ return !items.find((i) => i.variant_id === row.original.id);
12854
+ }
12855
+ },
12856
+ autoFocusSearch: true
12857
+ }
12858
+ ) }),
12859
+ /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
12860
+ /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
12861
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", type: "button", onClick: onSubmit, children: "Update items" })
12862
+ ] }) })
12863
+ ]
12864
+ }
12865
+ );
12866
+ };
12867
+ const columnHelper = ui.createDataTableColumnHelper();
12868
+ const useColumns = () => {
12869
+ return React.useMemo(() => {
12870
+ return [
12871
+ columnHelper.select(),
12872
+ columnHelper.accessor("product.title", {
12873
+ header: "Product",
12874
+ cell: ({ row }) => {
12875
+ var _a, _b, _c;
12876
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-x-2", children: [
12877
+ /* @__PURE__ */ jsxRuntime.jsx(
12878
+ Thumbnail,
12879
+ {
12880
+ thumbnail: (_a = row.original.product) == null ? void 0 : _a.thumbnail,
12881
+ alt: (_b = row.original.product) == null ? void 0 : _b.title
12882
+ }
12883
+ ),
12884
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: (_c = row.original.product) == null ? void 0 : _c.title })
12885
+ ] });
12886
+ },
12887
+ enableSorting: true
12888
+ }),
12889
+ columnHelper.accessor("title", {
12890
+ header: "Variant",
12891
+ enableSorting: true
12892
+ }),
12893
+ columnHelper.accessor("sku", {
12894
+ header: "SKU",
12895
+ cell: ({ getValue }) => {
12896
+ return getValue() ?? "-";
12897
+ },
12898
+ enableSorting: true
12899
+ }),
12900
+ columnHelper.accessor("updated_at", {
12901
+ header: "Updated",
12902
+ cell: ({ getValue }) => {
12903
+ return /* @__PURE__ */ jsxRuntime.jsx(
12904
+ ui.Tooltip,
13022
12905
  {
13023
- width: "12",
13024
- height: "12",
13025
- fill: "white",
13026
- transform: "matrix(0.865865 0.500278 -0.871576 0.490261 131.318 90.4594)"
12906
+ content: getFullDate({ date: getValue(), includeTime: true }),
12907
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { children: getFullDate({ date: getValue() }) })
13027
12908
  }
13028
- ) }),
13029
- /* @__PURE__ */ jsxRuntime.jsx("clipPath", { id: "clip5_20915_38670", children: /* @__PURE__ */ jsxRuntime.jsx(
13030
- "rect",
12909
+ );
12910
+ },
12911
+ enableSorting: true,
12912
+ sortAscLabel: "Oldest first",
12913
+ sortDescLabel: "Newest first"
12914
+ }),
12915
+ columnHelper.accessor("created_at", {
12916
+ header: "Created",
12917
+ cell: ({ getValue }) => {
12918
+ return /* @__PURE__ */ jsxRuntime.jsx(
12919
+ ui.Tooltip,
13031
12920
  {
13032
- width: "12",
13033
- height: "12",
13034
- fill: "white",
13035
- transform: "matrix(0.865865 0.500278 -0.871576 0.490261 141.709 96.4627)"
12921
+ content: getFullDate({ date: getValue(), includeTime: true }),
12922
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { children: getFullDate({ date: getValue() }) })
13036
12923
  }
13037
- ) })
13038
- ] })
13039
- ]
13040
- }
13041
- );
12924
+ );
12925
+ },
12926
+ enableSorting: true,
12927
+ sortAscLabel: "Oldest first",
12928
+ sortDescLabel: "Newest first"
12929
+ })
12930
+ ];
12931
+ }, []);
13042
12932
  };
13043
- const schema = objectType({
13044
- customer_id: stringType().min(1)
12933
+ const CustomItemForm = ({ orderId, currencyCode }) => {
12934
+ const { setIsOpen } = useStackedModal();
12935
+ const { mutateAsync: addItems } = useDraftOrderAddItems(orderId);
12936
+ const form = reactHookForm.useForm({
12937
+ defaultValues: {
12938
+ title: "",
12939
+ quantity: 1,
12940
+ unit_price: ""
12941
+ },
12942
+ resolver: zod.zodResolver(customItemSchema)
12943
+ });
12944
+ const onSubmit = form.handleSubmit(async (data) => {
12945
+ await addItems(
12946
+ {
12947
+ items: [
12948
+ {
12949
+ title: data.title,
12950
+ quantity: data.quantity,
12951
+ unit_price: convertNumber(data.unit_price)
12952
+ }
12953
+ ]
12954
+ },
12955
+ {
12956
+ onSuccess: () => {
12957
+ setIsOpen(STACKED_MODAL_ID, false);
12958
+ },
12959
+ onError: (e) => {
12960
+ ui.toast.error(e.message);
12961
+ }
12962
+ }
12963
+ );
12964
+ });
12965
+ return /* @__PURE__ */ jsxRuntime.jsx(Form$2, { ...form, children: /* @__PURE__ */ jsxRuntime.jsx(KeyboundForm, { onSubmit, children: /* @__PURE__ */ jsxRuntime.jsxs(StackedFocusModal.Content, { children: [
12966
+ /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Header, {}),
12967
+ /* @__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: [
12968
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
12969
+ /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: "Add custom item" }) }),
12970
+ /* @__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." }) })
12971
+ ] }),
12972
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { variant: "dashed" }),
12973
+ /* @__PURE__ */ jsxRuntime.jsx(
12974
+ Form$2.Field,
12975
+ {
12976
+ control: form.control,
12977
+ name: "title",
12978
+ render: ({ field }) => /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
12979
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
12980
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.Label, { children: "Title" }),
12981
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.Hint, { children: "Enter the title of the item" })
12982
+ ] }),
12983
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
12984
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Input, { ...field }) }),
12985
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.ErrorMessage, {})
12986
+ ] })
12987
+ ] }) })
12988
+ }
12989
+ ),
12990
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { variant: "dashed" }),
12991
+ /* @__PURE__ */ jsxRuntime.jsx(
12992
+ Form$2.Field,
12993
+ {
12994
+ control: form.control,
12995
+ name: "unit_price",
12996
+ render: ({ field: { onChange, ...field } }) => /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
12997
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
12998
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.Label, { children: "Unit price" }),
12999
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.Hint, { children: "Enter the unit price of the item" })
13000
+ ] }),
13001
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
13002
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.Control, { children: /* @__PURE__ */ jsxRuntime.jsx(
13003
+ ui.CurrencyInput,
13004
+ {
13005
+ symbol: getNativeSymbol(currencyCode),
13006
+ code: currencyCode,
13007
+ onValueChange: (_value, _name, values) => onChange(values == null ? void 0 : values.value),
13008
+ ...field
13009
+ }
13010
+ ) }),
13011
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.ErrorMessage, {})
13012
+ ] })
13013
+ ] }) })
13014
+ }
13015
+ ),
13016
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Divider, { variant: "dashed" }),
13017
+ /* @__PURE__ */ jsxRuntime.jsx(
13018
+ Form$2.Field,
13019
+ {
13020
+ control: form.control,
13021
+ name: "quantity",
13022
+ render: ({ field }) => /* @__PURE__ */ jsxRuntime.jsx(Form$2.Item, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
13023
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
13024
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.Label, { children: "Quantity" }),
13025
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.Hint, { children: "Enter the quantity of the item" })
13026
+ ] }),
13027
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full flex-1", children: [
13028
+ /* @__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" }) }) }),
13029
+ /* @__PURE__ */ jsxRuntime.jsx(Form$2.ErrorMessage, {})
13030
+ ] })
13031
+ ] }) })
13032
+ }
13033
+ )
13034
+ ] }) }) }),
13035
+ /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
13036
+ /* @__PURE__ */ jsxRuntime.jsx(StackedFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
13037
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", type: "button", onClick: onSubmit, children: "Add item" })
13038
+ ] }) })
13039
+ ] }) }) });
13040
+ };
13041
+ const customItemSchema = objectType({
13042
+ title: stringType().min(1),
13043
+ quantity: numberType(),
13044
+ unit_price: unionType([numberType(), stringType()])
13045
13045
  });
13046
13046
  const widgetModule = { widgets: [] };
13047
13047
  const routeModule = {
@@ -13067,17 +13067,13 @@ const routeModule = {
13067
13067
  Component: BillingAddress,
13068
13068
  path: "/draft-orders/:id/billing-address"
13069
13069
  },
13070
- {
13071
- Component: CustomItems,
13072
- path: "/draft-orders/:id/custom-items"
13073
- },
13074
13070
  {
13075
13071
  Component: Email,
13076
13072
  path: "/draft-orders/:id/email"
13077
13073
  },
13078
13074
  {
13079
- Component: Items,
13080
- path: "/draft-orders/:id/items"
13075
+ Component: CustomItems,
13076
+ path: "/draft-orders/:id/custom-items"
13081
13077
  },
13082
13078
  {
13083
13079
  Component: Metadata,
@@ -13102,6 +13098,10 @@ const routeModule = {
13102
13098
  {
13103
13099
  Component: TransferOwnership,
13104
13100
  path: "/draft-orders/:id/transfer-ownership"
13101
+ },
13102
+ {
13103
+ Component: Items,
13104
+ path: "/draft-orders/:id/items"
13105
13105
  }
13106
13106
  ]
13107
13107
  }