Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(dashboard,admin-shared): Fixes to inventory page #8941

Merged
merged 2 commits into from
Sep 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,15 @@ const RETURN_REASON_INJECTION_ZONES = [
"return_reason.list.after",
] as const

const INVENTORY_ITEM_INJECTION_ZONES = [
"inventory_item.details.before",
"inventory_item.details.after",
"inventory_item.details.side.before",
"inventory_item.details.side.after",
"inventory_item.list.before",
"inventory_item.list.after",
] as const

/**
* All valid injection zones in the admin panel. An injection zone is a specific place
* in the admin panel where a plugin can inject custom widgets.
Expand Down Expand Up @@ -220,4 +229,5 @@ export const INJECTION_ZONES = [
...PRODUCT_TYPE_INJECTION_ZONES,
...PRODUCT_TAG_INJECTION_ZONES,
...RETURN_REASON_INJECTION_ZONES,
...INVENTORY_ITEM_INJECTION_ZONES,
] as const
Original file line number Diff line number Diff line change
@@ -1,28 +1,48 @@
import { clx } from "@medusajs/ui"
import { ConditionalTooltip } from "../../../../common/conditional-tooltip"
import { PlaceholderCell } from "../placeholder-cell"

type CellProps = {
text?: string | number
align?: "left" | "center" | "right"
maxWidth?: number
}

type HeaderProps = {
text: string
align?: "left" | "center" | "right"
}

export const TextCell = ({ text }: CellProps) => {
export const TextCell = ({ text, align = "left", maxWidth = 220 }: CellProps) => {
if (!text) {
return <PlaceholderCell />
}

const stringLength = text.toString().length

return (
<div className="flex h-full w-full items-center gap-x-3 overflow-hidden">
<ConditionalTooltip content={text} showTooltip={stringLength > 20}>
<div className={clx("flex h-full w-full items-center gap-x-3 overflow-hidden", {
"justify-start text-start": align === "left",
"justify-center text-center": align === "center",
"justify-end text-end": align === "right",
})}
style={{
maxWidth: maxWidth,
}}>
<span className="truncate">{text}</span>
</div>
</ConditionalTooltip>
)
}

export const TextHeader = ({ text }: HeaderProps) => {
export const TextHeader = ({ text, align = "left" }: HeaderProps) => {
return (
<div className="flex h-full w-full items-center">
<div className={clx("flex h-full w-full items-center", {
"justify-start text-start": align === "left",
"justify-center text-center": align === "center",
"justify-end text-end": align === "right",
})}>
<span className="truncate">{text}</span>
</div>
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Container, Heading, IconButton } from "@medusajs/ui"
import { TriangleRightMini } from "@medusajs/icons"
import { Container, Heading } from "@medusajs/ui"
import { useTranslation } from "react-i18next"
import { ArrowUpRightOnBox } from "@medusajs/icons"
import { useNavigate } from "react-router-dom"
import { Link } from "react-router-dom"

import { ProductVariantDTO } from "@medusajs/types"
import { Thumbnail } from "../../../../../components/common/thumbnail"
Expand All @@ -14,7 +14,6 @@ export const InventoryItemVariantsSection = ({
variants,
}: InventoryItemVariantsSectionProps) => {
const { t } = useTranslation()
const navigate = useNavigate()

if (!variants?.length) {
return null
Expand All @@ -27,38 +26,46 @@ export const InventoryItemVariantsSection = ({
</div>

<div className="txt-small flex flex-col gap-2 px-2 pb-2">
{variants.map((variant) => (
<div
key={variant.id}
className="shadow-elevation-card-rest bg-ui-bg-component rounded-md px-4 py-2"
>
<div className="flex items-center gap-3">
<div className="shadow-elevation-card-rest rounded-md">
<Thumbnail src={variant.product?.thumbnail} />
</div>
<div className="flex flex-1 flex-col">
<span className="text-ui-fg-base font-medium">
{variant.title}
</span>
<span className="text-ui-fg-subtle">
{variant.options.map((o) => o.value).join(" ⋅ ")}
</span>
{variants.map((variant) => {
const link = variant.product
? `/products/${variant.product.id}/variants/${variant.id}`
: null

const Inner = (
<div className="shadow-elevation-card-rest bg-ui-bg-component rounded-md px-4 py-2 transition-colors">
<div className="flex items-center gap-3">
<div className="shadow-elevation-card-rest rounded-md">
<Thumbnail src={variant.product?.thumbnail} />
</div>
<div className="flex flex-1 flex-col">
<span className="text-ui-fg-base font-medium">
{variant.title}
</span>
<span className="text-ui-fg-subtle">
{variant.options.map((o) => o.value).join(" ⋅ ")}
</span>
</div>
<div className="size-7 flex items-center justify-center">
<TriangleRightMini className="text-ui-fg-muted" />
</div>
</div>
<IconButton
size="2xsmall"
variant="transparent"
type="button"
onClick={() =>
navigate(
`/products/${variant.product.id}/variants/${variant.id}`
)
}
>
<ArrowUpRightOnBox className="text-ui-fg-muted" />
</IconButton>
</div>
</div>
))}
)

if (!link) {
return <div key={variant.id}>{Inner}</div>
}

return (
<Link
to={link}
key={variant.id}
className="outline-none focus-within:shadow-borders-interactive-with-focus rounded-md [&:hover>div]:bg-ui-bg-component-hover"
>
{Inner}
</Link>
)
})}
</div>
</Container>
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { HttpTypes } from "@medusajs/types"
import { PlaceholderCell } from "../../../../../components/table/table-cells/common/placeholder-cell"
import { ReservationActions } from "./reservation-actions"
import { createColumnHelper } from "@tanstack/react-table"
import { useMemo } from "react"
import { useTranslation } from "react-i18next"
import { CreatedAtCell } from "../../../../../components/table/table-cells/common/created-at-cell"
import { PlaceholderCell } from "../../../../../components/table/table-cells/common/placeholder-cell"
import { TextCell, TextHeader } from "../../../../../components/table/table-cells/common/text-cell"
import { ReservationActions } from "./reservation-actions"

/**
* Adds missing properties to the InventoryItemDTO type.
Expand All @@ -22,17 +23,16 @@ export const useReservationTableColumn = ({ sku }: { sku: string }) => {
return useMemo(
() => [
columnHelper.display({
header: t("fields.sku"),
id: "sku",
header: () => <TextHeader text={t("fields.sku")} />,
cell: () => {
return (
<div className="flex size-full items-center overflow-hidden">
<span className="truncate">{sku}</span>
</div>
<TextCell text={sku} />
)
},
}),
columnHelper.accessor("line_item.order_id", {
header: t("inventory.reservation.orderID"),
header: () => <TextHeader text={t("inventory.reservation.orderID")} />,
cell: ({ getValue }) => {
const orderId = getValue()

Expand All @@ -41,14 +41,12 @@ export const useReservationTableColumn = ({ sku }: { sku: string }) => {
}

return (
<div className="flex size-full items-center overflow-hidden">
<span className="truncate">{orderId}</span>
</div>
<TextCell text={orderId} />
)
},
}),
columnHelper.accessor("description", {
header: t("fields.description"),
header: () => <TextHeader text={t("fields.description")} />,
cell: ({ getValue }) => {
const description = getValue()

Expand All @@ -57,14 +55,12 @@ export const useReservationTableColumn = ({ sku }: { sku: string }) => {
}

return (
<div className="flex size-full items-center overflow-hidden">
<span className="truncate">{description}</span>
</div>
<TextCell text={description} />
)
},
}),
columnHelper.accessor("location.name", {
header: t("inventory.reservation.location"),
header: () => <TextHeader text={t("inventory.reservation.location")} />,
cell: ({ getValue }) => {
const location = getValue()

Expand All @@ -73,16 +69,20 @@ export const useReservationTableColumn = ({ sku }: { sku: string }) => {
}

return (
<div className="flex size-full items-center overflow-hidden">
<span className="truncate">{location}</span>
</div>
<TextCell text={location} />
)
},
}),
columnHelper.accessor("created_at", {
header: t("fields.createdAt"),
header: () => <TextHeader text={t("fields.createdAt")} />,
cell: ({ getValue }) => <CreatedAtCell date={getValue()} />,
}),
columnHelper.accessor("quantity", {
header: () => <TextHeader text={t("fields.quantity")} align="right" />,
cell: ({ getValue }) => {
return <TextCell text={getValue()} align="right" />
},
}),
columnHelper.display({
id: "actions",
cell: ({ row }) => <ReservationActions reservation={row.original} />,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
import { Outlet, json, useLoaderData, useParams } from "react-router-dom"
import { useLoaderData, useParams } from "react-router-dom"

import { TwoColumnPageSkeleton } from "../../../components/common/skeleton"
import { TwoColumnPage } from "../../../components/layout/pages"
import { useInventoryItem } from "../../../hooks/api/inventory"
import { InventoryItemAttributeSection } from "./components/inventory-item-attributes/attributes-section"
import { InventoryItemGeneralSection } from "./components/inventory-item-general-section"
import { InventoryItemLocationLevelsSection } from "./components/inventory-item-location-levels"
import { InventoryItemReservationsSection } from "./components/inventory-item-reservations"
import { JsonViewSection } from "../../../components/common/json-view-section"
import { useInventoryItem } from "../../../hooks/api/inventory"
import { InventoryItemVariantsSection } from "./components/inventory-item-variants/variants-section"
import { inventoryItemLoader } from "./loader"

import after from "virtual:medusa/widgets/inventory_item/details/after"
import before from "virtual:medusa/widgets/inventory_item/details/before"
import sideAfter from "virtual:medusa/widgets/inventory_item/details/side/after"
import sideBefore from "virtual:medusa/widgets/inventory_item/details/side/before"

export const InventoryDetail = () => {
const { id } = useParams()

Expand All @@ -31,37 +37,45 @@ export const InventoryDetail = () => {
}
)

if (isLoading) {
return <div>Loading...</div>
if (isLoading || !inventory_item) {
return (
<TwoColumnPageSkeleton
showJSON
showMetadata
mainSections={3}
sidebarSections={2}
/>
)
}
if (isError || !inventory_item) {
if (error) {
throw error
}

throw json("An unknown error occurred", 500)
if (isError) {
throw error
}

return (
<div className="flex flex-col gap-y-2">
<div className="flex flex-col gap-x-4 lg:flex-row lg:items-start">
<div className="flex w-full flex-col gap-y-3">
<InventoryItemGeneralSection inventoryItem={inventory_item} />
<InventoryItemLocationLevelsSection inventoryItem={inventory_item} />
<InventoryItemReservationsSection inventoryItem={inventory_item} />
<div className="hidden lg:block">
<JsonViewSection data={inventory_item} />
</div>
<Outlet />
</div>
<div className="mt-2 flex w-full max-w-[100%] flex-col gap-y-2 lg:mt-0 lg:max-w-[400px]">
<InventoryItemVariantsSection variants={inventory_item.variants} />
<InventoryItemAttributeSection inventoryItem={inventory_item} />
<div className="lg:hidden">
<JsonViewSection data={inventory_item} />
</div>
</div>
</div>
</div>
<TwoColumnPage
widgets={{
after,
before,
sideAfter,
sideBefore,
}}
data={inventory_item}
showJSON
showMetadata
hasOutlet
>
<TwoColumnPage.Main>
<InventoryItemGeneralSection inventoryItem={inventory_item} />
<InventoryItemLocationLevelsSection inventoryItem={inventory_item} />
<InventoryItemReservationsSection inventoryItem={inventory_item} />
</TwoColumnPage.Main>
<TwoColumnPage.Sidebar>
<InventoryItemVariantsSection
variants={(inventory_item as any).variants}
/>
<InventoryItemAttributeSection inventoryItem={inventory_item as any} />
</TwoColumnPage.Sidebar>
</TwoColumnPage>
)
}
Loading