From a7e3f2d343c4059ba83022ec5c09f8101b251297 Mon Sep 17 00:00:00 2001
From: Philip Korsholm <88927411+pKorsholm@users.noreply.github.com>
Date: Wed, 29 Mar 2023 18:12:38 +0200
Subject: [PATCH] feat(admin-ui): move inventory item fields into manage
inventory modal (#3591)
---
.changeset/wise-colts-pretend.md | 5 +
.../edit-flow-variant-form/index.tsx | 18 +-
.../edit-flow-variant-form/index.tsx | 12 +-
.../variant-stock-form/index.tsx | 321 ++++++++++--------
.../edit-variant-inventory-modal.tsx | 137 ++++++--
5 files changed, 302 insertions(+), 191 deletions(-)
create mode 100644 .changeset/wise-colts-pretend.md
diff --git a/.changeset/wise-colts-pretend.md b/.changeset/wise-colts-pretend.md
new file mode 100644
index 0000000000..4e2cd4bf80
--- /dev/null
+++ b/.changeset/wise-colts-pretend.md
@@ -0,0 +1,5 @@
+---
+"@medusajs/medusa": minor
+---
+
+feat(admin-ui): move customs and shipping into manage inventory modal
diff --git a/packages/admin-ui/ui/src/components/forms/product/variant-form/edit-flow-variant-form/index.tsx b/packages/admin-ui/ui/src/components/forms/product/variant-form/edit-flow-variant-form/index.tsx
index 8aa506a148..cf609747e9 100644
--- a/packages/admin-ui/ui/src/components/forms/product/variant-form/edit-flow-variant-form/index.tsx
+++ b/packages/admin-ui/ui/src/components/forms/product/variant-form/edit-flow-variant-form/index.tsx
@@ -2,7 +2,7 @@ import { useFieldArray, UseFormReturn } from "react-hook-form"
import CustomsForm, { CustomsFormType } from "../../customs-form"
import DimensionsForm, { DimensionsFormType } from "../../dimensions-form"
import VariantGeneralForm, {
- VariantGeneralFormType
+ VariantGeneralFormType,
} from "../variant-general-form"
import VariantStockForm, { VariantStockFormType } from "../variant-stock-form"
@@ -115,13 +115,15 @@ const EditFlowVariantForm = ({ form, isEdit }: Props) => {
-
-
Customs
-
- Configure if you are shipping internationally.
-
-
-
+ {showStockAndInventory && (
+
+
Customs
+
+ Configure if you are shipping internationally.
+
+
+
+ )}
)
diff --git a/packages/admin-ui/ui/src/components/forms/product/variant-inventory-form/edit-flow-variant-form/index.tsx b/packages/admin-ui/ui/src/components/forms/product/variant-inventory-form/edit-flow-variant-form/index.tsx
index 2d7b4fe185..6b7ab49c75 100644
--- a/packages/admin-ui/ui/src/components/forms/product/variant-inventory-form/edit-flow-variant-form/index.tsx
+++ b/packages/admin-ui/ui/src/components/forms/product/variant-inventory-form/edit-flow-variant-form/index.tsx
@@ -1,11 +1,8 @@
-import { InventoryLevelDTO } from "@medusajs/medusa"
+import { InventoryLevelDTO } from "@medusajs/types"
import { UseFormReturn } from "react-hook-form"
-import { nestedForm } from "../../../../../utils/nested-form"
import VariantStockForm, { VariantStockFormType } from "../variant-stock-form"
-export type EditFlowVariantFormType = {
- stock: VariantStockFormType
-}
+export type EditFlowVariantFormType = VariantStockFormType
type Props = {
form: UseFormReturn
@@ -39,10 +36,7 @@ const EditFlowVariantForm = ({ form, isLoading, locationLevels }: Props) => {
return (
<>
-
+
>
)
}
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 66fd5da831..3ef8a712ef 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
@@ -1,15 +1,19 @@
-import { InventoryLevelDTO, StockLocationDTO } from "@medusajs/medusa"
-import { useAdminStockLocations } from "medusa-react"
+import { Controller, useFieldArray, UseFormReturn } from "react-hook-form"
+import { nestedForm } from "../../../../../utils/nested-form"
import React, { useMemo, useState } from "react"
-import { Controller, useFieldArray } from "react-hook-form"
-import { NestedForm } from "../../../../../utils/nested-form"
-import Switch from "../../../../atoms/switch"
-import Button from "../../../../fundamentals/button"
-import IconBadge from "../../../../fundamentals/icon-badge"
+
+import Accordion from "../../../../organisms/accordion"
import BuildingsIcon from "../../../../fundamentals/icons/buildings-icon"
+import Button from "../../../../fundamentals/button"
+import CustomsForm, { CustomsFormType } from "../../customs-form"
+import DimensionsForm, { DimensionsFormType } from "../../dimensions-form"
+import IconBadge from "../../../../fundamentals/icon-badge"
import InputField from "../../../../molecules/input"
import Modal from "../../../../molecules/modal"
+import Switch from "../../../../atoms/switch"
+import { useAdminStockLocations } from "medusa-react"
import { useLayeredModal } from "../../../../molecules/modal/layered-modal"
+import { InventoryLevelDTO, StockLocationDTO } from "@medusajs/types"
export type VariantStockFormType = {
manage_inventory?: boolean
@@ -20,11 +24,13 @@ export type VariantStockFormType = {
upc: string | null
barcode: string | null
location_levels?: Partial[] | null
+ dimensions: DimensionsFormType
+ customs: CustomsFormType
}
type Props = {
locationLevels: InventoryLevelDTO[]
- form: NestedForm
+ form: UseFormReturn
}
const VariantStockForm = ({ form, locationLevels }: Props) => {
@@ -44,9 +50,9 @@ const VariantStockForm = ({ form, locationLevels }: Props) => {
return new Map(locations.map((l) => [l.id, l]))
}, [locations, isLoading])
- const { path, control, register, watch } = form
+ const { control, register, watch } = form
- const manageInventory = watch(path("manage_inventory"))
+ const manageInventory = watch("manage_inventory")
const {
fields: selectedLocations,
@@ -54,10 +60,10 @@ const VariantStockForm = ({ form, locationLevels }: Props) => {
remove,
} = useFieldArray({
control,
- name: path("location_levels"),
+ name: "location_levels",
})
- const selectedLocationLevels = watch(path("location_levels"))
+ const selectedLocationLevels = watch("location_levels")
const levelMap = new Map(
selectedLocationLevels?.map((l) => [l.location_id, l])
@@ -83,140 +89,171 @@ const VariantStockForm = ({ form, locationLevels }: Props) => {
}
return (
-
-
-
-
General
-
-
-
-
-
+
+
+
-
-
-
Manage inventory
- {
- return
- }}
- />
-
-
- When checked Medusa will regulate the inventory when orders and
- returns are made.
-
-
- {manageInventory && (
- <>
-
-
-
- Allow backorders
-
- {
- return
- }}
- />
-
-
- When checked the product will be available for purchase despite
- the product being sold out
-
-
-
-
Quantity
- {!isLoading && locations && (
-
-
- {selectedLocations.map((level, i) => {
- const locationDetails = locationsMap.get(level.location_id)
- const locationLevel = levelMap.get(level.location_id)
-
- return (
-
-
-
-
-
- {locationDetails?.name}
-
-
-
-
- {`${locationLevel!.reserved_quantity} reserved`}
-
- {`${
- locationLevel!.stocked_quantity! -
- locationLevel!.reserved_quantity!
- } available`}
-
-
-
-
- )
- })}
-
- )}
-
-
-
+ {manageInventory && (
+ <>
+
+
+
+ Allow backorders
+
+ {
+ return (
+
+ )
+ }}
+ />
+
+
+ When checked the product will be available for purchase
+ despite the product being sold out
+
+
+
+
Quantity
+ {!isLoading && locations && (
+
+
+ {selectedLocations.map((level, i) => {
+ const locationDetails = locationsMap.get(
+ level.location_id
+ )
+ const locationLevel = levelMap.get(level.location_id)
+
+ return (
+
+
+
+
+
+ {locationDetails?.name}
+
+
+
+
+ {`${locationLevel!.reserved_quantity} reserved`}
+
+ {`${
+ locationLevel!.stocked_quantity! -
+ locationLevel!.reserved_quantity!
+ } available`}
+
+
+
+
+ )
+ })}
+
+ )}
+
+
+
+
+ >
+ )}
+
+
+
+
+ Shipping information can be required depending on your shipping
+ provider, and whether or not you are shipping internationally.
+
+
+
Dimensions
+
+ Configure to calculate the most accurate shipping rates.
+
+
+
+
+
Customs
+
+ Configure if you are shipping internationally.
+
+
+
+
+
)
}
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 7bdb0919ef..254bbfe42d 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
@@ -14,12 +14,13 @@ import {
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"
+import { countries } from "../../../utils/countries"
+import { Option } from "../../../types/shared"
type Props = {
onClose: () => void
@@ -44,19 +45,41 @@ const EditVariantInventoryModal = ({ onClose, product, variant }: Props) => {
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
+
+ return removeNullish({
+ ...updateDimensions,
+ ...updateCustoms,
+ ...data,
+ ...(originCountry && { origin_country: originCountry }),
+ })
+ }
+
const onSubmit = async (data: EditFlowVariantFormType) => {
- const locationLevels = data.stock.location_levels || []
- const manageInventory = data.stock.manage_inventory
+ const locationLevels = data.location_levels || []
+ const manageInventory = data.manage_inventory
const variantInventoryItem = variantInventory?.inventory?.[0]
const itemId = variantInventoryItem?.id
- delete data.stock.manage_inventory
- delete data.stock.location_levels
+ delete data.manage_inventory
+ delete data.location_levels
let inventoryItemId: string | undefined = itemId
- const upsertPayload = removeNullish(data.stock)
+ const { ean, barcode, upc } = data
+ const upsertPayload = createUpdateInventoryItemPayload(data)
let shouldInvalidateCache = false
if (variantInventoryItem) {
@@ -135,14 +158,27 @@ const EditVariantInventoryModal = ({ onClose, product, variant }: Props) => {
}
}
+ const { dimensions, customs, ...stock } = data
+
// @ts-ignore
- onUpdateVariant(variant.id, createUpdatePayload(data), () => {
- refetch()
- if (shouldInvalidateCache) {
- queryClient.invalidateQueries(adminInventoryItemsKeys.lists())
+ onUpdateVariant(
+ variant.id,
+ removeNullish({
+ ...dimensions,
+ ...customs,
+ ...stock,
+ ean,
+ barcode,
+ upc,
+ }),
+ () => {
+ refetch()
+ if (shouldInvalidateCache) {
+ queryClient.invalidateQueries(adminInventoryItemsKeys.lists())
+ }
+ handleClose()
}
- handleClose()
- })
+ )
}
return (
@@ -154,6 +190,7 @@ const EditVariantInventoryModal = ({ onClose, product, variant }: Props) => {
void
isLoadingInventory: boolean
handleClose: () => void
@@ -178,7 +217,7 @@ const StockForm = ({
}) => {
const form = useForm({
// @ts-ignore
- defaultValues: getEditVariantDefaultValues(variantInventory),
+ defaultValues: getEditVariantDefaultValues(variantInventory, variant),
})
const {
@@ -231,34 +270,68 @@ const StockForm = ({
}
export const getEditVariantDefaultValues = (
- variantInventory?: any
+ variantInventory?: any,
+ variant?: ProductVariant
): EditFlowVariantFormType => {
const inventoryItem = variantInventory?.inventory[0]
if (!inventoryItem) {
return {
- stock: {
- sku: null,
- ean: null,
- inventory_quantity: null,
- manage_inventory: false,
- allow_backorder: false,
- barcode: null,
- upc: null,
- location_levels: null,
+ sku: null,
+ ean: variant?.ean || null,
+ barcode: variant?.barcode || null,
+ upc: variant?.upc || null,
+ inventory_quantity: null,
+ manage_inventory: false,
+ 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 {
- stock: {
- sku: inventoryItem.sku,
- ean: inventoryItem.ean,
- inventory_quantity: inventoryItem.inventory_quantity,
- manage_inventory: !!inventoryItem,
- allow_backorder: inventoryItem.allow_backorder,
- barcode: inventoryItem.barcode,
- upc: inventoryItem.upc,
- location_levels: inventoryItem.location_levels,
+ 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: inventoryItem.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,
},
}
}