import { useTranslation } from "react-i18next" import EditFlowVariantForm, { EditFlowVariantFormType, } from "../../forms/product/variant-inventory-form/edit-flow-variant-form" 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 { Option } from "../../../types/shared" import { countries } from "../../../utils/countries" import { queryClient } from "../../../constants/query-client" import { removeFalsy, 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 product: Product variant: ProductVariant isDuplicate?: boolean } const EditVariantInventoryModal = ({ onClose, product, variant }: Props) => { const { t } = useTranslation() const { client } = useMedusa() const layeredModalContext = useContext(LayeredModalContext) const { // @ts-ignore variant: variantInventory, isLoading: isLoadingInventory, refetch, } = useAdminVariantsInventory(variant.id) const handleClose = () => { onClose() } const { onUpdateVariant, updatingVariant } = useEditProductActions(product.id) const createUpdateInventoryItemPayload = ( data: Partial ) => { const updateDimensions = data.dimensions || {} const updateCustoms = data.customs || {} const originCountry = data.customs?.origin_country?.value delete data.dimensions delete data.customs delete data.ean delete data.barcode delete data.upc delete data.allow_backorder return removeFalsy({ ...updateDimensions, ...updateCustoms, ...data, ...(originCountry && { origin_country: originCountry }), }) } const onSubmit = async (data: EditFlowVariantFormType) => { const locationLevels = data.location_levels || [] const manageInventory = data.manage_inventory const variantInventoryItem = variantInventory?.inventory?.[0] const itemId = variantInventoryItem?.id delete data.manage_inventory delete data.location_levels let inventoryItemId: string | undefined = itemId const { ean, barcode, upc, allow_backorder } = data const upsertPayload = createUpdateInventoryItemPayload(data) let shouldInvalidateCache = false if (variantInventoryItem) { // variant inventory exists and we can remove location levels // (it's important to do this before potentially deleting the inventory item) const deleteLocations = manageInventory ? variantInventoryItem?.location_levels?.filter( (itemLevel: InventoryLevelDTO) => { return !locationLevels.find( (level) => level.location_id === itemLevel.location_id ) } ) ?? [] : [] if (inventoryItemId) { await Promise.all( deleteLocations.map(async (location: InventoryLevelDTO) => { await client.admin.inventoryItems.deleteLocationLevel( inventoryItemId!, location.location_id ) }) ) 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) } } else if (manageInventory) { await client.admin.products.updateVariant(product.id, variant.id, { manage_inventory: true, }) // does not have an inventory item but wants to manage inventory const { inventory_item } = await client.admin.inventoryItems.create({ variant_id: variant.id, ...upsertPayload, }) inventoryItemId = inventory_item.id } // If some inventory Item exists update location levels if (inventoryItemId) { await Promise.all( locationLevels.map(async (level) => { if (!level.location_id) { return } if (level.id) { await client.admin.inventoryItems.updateLocationLevel( inventoryItemId!, level.location_id, { stocked_quantity: level.stocked_quantity, } ) } else { await client.admin.inventoryItems.createLocationLevel( inventoryItemId!, { location_id: level.location_id, stocked_quantity: level.stocked_quantity!, } ) } }) ) if (locationLevels.length) { shouldInvalidateCache = true } } const { dimensions, customs, ...stock } = data // @ts-ignore onUpdateVariant( variant.id, { ...removeNullish({ ...dimensions, ...customs, ...stock, ean, barcode, upc, allow_backorder, }), }, () => { refetch() if (shouldInvalidateCache) { queryClient.invalidateQueries(adminInventoryItemsKeys.lists()) } handleClose() } ) } return (

{t( "product-variants-section-edit-stock-inventory", "Edit stock & inventory" )}

{!isLoadingInventory && ( )}
) } const StockForm = ({ variantInventory, onSubmit, isLoadingInventory, handleClose, updatingVariant, variant, }: { variantInventory: VariantInventory variant: ProductVariant onSubmit: (data: EditFlowVariantFormType) => void isLoadingInventory: boolean handleClose: () => void updatingVariant: boolean }) => { const { t } = useTranslation() const form = useForm({ // @ts-ignore defaultValues: getEditVariantDefaultValues(variantInventory, variant), }) const { formState: { isDirty }, handleSubmit, reset, } = form const locationLevels = variantInventory.inventory[0]?.location_levels || [] const handleOnSubmit = handleSubmit((data) => { onSubmit(data) }) return (
) } export const getEditVariantDefaultValues = ( variantInventory?: any, variant?: ProductVariant ): EditFlowVariantFormType => { const inventoryItem = variantInventory?.inventory[0] if (!inventoryItem) { return { sku: null, ean: variant?.ean || null, barcode: variant?.barcode || null, upc: variant?.upc || null, inventory_quantity: null, manage_inventory: false, allow_backorder: variant?.allow_backorder ?? false, location_levels: null, dimensions: { height: null, length: null, width: null, weight: null, }, customs: { origin_country: null, mid_code: null, hs_code: null, }, } } let originCountry: Option | null = null if (inventoryItem.origin_country) { const country = countries.find( (c) => c.alpha2 === inventoryItem.origin_country || c.alpha3 === inventoryItem.origin_country ) if (country) { originCountry = { label: country?.name, value: country?.alpha2, } } } return { sku: inventoryItem.sku, ean: variant?.ean || null, barcode: variant?.barcode || null, upc: variant?.upc || null, inventory_quantity: inventoryItem.inventory_quantity, manage_inventory: !!inventoryItem, allow_backorder: !!variant?.allow_backorder, location_levels: inventoryItem.location_levels, dimensions: { height: inventoryItem.height, length: inventoryItem.length, width: inventoryItem.width, weight: inventoryItem.weight, }, customs: { origin_country: originCountry, mid_code: inventoryItem.mid_code, hs_code: inventoryItem.hs_code, }, } } export default EditVariantInventoryModal