From 284578a67a08f15a8fe59258c1ac45b83bc4c24f Mon Sep 17 00:00:00 2001 From: Philip Korsholm <88927411+pKorsholm@users.noreply.github.com> Date: Fri, 24 Mar 2023 15:11:40 +0100 Subject: [PATCH] Fix(admin-ui): multi warehouse minor fixes (#3540) **What** 1. Enable the "create location" button in "create stock location" when a field has changed 2. Remove the "successful delete" toast when cancelling stock location creation 3. Properly update available and reserved when editing stock levels for variant 4. invalidate inventoryItemList queryKeys when changing location levels **Why** - we had the same bug with form validation when creating location levels as we had when editing them (1) - when updating location levels, listing inventory items wouldn't show the newly added location levels (4) - fixing ui bugs (2, 4) --- .../variant-form/variant-stock-form/index.tsx | 22 +++++----- .../variant-stock-form/index.tsx | 27 +++++++++--- .../components/organisms/delete-prompt.tsx | 2 +- .../edit-variant-inventory-modal.tsx | 43 ++++++++++++------- .../domain/inventory/locations/new/index.tsx | 11 +++-- 5 files changed, 68 insertions(+), 37 deletions(-) diff --git a/packages/admin-ui/ui/src/components/forms/product/variant-form/variant-stock-form/index.tsx b/packages/admin-ui/ui/src/components/forms/product/variant-form/variant-stock-form/index.tsx index 86b18e8981..af88ce589c 100644 --- a/packages/admin-ui/ui/src/components/forms/product/variant-form/variant-stock-form/index.tsx +++ b/packages/admin-ui/ui/src/components/forms/product/variant-form/variant-stock-form/index.tsx @@ -1,23 +1,25 @@ -import { InventoryLevelDTO, StockLocationDTO } from "@medusajs/medusa" import { Controller, useFieldArray } from "react-hook-form" +import { InventoryLevelDTO, StockLocationDTO } from "@medusajs/types" -import clsx from "clsx" -import { sum } from "lodash" -import { useAdminStockLocations } from "medusa-react" -import React from "react" -import { useFeatureFlag } from "../../../../../providers/feature-flag-provider" -import { NestedForm } from "../../../../../utils/nested-form" -import Switch from "../../../../atoms/switch" +import BuildingsIcon from "../../../../fundamentals/icons/buildings-icon" import Button from "../../../../fundamentals/button" import FeatureToggle from "../../../../fundamentals/feature-toggle" import IconBadge from "../../../../fundamentals/icon-badge" -import BuildingsIcon from "../../../../fundamentals/icons/buildings-icon" import InputField from "../../../../molecules/input" import { LayeredModalContext } from "../../../../molecules/modal/layered-modal" import { ManageLocationsScreen } from "../../variant-inventory-form/variant-stock-form" +import { NestedForm } from "../../../../../utils/nested-form" +import React from "react" +import Switch from "../../../../atoms/switch" +import clsx from "clsx" +import { sum } from "lodash" +import { useAdminStockLocations } from "medusa-react" +import { useFeatureFlag } from "../../../../../providers/feature-flag-provider" +// import { InventoryLevelDTO, StockLocationDTO } from "@medusajs/medusa" + export type VariantStockFormType = { - manage_inventory: boolean + manage_inventory?: boolean allow_backorder: boolean inventory_quantity: number | null sku: string | null diff --git a/packages/admin-ui/ui/src/components/forms/product/variant-inventory-form/variant-stock-form/index.tsx b/packages/admin-ui/ui/src/components/forms/product/variant-inventory-form/variant-stock-form/index.tsx index 441d9930f1..e5b1692bc8 100644 --- a/packages/admin-ui/ui/src/components/forms/product/variant-inventory-form/variant-stock-form/index.tsx +++ b/packages/admin-ui/ui/src/components/forms/product/variant-inventory-form/variant-stock-form/index.tsx @@ -37,6 +37,13 @@ const VariantStockForm = ({ form, locationLevels }: Props) => { const { stock_locations: locations, isLoading } = useAdminStockLocations() + const locationsMap = useMemo(() => { + if (isLoading) { + return new Map() + } + + return new Map(locations.map((l) => [l.id, l])) + }, [locations, isLoading]) const { path, control, register, watch } = form const manageInventory = watch(path("manage_inventory")) @@ -50,6 +57,12 @@ const VariantStockForm = ({ form, locationLevels }: Props) => { name: path("location_levels"), }) + const selectedLocationLevels = watch(path("location_levels")) + + const levelMap = new Map( + selectedLocationLevels?.map((l) => [l.location_id, l]) + ) + const handleUpdateLocations = async (data: { added: string[] removed: string[] @@ -142,10 +155,8 @@ const VariantStockForm = ({ form, locationLevels }: Props) => {
In Stock
{selectedLocations.map((level, i) => { - console.log(level) - const locationDetails = locations.find( - (l: StockLocationDTO) => l.id === level.location_id - ) + const locationDetails = locationsMap.get(level.location_id) + const locationLevel = levelMap.get(level.location_id) return (
@@ -158,15 +169,17 @@ const VariantStockForm = ({ form, locationLevels }: Props) => {
- {`${level.reserved_quantity} reserved`} + {`${locationLevel!.reserved_quantity} reserved`} {`${ - level.stocked_quantity - level.reserved_quantity + locationLevel!.stocked_quantity! - + locationLevel!.reserved_quantity! } available`}
{ ManageLocationsScreen( layeredModalContext.pop, selectedLocations, - locations, + locations || [], handleUpdateLocations ) ) diff --git a/packages/admin-ui/ui/src/components/organisms/delete-prompt.tsx b/packages/admin-ui/ui/src/components/organisms/delete-prompt.tsx index f743e3824c..9f42184d82 100644 --- a/packages/admin-ui/ui/src/components/organisms/delete-prompt.tsx +++ b/packages/admin-ui/ui/src/components/organisms/delete-prompt.tsx @@ -8,7 +8,7 @@ import useNotification from "../../hooks/use-notification" type DeletePromptProps = { heading?: string text?: string - successText?: string + successText?: string | false cancelText?: string confirmText?: string handleClose: () => void diff --git a/packages/admin-ui/ui/src/components/organisms/product-variants-section/edit-variant-inventory-modal.tsx b/packages/admin-ui/ui/src/components/organisms/product-variants-section/edit-variant-inventory-modal.tsx index a9f83f3e4c..bbdd4250f0 100644 --- a/packages/admin-ui/ui/src/components/organisms/product-variants-section/edit-variant-inventory-modal.tsx +++ b/packages/admin-ui/ui/src/components/organisms/product-variants-section/edit-variant-inventory-modal.tsx @@ -1,23 +1,25 @@ -import { - InventoryLevelDTO, - Product, - ProductVariant, - VariantInventory, -} from "@medusajs/medusa" -import { useAdminVariantsInventory, useMedusa } from "medusa-react" -import { useContext } from "react" -import { useForm } from "react-hook-form" -import useEditProductActions from "../../../hooks/use-edit-product-actions" -import { removeNullish } from "../../../utils/remove-nullish" import EditFlowVariantForm, { EditFlowVariantFormType, } from "../../forms/product/variant-form/edit-flow-variant-form" -import Button from "../../fundamentals/button" -import Modal from "../../molecules/modal" import LayeredModal, { LayeredModalContext, } from "../../molecules/modal/layered-modal" +import { Product, ProductVariant, VariantInventory } from "@medusajs/medusa" +import { + adminInventoryItemsKeys, + useAdminVariantsInventory, + useMedusa, +} from "medusa-react" + +import Button from "../../fundamentals/button" +import { InventoryLevelDTO } from "@medusajs/types" +import Modal from "../../molecules/modal" import { createUpdatePayload } from "./edit-variants-modal/edit-variant-screen" +import { queryClient } from "../../../constants/query-client" +import { removeNullish } from "../../../utils/remove-nullish" +import { useContext } from "react" +import useEditProductActions from "../../../hooks/use-edit-product-actions" +import { useForm } from "react-hook-form" type Props = { onClose: () => void @@ -46,14 +48,15 @@ const EditVariantInventoryModal = ({ onClose, product, variant }: Props) => { const { onUpdateVariant, updatingVariant } = useEditProductActions(product.id) const onSubmit = async (data: EditFlowVariantFormType) => { - const locationLevels = data.stock.location_levels || [] + const locationLevels = data.stock.stock_location || [] const manageInventory = data.stock.manage_inventory delete data.stock.manage_inventory - delete data.stock.location_levels + delete data.stock.stock_location let inventoryItemId: string | undefined = itemId const upsertPayload = removeNullish(data.stock) + let shouldInvalidateCache = false if (variantInventoryItem) { // variant inventory exists and we can remove location levels @@ -77,12 +80,16 @@ const EditVariantInventoryModal = ({ onClose, product, variant }: Props) => { ) }) ) + if (deleteLocations.length) { + shouldInvalidateCache = true + } } if (!manageInventory) { // has an inventory item but no longer wants to manage inventory await client.admin.inventoryItems.delete(itemId!) inventoryItemId = undefined + shouldInvalidateCache = true } else { // has an inventory item and wants to update inventory await client.admin.inventoryItems.update(itemId!, upsertPayload) @@ -122,11 +129,17 @@ const EditVariantInventoryModal = ({ onClose, product, variant }: Props) => { } }) ) + if (locationLevels.length) { + shouldInvalidateCache = true + } } // @ts-ignore onUpdateVariant(variant.id, createUpdatePayload(data), () => { refetch() + if (shouldInvalidateCache) { + queryClient.invalidateQueries(adminInventoryItemsKeys.lists()) + } handleClose() }) } diff --git a/packages/admin-ui/ui/src/domain/inventory/locations/new/index.tsx b/packages/admin-ui/ui/src/domain/inventory/locations/new/index.tsx index 2c89f9ae7a..771fb500d7 100644 --- a/packages/admin-ui/ui/src/domain/inventory/locations/new/index.tsx +++ b/packages/admin-ui/ui/src/domain/inventory/locations/new/index.tsx @@ -47,7 +47,7 @@ const NewLocation = ({ onClose }: { onClose: () => void }) => { }) const { handleSubmit, - formState: { isDirty, isValid }, + formState: { isDirty }, } = form const { @@ -63,7 +63,10 @@ const NewLocation = ({ onClose }: { onClose: () => void }) => { const { mutateAsync: associateSalesChannel } = useAdminAddLocationToSalesChannel() - const createSalesChannelAssociationPromise = (salesChannelId, locationId) => + const createSalesChannelAssociationPromise = ( + salesChannelId: string, + locationId: string + ) => associateSalesChannel({ sales_channel_id: salesChannelId, location_id: locationId, @@ -126,7 +129,7 @@ const NewLocation = ({ onClose }: { onClose: () => void }) => { heading="Are you sure you want to cancel with unsaved changes" confirmText="Yes, cancel" cancelText="No, continue creating" - successText={undefined} + successText={false} handleClose={closeClosePrompt} onDelete={async () => onClose()} /> @@ -136,7 +139,7 @@ const NewLocation = ({ onClose }: { onClose: () => void }) => { size="small" variant="primary" type="button" - disabled={!isDirty || !isValid} + disabled={!isDirty} onClick={onSubmit()} > Add location