import * as zod from "zod" import { Button, Heading, Input, Text, Textarea, toast } from "@medusajs/ui" import { RouteFocusModal, useRouteModal, } from "../../../../../components/modals" import { zodResolver } from "@hookform/resolvers/zod" import { HttpTypes } from "@medusajs/types" import React from "react" import { useForm } from "react-hook-form" import { useTranslation } from "react-i18next" import { Form } from "../../../../../components/common/form" import { Combobox } from "../../../../../components/inputs/combobox" import { KeyboundForm } from "../../../../../components/utilities/keybound-form" import { useInventoryItems } from "../../../../../hooks/api/inventory" import { useCreateReservationItem } from "../../../../../hooks/api/reservations" import { useStockLocations } from "../../../../../hooks/api/stock-locations" export const CreateReservationSchema = zod.object({ inventory_item_id: zod.string().min(1), location_id: zod.string().min(1), quantity: zod.number().min(1), 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 [inventorySearch, setInventorySearch] = React.useState( null ) const form = useForm>({ defaultValues: { inventory_item_id: props.inventoryItemId || "", location_id: "", quantity: 0, description: "", }, resolver: zodResolver(CreateReservationSchema), }) const { inventory_items } = useInventoryItems({ q: inventorySearch ?? undefined, }) const inventoryItemId = form.watch("inventory_item_id") const selectedInventoryItem = inventory_items?.find( (it) => it.id === inventoryItemId ) 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 min = 1 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 < min || 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")} setInventorySearch(value) } value={value} onChange={(v) => { onChange(v) }} {...field} disabled={!!props.inventoryItemId} options={(inventory_items ?? []).map( (inventoryItem) => ({ label: inventoryItem.title ?? inventoryItem.sku!, value: inventoryItem.id, }) )} /> ) }} /> { 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")}