diff --git a/.changeset/cuddly-news-battle.md b/.changeset/cuddly-news-battle.md new file mode 100644 index 0000000000000..8bbb0f786b255 --- /dev/null +++ b/.changeset/cuddly-news-battle.md @@ -0,0 +1,5 @@ +--- +"@medusajs/dashboard": patch +--- + +fix(dashboard): Fix broken number input in adjust inventory form diff --git a/packages/admin/dashboard/src/i18n/translations/$schema.json b/packages/admin/dashboard/src/i18n/translations/$schema.json index 53a017191a54f..b4c6e4c51dc7a 100644 --- a/packages/admin/dashboard/src/i18n/translations/$schema.json +++ b/packages/admin/dashboard/src/i18n/translations/$schema.json @@ -3267,6 +3267,27 @@ ], "additionalProperties": false }, + "adjustInventory": { + "type": "object", + "properties": { + "errors": { + "type": "object", + "properties": { + "stockedQuantity": { + "type": "string" + } + }, + "required": [ + "stockedQuantity" + ], + "additionalProperties": false + } + }, + "required": [ + "errors" + ], + "additionalProperties": false + }, "toast": { "type": "object", "properties": { @@ -3300,6 +3321,7 @@ "editItemDetails", "create", "reservation", + "adjustInventory", "toast" ], "additionalProperties": false diff --git a/packages/admin/dashboard/src/i18n/translations/en.json b/packages/admin/dashboard/src/i18n/translations/en.json index 3648ef378d9cd..feaf8f03810b0 100644 --- a/packages/admin/dashboard/src/i18n/translations/en.json +++ b/packages/admin/dashboard/src/i18n/translations/en.json @@ -790,6 +790,11 @@ "quantityOutOfRange": "Minimum quantity is 1 and maximum quantity is {{max}}" } }, + "adjustInventory": { + "errors": { + "stockedQuantity": "Stocked quantity cannot be updated to less than the reserved quantity of {{quantity}}." + } + }, "toast": { "updateLocations": "Locations updated successfully.", "updateLevel": "Inventory level updated successfully.", diff --git a/packages/admin/dashboard/src/routes/inventory/inventory-detail/components/adjust-inventory/components/adjust-inventory-form.tsx b/packages/admin/dashboard/src/routes/inventory/inventory-detail/components/adjust-inventory/components/adjust-inventory-form.tsx index b2c5c3602dc5d..3bb6d4a8c6b14 100644 --- a/packages/admin/dashboard/src/routes/inventory/inventory-detail/components/adjust-inventory/components/adjust-inventory-form.tsx +++ b/packages/admin/dashboard/src/routes/inventory/inventory-detail/components/adjust-inventory/components/adjust-inventory-form.tsx @@ -1,15 +1,15 @@ import { zodResolver } from "@hookform/resolvers/zod" -import * as zod from "zod" - import { HttpTypes, InventoryLevelDTO, StockLocationDTO } from "@medusajs/types" import { Button, Input, Text, toast } from "@medusajs/ui" -import { RouteDrawer, useRouteModal } from "../../../../../../components/modals" - -import { useForm } from "react-hook-form" +import { useForm, useWatch } from "react-hook-form" import { useTranslation } from "react-i18next" +import { z } from "zod" + import { Form } from "../../../../../../components/common/form" +import { RouteDrawer, useRouteModal } from "../../../../../../components/modals" import { KeyboundForm } from "../../../../../../components/utilities/keybound-form" import { useUpdateInventoryLevel } from "../../../../../../hooks/api/inventory" +import { castNumber } from "../../../../../../lib/cast-number" type AdjustInventoryFormProps = { item: HttpTypes.AdminInventoryItem @@ -44,18 +44,52 @@ export const AdjustInventoryForm = ({ const { t } = useTranslation() const { handleSuccess } = useRouteModal() - const AdjustInventorySchema = zod.object({ - stocked_quantity: zod.number().min(level.reserved_quantity), - }) + const AdjustInventorySchema = z + .object({ + stocked_quantity: z.union([z.number(), z.string()]), + }) + .superRefine((data, ctx) => { + const quantity = data.stocked_quantity + ? castNumber(data.stocked_quantity) + : null - const form = useForm>({ + if (quantity === null) { + ctx.addIssue({ + code: z.ZodIssueCode.invalid_type, + expected: "number", + received: "undefined", + path: ["stocked_quantity"], + }) + + return + } + + if (quantity < level.reserved_quantity) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: t("inventory.adjustInventory.errors.stockedQuantity", { + quantity: level.reserved_quantity, + }), + path: ["stocked_quantity"], + }) + } + }) + + const form = useForm>({ defaultValues: { stocked_quantity: level.stocked_quantity, }, resolver: zodResolver(AdjustInventorySchema), }) - const stockedQuantityUpdate = form.watch("stocked_quantity") + const stockedQuantityUpdate = useWatch({ + control: form.control, + name: "stocked_quantity", + }) + + const availableQuantity = stockedQuantityUpdate + ? castNumber(stockedQuantityUpdate) - level.reserved_quantity + : 0 - level.reserved_quantity const { mutateAsync, isPending: isLoading } = useUpdateInventoryLevel( item.id, @@ -63,13 +97,9 @@ export const AdjustInventoryForm = ({ ) const handleSubmit = form.handleSubmit(async (value) => { - if (value.stocked_quantity === level.stocked_quantity) { - return handleSuccess() - } - await mutateAsync( { - stocked_quantity: value.stocked_quantity, + stocked_quantity: castNumber(value.stocked_quantity), }, { onSuccess: () => { @@ -106,7 +136,7 @@ export const AdjustInventoryForm = ({ /> { - const value = e.target.value - - if (value === "") { - onChange(null) - } else { - onChange(parseFloat(value)) - } - }} + value={value} + onChange={onChange} {...field} />