feat(admin-ui): move inventory item fields into manage inventory modal (#3591)
This commit is contained in:
1 parent
7428ffa300
commit
a7e3f2d343
5 files changed
+302
-191
No files matched your search
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@medusajs/medusa": minor
|
||||||
|
---
|
||||||
|
|
||||||
|
feat(admin-ui): move customs and shipping into manage inventory modal
|
||||||
+10
-8
@@ -2,7 +2,7 @@ import { useFieldArray, UseFormReturn } from "react-hook-form"
|
|||||||
import CustomsForm, { CustomsFormType } from "../../customs-form"
|
import CustomsForm, { CustomsFormType } from "../../customs-form"
|
||||||
import DimensionsForm, { DimensionsFormType } from "../../dimensions-form"
|
import DimensionsForm, { DimensionsFormType } from "../../dimensions-form"
|
||||||
import VariantGeneralForm, {
|
import VariantGeneralForm, {
|
||||||
VariantGeneralFormType
|
VariantGeneralFormType,
|
||||||
} from "../variant-general-form"
|
} from "../variant-general-form"
|
||||||
import VariantStockForm, { VariantStockFormType } from "../variant-stock-form"
|
import VariantStockForm, { VariantStockFormType } from "../variant-stock-form"
|
||||||
|
|
||||||
@@ -115,13 +115,15 @@ const EditFlowVariantForm = ({ form, isEdit }: Props) => {
|
|||||||
</p>
|
</p>
|
||||||
<DimensionsForm form={nestedForm(form, "dimensions")} />
|
<DimensionsForm form={nestedForm(form, "dimensions")} />
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-xlarge">
|
{showStockAndInventory && (
|
||||||
<h3 className="inter-base-semibold mb-2xsmall">Customs</h3>
|
<div className="mt-xlarge">
|
||||||
<p className="inter-base-regular text-grey-50 mb-large">
|
<h3 className="inter-base-semibold mb-2xsmall">Customs</h3>
|
||||||
Configure if you are shipping internationally.
|
<p className="inter-base-regular text-grey-50 mb-large">
|
||||||
</p>
|
Configure if you are shipping internationally.
|
||||||
<CustomsForm form={nestedForm(form, "customs")} />
|
</p>
|
||||||
</div>
|
<CustomsForm form={nestedForm(form, "customs")} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</Accordion.Item>
|
</Accordion.Item>
|
||||||
</Accordion>
|
</Accordion>
|
||||||
)
|
)
|
||||||
|
|||||||
+3
-9
@@ -1,11 +1,8 @@
|
|||||||
import { InventoryLevelDTO } from "@medusajs/medusa"
|
import { InventoryLevelDTO } from "@medusajs/types"
|
||||||
import { UseFormReturn } from "react-hook-form"
|
import { UseFormReturn } from "react-hook-form"
|
||||||
import { nestedForm } from "../../../../../utils/nested-form"
|
|
||||||
import VariantStockForm, { VariantStockFormType } from "../variant-stock-form"
|
import VariantStockForm, { VariantStockFormType } from "../variant-stock-form"
|
||||||
|
|
||||||
export type EditFlowVariantFormType = {
|
export type EditFlowVariantFormType = VariantStockFormType
|
||||||
stock: VariantStockFormType
|
|
||||||
}
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
form: UseFormReturn<EditFlowVariantFormType, any>
|
form: UseFormReturn<EditFlowVariantFormType, any>
|
||||||
@@ -39,10 +36,7 @@ const EditFlowVariantForm = ({ form, isLoading, locationLevels }: Props) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<VariantStockForm
|
<VariantStockForm locationLevels={locationLevels} form={form} />
|
||||||
locationLevels={locationLevels}
|
|
||||||
form={nestedForm(form, "stock")}
|
|
||||||
/>
|
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+179
-142
@@ -1,15 +1,19 @@
|
|||||||
import { InventoryLevelDTO, StockLocationDTO } from "@medusajs/medusa"
|
import { Controller, useFieldArray, UseFormReturn } from "react-hook-form"
|
||||||
import { useAdminStockLocations } from "medusa-react"
|
import { nestedForm } from "../../../../../utils/nested-form"
|
||||||
import React, { useMemo, useState } from "react"
|
import React, { useMemo, useState } from "react"
|
||||||
import { Controller, useFieldArray } from "react-hook-form"
|
|
||||||
import { NestedForm } from "../../../../../utils/nested-form"
|
import Accordion from "../../../../organisms/accordion"
|
||||||
import Switch from "../../../../atoms/switch"
|
|
||||||
import Button from "../../../../fundamentals/button"
|
|
||||||
import IconBadge from "../../../../fundamentals/icon-badge"
|
|
||||||
import BuildingsIcon from "../../../../fundamentals/icons/buildings-icon"
|
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 InputField from "../../../../molecules/input"
|
||||||
import Modal from "../../../../molecules/modal"
|
import Modal from "../../../../molecules/modal"
|
||||||
|
import Switch from "../../../../atoms/switch"
|
||||||
|
import { useAdminStockLocations } from "medusa-react"
|
||||||
import { useLayeredModal } from "../../../../molecules/modal/layered-modal"
|
import { useLayeredModal } from "../../../../molecules/modal/layered-modal"
|
||||||
|
import { InventoryLevelDTO, StockLocationDTO } from "@medusajs/types"
|
||||||
|
|
||||||
export type VariantStockFormType = {
|
export type VariantStockFormType = {
|
||||||
manage_inventory?: boolean
|
manage_inventory?: boolean
|
||||||
@@ -20,11 +24,13 @@ export type VariantStockFormType = {
|
|||||||
upc: string | null
|
upc: string | null
|
||||||
barcode: string | null
|
barcode: string | null
|
||||||
location_levels?: Partial<InventoryLevelDTO>[] | null
|
location_levels?: Partial<InventoryLevelDTO>[] | null
|
||||||
|
dimensions: DimensionsFormType
|
||||||
|
customs: CustomsFormType
|
||||||
}
|
}
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
locationLevels: InventoryLevelDTO[]
|
locationLevels: InventoryLevelDTO[]
|
||||||
form: NestedForm<VariantStockFormType>
|
form: UseFormReturn<VariantStockFormType>
|
||||||
}
|
}
|
||||||
|
|
||||||
const VariantStockForm = ({ form, locationLevels }: Props) => {
|
const VariantStockForm = ({ form, locationLevels }: Props) => {
|
||||||
@@ -44,9 +50,9 @@ const VariantStockForm = ({ form, locationLevels }: Props) => {
|
|||||||
|
|
||||||
return new Map(locations.map((l) => [l.id, l]))
|
return new Map(locations.map((l) => [l.id, l]))
|
||||||
}, [locations, isLoading])
|
}, [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 {
|
const {
|
||||||
fields: selectedLocations,
|
fields: selectedLocations,
|
||||||
@@ -54,10 +60,10 @@ const VariantStockForm = ({ form, locationLevels }: Props) => {
|
|||||||
remove,
|
remove,
|
||||||
} = useFieldArray({
|
} = useFieldArray({
|
||||||
control,
|
control,
|
||||||
name: path("location_levels"),
|
name: "location_levels",
|
||||||
})
|
})
|
||||||
|
|
||||||
const selectedLocationLevels = watch(path("location_levels"))
|
const selectedLocationLevels = watch("location_levels")
|
||||||
|
|
||||||
const levelMap = new Map(
|
const levelMap = new Map(
|
||||||
selectedLocationLevels?.map((l) => [l.location_id, l])
|
selectedLocationLevels?.map((l) => [l.location_id, l])
|
||||||
@@ -83,140 +89,171 @@ const VariantStockForm = ({ form, locationLevels }: Props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<Accordion type="multiple" defaultValue={["general"]}>
|
||||||
<div className="gap-y-xlarge flex flex-col">
|
<Accordion.Item title="General" value="general">
|
||||||
<div className="flex flex-col gap-y-4">
|
<div className="gap-y-xlarge mt-large flex flex-col">
|
||||||
<h3 className="inter-base-semibold">General</h3>
|
<div className="flex flex-col gap-y-4">
|
||||||
<div className="gap-large grid grid-cols-2">
|
<div className="gap-large grid grid-cols-2">
|
||||||
<InputField
|
<InputField
|
||||||
label="Stock keeping unit (SKU)"
|
label="Stock keeping unit (SKU)"
|
||||||
placeholder="SUN-G, JK1234..."
|
placeholder="SUN-G, JK1234..."
|
||||||
{...register(path("sku"))}
|
{...register("sku")}
|
||||||
/>
|
/>
|
||||||
<InputField
|
<InputField
|
||||||
label="EAN (Barcode)"
|
label="EAN (Barcode)"
|
||||||
placeholder="123456789102..."
|
placeholder="123456789102..."
|
||||||
{...register(path("ean"))}
|
{...register("ean")}
|
||||||
/>
|
/>
|
||||||
<InputField
|
<InputField
|
||||||
label="UPC (Barcode)"
|
label="UPC (Barcode)"
|
||||||
placeholder="023456789104..."
|
placeholder="023456789104..."
|
||||||
{...register(path("upc"))}
|
{...register("upc")}
|
||||||
/>
|
/>
|
||||||
<InputField
|
<InputField
|
||||||
label="Barcode"
|
label="Barcode"
|
||||||
placeholder="123456789104..."
|
placeholder="123456789104..."
|
||||||
{...register(path("barcode"))}
|
{...register("barcode")}
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="gap-y-2xsmall flex flex-col">
|
</Accordion.Item>
|
||||||
<div className="flex items-center justify-between">
|
<Accordion.Item title="Inventory" value="inventory">
|
||||||
<h3 className="inter-base-semibold mb-2xsmall">Manage inventory</h3>
|
<div className="gap-y-small mt-large flex flex-col">
|
||||||
<Controller
|
<div className="gap-y-2xsmall flex flex-col">
|
||||||
control={control}
|
<div className="flex items-center justify-between">
|
||||||
name={path("manage_inventory")}
|
<h3 className="inter-base-semibold mb-2xsmall">
|
||||||
render={({ field: { value, onChange } }) => {
|
Manage inventory
|
||||||
return <Switch checked={value} onCheckedChange={onChange} />
|
</h3>
|
||||||
}}
|
<Controller
|
||||||
/>
|
control={control}
|
||||||
</div>
|
name={"manage_inventory"}
|
||||||
<p className="inter-base-regular text-grey-50">
|
render={({ field: { value, onChange } }) => {
|
||||||
When checked Medusa will regulate the inventory when orders and
|
return <Switch checked={value} onCheckedChange={onChange} />
|
||||||
returns are made.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
{manageInventory && (
|
|
||||||
<>
|
|
||||||
<div className="gap-y-2xsmall flex flex-col">
|
|
||||||
<div className="flex items-center justify-between">
|
|
||||||
<h3 className="inter-base-semibold mb-2xsmall">
|
|
||||||
Allow backorders
|
|
||||||
</h3>
|
|
||||||
<Controller
|
|
||||||
control={control}
|
|
||||||
name={path("allow_backorder")}
|
|
||||||
render={({ field: { value, onChange } }) => {
|
|
||||||
return <Switch checked={value} onCheckedChange={onChange} />
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<p className="inter-base-regular text-grey-50">
|
|
||||||
When checked the product will be available for purchase despite
|
|
||||||
the product being sold out
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div className="flex w-full flex-col text-base">
|
|
||||||
<h3 className="inter-base-semibold mb-2xsmall">Quantity</h3>
|
|
||||||
{!isLoading && locations && (
|
|
||||||
<div className="flex w-full flex-col">
|
|
||||||
<div className="inter-base-regular text-grey-50 flex justify-between py-3">
|
|
||||||
<div className="">Location</div>
|
|
||||||
<div className="">In Stock</div>
|
|
||||||
</div>
|
|
||||||
{selectedLocations.map((level, i) => {
|
|
||||||
const locationDetails = locationsMap.get(level.location_id)
|
|
||||||
const locationLevel = levelMap.get(level.location_id)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div key={level.id} className="flex items-center py-3">
|
|
||||||
<div className="inter-base-regular flex items-center">
|
|
||||||
<IconBadge className="mr-base">
|
|
||||||
<BuildingsIcon />
|
|
||||||
</IconBadge>
|
|
||||||
{locationDetails?.name}
|
|
||||||
</div>
|
|
||||||
<div className="ml-auto flex">
|
|
||||||
<div className="mr-base text-small text-grey-50 flex flex-col">
|
|
||||||
<span className="whitespace-nowrap text-right">
|
|
||||||
{`${locationLevel!.reserved_quantity} reserved`}
|
|
||||||
</span>
|
|
||||||
<span className="whitespace-nowrap text-right">{`${
|
|
||||||
locationLevel!.stocked_quantity! -
|
|
||||||
locationLevel!.reserved_quantity!
|
|
||||||
} available`}</span>
|
|
||||||
</div>
|
|
||||||
<InputField
|
|
||||||
placeholder={"0"}
|
|
||||||
type="number"
|
|
||||||
min={0}
|
|
||||||
{...register(
|
|
||||||
path(`location_levels.${i}.stocked_quantity`),
|
|
||||||
{ valueAsNumber: true }
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div className="flex">
|
|
||||||
<Button
|
|
||||||
variant="secondary"
|
|
||||||
size="small"
|
|
||||||
type="button"
|
|
||||||
className="w-full"
|
|
||||||
onClick={() => {
|
|
||||||
layeredModalContext.push(
|
|
||||||
// @ts-ignore
|
|
||||||
ManageLocationsScreen(
|
|
||||||
layeredModalContext.pop,
|
|
||||||
selectedLocations,
|
|
||||||
locations || [],
|
|
||||||
handleUpdateLocations
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}}
|
}}
|
||||||
>
|
/>
|
||||||
Manage locations
|
|
||||||
</Button>
|
|
||||||
</div>
|
</div>
|
||||||
</>
|
<p className="inter-base-regular text-grey-50">
|
||||||
)}
|
When checked Medusa will regulate the inventory when orders and
|
||||||
</div>
|
returns are made.
|
||||||
</div>
|
</p>
|
||||||
|
</div>
|
||||||
|
{manageInventory && (
|
||||||
|
<>
|
||||||
|
<div className="gap-y-2xsmall flex flex-col">
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<h3 className="inter-base-semibold mb-2xsmall">
|
||||||
|
Allow backorders
|
||||||
|
</h3>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name={"allow_backorder"}
|
||||||
|
render={({ field: { value, onChange } }) => {
|
||||||
|
return (
|
||||||
|
<Switch checked={value} onCheckedChange={onChange} />
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<p className="inter-base-regular text-grey-50">
|
||||||
|
When checked the product will be available for purchase
|
||||||
|
despite the product being sold out
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="flex w-full flex-col text-base">
|
||||||
|
<h3 className="inter-base-semibold mb-2xsmall">Quantity</h3>
|
||||||
|
{!isLoading && locations && (
|
||||||
|
<div className="flex w-full flex-col">
|
||||||
|
<div className="inter-base-regular text-grey-50 flex justify-between py-3">
|
||||||
|
<div className="">Location</div>
|
||||||
|
<div className="">In Stock</div>
|
||||||
|
</div>
|
||||||
|
{selectedLocations.map((level, i) => {
|
||||||
|
const locationDetails = locationsMap.get(
|
||||||
|
level.location_id
|
||||||
|
)
|
||||||
|
const locationLevel = levelMap.get(level.location_id)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div key={level.id} className="flex items-center py-3">
|
||||||
|
<div className="inter-base-regular flex items-center">
|
||||||
|
<IconBadge className="mr-base">
|
||||||
|
<BuildingsIcon />
|
||||||
|
</IconBadge>
|
||||||
|
{locationDetails?.name}
|
||||||
|
</div>
|
||||||
|
<div className="ml-auto flex">
|
||||||
|
<div className="mr-base text-small text-grey-50 flex flex-col">
|
||||||
|
<span className="whitespace-nowrap text-right">
|
||||||
|
{`${locationLevel!.reserved_quantity} reserved`}
|
||||||
|
</span>
|
||||||
|
<span className="whitespace-nowrap text-right">{`${
|
||||||
|
locationLevel!.stocked_quantity! -
|
||||||
|
locationLevel!.reserved_quantity!
|
||||||
|
} available`}</span>
|
||||||
|
</div>
|
||||||
|
<InputField
|
||||||
|
placeholder={"0"}
|
||||||
|
type="number"
|
||||||
|
min={0}
|
||||||
|
{...register(
|
||||||
|
`location_levels.${i}.stocked_quantity`,
|
||||||
|
{ valueAsNumber: true }
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="flex">
|
||||||
|
<Button
|
||||||
|
variant="secondary"
|
||||||
|
size="small"
|
||||||
|
type="button"
|
||||||
|
className="w-full"
|
||||||
|
onClick={() => {
|
||||||
|
layeredModalContext.push(
|
||||||
|
// @ts-ignore
|
||||||
|
ManageLocationsScreen(
|
||||||
|
layeredModalContext.pop,
|
||||||
|
selectedLocations,
|
||||||
|
locations || [],
|
||||||
|
handleUpdateLocations
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Manage locations
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</Accordion.Item>
|
||||||
|
<Accordion.Item title="Shipping" value="shipping">
|
||||||
|
<p className="inter-base-regular text-grey-50">
|
||||||
|
Shipping information can be required depending on your shipping
|
||||||
|
provider, and whether or not you are shipping internationally.
|
||||||
|
</p>
|
||||||
|
<div className="mt-large">
|
||||||
|
<h3 className="inter-base-semibold mb-2xsmall">Dimensions</h3>
|
||||||
|
<p className="inter-base-regular text-grey-50 mb-large">
|
||||||
|
Configure to calculate the most accurate shipping rates.
|
||||||
|
</p>
|
||||||
|
<DimensionsForm form={nestedForm(form, "dimensions")} />
|
||||||
|
</div>
|
||||||
|
<div className="mt-xlarge">
|
||||||
|
<h3 className="inter-base-semibold mb-2xsmall">Customs</h3>
|
||||||
|
<p className="inter-base-regular text-grey-50 mb-large">
|
||||||
|
Configure if you are shipping internationally.
|
||||||
|
</p>
|
||||||
|
<CustomsForm form={nestedForm(form, "customs")} />
|
||||||
|
</div>
|
||||||
|
</Accordion.Item>
|
||||||
|
</Accordion>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+105
-32
@@ -14,12 +14,13 @@ import {
|
|||||||
import Button from "../../fundamentals/button"
|
import Button from "../../fundamentals/button"
|
||||||
import { InventoryLevelDTO } from "@medusajs/types"
|
import { InventoryLevelDTO } from "@medusajs/types"
|
||||||
import Modal from "../../molecules/modal"
|
import Modal from "../../molecules/modal"
|
||||||
import { createUpdatePayload } from "./edit-variants-modal/edit-variant-screen"
|
|
||||||
import { queryClient } from "../../../constants/query-client"
|
import { queryClient } from "../../../constants/query-client"
|
||||||
import { removeNullish } from "../../../utils/remove-nullish"
|
import { removeNullish } from "../../../utils/remove-nullish"
|
||||||
import { useContext } from "react"
|
import { useContext } from "react"
|
||||||
import useEditProductActions from "../../../hooks/use-edit-product-actions"
|
import useEditProductActions from "../../../hooks/use-edit-product-actions"
|
||||||
import { useForm } from "react-hook-form"
|
import { useForm } from "react-hook-form"
|
||||||
|
import { countries } from "../../../utils/countries"
|
||||||
|
import { Option } from "../../../types/shared"
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
onClose: () => void
|
onClose: () => void
|
||||||
@@ -44,19 +45,41 @@ const EditVariantInventoryModal = ({ onClose, product, variant }: Props) => {
|
|||||||
|
|
||||||
const { onUpdateVariant, updatingVariant } = useEditProductActions(product.id)
|
const { onUpdateVariant, updatingVariant } = useEditProductActions(product.id)
|
||||||
|
|
||||||
|
const createUpdateInventoryItemPayload = (
|
||||||
|
data: Partial<EditFlowVariantFormType>
|
||||||
|
) => {
|
||||||
|
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 onSubmit = async (data: EditFlowVariantFormType) => {
|
||||||
const locationLevels = data.stock.location_levels || []
|
const locationLevels = data.location_levels || []
|
||||||
const manageInventory = data.stock.manage_inventory
|
const manageInventory = data.manage_inventory
|
||||||
|
|
||||||
const variantInventoryItem = variantInventory?.inventory?.[0]
|
const variantInventoryItem = variantInventory?.inventory?.[0]
|
||||||
const itemId = variantInventoryItem?.id
|
const itemId = variantInventoryItem?.id
|
||||||
|
|
||||||
delete data.stock.manage_inventory
|
delete data.manage_inventory
|
||||||
delete data.stock.location_levels
|
delete data.location_levels
|
||||||
|
|
||||||
let inventoryItemId: string | undefined = itemId
|
let inventoryItemId: string | undefined = itemId
|
||||||
|
|
||||||
const upsertPayload = removeNullish(data.stock)
|
const { ean, barcode, upc } = data
|
||||||
|
const upsertPayload = createUpdateInventoryItemPayload(data)
|
||||||
let shouldInvalidateCache = false
|
let shouldInvalidateCache = false
|
||||||
|
|
||||||
if (variantInventoryItem) {
|
if (variantInventoryItem) {
|
||||||
@@ -135,14 +158,27 @@ const EditVariantInventoryModal = ({ onClose, product, variant }: Props) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { dimensions, customs, ...stock } = data
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
onUpdateVariant(variant.id, createUpdatePayload(data), () => {
|
onUpdateVariant(
|
||||||
refetch()
|
variant.id,
|
||||||
if (shouldInvalidateCache) {
|
removeNullish({
|
||||||
queryClient.invalidateQueries(adminInventoryItemsKeys.lists())
|
...dimensions,
|
||||||
|
...customs,
|
||||||
|
...stock,
|
||||||
|
ean,
|
||||||
|
barcode,
|
||||||
|
upc,
|
||||||
|
}),
|
||||||
|
() => {
|
||||||
|
refetch()
|
||||||
|
if (shouldInvalidateCache) {
|
||||||
|
queryClient.invalidateQueries(adminInventoryItemsKeys.lists())
|
||||||
|
}
|
||||||
|
handleClose()
|
||||||
}
|
}
|
||||||
handleClose()
|
)
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -154,6 +190,7 @@ const EditVariantInventoryModal = ({ onClose, product, variant }: Props) => {
|
|||||||
<StockForm
|
<StockForm
|
||||||
variantInventory={variantInventory!}
|
variantInventory={variantInventory!}
|
||||||
onSubmit={onSubmit}
|
onSubmit={onSubmit}
|
||||||
|
variant={variant}
|
||||||
isLoadingInventory={isLoadingInventory}
|
isLoadingInventory={isLoadingInventory}
|
||||||
handleClose={handleClose}
|
handleClose={handleClose}
|
||||||
updatingVariant={updatingVariant}
|
updatingVariant={updatingVariant}
|
||||||
@@ -169,8 +206,10 @@ const StockForm = ({
|
|||||||
isLoadingInventory,
|
isLoadingInventory,
|
||||||
handleClose,
|
handleClose,
|
||||||
updatingVariant,
|
updatingVariant,
|
||||||
|
variant,
|
||||||
}: {
|
}: {
|
||||||
variantInventory: VariantInventory
|
variantInventory: VariantInventory
|
||||||
|
variant: ProductVariant
|
||||||
onSubmit: (data: EditFlowVariantFormType) => void
|
onSubmit: (data: EditFlowVariantFormType) => void
|
||||||
isLoadingInventory: boolean
|
isLoadingInventory: boolean
|
||||||
handleClose: () => void
|
handleClose: () => void
|
||||||
@@ -178,7 +217,7 @@ const StockForm = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const form = useForm<EditFlowVariantFormType>({
|
const form = useForm<EditFlowVariantFormType>({
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
defaultValues: getEditVariantDefaultValues(variantInventory),
|
defaultValues: getEditVariantDefaultValues(variantInventory, variant),
|
||||||
})
|
})
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@@ -231,34 +270,68 @@ const StockForm = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const getEditVariantDefaultValues = (
|
export const getEditVariantDefaultValues = (
|
||||||
variantInventory?: any
|
variantInventory?: any,
|
||||||
|
variant?: ProductVariant
|
||||||
): EditFlowVariantFormType => {
|
): EditFlowVariantFormType => {
|
||||||
const inventoryItem = variantInventory?.inventory[0]
|
const inventoryItem = variantInventory?.inventory[0]
|
||||||
if (!inventoryItem) {
|
if (!inventoryItem) {
|
||||||
return {
|
return {
|
||||||
stock: {
|
sku: null,
|
||||||
sku: null,
|
ean: variant?.ean || null,
|
||||||
ean: null,
|
barcode: variant?.barcode || null,
|
||||||
inventory_quantity: null,
|
upc: variant?.upc || null,
|
||||||
manage_inventory: false,
|
inventory_quantity: null,
|
||||||
allow_backorder: false,
|
manage_inventory: false,
|
||||||
barcode: null,
|
allow_backorder: false,
|
||||||
upc: null,
|
location_levels: null,
|
||||||
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 {
|
return {
|
||||||
stock: {
|
sku: inventoryItem.sku,
|
||||||
sku: inventoryItem.sku,
|
ean: variant?.ean || null,
|
||||||
ean: inventoryItem.ean,
|
barcode: variant?.barcode || null,
|
||||||
inventory_quantity: inventoryItem.inventory_quantity,
|
upc: variant?.upc || null,
|
||||||
manage_inventory: !!inventoryItem,
|
inventory_quantity: inventoryItem.inventory_quantity,
|
||||||
allow_backorder: inventoryItem.allow_backorder,
|
manage_inventory: !!inventoryItem,
|
||||||
barcode: inventoryItem.barcode,
|
allow_backorder: inventoryItem.allow_backorder,
|
||||||
upc: inventoryItem.upc,
|
location_levels: inventoryItem.location_levels,
|
||||||
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,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user