@medusajs/draft-order 2.11.0-preview-20251016000321 → 2.11.0-preview-20251016060156

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.
@@ -9567,27 +9567,6 @@ const ID = () => {
9567
9567
  /* @__PURE__ */ jsx(Outlet, {})
9568
9568
  ] });
9569
9569
  };
9570
- const CustomItems = () => {
9571
- return /* @__PURE__ */ jsxs(RouteDrawer, { children: [
9572
- /* @__PURE__ */ jsx(RouteDrawer.Header, { children: /* @__PURE__ */ jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Edit Custom Items" }) }) }),
9573
- /* @__PURE__ */ jsx(CustomItemsForm, {})
9574
- ] });
9575
- };
9576
- const CustomItemsForm = () => {
9577
- const form = useForm({
9578
- resolver: zodResolver(schema$5)
9579
- });
9580
- return /* @__PURE__ */ jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxs(KeyboundForm, { className: "flex flex-1 flex-col", children: [
9581
- /* @__PURE__ */ jsx(RouteDrawer.Body, {}),
9582
- /* @__PURE__ */ jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
9583
- /* @__PURE__ */ jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
9584
- /* @__PURE__ */ jsx(Button, { size: "small", type: "submit", children: "Save" })
9585
- ] }) })
9586
- ] }) });
9587
- };
9588
- const schema$5 = objectType({
9589
- email: stringType().email()
9590
- });
9591
9570
  const BillingAddress = () => {
9592
9571
  const { id } = useParams();
9593
9572
  const { order, isPending, isError, error } = useOrder(id, {
@@ -9620,7 +9599,7 @@ const BillingAddressForm = ({ order }) => {
9620
9599
  postal_code: ((_i = order.billing_address) == null ? void 0 : _i.postal_code) ?? "",
9621
9600
  phone: ((_j = order.billing_address) == null ? void 0 : _j.phone) ?? ""
9622
9601
  },
9623
- resolver: zodResolver(schema$4)
9602
+ resolver: zodResolver(schema$5)
9624
9603
  });
9625
9604
  const { mutateAsync, isPending } = useUpdateDraftOrder(order.id);
9626
9605
  const { handleSuccess } = useRouteModal();
@@ -9777,7 +9756,7 @@ const BillingAddressForm = ({ order }) => {
9777
9756
  }
9778
9757
  ) });
9779
9758
  };
9780
- const schema$4 = addressSchema;
9759
+ const schema$5 = addressSchema;
9781
9760
  const Email = () => {
9782
9761
  const { id } = useParams();
9783
9762
  const { order, isPending, isError, error } = useOrder(id, {
@@ -9800,7 +9779,7 @@ const EmailForm = ({ order }) => {
9800
9779
  defaultValues: {
9801
9780
  email: order.email ?? ""
9802
9781
  },
9803
- resolver: zodResolver(schema$3)
9782
+ resolver: zodResolver(schema$4)
9804
9783
  });
9805
9784
  const { mutateAsync, isPending } = useUpdateDraftOrder(order.id);
9806
9785
  const { handleSuccess } = useRouteModal();
@@ -9843,115 +9822,459 @@ const EmailForm = ({ order }) => {
9843
9822
  }
9844
9823
  ) });
9845
9824
  };
9825
+ const schema$4 = objectType({
9826
+ email: stringType().email()
9827
+ });
9828
+ const CustomItems = () => {
9829
+ return /* @__PURE__ */ jsxs(RouteDrawer, { children: [
9830
+ /* @__PURE__ */ jsx(RouteDrawer.Header, { children: /* @__PURE__ */ jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Edit Custom Items" }) }) }),
9831
+ /* @__PURE__ */ jsx(CustomItemsForm, {})
9832
+ ] });
9833
+ };
9834
+ const CustomItemsForm = () => {
9835
+ const form = useForm({
9836
+ resolver: zodResolver(schema$3)
9837
+ });
9838
+ return /* @__PURE__ */ jsx(RouteDrawer.Form, { form, children: /* @__PURE__ */ jsxs(KeyboundForm, { className: "flex flex-1 flex-col", children: [
9839
+ /* @__PURE__ */ jsx(RouteDrawer.Body, {}),
9840
+ /* @__PURE__ */ jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
9841
+ /* @__PURE__ */ jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
9842
+ /* @__PURE__ */ jsx(Button, { size: "small", type: "submit", children: "Save" })
9843
+ ] }) })
9844
+ ] }) });
9845
+ };
9846
9846
  const schema$3 = objectType({
9847
9847
  email: stringType().email()
9848
9848
  });
9849
- const InlineTip = forwardRef(
9850
- ({ variant = "tip", label, className, children, ...props }, ref) => {
9851
- const labelValue = label || (variant === "warning" ? "Warning" : "Tip");
9852
- return /* @__PURE__ */ jsxs(
9853
- "div",
9854
- {
9855
- ref,
9856
- className: clx(
9857
- "bg-ui-bg-component txt-small text-ui-fg-subtle grid grid-cols-[4px_1fr] items-start gap-3 rounded-lg border p-3",
9858
- className
9859
- ),
9860
- ...props,
9861
- children: [
9862
- /* @__PURE__ */ jsx(
9863
- "div",
9864
- {
9865
- role: "presentation",
9866
- className: clx("w-4px bg-ui-tag-neutral-icon h-full rounded-full", {
9867
- "bg-ui-tag-orange-icon": variant === "warning"
9868
- })
9869
- }
9870
- ),
9871
- /* @__PURE__ */ jsxs("div", { className: "text-pretty", children: [
9872
- /* @__PURE__ */ jsxs("strong", { className: "txt-small-plus text-ui-fg-base", children: [
9873
- labelValue,
9874
- ":"
9875
- ] }),
9876
- " ",
9877
- children
9878
- ] })
9879
- ]
9849
+ const PROMOTION_QUERY_KEY = "promotions";
9850
+ const promotionsQueryKeys = {
9851
+ list: (query2) => [
9852
+ PROMOTION_QUERY_KEY,
9853
+ query2 ? query2 : void 0
9854
+ ],
9855
+ detail: (id, query2) => [
9856
+ PROMOTION_QUERY_KEY,
9857
+ id,
9858
+ query2 ? query2 : void 0
9859
+ ]
9860
+ };
9861
+ const usePromotions = (query2, options) => {
9862
+ const { data, ...rest } = useQuery({
9863
+ queryKey: promotionsQueryKeys.list(query2),
9864
+ queryFn: async () => sdk.admin.promotion.list(query2),
9865
+ ...options
9866
+ });
9867
+ return { ...data, ...rest };
9868
+ };
9869
+ const useCancelOrderEdit = ({ preview }) => {
9870
+ const { mutateAsync: cancelOrderEdit } = useDraftOrderCancelEdit(preview == null ? void 0 : preview.id);
9871
+ const onCancel = useCallback(async () => {
9872
+ if (!preview) {
9873
+ return true;
9874
+ }
9875
+ let res = false;
9876
+ await cancelOrderEdit(void 0, {
9877
+ onError: (e) => {
9878
+ toast.error(e.message);
9879
+ },
9880
+ onSuccess: () => {
9881
+ res = true;
9880
9882
  }
9881
- );
9882
- }
9883
- );
9884
- InlineTip.displayName = "InlineTip";
9885
- const MetadataFieldSchema = objectType({
9886
- key: stringType(),
9887
- disabled: booleanType().optional(),
9888
- value: anyType()
9889
- });
9890
- const MetadataSchema = objectType({
9891
- metadata: arrayType(MetadataFieldSchema)
9892
- });
9893
- const Metadata = () => {
9883
+ });
9884
+ return res;
9885
+ }, [preview, cancelOrderEdit]);
9886
+ return { onCancel };
9887
+ };
9888
+ let IS_REQUEST_RUNNING = false;
9889
+ const useInitiateOrderEdit = ({
9890
+ preview
9891
+ }) => {
9892
+ const navigate = useNavigate();
9893
+ const { mutateAsync } = useDraftOrderBeginEdit(preview == null ? void 0 : preview.id);
9894
+ useEffect(() => {
9895
+ async function run() {
9896
+ if (IS_REQUEST_RUNNING || !preview) {
9897
+ return;
9898
+ }
9899
+ if (preview.order_change) {
9900
+ return;
9901
+ }
9902
+ IS_REQUEST_RUNNING = true;
9903
+ await mutateAsync(void 0, {
9904
+ onError: (e) => {
9905
+ toast.error(e.message);
9906
+ navigate(`/draft-orders/${preview.id}`, { replace: true });
9907
+ return;
9908
+ }
9909
+ });
9910
+ IS_REQUEST_RUNNING = false;
9911
+ }
9912
+ run();
9913
+ }, [preview, navigate, mutateAsync]);
9914
+ };
9915
+ const Promotions = () => {
9894
9916
  const { id } = useParams();
9895
- const { order, isPending, isError, error } = useOrder(id, {
9896
- fields: "metadata"
9897
- });
9898
- if (isError) {
9899
- throw error;
9917
+ const {
9918
+ order: preview,
9919
+ isError: isPreviewError,
9920
+ error: previewError
9921
+ } = useOrderPreview(id, void 0);
9922
+ useInitiateOrderEdit({ preview });
9923
+ const { onCancel } = useCancelOrderEdit({ preview });
9924
+ if (isPreviewError) {
9925
+ throw previewError;
9900
9926
  }
9901
- const isReady = !isPending && !!order;
9902
- return /* @__PURE__ */ jsxs(RouteDrawer, { children: [
9903
- /* @__PURE__ */ jsxs(RouteDrawer.Header, { children: [
9904
- /* @__PURE__ */ jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Metadata" }) }),
9905
- /* @__PURE__ */ jsx(RouteDrawer.Description, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Add metadata to the draft order." }) })
9906
- ] }),
9907
- !isReady ? /* @__PURE__ */ jsx(PlaceholderInner, {}) : /* @__PURE__ */ jsx(MetadataForm, { orderId: id, metadata: order == null ? void 0 : order.metadata })
9927
+ const isReady = !!preview;
9928
+ return /* @__PURE__ */ jsxs(RouteDrawer, { onClose: onCancel, children: [
9929
+ /* @__PURE__ */ jsx(RouteDrawer.Header, { children: /* @__PURE__ */ jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Edit Promotions" }) }) }),
9930
+ isReady && /* @__PURE__ */ jsx(PromotionForm, { preview })
9908
9931
  ] });
9909
9932
  };
9910
- const METADATA_KEY_LABEL_ID = "metadata-form-key-label";
9911
- const METADATA_VALUE_LABEL_ID = "metadata-form-value-label";
9912
- const MetadataForm = ({ orderId, metadata }) => {
9933
+ const PromotionForm = ({ preview }) => {
9934
+ const { items, shipping_methods } = preview;
9935
+ const [isSubmitting, setIsSubmitting] = useState(false);
9936
+ const [comboboxValue, setComboboxValue] = useState("");
9913
9937
  const { handleSuccess } = useRouteModal();
9914
- const hasUneditableRows = getHasUneditableRows(metadata);
9915
- const { mutateAsync, isPending } = useUpdateDraftOrder(orderId);
9916
- const form = useForm({
9917
- defaultValues: {
9918
- metadata: getDefaultValues(metadata)
9938
+ const { mutateAsync: addPromotions, isPending: isAddingPromotions } = useDraftOrderAddPromotions(preview.id);
9939
+ const promoIds = getPromotionIds(items, shipping_methods);
9940
+ const { promotions, isPending, isError, error } = usePromotions(
9941
+ {
9942
+ id: promoIds
9919
9943
  },
9920
- resolver: zodResolver(MetadataSchema)
9944
+ {
9945
+ enabled: !!promoIds.length
9946
+ }
9947
+ );
9948
+ const comboboxData = useComboboxData({
9949
+ queryKey: ["promotions", "combobox", promoIds],
9950
+ queryFn: async (params) => {
9951
+ return await sdk.admin.promotion.list({
9952
+ ...params,
9953
+ id: {
9954
+ $nin: promoIds
9955
+ }
9956
+ });
9957
+ },
9958
+ getOptions: (data) => {
9959
+ return data.promotions.map((promotion) => ({
9960
+ label: promotion.code,
9961
+ value: promotion.code
9962
+ }));
9963
+ }
9921
9964
  });
9922
- const handleSubmit = form.handleSubmit(async (data) => {
9923
- const parsedData = parseValues(data);
9924
- await mutateAsync(
9965
+ const add = async (value) => {
9966
+ if (!value) {
9967
+ return;
9968
+ }
9969
+ addPromotions(
9925
9970
  {
9926
- metadata: parsedData
9971
+ promo_codes: [value]
9927
9972
  },
9928
9973
  {
9929
- onSuccess: () => {
9930
- toast.success("Metadata updated");
9931
- handleSuccess();
9974
+ onError: (e) => {
9975
+ toast.error(e.message);
9976
+ comboboxData.onSearchValueChange("");
9977
+ setComboboxValue("");
9932
9978
  },
9933
- onError: (error) => {
9934
- toast.error(error.message);
9979
+ onSuccess: () => {
9980
+ comboboxData.onSearchValueChange("");
9981
+ setComboboxValue("");
9935
9982
  }
9936
9983
  }
9937
9984
  );
9938
- });
9939
- const { fields, insert, remove } = useFieldArray({
9940
- control: form.control,
9941
- name: "metadata"
9942
- });
9943
- function deleteRow(index) {
9944
- remove(index);
9945
- if (fields.length === 1) {
9946
- insert(0, {
9947
- key: "",
9948
- value: "",
9949
- disabled: false
9950
- });
9951
- }
9952
- }
9953
- function insertRow(index, position) {
9954
- insert(index + (position === "above" ? 0 : 1), {
9985
+ };
9986
+ const { mutateAsync: confirmOrderEdit } = useDraftOrderConfirmEdit(preview.id);
9987
+ const { mutateAsync: requestOrderEdit } = useOrderEditRequest(preview.id);
9988
+ const onSubmit = async () => {
9989
+ setIsSubmitting(true);
9990
+ let requestSucceeded = false;
9991
+ await requestOrderEdit(void 0, {
9992
+ onError: (e) => {
9993
+ toast.error(e.message);
9994
+ },
9995
+ onSuccess: () => {
9996
+ requestSucceeded = true;
9997
+ }
9998
+ });
9999
+ if (!requestSucceeded) {
10000
+ setIsSubmitting(false);
10001
+ return;
10002
+ }
10003
+ await confirmOrderEdit(void 0, {
10004
+ onError: (e) => {
10005
+ toast.error(e.message);
10006
+ },
10007
+ onSuccess: () => {
10008
+ handleSuccess();
10009
+ },
10010
+ onSettled: () => {
10011
+ setIsSubmitting(false);
10012
+ }
10013
+ });
10014
+ };
10015
+ if (isError) {
10016
+ throw error;
10017
+ }
10018
+ return /* @__PURE__ */ jsxs(KeyboundForm, { className: "flex flex-1 flex-col", onSubmit, children: [
10019
+ /* @__PURE__ */ jsx(RouteDrawer.Body, { children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
10020
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
10021
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
10022
+ /* @__PURE__ */ jsx(Label$1, { size: "small", weight: "plus", htmlFor: "promotion-combobox", children: "Apply promotions" }),
10023
+ /* @__PURE__ */ jsx(Hint$1, { id: "promotion-combobox-hint", children: "Manage promotions that should be applied to the order." })
10024
+ ] }),
10025
+ /* @__PURE__ */ jsx(
10026
+ Combobox,
10027
+ {
10028
+ id: "promotion-combobox",
10029
+ "aria-describedby": "promotion-combobox-hint",
10030
+ isFetchingNextPage: comboboxData.isFetchingNextPage,
10031
+ fetchNextPage: comboboxData.fetchNextPage,
10032
+ options: comboboxData.options,
10033
+ onSearchValueChange: comboboxData.onSearchValueChange,
10034
+ searchValue: comboboxData.searchValue,
10035
+ disabled: comboboxData.disabled || isAddingPromotions,
10036
+ onChange: add,
10037
+ value: comboboxValue
10038
+ }
10039
+ )
10040
+ ] }),
10041
+ /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
10042
+ /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-2", children: promotions == null ? void 0 : promotions.map((promotion) => /* @__PURE__ */ jsx(
10043
+ PromotionItem,
10044
+ {
10045
+ promotion,
10046
+ orderId: preview.id,
10047
+ isLoading: isPending
10048
+ },
10049
+ promotion.id
10050
+ )) })
10051
+ ] }) }),
10052
+ /* @__PURE__ */ jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
10053
+ /* @__PURE__ */ jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
10054
+ /* @__PURE__ */ jsx(
10055
+ Button,
10056
+ {
10057
+ size: "small",
10058
+ type: "submit",
10059
+ isLoading: isSubmitting || isAddingPromotions,
10060
+ children: "Save"
10061
+ }
10062
+ )
10063
+ ] }) })
10064
+ ] });
10065
+ };
10066
+ const PromotionItem = ({
10067
+ promotion,
10068
+ orderId,
10069
+ isLoading
10070
+ }) => {
10071
+ var _a;
10072
+ const { mutateAsync: removePromotions, isPending } = useDraftOrderRemovePromotions(orderId);
10073
+ const onRemove = async () => {
10074
+ removePromotions(
10075
+ {
10076
+ promo_codes: [promotion.code]
10077
+ },
10078
+ {
10079
+ onError: (e) => {
10080
+ toast.error(e.message);
10081
+ }
10082
+ }
10083
+ );
10084
+ };
10085
+ const displayValue = getDisplayValue(promotion);
10086
+ return /* @__PURE__ */ jsxs(
10087
+ "div",
10088
+ {
10089
+ className: clx(
10090
+ "bg-ui-bg-component shadow-elevation-card-rest flex items-center justify-between rounded-lg px-3 py-2",
10091
+ {
10092
+ "animate-pulse": isLoading
10093
+ }
10094
+ ),
10095
+ children: [
10096
+ /* @__PURE__ */ jsxs("div", { children: [
10097
+ /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: promotion.code }),
10098
+ /* @__PURE__ */ jsxs("div", { className: "text-ui-fg-subtle flex items-center gap-1.5", children: [
10099
+ displayValue && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
10100
+ /* @__PURE__ */ jsx(Text, { size: "small", leading: "compact", children: displayValue }),
10101
+ /* @__PURE__ */ jsx(Text, { size: "small", leading: "compact", children: "·" })
10102
+ ] }),
10103
+ /* @__PURE__ */ jsx(Text, { size: "small", leading: "compact", className: "capitalize", children: (_a = promotion.application_method) == null ? void 0 : _a.allocation })
10104
+ ] })
10105
+ ] }),
10106
+ /* @__PURE__ */ jsx(
10107
+ IconButton,
10108
+ {
10109
+ size: "small",
10110
+ type: "button",
10111
+ variant: "transparent",
10112
+ onClick: onRemove,
10113
+ isLoading: isPending || isLoading,
10114
+ children: /* @__PURE__ */ jsx(XMark, {})
10115
+ }
10116
+ )
10117
+ ]
10118
+ },
10119
+ promotion.id
10120
+ );
10121
+ };
10122
+ function getDisplayValue(promotion) {
10123
+ var _a, _b, _c, _d;
10124
+ const value = (_a = promotion.application_method) == null ? void 0 : _a.value;
10125
+ if (!value) {
10126
+ return null;
10127
+ }
10128
+ if (((_b = promotion.application_method) == null ? void 0 : _b.type) === "fixed") {
10129
+ const currency = (_c = promotion.application_method) == null ? void 0 : _c.currency_code;
10130
+ if (!currency) {
10131
+ return null;
10132
+ }
10133
+ return getLocaleAmount(value, currency);
10134
+ } else if (((_d = promotion.application_method) == null ? void 0 : _d.type) === "percentage") {
10135
+ return formatPercentage(value);
10136
+ }
10137
+ return null;
10138
+ }
10139
+ const formatter = new Intl.NumberFormat([], {
10140
+ style: "percent",
10141
+ minimumFractionDigits: 2
10142
+ });
10143
+ const formatPercentage = (value, isPercentageValue = false) => {
10144
+ let val = value || 0;
10145
+ if (!isPercentageValue) {
10146
+ val = val / 100;
10147
+ }
10148
+ return formatter.format(val);
10149
+ };
10150
+ function getPromotionIds(items, shippingMethods) {
10151
+ const promotionIds = /* @__PURE__ */ new Set();
10152
+ for (const item of items) {
10153
+ if (item.adjustments) {
10154
+ for (const adjustment of item.adjustments) {
10155
+ if (adjustment.promotion_id) {
10156
+ promotionIds.add(adjustment.promotion_id);
10157
+ }
10158
+ }
10159
+ }
10160
+ }
10161
+ for (const shippingMethod of shippingMethods) {
10162
+ if (shippingMethod.adjustments) {
10163
+ for (const adjustment of shippingMethod.adjustments) {
10164
+ if (adjustment.promotion_id) {
10165
+ promotionIds.add(adjustment.promotion_id);
10166
+ }
10167
+ }
10168
+ }
10169
+ }
10170
+ return Array.from(promotionIds);
10171
+ }
10172
+ const InlineTip = forwardRef(
10173
+ ({ variant = "tip", label, className, children, ...props }, ref) => {
10174
+ const labelValue = label || (variant === "warning" ? "Warning" : "Tip");
10175
+ return /* @__PURE__ */ jsxs(
10176
+ "div",
10177
+ {
10178
+ ref,
10179
+ className: clx(
10180
+ "bg-ui-bg-component txt-small text-ui-fg-subtle grid grid-cols-[4px_1fr] items-start gap-3 rounded-lg border p-3",
10181
+ className
10182
+ ),
10183
+ ...props,
10184
+ children: [
10185
+ /* @__PURE__ */ jsx(
10186
+ "div",
10187
+ {
10188
+ role: "presentation",
10189
+ className: clx("w-4px bg-ui-tag-neutral-icon h-full rounded-full", {
10190
+ "bg-ui-tag-orange-icon": variant === "warning"
10191
+ })
10192
+ }
10193
+ ),
10194
+ /* @__PURE__ */ jsxs("div", { className: "text-pretty", children: [
10195
+ /* @__PURE__ */ jsxs("strong", { className: "txt-small-plus text-ui-fg-base", children: [
10196
+ labelValue,
10197
+ ":"
10198
+ ] }),
10199
+ " ",
10200
+ children
10201
+ ] })
10202
+ ]
10203
+ }
10204
+ );
10205
+ }
10206
+ );
10207
+ InlineTip.displayName = "InlineTip";
10208
+ const MetadataFieldSchema = objectType({
10209
+ key: stringType(),
10210
+ disabled: booleanType().optional(),
10211
+ value: anyType()
10212
+ });
10213
+ const MetadataSchema = objectType({
10214
+ metadata: arrayType(MetadataFieldSchema)
10215
+ });
10216
+ const Metadata = () => {
10217
+ const { id } = useParams();
10218
+ const { order, isPending, isError, error } = useOrder(id, {
10219
+ fields: "metadata"
10220
+ });
10221
+ if (isError) {
10222
+ throw error;
10223
+ }
10224
+ const isReady = !isPending && !!order;
10225
+ return /* @__PURE__ */ jsxs(RouteDrawer, { children: [
10226
+ /* @__PURE__ */ jsxs(RouteDrawer.Header, { children: [
10227
+ /* @__PURE__ */ jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Metadata" }) }),
10228
+ /* @__PURE__ */ jsx(RouteDrawer.Description, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Add metadata to the draft order." }) })
10229
+ ] }),
10230
+ !isReady ? /* @__PURE__ */ jsx(PlaceholderInner, {}) : /* @__PURE__ */ jsx(MetadataForm, { orderId: id, metadata: order == null ? void 0 : order.metadata })
10231
+ ] });
10232
+ };
10233
+ const METADATA_KEY_LABEL_ID = "metadata-form-key-label";
10234
+ const METADATA_VALUE_LABEL_ID = "metadata-form-value-label";
10235
+ const MetadataForm = ({ orderId, metadata }) => {
10236
+ const { handleSuccess } = useRouteModal();
10237
+ const hasUneditableRows = getHasUneditableRows(metadata);
10238
+ const { mutateAsync, isPending } = useUpdateDraftOrder(orderId);
10239
+ const form = useForm({
10240
+ defaultValues: {
10241
+ metadata: getDefaultValues(metadata)
10242
+ },
10243
+ resolver: zodResolver(MetadataSchema)
10244
+ });
10245
+ const handleSubmit = form.handleSubmit(async (data) => {
10246
+ const parsedData = parseValues(data);
10247
+ await mutateAsync(
10248
+ {
10249
+ metadata: parsedData
10250
+ },
10251
+ {
10252
+ onSuccess: () => {
10253
+ toast.success("Metadata updated");
10254
+ handleSuccess();
10255
+ },
10256
+ onError: (error) => {
10257
+ toast.error(error.message);
10258
+ }
10259
+ }
10260
+ );
10261
+ });
10262
+ const { fields, insert, remove } = useFieldArray({
10263
+ control: form.control,
10264
+ name: "metadata"
10265
+ });
10266
+ function deleteRow(index) {
10267
+ remove(index);
10268
+ if (fields.length === 1) {
10269
+ insert(0, {
10270
+ key: "",
10271
+ value: "",
10272
+ disabled: false
10273
+ });
10274
+ }
10275
+ }
10276
+ function insertRow(index, position) {
10277
+ insert(index + (position === "above" ? 0 : 1), {
9955
10278
  key: "",
9956
10279
  value: "",
9957
10280
  disabled: false
@@ -10321,52 +10644,6 @@ const useProductVariants = (query2, options) => {
10321
10644
  });
10322
10645
  return { ...data, ...rest };
10323
10646
  };
10324
- const useCancelOrderEdit = ({ preview }) => {
10325
- const { mutateAsync: cancelOrderEdit } = useDraftOrderCancelEdit(preview == null ? void 0 : preview.id);
10326
- const onCancel = useCallback(async () => {
10327
- if (!preview) {
10328
- return true;
10329
- }
10330
- let res = false;
10331
- await cancelOrderEdit(void 0, {
10332
- onError: (e) => {
10333
- toast.error(e.message);
10334
- },
10335
- onSuccess: () => {
10336
- res = true;
10337
- }
10338
- });
10339
- return res;
10340
- }, [preview, cancelOrderEdit]);
10341
- return { onCancel };
10342
- };
10343
- let IS_REQUEST_RUNNING = false;
10344
- const useInitiateOrderEdit = ({
10345
- preview
10346
- }) => {
10347
- const navigate = useNavigate();
10348
- const { mutateAsync } = useDraftOrderBeginEdit(preview == null ? void 0 : preview.id);
10349
- useEffect(() => {
10350
- async function run() {
10351
- if (IS_REQUEST_RUNNING || !preview) {
10352
- return;
10353
- }
10354
- if (preview.order_change) {
10355
- return;
10356
- }
10357
- IS_REQUEST_RUNNING = true;
10358
- await mutateAsync(void 0, {
10359
- onError: (e) => {
10360
- toast.error(e.message);
10361
- navigate(`/draft-orders/${preview.id}`, { replace: true });
10362
- return;
10363
- }
10364
- });
10365
- IS_REQUEST_RUNNING = false;
10366
- }
10367
- run();
10368
- }, [preview, navigate, mutateAsync]);
10369
- };
10370
10647
  function convertNumber(value) {
10371
10648
  return typeof value === "string" ? Number(value.replace(",", ".")) : value;
10372
10649
  }
@@ -10614,155 +10891,7 @@ const VariantItem = ({ item, preview, currencyCode }) => {
10614
10891
  const { mutateAsync: updateOriginalItem, isPending: isUpdatingOriginalItem } = useDraftOrderUpdateItem(preview.id);
10615
10892
  const isPending = isUpdatingActionItem || isUpdatingOriginalItem;
10616
10893
  const onSubmit = form.handleSubmit(async (data) => {
10617
- if (convertNumber(data.unit_price) === item.unit_price && data.quantity === item.quantity) {
10618
- setEditing(false);
10619
- return;
10620
- }
10621
- if (!actionId) {
10622
- await updateOriginalItem(
10623
- {
10624
- item_id: item.id,
10625
- quantity: data.quantity,
10626
- unit_price: convertNumber(data.unit_price)
10627
- },
10628
- {
10629
- onSuccess: () => {
10630
- setEditing(false);
10631
- },
10632
- onError: (e) => {
10633
- toast.error(e.message);
10634
- }
10635
- }
10636
- );
10637
- return;
10638
- }
10639
- await updateActionItem(
10640
- {
10641
- action_id: actionId,
10642
- quantity: data.quantity,
10643
- unit_price: convertNumber(data.unit_price)
10644
- },
10645
- {
10646
- onSuccess: () => {
10647
- setEditing(false);
10648
- },
10649
- onError: (e) => {
10650
- toast.error(e.message);
10651
- }
10652
- }
10653
- );
10654
- });
10655
- return /* @__PURE__ */ jsx(Form$2, { ...form, children: /* @__PURE__ */ jsx("form", { onSubmit, children: /* @__PURE__ */ 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: [
10656
- /* @__PURE__ */ jsxs("div", { className: "flex w-full items-center gap-x-3", children: [
10657
- /* @__PURE__ */ jsx(
10658
- Thumbnail,
10659
- {
10660
- thumbnail: item.thumbnail,
10661
- alt: item.product_title ?? void 0
10662
- }
10663
- ),
10664
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
10665
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-1", children: [
10666
- /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: item.product_title }),
10667
- /* @__PURE__ */ jsxs(
10668
- Text,
10669
- {
10670
- size: "small",
10671
- leading: "compact",
10672
- className: "text-ui-fg-subtle",
10673
- children: [
10674
- "(",
10675
- item.variant_title,
10676
- ")"
10677
- ]
10678
- }
10679
- )
10680
- ] }),
10681
- /* @__PURE__ */ jsx(
10682
- Text,
10683
- {
10684
- size: "small",
10685
- leading: "compact",
10686
- className: "text-ui-fg-subtle",
10687
- children: item.variant_sku
10688
- }
10689
- )
10690
- ] })
10691
- ] }),
10692
- editing ? /* @__PURE__ */ jsx("div", { className: "w-full flex-1", children: /* @__PURE__ */ jsx(
10693
- Form$2.Field,
10694
- {
10695
- control: form.control,
10696
- name: "quantity",
10697
- render: ({ field }) => {
10698
- return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(NumberInput, { ...field }) }) });
10699
- }
10700
- }
10701
- ) }) : /* @__PURE__ */ jsx("div", { className: "w-full flex-1", children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: item.quantity }) }),
10702
- editing ? /* @__PURE__ */ jsx("div", { className: "w-full flex-1", children: /* @__PURE__ */ jsx(
10703
- Form$2.Field,
10704
- {
10705
- control: form.control,
10706
- name: "unit_price",
10707
- render: ({ field: { onChange, ...field } }) => {
10708
- return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
10709
- CurrencyInput,
10710
- {
10711
- ...field,
10712
- symbol: getNativeSymbol(currencyCode),
10713
- code: currencyCode,
10714
- onValueChange: (_value, _name, values) => onChange(values == null ? void 0 : values.value)
10715
- }
10716
- ) }) });
10717
- }
10718
- }
10719
- ) }) : /* @__PURE__ */ jsx("div", { className: "flex w-full flex-1 items-center justify-end", children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: getLocaleAmount(item.unit_price, currencyCode) }) }),
10720
- /* @__PURE__ */ jsx(
10721
- IconButton,
10722
- {
10723
- type: "button",
10724
- size: "small",
10725
- onClick: editing ? onSubmit : () => {
10726
- setEditing(true);
10727
- },
10728
- disabled: isPending,
10729
- children: editing ? /* @__PURE__ */ jsx(Check, {}) : /* @__PURE__ */ jsx(PencilSquare, {})
10730
- }
10731
- )
10732
- ] }) }) });
10733
- };
10734
- const variantItemSchema = objectType({
10735
- quantity: numberType(),
10736
- unit_price: unionType([numberType(), stringType()])
10737
- });
10738
- const CustomItem = ({ item, preview, currencyCode }) => {
10739
- const [editing, setEditing] = useState(false);
10740
- const { quantity, unit_price, title } = item;
10741
- const form = useForm({
10742
- defaultValues: {
10743
- title,
10744
- quantity,
10745
- unit_price
10746
- },
10747
- resolver: zodResolver(customItemSchema)
10748
- });
10749
- useEffect(() => {
10750
- form.reset({
10751
- title,
10752
- quantity,
10753
- unit_price
10754
- });
10755
- }, [form, title, quantity, unit_price]);
10756
- const actionId = useMemo(() => {
10757
- var _a, _b;
10758
- return (_b = (_a = item.actions) == null ? void 0 : _a.find((a) => a.action === "ITEM_ADD")) == null ? void 0 : _b.id;
10759
- }, [item]);
10760
- const { mutateAsync: updateActionItem, isPending: isUpdatingActionItem } = useDraftOrderUpdateActionItem(preview.id);
10761
- const { mutateAsync: removeActionItem, isPending: isRemovingActionItem } = useDraftOrderRemoveActionItem(preview.id);
10762
- const { mutateAsync: updateOriginalItem, isPending: isUpdatingOriginalItem } = useDraftOrderUpdateItem(preview.id);
10763
- const isPending = isUpdatingActionItem || isUpdatingOriginalItem;
10764
- const onSubmit = form.handleSubmit(async (data) => {
10765
- if (convertNumber(data.unit_price) === item.unit_price && data.quantity === item.quantity && data.title === item.title) {
10894
+ if (convertNumber(data.unit_price) === item.unit_price && data.quantity === item.quantity) {
10766
10895
  setEditing(false);
10767
10896
  return;
10768
10897
  }
@@ -10784,17 +10913,6 @@ const CustomItem = ({ item, preview, currencyCode }) => {
10784
10913
  );
10785
10914
  return;
10786
10915
  }
10787
- if (data.quantity === 0) {
10788
- await removeActionItem(actionId, {
10789
- onSuccess: () => {
10790
- setEditing(false);
10791
- },
10792
- onError: (e) => {
10793
- toast.error(e.message);
10794
- }
10795
- });
10796
- return;
10797
- }
10798
10916
  await updateActionItem(
10799
10917
  {
10800
10918
  action_id: actionId,
@@ -10812,276 +10930,157 @@ const CustomItem = ({ item, preview, currencyCode }) => {
10812
10930
  );
10813
10931
  });
10814
10932
  return /* @__PURE__ */ jsx(Form$2, { ...form, children: /* @__PURE__ */ jsx("form", { onSubmit, children: /* @__PURE__ */ 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: [
10815
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-3", children: [
10933
+ /* @__PURE__ */ jsxs("div", { className: "flex w-full items-center gap-x-3", children: [
10816
10934
  /* @__PURE__ */ jsx(
10817
10935
  Thumbnail,
10818
10936
  {
10819
10937
  thumbnail: item.thumbnail,
10820
- alt: item.title ?? void 0
10938
+ alt: item.product_title ?? void 0
10821
10939
  }
10822
10940
  ),
10823
- editing ? /* @__PURE__ */ jsx(
10824
- Form$2.Field,
10825
- {
10826
- control: form.control,
10827
- name: "title",
10828
- render: ({ field }) => {
10829
- return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(Input, { ...field }) }) });
10830
- }
10831
- }
10832
- ) : /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: item.title })
10833
- ] }),
10834
- editing ? /* @__PURE__ */ jsx(
10835
- Form$2.Field,
10836
- {
10837
- control: form.control,
10838
- name: "quantity",
10839
- render: ({ field }) => {
10840
- return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(NumberInput, { ...field }) }) });
10841
- }
10842
- }
10843
- ) : /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: item.quantity }),
10844
- editing ? /* @__PURE__ */ jsx(
10845
- Form$2.Field,
10846
- {
10847
- control: form.control,
10848
- name: "unit_price",
10849
- render: ({ field: { onChange, ...field } }) => {
10850
- return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
10851
- CurrencyInput,
10941
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
10942
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-1", children: [
10943
+ /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: item.product_title }),
10944
+ /* @__PURE__ */ jsxs(
10945
+ Text,
10852
10946
  {
10853
- ...field,
10854
- symbol: getNativeSymbol(currencyCode),
10855
- code: currencyCode,
10856
- onValueChange: (_value, _name, values) => onChange(values == null ? void 0 : values.value)
10947
+ size: "small",
10948
+ leading: "compact",
10949
+ className: "text-ui-fg-subtle",
10950
+ children: [
10951
+ "(",
10952
+ item.variant_title,
10953
+ ")"
10954
+ ]
10857
10955
  }
10858
- ) }) });
10859
- }
10860
- }
10861
- ) : /* @__PURE__ */ jsx("div", { className: "flex flex-1 items-center justify-end", children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: getLocaleAmount(item.unit_price, currencyCode) }) }),
10862
- /* @__PURE__ */ jsx(
10863
- IconButton,
10864
- {
10865
- type: "button",
10866
- size: "small",
10867
- onClick: editing ? onSubmit : () => {
10868
- setEditing(true);
10869
- },
10870
- disabled: isPending,
10871
- children: editing ? /* @__PURE__ */ jsx(Check, {}) : /* @__PURE__ */ jsx(PencilSquare, {})
10872
- }
10873
- )
10874
- ] }) }) });
10875
- };
10876
- const StackedModalTrigger$1 = ({
10877
- type,
10878
- setModalContent
10879
- }) => {
10880
- const { setIsOpen } = useStackedModal();
10881
- const onClick = useCallback(() => {
10882
- setModalContent(type);
10883
- setIsOpen(STACKED_MODAL_ID, true);
10884
- }, [setModalContent, setIsOpen, type]);
10885
- return /* @__PURE__ */ jsx(StackedFocusModal.Trigger, { asChild: true, children: /* @__PURE__ */ jsx(DropdownMenu.Item, { onClick, children: type === "add-items" ? "Add items" : "Add custom item" }) });
10886
- };
10887
- const VARIANT_PREFIX = "items";
10888
- const LIMIT = 50;
10889
- const ExistingItemsForm = ({ orderId, items }) => {
10890
- const { setIsOpen } = useStackedModal();
10891
- const [rowSelection, setRowSelection] = useState(
10892
- items.reduce((acc, item) => {
10893
- acc[item.variant_id] = true;
10894
- return acc;
10895
- }, {})
10896
- );
10897
- useEffect(() => {
10898
- setRowSelection(
10899
- items.reduce((acc, item) => {
10900
- if (item.variant_id) {
10901
- acc[item.variant_id] = true;
10902
- }
10903
- return acc;
10904
- }, {})
10905
- );
10906
- }, [items]);
10907
- const { q, order, offset } = useQueryParams(
10908
- ["q", "order", "offset"],
10909
- VARIANT_PREFIX
10910
- );
10911
- const { variants, count, isPending, isError, error } = useProductVariants(
10912
- {
10913
- q,
10914
- order,
10915
- offset: offset ? parseInt(offset) : void 0,
10916
- limit: LIMIT
10917
- },
10918
- {
10919
- placeholderData: keepPreviousData
10920
- }
10921
- );
10922
- const columns = useColumns();
10923
- const { mutateAsync } = useDraftOrderAddItems(orderId);
10924
- const onSubmit = async () => {
10925
- const ids = Object.keys(rowSelection).filter(
10926
- (id) => !items.find((i) => i.variant_id === id)
10927
- );
10928
- await mutateAsync(
10929
- {
10930
- items: ids.map((id) => ({
10931
- variant_id: id,
10932
- quantity: 1
10933
- }))
10934
- },
10935
- {
10936
- onSuccess: () => {
10937
- setRowSelection({});
10938
- setIsOpen(STACKED_MODAL_ID, false);
10939
- },
10940
- onError: (e) => {
10941
- toast.error(e.message);
10942
- }
10943
- }
10944
- );
10945
- };
10946
- if (isError) {
10947
- throw error;
10948
- }
10949
- return /* @__PURE__ */ jsxs(
10950
- StackedFocusModal.Content,
10951
- {
10952
- onOpenAutoFocus: (e) => {
10953
- e.preventDefault();
10954
- const searchInput = document.querySelector(
10955
- "[data-modal-id='modal-search-input']"
10956
- );
10957
- if (searchInput) {
10958
- searchInput.focus();
10959
- }
10960
- },
10961
- children: [
10962
- /* @__PURE__ */ jsxs(StackedFocusModal.Header, { children: [
10963
- /* @__PURE__ */ jsx(StackedFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Product Variants" }) }),
10964
- /* @__PURE__ */ jsx(StackedFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Choose product variants to add to the order." }) })
10956
+ )
10965
10957
  ] }),
10966
- /* @__PURE__ */ jsx(StackedFocusModal.Body, { className: "flex-1 overflow-hidden", children: /* @__PURE__ */ jsx(
10967
- DataTable,
10958
+ /* @__PURE__ */ jsx(
10959
+ Text,
10968
10960
  {
10969
- data: variants,
10970
- columns,
10971
- isLoading: isPending,
10972
- getRowId: (row) => row.id,
10973
- rowCount: count,
10974
- prefix: VARIANT_PREFIX,
10975
- layout: "fill",
10976
- rowSelection: {
10977
- state: rowSelection,
10978
- onRowSelectionChange: setRowSelection,
10979
- enableRowSelection: (row) => {
10980
- return !items.find((i) => i.variant_id === row.original.id);
10981
- }
10982
- },
10983
- autoFocusSearch: true
10984
- }
10985
- ) }),
10986
- /* @__PURE__ */ jsx(StackedFocusModal.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
10987
- /* @__PURE__ */ jsx(StackedFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
10988
- /* @__PURE__ */ jsx(Button, { size: "small", type: "button", onClick: onSubmit, children: "Update items" })
10989
- ] }) })
10990
- ]
10991
- }
10992
- );
10993
- };
10994
- const columnHelper = createDataTableColumnHelper();
10995
- const useColumns = () => {
10996
- return useMemo(() => {
10997
- return [
10998
- columnHelper.select(),
10999
- columnHelper.accessor("product.title", {
11000
- header: "Product",
11001
- cell: ({ row }) => {
11002
- var _a, _b, _c;
11003
- return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-2", children: [
11004
- /* @__PURE__ */ jsx(
11005
- Thumbnail,
11006
- {
11007
- thumbnail: (_a = row.original.product) == null ? void 0 : _a.thumbnail,
11008
- alt: (_b = row.original.product) == null ? void 0 : _b.title
11009
- }
11010
- ),
11011
- /* @__PURE__ */ jsx("span", { children: (_c = row.original.product) == null ? void 0 : _c.title })
11012
- ] });
11013
- },
11014
- enableSorting: true
11015
- }),
11016
- columnHelper.accessor("title", {
11017
- header: "Variant",
11018
- enableSorting: true
11019
- }),
11020
- columnHelper.accessor("sku", {
11021
- header: "SKU",
11022
- cell: ({ getValue }) => {
11023
- return getValue() ?? "-";
11024
- },
11025
- enableSorting: true
11026
- }),
11027
- columnHelper.accessor("updated_at", {
11028
- header: "Updated",
11029
- cell: ({ getValue }) => {
11030
- return /* @__PURE__ */ jsx(
11031
- Tooltip,
11032
- {
11033
- content: getFullDate({ date: getValue(), includeTime: true }),
11034
- children: /* @__PURE__ */ jsx("span", { children: getFullDate({ date: getValue() }) })
11035
- }
11036
- );
11037
- },
11038
- enableSorting: true,
11039
- sortAscLabel: "Oldest first",
11040
- sortDescLabel: "Newest first"
11041
- }),
11042
- columnHelper.accessor("created_at", {
11043
- header: "Created",
11044
- cell: ({ getValue }) => {
11045
- return /* @__PURE__ */ jsx(
11046
- Tooltip,
10961
+ size: "small",
10962
+ leading: "compact",
10963
+ className: "text-ui-fg-subtle",
10964
+ children: item.variant_sku
10965
+ }
10966
+ )
10967
+ ] })
10968
+ ] }),
10969
+ editing ? /* @__PURE__ */ jsx("div", { className: "w-full flex-1", children: /* @__PURE__ */ jsx(
10970
+ Form$2.Field,
10971
+ {
10972
+ control: form.control,
10973
+ name: "quantity",
10974
+ render: ({ field }) => {
10975
+ return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(NumberInput, { ...field }) }) });
10976
+ }
10977
+ }
10978
+ ) }) : /* @__PURE__ */ jsx("div", { className: "w-full flex-1", children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: item.quantity }) }),
10979
+ editing ? /* @__PURE__ */ jsx("div", { className: "w-full flex-1", children: /* @__PURE__ */ jsx(
10980
+ Form$2.Field,
10981
+ {
10982
+ control: form.control,
10983
+ name: "unit_price",
10984
+ render: ({ field: { onChange, ...field } }) => {
10985
+ return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
10986
+ CurrencyInput,
11047
10987
  {
11048
- content: getFullDate({ date: getValue(), includeTime: true }),
11049
- children: /* @__PURE__ */ jsx("span", { children: getFullDate({ date: getValue() }) })
10988
+ ...field,
10989
+ symbol: getNativeSymbol(currencyCode),
10990
+ code: currencyCode,
10991
+ onValueChange: (_value, _name, values) => onChange(values == null ? void 0 : values.value)
11050
10992
  }
11051
- );
10993
+ ) }) });
10994
+ }
10995
+ }
10996
+ ) }) : /* @__PURE__ */ jsx("div", { className: "flex w-full flex-1 items-center justify-end", children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: getLocaleAmount(item.unit_price, currencyCode) }) }),
10997
+ /* @__PURE__ */ jsx(
10998
+ IconButton,
10999
+ {
11000
+ type: "button",
11001
+ size: "small",
11002
+ onClick: editing ? onSubmit : () => {
11003
+ setEditing(true);
11052
11004
  },
11053
- enableSorting: true,
11054
- sortAscLabel: "Oldest first",
11055
- sortDescLabel: "Newest first"
11056
- })
11057
- ];
11058
- }, []);
11005
+ disabled: isPending,
11006
+ children: editing ? /* @__PURE__ */ jsx(Check, {}) : /* @__PURE__ */ jsx(PencilSquare, {})
11007
+ }
11008
+ )
11009
+ ] }) }) });
11059
11010
  };
11060
- const CustomItemForm = ({ orderId, currencyCode }) => {
11061
- const { setIsOpen } = useStackedModal();
11062
- const { mutateAsync: addItems } = useDraftOrderAddItems(orderId);
11011
+ const variantItemSchema = objectType({
11012
+ quantity: numberType(),
11013
+ unit_price: unionType([numberType(), stringType()])
11014
+ });
11015
+ const CustomItem = ({ item, preview, currencyCode }) => {
11016
+ const [editing, setEditing] = useState(false);
11017
+ const { quantity, unit_price, title } = item;
11063
11018
  const form = useForm({
11064
11019
  defaultValues: {
11065
- title: "",
11066
- quantity: 1,
11067
- unit_price: ""
11020
+ title,
11021
+ quantity,
11022
+ unit_price
11068
11023
  },
11069
11024
  resolver: zodResolver(customItemSchema)
11070
11025
  });
11026
+ useEffect(() => {
11027
+ form.reset({
11028
+ title,
11029
+ quantity,
11030
+ unit_price
11031
+ });
11032
+ }, [form, title, quantity, unit_price]);
11033
+ const actionId = useMemo(() => {
11034
+ var _a, _b;
11035
+ return (_b = (_a = item.actions) == null ? void 0 : _a.find((a) => a.action === "ITEM_ADD")) == null ? void 0 : _b.id;
11036
+ }, [item]);
11037
+ const { mutateAsync: updateActionItem, isPending: isUpdatingActionItem } = useDraftOrderUpdateActionItem(preview.id);
11038
+ const { mutateAsync: removeActionItem, isPending: isRemovingActionItem } = useDraftOrderRemoveActionItem(preview.id);
11039
+ const { mutateAsync: updateOriginalItem, isPending: isUpdatingOriginalItem } = useDraftOrderUpdateItem(preview.id);
11040
+ const isPending = isUpdatingActionItem || isUpdatingOriginalItem;
11071
11041
  const onSubmit = form.handleSubmit(async (data) => {
11072
- await addItems(
11073
- {
11074
- items: [
11075
- {
11076
- title: data.title,
11077
- quantity: data.quantity,
11078
- unit_price: convertNumber(data.unit_price)
11042
+ if (convertNumber(data.unit_price) === item.unit_price && data.quantity === item.quantity && data.title === item.title) {
11043
+ setEditing(false);
11044
+ return;
11045
+ }
11046
+ if (!actionId) {
11047
+ await updateOriginalItem(
11048
+ {
11049
+ item_id: item.id,
11050
+ quantity: data.quantity,
11051
+ unit_price: convertNumber(data.unit_price)
11052
+ },
11053
+ {
11054
+ onSuccess: () => {
11055
+ setEditing(false);
11056
+ },
11057
+ onError: (e) => {
11058
+ toast.error(e.message);
11079
11059
  }
11080
- ]
11060
+ }
11061
+ );
11062
+ return;
11063
+ }
11064
+ if (data.quantity === 0) {
11065
+ await removeActionItem(actionId, {
11066
+ onSuccess: () => {
11067
+ setEditing(false);
11068
+ },
11069
+ onError: (e) => {
11070
+ toast.error(e.message);
11071
+ }
11072
+ });
11073
+ return;
11074
+ }
11075
+ await updateActionItem(
11076
+ {
11077
+ action_id: actionId,
11078
+ quantity: data.quantity,
11079
+ unit_price: convertNumber(data.unit_price)
11081
11080
  },
11082
11081
  {
11083
11082
  onSuccess: () => {
11084
- setIsOpen(STACKED_MODAL_ID, false);
11083
+ setEditing(false);
11085
11084
  },
11086
11085
  onError: (e) => {
11087
11086
  toast.error(e.message);
@@ -11089,364 +11088,365 @@ const CustomItemForm = ({ orderId, currencyCode }) => {
11089
11088
  }
11090
11089
  );
11091
11090
  });
11092
- return /* @__PURE__ */ jsx(Form$2, { ...form, children: /* @__PURE__ */ jsx(KeyboundForm, { onSubmit, children: /* @__PURE__ */ jsxs(StackedFocusModal.Content, { children: [
11093
- /* @__PURE__ */ jsx(StackedFocusModal.Header, {}),
11094
- /* @__PURE__ */ jsx(StackedFocusModal.Body, { className: "flex flex-1 flex-col overflow-hidden", children: /* @__PURE__ */ jsx("div", { className: "flex flex-1 flex-col items-center overflow-y-auto", children: /* @__PURE__ */ jsxs("div", { className: "flex w-full max-w-[720px] flex-col gap-y-6 px-2 py-16", children: [
11095
- /* @__PURE__ */ jsxs("div", { children: [
11096
- /* @__PURE__ */ jsx(StackedFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Add custom item" }) }),
11097
- /* @__PURE__ */ jsx(StackedFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsx(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." }) })
11098
- ] }),
11099
- /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
11091
+ return /* @__PURE__ */ jsx(Form$2, { ...form, children: /* @__PURE__ */ jsx("form", { onSubmit, children: /* @__PURE__ */ 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: [
11092
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-3", children: [
11100
11093
  /* @__PURE__ */ jsx(
11101
- Form$2.Field,
11094
+ Thumbnail,
11102
11095
  {
11103
- control: form.control,
11104
- name: "title",
11105
- render: ({ field }) => /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
11106
- /* @__PURE__ */ jsxs("div", { children: [
11107
- /* @__PURE__ */ jsx(Form$2.Label, { children: "Title" }),
11108
- /* @__PURE__ */ jsx(Form$2.Hint, { children: "Enter the title of the item" })
11109
- ] }),
11110
- /* @__PURE__ */ jsxs("div", { children: [
11111
- /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(Input, { ...field }) }),
11112
- /* @__PURE__ */ jsx(Form$2.ErrorMessage, {})
11113
- ] })
11114
- ] }) })
11096
+ thumbnail: item.thumbnail,
11097
+ alt: item.title ?? void 0
11115
11098
  }
11116
11099
  ),
11117
- /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
11118
- /* @__PURE__ */ jsx(
11100
+ editing ? /* @__PURE__ */ jsx(
11119
11101
  Form$2.Field,
11120
11102
  {
11121
11103
  control: form.control,
11122
- name: "unit_price",
11123
- render: ({ field: { onChange, ...field } }) => /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
11124
- /* @__PURE__ */ jsxs("div", { children: [
11125
- /* @__PURE__ */ jsx(Form$2.Label, { children: "Unit price" }),
11126
- /* @__PURE__ */ jsx(Form$2.Hint, { children: "Enter the unit price of the item" })
11127
- ] }),
11128
- /* @__PURE__ */ jsxs("div", { children: [
11129
- /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
11130
- CurrencyInput,
11131
- {
11132
- symbol: getNativeSymbol(currencyCode),
11133
- code: currencyCode,
11134
- onValueChange: (_value, _name, values) => onChange(values == null ? void 0 : values.value),
11135
- ...field
11136
- }
11137
- ) }),
11138
- /* @__PURE__ */ jsx(Form$2.ErrorMessage, {})
11139
- ] })
11140
- ] }) })
11104
+ name: "title",
11105
+ render: ({ field }) => {
11106
+ return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(Input, { ...field }) }) });
11107
+ }
11141
11108
  }
11142
- ),
11143
- /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
11144
- /* @__PURE__ */ jsx(
11145
- Form$2.Field,
11146
- {
11147
- control: form.control,
11148
- name: "quantity",
11149
- render: ({ field }) => /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
11150
- /* @__PURE__ */ jsxs("div", { children: [
11151
- /* @__PURE__ */ jsx(Form$2.Label, { children: "Quantity" }),
11152
- /* @__PURE__ */ jsx(Form$2.Hint, { children: "Enter the quantity of the item" })
11153
- ] }),
11154
- /* @__PURE__ */ jsxs("div", { className: "w-full flex-1", children: [
11155
- /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx("div", { className: "w-full flex-1", children: /* @__PURE__ */ jsx(NumberInput, { ...field, className: "w-full" }) }) }),
11156
- /* @__PURE__ */ jsx(Form$2.ErrorMessage, {})
11157
- ] })
11158
- ] }) })
11109
+ ) : /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: item.title })
11110
+ ] }),
11111
+ editing ? /* @__PURE__ */ jsx(
11112
+ Form$2.Field,
11113
+ {
11114
+ control: form.control,
11115
+ name: "quantity",
11116
+ render: ({ field }) => {
11117
+ return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(NumberInput, { ...field }) }) });
11159
11118
  }
11160
- )
11161
- ] }) }) }),
11162
- /* @__PURE__ */ jsx(StackedFocusModal.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
11163
- /* @__PURE__ */ jsx(StackedFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
11164
- /* @__PURE__ */ jsx(Button, { size: "small", type: "button", onClick: onSubmit, children: "Add item" })
11165
- ] }) })
11166
- ] }) }) });
11167
- };
11168
- const customItemSchema = objectType({
11169
- title: stringType().min(1),
11170
- quantity: numberType(),
11171
- unit_price: unionType([numberType(), stringType()])
11172
- });
11173
- const PROMOTION_QUERY_KEY = "promotions";
11174
- const promotionsQueryKeys = {
11175
- list: (query2) => [
11176
- PROMOTION_QUERY_KEY,
11177
- query2 ? query2 : void 0
11178
- ],
11179
- detail: (id, query2) => [
11180
- PROMOTION_QUERY_KEY,
11181
- id,
11182
- query2 ? query2 : void 0
11183
- ]
11184
- };
11185
- const usePromotions = (query2, options) => {
11186
- const { data, ...rest } = useQuery({
11187
- queryKey: promotionsQueryKeys.list(query2),
11188
- queryFn: async () => sdk.admin.promotion.list(query2),
11189
- ...options
11190
- });
11191
- return { ...data, ...rest };
11119
+ }
11120
+ ) : /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: item.quantity }),
11121
+ editing ? /* @__PURE__ */ jsx(
11122
+ Form$2.Field,
11123
+ {
11124
+ control: form.control,
11125
+ name: "unit_price",
11126
+ render: ({ field: { onChange, ...field } }) => {
11127
+ return /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
11128
+ CurrencyInput,
11129
+ {
11130
+ ...field,
11131
+ symbol: getNativeSymbol(currencyCode),
11132
+ code: currencyCode,
11133
+ onValueChange: (_value, _name, values) => onChange(values == null ? void 0 : values.value)
11134
+ }
11135
+ ) }) });
11136
+ }
11137
+ }
11138
+ ) : /* @__PURE__ */ jsx("div", { className: "flex flex-1 items-center justify-end", children: /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: getLocaleAmount(item.unit_price, currencyCode) }) }),
11139
+ /* @__PURE__ */ jsx(
11140
+ IconButton,
11141
+ {
11142
+ type: "button",
11143
+ size: "small",
11144
+ onClick: editing ? onSubmit : () => {
11145
+ setEditing(true);
11146
+ },
11147
+ disabled: isPending,
11148
+ children: editing ? /* @__PURE__ */ jsx(Check, {}) : /* @__PURE__ */ jsx(PencilSquare, {})
11149
+ }
11150
+ )
11151
+ ] }) }) });
11192
11152
  };
11193
- const Promotions = () => {
11194
- const { id } = useParams();
11195
- const {
11196
- order: preview,
11197
- isError: isPreviewError,
11198
- error: previewError
11199
- } = useOrderPreview(id, void 0);
11200
- useInitiateOrderEdit({ preview });
11201
- const { onCancel } = useCancelOrderEdit({ preview });
11202
- if (isPreviewError) {
11203
- throw previewError;
11204
- }
11205
- const isReady = !!preview;
11206
- return /* @__PURE__ */ jsxs(RouteDrawer, { onClose: onCancel, children: [
11207
- /* @__PURE__ */ jsx(RouteDrawer.Header, { children: /* @__PURE__ */ jsx(RouteDrawer.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Edit Promotions" }) }) }),
11208
- isReady && /* @__PURE__ */ jsx(PromotionForm, { preview })
11209
- ] });
11153
+ const StackedModalTrigger$1 = ({
11154
+ type,
11155
+ setModalContent
11156
+ }) => {
11157
+ const { setIsOpen } = useStackedModal();
11158
+ const onClick = useCallback(() => {
11159
+ setModalContent(type);
11160
+ setIsOpen(STACKED_MODAL_ID, true);
11161
+ }, [setModalContent, setIsOpen, type]);
11162
+ return /* @__PURE__ */ jsx(StackedFocusModal.Trigger, { asChild: true, children: /* @__PURE__ */ jsx(DropdownMenu.Item, { onClick, children: type === "add-items" ? "Add items" : "Add custom item" }) });
11210
11163
  };
11211
- const PromotionForm = ({ preview }) => {
11212
- const { items, shipping_methods } = preview;
11213
- const [isSubmitting, setIsSubmitting] = useState(false);
11214
- const [comboboxValue, setComboboxValue] = useState("");
11215
- const { handleSuccess } = useRouteModal();
11216
- const { mutateAsync: addPromotions, isPending: isAddingPromotions } = useDraftOrderAddPromotions(preview.id);
11217
- const promoIds = getPromotionIds(items, shipping_methods);
11218
- const { promotions, isPending, isError, error } = usePromotions(
11164
+ const VARIANT_PREFIX = "items";
11165
+ const LIMIT = 50;
11166
+ const ExistingItemsForm = ({ orderId, items }) => {
11167
+ const { setIsOpen } = useStackedModal();
11168
+ const [rowSelection, setRowSelection] = useState(
11169
+ items.reduce((acc, item) => {
11170
+ acc[item.variant_id] = true;
11171
+ return acc;
11172
+ }, {})
11173
+ );
11174
+ useEffect(() => {
11175
+ setRowSelection(
11176
+ items.reduce((acc, item) => {
11177
+ if (item.variant_id) {
11178
+ acc[item.variant_id] = true;
11179
+ }
11180
+ return acc;
11181
+ }, {})
11182
+ );
11183
+ }, [items]);
11184
+ const { q, order, offset } = useQueryParams(
11185
+ ["q", "order", "offset"],
11186
+ VARIANT_PREFIX
11187
+ );
11188
+ const { variants, count, isPending, isError, error } = useProductVariants(
11219
11189
  {
11220
- id: promoIds
11190
+ q,
11191
+ order,
11192
+ offset: offset ? parseInt(offset) : void 0,
11193
+ limit: LIMIT
11221
11194
  },
11222
11195
  {
11223
- enabled: !!promoIds.length
11196
+ placeholderData: keepPreviousData
11224
11197
  }
11225
11198
  );
11226
- const comboboxData = useComboboxData({
11227
- queryKey: ["promotions", "combobox", promoIds],
11228
- queryFn: async (params) => {
11229
- return await sdk.admin.promotion.list({
11230
- ...params,
11231
- id: {
11232
- $nin: promoIds
11233
- }
11234
- });
11235
- },
11236
- getOptions: (data) => {
11237
- return data.promotions.map((promotion) => ({
11238
- label: promotion.code,
11239
- value: promotion.code
11240
- }));
11241
- }
11242
- });
11243
- const add = async (value) => {
11244
- if (!value) {
11245
- return;
11246
- }
11247
- addPromotions(
11199
+ const columns = useColumns();
11200
+ const { mutateAsync } = useDraftOrderAddItems(orderId);
11201
+ const onSubmit = async () => {
11202
+ const ids = Object.keys(rowSelection).filter(
11203
+ (id) => !items.find((i) => i.variant_id === id)
11204
+ );
11205
+ await mutateAsync(
11248
11206
  {
11249
- promo_codes: [value]
11207
+ items: ids.map((id) => ({
11208
+ variant_id: id,
11209
+ quantity: 1
11210
+ }))
11250
11211
  },
11251
11212
  {
11213
+ onSuccess: () => {
11214
+ setRowSelection({});
11215
+ setIsOpen(STACKED_MODAL_ID, false);
11216
+ },
11252
11217
  onError: (e) => {
11253
11218
  toast.error(e.message);
11254
- comboboxData.onSearchValueChange("");
11255
- setComboboxValue("");
11256
- },
11257
- onSuccess: () => {
11258
- comboboxData.onSearchValueChange("");
11259
- setComboboxValue("");
11260
11219
  }
11261
11220
  }
11262
11221
  );
11263
11222
  };
11264
- const { mutateAsync: confirmOrderEdit } = useDraftOrderConfirmEdit(preview.id);
11265
- const { mutateAsync: requestOrderEdit } = useOrderEditRequest(preview.id);
11266
- const onSubmit = async () => {
11267
- setIsSubmitting(true);
11268
- let requestSucceeded = false;
11269
- await requestOrderEdit(void 0, {
11270
- onError: (e) => {
11271
- toast.error(e.message);
11272
- },
11273
- onSuccess: () => {
11274
- requestSucceeded = true;
11275
- }
11276
- });
11277
- if (!requestSucceeded) {
11278
- setIsSubmitting(false);
11279
- return;
11280
- }
11281
- await confirmOrderEdit(void 0, {
11282
- onError: (e) => {
11283
- toast.error(e.message);
11284
- },
11285
- onSuccess: () => {
11286
- handleSuccess();
11287
- },
11288
- onSettled: () => {
11289
- setIsSubmitting(false);
11290
- }
11291
- });
11292
- };
11293
11223
  if (isError) {
11294
11224
  throw error;
11295
11225
  }
11296
- return /* @__PURE__ */ jsxs(KeyboundForm, { className: "flex flex-1 flex-col", onSubmit, children: [
11297
- /* @__PURE__ */ jsx(RouteDrawer.Body, { children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
11298
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
11299
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
11300
- /* @__PURE__ */ jsx(Label$1, { size: "small", weight: "plus", htmlFor: "promotion-combobox", children: "Apply promotions" }),
11301
- /* @__PURE__ */ jsx(Hint$1, { id: "promotion-combobox-hint", children: "Manage promotions that should be applied to the order." })
11226
+ return /* @__PURE__ */ jsxs(
11227
+ StackedFocusModal.Content,
11228
+ {
11229
+ onOpenAutoFocus: (e) => {
11230
+ e.preventDefault();
11231
+ const searchInput = document.querySelector(
11232
+ "[data-modal-id='modal-search-input']"
11233
+ );
11234
+ if (searchInput) {
11235
+ searchInput.focus();
11236
+ }
11237
+ },
11238
+ children: [
11239
+ /* @__PURE__ */ jsxs(StackedFocusModal.Header, { children: [
11240
+ /* @__PURE__ */ jsx(StackedFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Product Variants" }) }),
11241
+ /* @__PURE__ */ jsx(StackedFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Choose product variants to add to the order." }) })
11302
11242
  ] }),
11303
- /* @__PURE__ */ jsx(
11304
- Combobox,
11243
+ /* @__PURE__ */ jsx(StackedFocusModal.Body, { className: "flex-1 overflow-hidden", children: /* @__PURE__ */ jsx(
11244
+ DataTable,
11305
11245
  {
11306
- id: "promotion-combobox",
11307
- "aria-describedby": "promotion-combobox-hint",
11308
- isFetchingNextPage: comboboxData.isFetchingNextPage,
11309
- fetchNextPage: comboboxData.fetchNextPage,
11310
- options: comboboxData.options,
11311
- onSearchValueChange: comboboxData.onSearchValueChange,
11312
- searchValue: comboboxData.searchValue,
11313
- disabled: comboboxData.disabled || isAddingPromotions,
11314
- onChange: add,
11315
- value: comboboxValue
11246
+ data: variants,
11247
+ columns,
11248
+ isLoading: isPending,
11249
+ getRowId: (row) => row.id,
11250
+ rowCount: count,
11251
+ prefix: VARIANT_PREFIX,
11252
+ layout: "fill",
11253
+ rowSelection: {
11254
+ state: rowSelection,
11255
+ onRowSelectionChange: setRowSelection,
11256
+ enableRowSelection: (row) => {
11257
+ return !items.find((i) => i.variant_id === row.original.id);
11258
+ }
11259
+ },
11260
+ autoFocusSearch: true
11316
11261
  }
11317
- )
11318
- ] }),
11319
- /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
11320
- /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-2", children: promotions == null ? void 0 : promotions.map((promotion) => /* @__PURE__ */ jsx(
11321
- PromotionItem,
11322
- {
11323
- promotion,
11324
- orderId: preview.id,
11325
- isLoading: isPending
11262
+ ) }),
11263
+ /* @__PURE__ */ jsx(StackedFocusModal.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
11264
+ /* @__PURE__ */ jsx(StackedFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
11265
+ /* @__PURE__ */ jsx(Button, { size: "small", type: "button", onClick: onSubmit, children: "Update items" })
11266
+ ] }) })
11267
+ ]
11268
+ }
11269
+ );
11270
+ };
11271
+ const columnHelper = createDataTableColumnHelper();
11272
+ const useColumns = () => {
11273
+ return useMemo(() => {
11274
+ return [
11275
+ columnHelper.select(),
11276
+ columnHelper.accessor("product.title", {
11277
+ header: "Product",
11278
+ cell: ({ row }) => {
11279
+ var _a, _b, _c;
11280
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-2", children: [
11281
+ /* @__PURE__ */ jsx(
11282
+ Thumbnail,
11283
+ {
11284
+ thumbnail: (_a = row.original.product) == null ? void 0 : _a.thumbnail,
11285
+ alt: (_b = row.original.product) == null ? void 0 : _b.title
11286
+ }
11287
+ ),
11288
+ /* @__PURE__ */ jsx("span", { children: (_c = row.original.product) == null ? void 0 : _c.title })
11289
+ ] });
11290
+ },
11291
+ enableSorting: true
11292
+ }),
11293
+ columnHelper.accessor("title", {
11294
+ header: "Variant",
11295
+ enableSorting: true
11296
+ }),
11297
+ columnHelper.accessor("sku", {
11298
+ header: "SKU",
11299
+ cell: ({ getValue }) => {
11300
+ return getValue() ?? "-";
11301
+ },
11302
+ enableSorting: true
11303
+ }),
11304
+ columnHelper.accessor("updated_at", {
11305
+ header: "Updated",
11306
+ cell: ({ getValue }) => {
11307
+ return /* @__PURE__ */ jsx(
11308
+ Tooltip,
11309
+ {
11310
+ content: getFullDate({ date: getValue(), includeTime: true }),
11311
+ children: /* @__PURE__ */ jsx("span", { children: getFullDate({ date: getValue() }) })
11312
+ }
11313
+ );
11326
11314
  },
11327
- promotion.id
11328
- )) })
11329
- ] }) }),
11330
- /* @__PURE__ */ jsx(RouteDrawer.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
11331
- /* @__PURE__ */ jsx(RouteDrawer.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", children: "Cancel" }) }),
11332
- /* @__PURE__ */ jsx(
11333
- Button,
11334
- {
11335
- size: "small",
11336
- type: "submit",
11337
- isLoading: isSubmitting || isAddingPromotions,
11338
- children: "Save"
11339
- }
11340
- )
11341
- ] }) })
11342
- ] });
11315
+ enableSorting: true,
11316
+ sortAscLabel: "Oldest first",
11317
+ sortDescLabel: "Newest first"
11318
+ }),
11319
+ columnHelper.accessor("created_at", {
11320
+ header: "Created",
11321
+ cell: ({ getValue }) => {
11322
+ return /* @__PURE__ */ jsx(
11323
+ Tooltip,
11324
+ {
11325
+ content: getFullDate({ date: getValue(), includeTime: true }),
11326
+ children: /* @__PURE__ */ jsx("span", { children: getFullDate({ date: getValue() }) })
11327
+ }
11328
+ );
11329
+ },
11330
+ enableSorting: true,
11331
+ sortAscLabel: "Oldest first",
11332
+ sortDescLabel: "Newest first"
11333
+ })
11334
+ ];
11335
+ }, []);
11343
11336
  };
11344
- const PromotionItem = ({
11345
- promotion,
11346
- orderId,
11347
- isLoading
11348
- }) => {
11349
- var _a;
11350
- const { mutateAsync: removePromotions, isPending } = useDraftOrderRemovePromotions(orderId);
11351
- const onRemove = async () => {
11352
- removePromotions(
11337
+ const CustomItemForm = ({ orderId, currencyCode }) => {
11338
+ const { setIsOpen } = useStackedModal();
11339
+ const { mutateAsync: addItems } = useDraftOrderAddItems(orderId);
11340
+ const form = useForm({
11341
+ defaultValues: {
11342
+ title: "",
11343
+ quantity: 1,
11344
+ unit_price: ""
11345
+ },
11346
+ resolver: zodResolver(customItemSchema)
11347
+ });
11348
+ const onSubmit = form.handleSubmit(async (data) => {
11349
+ await addItems(
11353
11350
  {
11354
- promo_codes: [promotion.code]
11351
+ items: [
11352
+ {
11353
+ title: data.title,
11354
+ quantity: data.quantity,
11355
+ unit_price: convertNumber(data.unit_price)
11356
+ }
11357
+ ]
11355
11358
  },
11356
11359
  {
11360
+ onSuccess: () => {
11361
+ setIsOpen(STACKED_MODAL_ID, false);
11362
+ },
11357
11363
  onError: (e) => {
11358
11364
  toast.error(e.message);
11359
11365
  }
11360
11366
  }
11361
11367
  );
11362
- };
11363
- const displayValue = getDisplayValue(promotion);
11364
- return /* @__PURE__ */ jsxs(
11365
- "div",
11366
- {
11367
- className: clx(
11368
- "bg-ui-bg-component shadow-elevation-card-rest flex items-center justify-between rounded-lg px-3 py-2",
11368
+ });
11369
+ return /* @__PURE__ */ jsx(Form$2, { ...form, children: /* @__PURE__ */ jsx(KeyboundForm, { onSubmit, children: /* @__PURE__ */ jsxs(StackedFocusModal.Content, { children: [
11370
+ /* @__PURE__ */ jsx(StackedFocusModal.Header, {}),
11371
+ /* @__PURE__ */ jsx(StackedFocusModal.Body, { className: "flex flex-1 flex-col overflow-hidden", children: /* @__PURE__ */ jsx("div", { className: "flex flex-1 flex-col items-center overflow-y-auto", children: /* @__PURE__ */ jsxs("div", { className: "flex w-full max-w-[720px] flex-col gap-y-6 px-2 py-16", children: [
11372
+ /* @__PURE__ */ jsxs("div", { children: [
11373
+ /* @__PURE__ */ jsx(StackedFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: "Add custom item" }) }),
11374
+ /* @__PURE__ */ jsx(StackedFocusModal.Description, { asChild: true, children: /* @__PURE__ */ jsx(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." }) })
11375
+ ] }),
11376
+ /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
11377
+ /* @__PURE__ */ jsx(
11378
+ Form$2.Field,
11369
11379
  {
11370
- "animate-pulse": isLoading
11380
+ control: form.control,
11381
+ name: "title",
11382
+ render: ({ field }) => /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
11383
+ /* @__PURE__ */ jsxs("div", { children: [
11384
+ /* @__PURE__ */ jsx(Form$2.Label, { children: "Title" }),
11385
+ /* @__PURE__ */ jsx(Form$2.Hint, { children: "Enter the title of the item" })
11386
+ ] }),
11387
+ /* @__PURE__ */ jsxs("div", { children: [
11388
+ /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(Input, { ...field }) }),
11389
+ /* @__PURE__ */ jsx(Form$2.ErrorMessage, {})
11390
+ ] })
11391
+ ] }) })
11371
11392
  }
11372
11393
  ),
11373
- children: [
11374
- /* @__PURE__ */ jsxs("div", { children: [
11375
- /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: promotion.code }),
11376
- /* @__PURE__ */ jsxs("div", { className: "text-ui-fg-subtle flex items-center gap-1.5", children: [
11377
- displayValue && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
11378
- /* @__PURE__ */ jsx(Text, { size: "small", leading: "compact", children: displayValue }),
11379
- /* @__PURE__ */ jsx(Text, { size: "small", leading: "compact", children: "·" })
11394
+ /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
11395
+ /* @__PURE__ */ jsx(
11396
+ Form$2.Field,
11397
+ {
11398
+ control: form.control,
11399
+ name: "unit_price",
11400
+ render: ({ field: { onChange, ...field } }) => /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
11401
+ /* @__PURE__ */ jsxs("div", { children: [
11402
+ /* @__PURE__ */ jsx(Form$2.Label, { children: "Unit price" }),
11403
+ /* @__PURE__ */ jsx(Form$2.Hint, { children: "Enter the unit price of the item" })
11380
11404
  ] }),
11381
- /* @__PURE__ */ jsx(Text, { size: "small", leading: "compact", className: "capitalize", children: (_a = promotion.application_method) == null ? void 0 : _a.allocation })
11382
- ] })
11383
- ] }),
11384
- /* @__PURE__ */ jsx(
11385
- IconButton,
11386
- {
11387
- size: "small",
11388
- type: "button",
11389
- variant: "transparent",
11390
- onClick: onRemove,
11391
- isLoading: isPending || isLoading,
11392
- children: /* @__PURE__ */ jsx(XMark, {})
11393
- }
11394
- )
11395
- ]
11396
- },
11397
- promotion.id
11398
- );
11399
- };
11400
- function getDisplayValue(promotion) {
11401
- var _a, _b, _c, _d;
11402
- const value = (_a = promotion.application_method) == null ? void 0 : _a.value;
11403
- if (!value) {
11404
- return null;
11405
- }
11406
- if (((_b = promotion.application_method) == null ? void 0 : _b.type) === "fixed") {
11407
- const currency = (_c = promotion.application_method) == null ? void 0 : _c.currency_code;
11408
- if (!currency) {
11409
- return null;
11410
- }
11411
- return getLocaleAmount(value, currency);
11412
- } else if (((_d = promotion.application_method) == null ? void 0 : _d.type) === "percentage") {
11413
- return formatPercentage(value);
11414
- }
11415
- return null;
11416
- }
11417
- const formatter = new Intl.NumberFormat([], {
11418
- style: "percent",
11419
- minimumFractionDigits: 2
11420
- });
11421
- const formatPercentage = (value, isPercentageValue = false) => {
11422
- let val = value || 0;
11423
- if (!isPercentageValue) {
11424
- val = val / 100;
11425
- }
11426
- return formatter.format(val);
11427
- };
11428
- function getPromotionIds(items, shippingMethods) {
11429
- const promotionIds = /* @__PURE__ */ new Set();
11430
- for (const item of items) {
11431
- if (item.adjustments) {
11432
- for (const adjustment of item.adjustments) {
11433
- if (adjustment.promotion_id) {
11434
- promotionIds.add(adjustment.promotion_id);
11405
+ /* @__PURE__ */ jsxs("div", { children: [
11406
+ /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx(
11407
+ CurrencyInput,
11408
+ {
11409
+ symbol: getNativeSymbol(currencyCode),
11410
+ code: currencyCode,
11411
+ onValueChange: (_value, _name, values) => onChange(values == null ? void 0 : values.value),
11412
+ ...field
11413
+ }
11414
+ ) }),
11415
+ /* @__PURE__ */ jsx(Form$2.ErrorMessage, {})
11416
+ ] })
11417
+ ] }) })
11435
11418
  }
11436
- }
11437
- }
11438
- }
11439
- for (const shippingMethod of shippingMethods) {
11440
- if (shippingMethod.adjustments) {
11441
- for (const adjustment of shippingMethod.adjustments) {
11442
- if (adjustment.promotion_id) {
11443
- promotionIds.add(adjustment.promotion_id);
11419
+ ),
11420
+ /* @__PURE__ */ jsx(Divider, { variant: "dashed" }),
11421
+ /* @__PURE__ */ jsx(
11422
+ Form$2.Field,
11423
+ {
11424
+ control: form.control,
11425
+ name: "quantity",
11426
+ render: ({ field }) => /* @__PURE__ */ jsx(Form$2.Item, { children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-x-3", children: [
11427
+ /* @__PURE__ */ jsxs("div", { children: [
11428
+ /* @__PURE__ */ jsx(Form$2.Label, { children: "Quantity" }),
11429
+ /* @__PURE__ */ jsx(Form$2.Hint, { children: "Enter the quantity of the item" })
11430
+ ] }),
11431
+ /* @__PURE__ */ jsxs("div", { className: "w-full flex-1", children: [
11432
+ /* @__PURE__ */ jsx(Form$2.Control, { children: /* @__PURE__ */ jsx("div", { className: "w-full flex-1", children: /* @__PURE__ */ jsx(NumberInput, { ...field, className: "w-full" }) }) }),
11433
+ /* @__PURE__ */ jsx(Form$2.ErrorMessage, {})
11434
+ ] })
11435
+ ] }) })
11444
11436
  }
11445
- }
11446
- }
11447
- }
11448
- return Array.from(promotionIds);
11449
- }
11437
+ )
11438
+ ] }) }) }),
11439
+ /* @__PURE__ */ jsx(StackedFocusModal.Footer, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
11440
+ /* @__PURE__ */ jsx(StackedFocusModal.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", type: "button", children: "Cancel" }) }),
11441
+ /* @__PURE__ */ jsx(Button, { size: "small", type: "button", onClick: onSubmit, children: "Add item" })
11442
+ ] }) })
11443
+ ] }) }) });
11444
+ };
11445
+ const customItemSchema = objectType({
11446
+ title: stringType().min(1),
11447
+ quantity: numberType(),
11448
+ unit_price: unionType([numberType(), stringType()])
11449
+ });
11450
11450
  const SalesChannel = () => {
11451
11451
  const { id } = useParams();
11452
11452
  const { draft_order, isPending, isError, error } = useDraftOrder(
@@ -13059,10 +13059,6 @@ const routeModule = {
13059
13059
  handle,
13060
13060
  loader,
13061
13061
  children: [
13062
- {
13063
- Component: CustomItems,
13064
- path: "/draft-orders/:id/custom-items"
13065
- },
13066
13062
  {
13067
13063
  Component: BillingAddress,
13068
13064
  path: "/draft-orders/:id/billing-address"
@@ -13071,6 +13067,14 @@ const routeModule = {
13071
13067
  Component: Email,
13072
13068
  path: "/draft-orders/:id/email"
13073
13069
  },
13070
+ {
13071
+ Component: CustomItems,
13072
+ path: "/draft-orders/:id/custom-items"
13073
+ },
13074
+ {
13075
+ Component: Promotions,
13076
+ path: "/draft-orders/:id/promotions"
13077
+ },
13074
13078
  {
13075
13079
  Component: Metadata,
13076
13080
  path: "/draft-orders/:id/metadata"
@@ -13079,10 +13083,6 @@ const routeModule = {
13079
13083
  Component: Items,
13080
13084
  path: "/draft-orders/:id/items"
13081
13085
  },
13082
- {
13083
- Component: Promotions,
13084
- path: "/draft-orders/:id/promotions"
13085
- },
13086
13086
  {
13087
13087
  Component: SalesChannel,
13088
13088
  path: "/draft-orders/:id/sales-channel"