import * as zod from "zod"
import { Button, Heading, Text, Textarea, toast } from "@medusajs/ui"
import {
RouteFocusModal,
useRouteModal,
} from "../../../../../components/modals"
import { zodResolver } from "@hookform/resolvers/zod"
import { HttpTypes } from "@medusajs/types"
import { useForm } from "react-hook-form"
import { useTranslation } from "react-i18next"
import { Form } from "../../../../../components/common/form"
import { Combobox } from "../../../../../components/inputs/combobox"
import { QuantityInput } from "../../../../../components/inputs/quantity-input"
import { KeyboundForm } from "../../../../../components/utilities/keybound-form"
import { useComboboxData } from "../../../../../hooks/use-combobox-data"
import { sdk } from "../../../../../lib/client"
import { formatQuantity } from "../../../../../lib/format-quantity"
import { useCreateReservationItem } from "../../../../../hooks/api/reservations"
import { useStockLocations } from "../../../../../hooks/api/stock-locations"
import { inventoryItemsQueryKeys } from "../../../../../hooks/api/inventory"
export const CreateReservationSchema = zod.object({
inventory_item_id: zod.string().min(1),
location_id: zod.string().min(1),
quantity: zod.number().positive(),
description: zod.string().optional(),
})
const AttributeGridRow = ({
title,
value,
}: {
title: string
value: string | number
}) => {
return (
{title}
{value}
)
}
export const ReservationCreateForm = (props: { inventoryItemId?: string }) => {
const { t } = useTranslation()
const { handleSuccess } = useRouteModal()
const form = useForm>({
defaultValues: {
inventory_item_id: props.inventoryItemId || "",
location_id: "",
quantity: 0,
description: "",
},
resolver: zodResolver(CreateReservationSchema),
})
const inventoryItemId = form.watch("inventory_item_id")
const inventoryItems = useComboboxData({
queryKey: inventoryItemsQueryKeys.list(),
queryFn: (params) => sdk.admin.inventoryItem.list(params),
getOptions: (data) =>
data.inventory_items.map((inventoryItem) => ({
label: inventoryItem.title ?? inventoryItem.sku!,
value: inventoryItem.id,
inventoryItem,
})),
defaultValueKey: "id",
defaultValue: props.inventoryItemId,
selectedValue: inventoryItemId,
})
const selectedInventoryItem = inventoryItems.options.find(
(option) => option.value === inventoryItemId
)?.inventoryItem as
| HttpTypes.AdminInventoryItemResponse["inventory_item"]
| undefined
const locationId = form.watch("location_id")
const selectedLocationLevel = selectedInventoryItem?.location_levels?.find(
(it) => it.location_id === locationId
)
const quantity = form.watch("quantity")
const { stock_locations } = useStockLocations(
{
id:
selectedInventoryItem?.location_levels?.map(
(level: HttpTypes.AdminInventoryLevel) => level.location_id
) ?? [],
},
{
enabled: !!selectedInventoryItem,
}
)
const { mutateAsync, isPending } = useCreateReservationItem()
const handleSubmit = form.handleSubmit(async (data) => {
const max = selectedLocationLevel?.available_quantity
? selectedLocationLevel.available_quantity
: 0
if (!selectedLocationLevel?.available_quantity) {
form.setError("quantity", {
type: "manual",
message: t("inventory.reservation.errors.noAvaliableQuantity"),
})
return
}
if (data.quantity > max) {
form.setError("quantity", {
type: "manual",
message: t("inventory.reservation.errors.quantityOutOfRange", {
max: max,
}),
})
return
}
await mutateAsync(data, {
onSuccess: ({ reservation }) => {
toast.success(t("inventory.reservation.successToast"))
handleSuccess(
props.inventoryItemId
? `/inventory/${props.inventoryItemId}`
: `/reservations/${reservation.id}`
)
},
onError: (e) => {
toast.error(e.message)
},
})
})
return (
{t("inventory.reservation.create")}
{
return (
{t("inventory.reservation.itemToReserve")}
{
onChange(v)
}}
{...field}
disabled={!!props.inventoryItemId}
options={inventoryItems.options}
searchValue={inventoryItems.searchValue}
onSearchValueChange={
inventoryItems.onSearchValueChange
}
fetchNextPage={inventoryItems.fetchNextPage}
/>
)
}}
/>
{
return (
{t("fields.location")}
{
onChange(v)
}}
{...field}
disabled={!inventoryItemId}
options={(stock_locations ?? []).map(
(stockLocation) => ({
label: stockLocation.name,
value: stockLocation.id,
})
)}
/>
)
}}
/>
{
return (
{t("fields.quantity")}
{
const value = e.target.value
if (value === "") {
onChange(null)
} else {
onChange(parseFloat(value))
}
}}
{...field}
disabled={!inventoryItemId || !locationId}
/>
)
}}
/>
{
return (
{t("fields.description")}
)
}}
/>
)
}