import { Controller, useForm, useWatch } from "react-hook-form" import { InventoryLevelDTO, ReservationItemDTO, StockLocationDTO, } from "@medusajs/types" import MetadataForm, { getMetadataFormValues, getSubmittableMetadata, MetadataFormType, } from "../../../../components/forms/general/metadata-form" import { useAdminDeleteReservation, useAdminInventoryItem, useAdminStockLocations, useAdminUpdateReservation, } from "medusa-react" import { useEffect, useMemo } from "react" import { useTranslation } from "react-i18next" import Button from "../../../../components/fundamentals/button" import CrossIcon from "../../../../components/fundamentals/icons/cross-icon" import InputField from "../../../../components/molecules/input" import { LineItem } from "@medusajs/medusa" import { ReserveLineItemForm } from "./reserve-items-modal" import Select from "../../../../components/molecules/select/next-select/select" import SideModal from "../../../../components/molecules/modal/side-modal" import Thumbnail from "../../../../components/atoms/thumbnail" import { getFulfillableQuantity } from "../create-fulfillment/item-table" import { nestedForm } from "../../../../utils/nested-form" import useNotification from "../../../../hooks/use-notification" import useToggleState from "../../../../hooks/use-toggle-state" type EditReservationLineItemForm = { location: { label: string; value: string } item: ReserveLineItemForm metadata: MetadataFormType } const EditReservationDrawer = ({ close, reservation, item, totalReservedQuantity = 0, }: { close: () => void reservation: ReservationItemDTO item?: LineItem totalReservedQuantity?: number }) => { const { t } = useTranslation() const form = useForm({ defaultValues: { item: { description: reservation.description, }, metadata: getMetadataFormValues(reservation?.metadata), }, }) const { state: hasMetadata, toggle: toggleHasMetadata } = useToggleState( !!reservation.metadata ) const { control, setValue, handleSubmit, register } = form const { stock_locations, isLoading: isLoadingStockLocations } = useAdminStockLocations() const { inventory_item, isLoading } = useAdminInventoryItem( reservation.inventory_item_id ) const { mutate: updateReservation } = useAdminUpdateReservation( reservation?.id || "" ) const { mutate: deleteReservation } = useAdminDeleteReservation( reservation?.id || "" ) const locationOptions = useMemo(() => { if (!stock_locations || isLoadingStockLocations) { return [] } return stock_locations.map((sl: StockLocationDTO) => ({ value: sl.id, label: sl.name, })) }, [isLoadingStockLocations, stock_locations]) const notification = useNotification() const handleDelete = () => { deleteReservation(undefined, { onSuccess: () => { notification( t("reservation-reservation-was-deleted", "Reservation was deleted"), t( "reservation-the-allocated-items-have-been-released", "The allocated items have been released." ), "success" ) close() }, onError: () => { notification( t("reservation-error", "Error"), t( "reservation-failed-to-delete-the-reservation", "Failed to delete the reservation " ), "error" ) }, }) } const selectedLocation = useWatch({ control, name: "location", }) useEffect(() => { if (stock_locations?.length && reservation) { const defaultLocation = stock_locations.find( (sl: StockLocationDTO) => sl.id === reservation.location_id ) if (defaultLocation) { setValue("location", { value: defaultLocation?.id, label: defaultLocation?.name, }) } } }, [stock_locations, reservation, setValue]) useEffect(() => { if (reservation) { setValue("item.quantity", reservation?.quantity) } }, [reservation, setValue]) const submit = (data: EditReservationLineItemForm) => { if (!data.item.quantity) { return handleDelete() } updateReservation( { quantity: data.item.quantity, location_id: data.location.value, description: data.item.description, metadata: hasMetadata ? getSubmittableMetadata(data.metadata) : undefined, }, { onSuccess: () => { notification( t("reservation-reservation-was-updated", "Reservation was updated"), t( "reservation-the-reservation-change-was-saved", "The reservation change was saved." ), "success" ) close() }, onError: () => { notification( t("reservation-errors", "Errors"), t( "reservation-failed-to-update-reservation", "Failed to update reservation" ), "error" ) }, } ) } const { availableQuantity, inStockQuantity } = useMemo(() => { if (isLoading || !selectedLocation?.value || !inventory_item) { return {} } const locationInventory = inventory_item.location_levels?.find( (inv: InventoryLevelDTO) => inv.location_id === selectedLocation?.value ) if (!locationInventory) { return {} } return { availableQuantity: locationInventory.available_quantity, inStockQuantity: locationInventory.stocked_quantity, } }, [isLoading, selectedLocation?.value, inventory_item]) const maxReservation = useMemo(() => { if (!item) { return typeof availableQuantity === "number" ? availableQuantity + reservation.quantity : reservation.quantity } const lineItemReservationCapacity = getFulfillableQuantity(item) - (totalReservedQuantity - (reservation?.quantity || 0)) const inventoryItemReservationCapacity = typeof availableQuantity === "number" ? availableQuantity : 0 return Math.min( lineItemReservationCapacity, inventoryItemReservationCapacity ) }, [availableQuantity, item, reservation?.quantity, totalReservedQuantity]) const closeModal = (e) => { e.preventDefault() close() } return (

{t("reservation-edit-reservation", "Edit Reservation")}

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

{t( "reservation-choose-which-location-you-want-to-ship-the-items-from", "Choose which location you want to ship the items from." )} ( {maxReservation ? t( "reservation-max-reservation-requested", " / {{maxReservation}} requested", { maxReservation, } ) : t("reservation-reserved", " reserved")}

{t("reservation-description", "Description")}

{t( "reservation-what-type-of-reservation-is-this", "What type of reservation is this?" )}

{t("reservation-metadata", "Metadata")}

{hasMetadata && ( )}
) } export default EditReservationDrawer