import { Controller, useForm, useWatch } from "react-hook-form" import { NestedForm, nestedForm } from "../../../../utils/nested-form" import React, { useEffect, useMemo } from "react" import { useAdminCreateReservation, useAdminStockLocations, useAdminVariantsInventory, useMedusa, } from "medusa-react" import { useTranslation } from "react-i18next" import Button from "../../../../components/fundamentals/button" import CrossIcon from "../../../../components/fundamentals/icons/cross-icon" import FocusModal from "../../../../components/molecules/modal/focus-modal" import InputField from "../../../../components/molecules/input" import { LineItem } from "@medusajs/medusa" import { ReservationItemDTO } from "@medusajs/types" import Select from "../../../../components/molecules/select/next-select/select" import Thumbnail from "../../../../components/atoms/thumbnail" import clsx from "clsx" import { getErrorMessage } from "../../../../utils/error-messages" import { getFulfillableQuantity } from "../create-fulfillment/item-table" import { sum } from "lodash" import useNotification from "../../../../hooks/use-notification" type ReserveModalFormData = { location?: { label: string; value: string } items: ReserveLineItemForm[] } type ReserveItemsModalProps = { items: LineItem[] reservationItemsMap: Record close: () => void } const ReserveItemsModal: React.FC = ({ items, close, reservationItemsMap, }) => { const { t } = useTranslation() const { mutateAsync: createReservation } = useAdminCreateReservation() const { client: medusaClient } = useMedusa() const notification = useNotification() const form = useForm({ defaultValues: { items: [], }, }) const { handleSubmit, control } = form const selectedLocation = useWatch({ control, name: "location" }) const { stock_locations, isLoading } = useAdminStockLocations() const locationOptions = useMemo(() => { if (!stock_locations) { return [] } return stock_locations.map((sl) => ({ value: sl.id, label: sl.name, })) }, [stock_locations]) const onSubmit = async (data: ReserveModalFormData) => { if (!data.location?.value) { return } const results: { result?: ReservationItemDTO; error?: Error }[] = await Promise.all( data.items.map(async (item) => { if (!item.quantity) { return {} } return await createReservation({ quantity: item.quantity, line_item_id: item.line_item_id, inventory_item_id: item.inventory_item_id, location_id: data.location!.value, }) .then((result) => ({ result })) .catch((error: Error) => ({ error })) }) ) if (results.some((r) => r.error)) { await Promise.all( results.map(async ({ result }) => { if (result) { await medusaClient.admin.reservations.delete(result.id) } }) ) const error = results .filter(({ error }) => !!error) .map(({ error }) => getErrorMessage(error)) .join(", ") notification( t("reservation-couldnt-allocate-items", "Couldn't allocate items"), error, "error" ) } else { notification( t("reservation-items-allocated", "Items allocated"), t( "reservation-items-have-been-allocated-successfully", "Items have been allocated successfully" ), "success" ) close() } } return (
{isLoading || !stock_locations ? (
{t("reservation-loading", "Loading...")}
) : (

{t("reservation-allocate-order-items", "Allocate order items")}

{t("reservation-location", "Location")}

{t( "reservation-choose-where-you-wish-to-allocate-from", "Choose where you wish to allocate from" )}

(