diff --git a/.changeset/cool-buckets-explode.md b/.changeset/cool-buckets-explode.md new file mode 100644 index 0000000000..d27abb339b --- /dev/null +++ b/.changeset/cool-buckets-explode.md @@ -0,0 +1,5 @@ +--- +"@medusajs/medusa": patch +--- + +feaet(medusa): add description to reservation default fields diff --git a/.changeset/curly-carpets-remain.md b/.changeset/curly-carpets-remain.md new file mode 100644 index 0000000000..520e4df04b --- /dev/null +++ b/.changeset/curly-carpets-remain.md @@ -0,0 +1,5 @@ +--- +"@medusajs/admin-ui": patch +--- + +feat(admin-ui): update edit allocation modal design diff --git a/packages/admin-ui/ui/src/components/atoms/thumbnail/thumbnail.tsx b/packages/admin-ui/ui/src/components/atoms/thumbnail/thumbnail.tsx index e098fa5038..9ef9bc554b 100644 --- a/packages/admin-ui/ui/src/components/atoms/thumbnail/thumbnail.tsx +++ b/packages/admin-ui/ui/src/components/atoms/thumbnail/thumbnail.tsx @@ -1,10 +1,10 @@ -import clsx from "clsx" import ImagePlaceholderIcon from "../../fundamentals/icons/image-placeholder-icon" +import clsx from "clsx" type Props = { src?: string | null className?: string - size?: "small" | "medium" | "large" + size?: "xsmall" | "small" | "medium" | "large" } export const Thumbnail = ({ src, className, size = "small" }: Props) => { @@ -13,6 +13,7 @@ export const Thumbnail = ({ src, className, size = "small" }: Props) => { className={clsx( "bg-grey-5 rounded-rounded flex items-center justify-center overflow-hidden", { + "h-6 w-[18px]": size === "xsmall", "h-10 w-[30px]": size === "small", "h-12 w-9": size === "medium", "h-[226px] w-[170px]": size === "large", diff --git a/packages/admin-ui/ui/src/domain/orders/details/allocations/allocate-items-modal.tsx b/packages/admin-ui/ui/src/domain/orders/details/allocations/allocate-items-modal.tsx index d49156f8ea..6d99efff43 100644 --- a/packages/admin-ui/ui/src/domain/orders/details/allocations/allocate-items-modal.tsx +++ b/packages/admin-ui/ui/src/domain/orders/details/allocations/allocate-items-modal.tsx @@ -1,5 +1,4 @@ import { Controller, useForm, useWatch } from "react-hook-form" -import { LineItem } from "@medusajs/medusa" import { NestedForm, nestedForm } from "../../../../utils/nested-form" import React, { useEffect, useMemo } from "react" import { @@ -13,6 +12,8 @@ import Button from "../../../../components/fundamentals/button" import CrossIcon from "../../../../components/fundamentals/icons/cross-icon" import FocusModal from "../../../../components/molecules/modal/focus-modal" import InputField from "../../../../components/molecules/input" +import { LineItem } from "@medusajs/medusa" +import { ReservationItemDTO } from "@medusajs/types" import Select from "../../../../components/molecules/select/next-select/select" import Thumbnail from "../../../../components/atoms/thumbnail" import clsx from "clsx" @@ -20,7 +21,6 @@ import { getErrorMessage } from "../../../../utils/error-messages" import { getFulfillableQuantity } from "../create-fulfillment/item-table" import { sum } from "lodash" import useNotification from "../../../../hooks/use-notification" -import { ReservationItemDTO } from "@medusajs/types" type AllocationModalFormData = { location?: { label: string; value: string } @@ -205,6 +205,7 @@ export type AllocationLineItemForm = { inventory_item_id: string line_item_id: string quantity: number + description?: string | null } export const AllocationLineItem: React.FC<{ diff --git a/packages/admin-ui/ui/src/domain/orders/details/allocations/edit-allocation-modal.tsx b/packages/admin-ui/ui/src/domain/orders/details/allocations/edit-allocation-modal.tsx index 94c181085a..78e6457d99 100644 --- a/packages/admin-ui/ui/src/domain/orders/details/allocations/edit-allocation-modal.tsx +++ b/packages/admin-ui/ui/src/domain/orders/details/allocations/edit-allocation-modal.tsx @@ -1,47 +1,72 @@ -import { AllocationLineItemForm } from "./allocate-items-modal" import { Controller, useForm, useWatch } from "react-hook-form" -import { LineItem, ReservationItemDTO } from "@medusajs/medusa" +import { + InventoryLevelDTO, + ReservationItemDTO, + StockLocationDTO, +} from "@medusajs/types" +import MetadataForm, { + MetadataFormType, + getMetadataFormValues, + getSubmittableMetadata, +} from "../../../../components/forms/general/metadata-form" import { useAdminDeleteReservation, + useAdminInventoryItem, useAdminStockLocations, useAdminUpdateReservation, - useAdminVariantsInventory, } from "medusa-react" import { useEffect, useMemo } from "react" +import { AllocationLineItemForm } from "./allocate-items-modal" import Button from "../../../../components/fundamentals/button" import CrossIcon from "../../../../components/fundamentals/icons/cross-icon" +import InputField from "../../../../components/molecules/input" +import { LineItem } from "@medusajs/medusa" import Select from "../../../../components/molecules/select/next-select/select" import SideModal from "../../../../components/molecules/modal/side-modal" -import useNotification from "../../../../hooks/use-notification" import Thumbnail from "../../../../components/atoms/thumbnail" import { getFulfillableQuantity } from "../create-fulfillment/item-table" +import { nestedForm } from "../../../../utils/nested-form" +import useNotification from "../../../../hooks/use-notification" +import useToggleState from "../../../../hooks/use-toggle-state" type EditAllocationLineItemForm = { location: { label: string; value: string } item: AllocationLineItemForm + metadata: MetadataFormType } const EditAllocationDrawer = ({ close, reservation, item, - totalReservedQuantity, + totalReservedQuantity = 0, }: { close: () => void - reservation?: ReservationItemDTO - item: LineItem - totalReservedQuantity: number + reservation: ReservationItemDTO + item?: LineItem + totalReservedQuantity?: number }) => { - const form = useForm() + const form = useForm({ + defaultValues: { + item: { + description: reservation.description, + }, + metadata: getMetadataFormValues(reservation?.metadata), + }, + }) - const { control, setValue, handleSubmit } = form + const { state: hasMetadata, toggle: toggleHasMetadata } = useToggleState( + !!reservation.metadata + ) + + const { control, setValue, handleSubmit, register } = form const { stock_locations, isLoading: isLoadingStockLocations } = useAdminStockLocations() - const { variant, isLoading } = useAdminVariantsInventory( - item.variant_id as string + const { inventory_item, isLoading } = useAdminInventoryItem( + reservation.inventory_item_id ) const { mutate: updateReservation } = useAdminUpdateReservation( @@ -55,7 +80,8 @@ const EditAllocationDrawer = ({ if (!stock_locations || isLoadingStockLocations) { return [] } - return stock_locations.map((sl) => ({ + + return stock_locations.map((sl: StockLocationDTO) => ({ value: sl.id, label: sl.name, })) @@ -86,7 +112,7 @@ const EditAllocationDrawer = ({ useEffect(() => { if (stock_locations?.length && reservation) { const defaultLocation = stock_locations.find( - (sl) => sl.id === reservation.location_id + (sl: StockLocationDTO) => sl.id === reservation.location_id ) if (defaultLocation) { @@ -113,6 +139,8 @@ const EditAllocationDrawer = ({ { quantity: data.item.quantity, location_id: data.location.value, + description: data.item.description, + metadata: hasMetadata ? getSubmittableMetadata(data.metadata) : null, }, { onSuccess: () => { @@ -131,12 +159,12 @@ const EditAllocationDrawer = ({ } const { availableQuantity, inStockQuantity } = useMemo(() => { - if (isLoading || !selectedLocation?.value || !variant) { + if (isLoading || !selectedLocation?.value || !inventory_item) { return {} } - const { inventory } = variant - const locationInventory = inventory[0].location_levels?.find( - (inv) => inv.location_id === selectedLocation?.value + + const locationInventory = inventory_item.location_levels?.find( + (inv: InventoryLevelDTO) => inv.location_id === selectedLocation?.value ) if (!locationInventory) { return {} @@ -145,20 +173,30 @@ const EditAllocationDrawer = ({ availableQuantity: locationInventory.available_quantity, inStockQuantity: locationInventory.stocked_quantity, } - }, [variant, selectedLocation, isLoading]) + }, [isLoading, selectedLocation?.value, inventory_item]) - // we can adjust up to fulfillable quantity - the quantity reserved in other reservations - const lineItemReservationCapacity = - getFulfillableQuantity(item) - - (totalReservedQuantity - (reservation?.quantity || 0)) + const maxReservation = useMemo(() => { + if (!item) { + return typeof availableQuantity === "number" ? availableQuantity : 0 + } - const inventoryItemReservationCapacity = - typeof availableQuantity === "number" ? availableQuantity : 0 + const lineItemReservationCapacity = + getFulfillableQuantity(item) - + (totalReservedQuantity - (reservation?.quantity || 0)) - const maxReservation = Math.min( - lineItemReservationCapacity, - inventoryItemReservationCapacity - ) + const inventoryItemReservationCapacity = + typeof availableQuantity === "number" ? availableQuantity : 0 + + return Math.min( + lineItemReservationCapacity, + inventoryItemReservationCapacity + ) + }, [availableQuantity, item, reservation?.quantity, totalReservedQuantity]) + + const closeModal = (e) => { + e.preventDefault() + close() + } return ( @@ -167,98 +205,118 @@ const EditAllocationDrawer = ({ onSubmit={handleSubmit(submit)} >
-
-
-

Edit allocation

- -
+
+

Edit allocation

+ +
+
-
-

Location

- - Choose which location you want to ship the items from. - - ( - + )} + /> +
+ +
+

Items to Allocate

Select the number of items that you wish to allocate. -
-
- -
-
-

- {item.title} -

-

-

{`(${item.variant.sku})`}

- · - - {item.variant.options - ?.map((option, i) => [ - - {option.value} - , - ·, - ]) - .flat() - .slice(0, -1) || - item.variant.title || - "-"} - -

-
-
-
*]:border-r [&>*]:border-b [&>*]:py-2 [&>*:nth-child(odd)]:border-l [&>*:nth-child(odd)]:pl-4 [&>*:nth-child(even)]:pr-4 [&>*:nth-child(even)]:text-right [&>*:nth-child(-n+2)]:border-t`} > -
In stock
-
- {inStockQuantity ?? "N/A"} +
Item
+
+

+ {inventory_item?.title ?? item?.title ?? "-"} +

+
-
Available
-
{availableQuantity ?? "N/A"}
+
SKU
+
{inventory_item?.sku ?? "N/A"}
+
In stock
+
{inStockQuantity ?? "N/A"}
+
Available
+
{availableQuantity ?? "N/A"}
Allocate
- {` / ${maxReservation} requested`} + + {maxReservation + ? ` / ${maxReservation} requested` + : " reserved"} +
+
+

Description

+

+ What type of reservation is this? +

+ +
+
+
+

Metadata

+ +
+ {hasMetadata && ( + + )} +