feat(admin-ui): ProductCategory list page (#3380)

This commit is contained in:
Riqwan Thamir
2023-03-05 16:16:53 +01:00
committed by GitHub
parent 5d809a7a39
commit d4e3e119de
7 changed files with 169 additions and 39 deletions

View File

@@ -0,0 +1,5 @@
---
"@medusajs/admin-ui": patch
---
feat(admin-ui): add empty state for product categories

View File

@@ -0,0 +1,29 @@
import React from "react"
import IconProps from "../types/icon-type"
const SwatchIcon: React.FC<IconProps> = ({
size = "24px",
color = "currentColor",
...attributes
}) => {
return (
<svg
width={size}
height={size}
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...attributes}
>
<path
d="M3.415 16.585C3.70519 16.8753 4.04973 17.1055 4.42892 17.2626C4.80812 17.4197 5.21455 17.5006 5.625 17.5006M3.415 16.585C4.00105 17.1711 4.7962 17.5006 5.625 17.5006M3.415 16.585C2.82895 15.9989 2.5 15.2038 2.5 14.375V3.4375C2.5 2.92 2.92 2.5 3.4375 2.5H7.8125C8.33 2.5 8.75 2.92 8.75 3.4375V6.83083M5.625 17.5006C6.03545 17.5006 6.44188 17.4197 6.82108 17.2626C7.20027 17.1055 7.54481 16.8753 7.835 16.585M5.625 17.5006C6.4538 17.5006 7.24895 17.1711 7.835 16.585M5.625 17.5006L16.5625 17.5C17.08 17.5 17.5 17.08 17.5 16.5625V12.1875C17.5 11.67 17.08 11.25 16.5625 11.25H13.1692M7.835 16.585L13.1692 11.25M7.835 16.585C8.42105 15.9989 8.75 15.2038 8.75 14.375V6.83083M13.1692 11.25L15.5683 8.85C15.935 8.485 15.935 7.89167 15.5683 7.525L12.475 4.43083C12.1083 4.065 11.515 4.065 11.15 4.43083L8.75 6.83083M5.625 14.375H5.63167V14.3817H5.625V14.375Z"
stroke={color}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
)
}
export default SwatchIcon

View File

@@ -32,13 +32,15 @@ const BodyCard: React.FC<BodyCardProps> = ({
className,
children,
compact = false,
setBorders = false,
footerMinHeight = 24,
...rest
}) => {
const { isScrolled, scrollListener } = useScroll({ threshold: 16 })
return (
<div
className={clsx(
"rounded-rounded border bg-grey-0 border-grey-20 overflow-hidden flex flex-col h-full w-full",
"rounded-rounded bg-grey-0 border-grey-20 flex h-full w-full flex-col overflow-hidden border",
{ "min-h-[350px]": !compact },
className
)}
@@ -46,49 +48,63 @@ const BodyCard: React.FC<BodyCardProps> = ({
>
<div className="relative">
{isScrolled && (
<div className="absolute rounded-t-rounded top-0 left-0 right-0 bg-gradient-to-b from-grey-0 to-[rgba(255,255,255,0)] h-xlarge z-10" />
<div className="rounded-t-rounded from-grey-0 h-xlarge absolute top-0 left-0 right-0 z-10 bg-gradient-to-b to-[rgba(255,255,255,0)]" />
)}
</div>
<div
className="pt-medium px-xlarge flex flex-col grow overflow-y-auto"
className={clsx("flex grow flex-col overflow-y-auto", {
"border-grey-20 border-b border-solid": setBorders,
})}
onScroll={scrollListener}
>
<div className="flex items-center justify-between mt-6 h-xlarge">
{customHeader ? (
<div>{customHeader}</div>
) : title ? (
<h1 className="inter-xlarge-semibold text-grey-90">{title}</h1>
) : (
<div />
)}
<div
className={clsx("px-xlarge py-large", {
"border-grey-20 border-b border-solid": setBorders,
})}
>
<div className="flex items-center justify-between">
<div>
{customHeader ? (
<div>{customHeader}</div>
) : title ? (
<h1 className="inter-xlarge-semibold text-grey-90">{title}</h1>
) : (
<div />
)}
<div className="flex items-center space-x-2">
{status && status}
<Actionables
actions={actionables}
forceDropdown={forceDropdown}
customTrigger={customActionable}
/>
{subtitle && (
<h3 className="inter-small-regular text-grey-50 pt-1.5">
{subtitle}
</h3>
)}
</div>
<div className="flex items-center space-x-2">
{status && status}
<Actionables
actions={actionables}
forceDropdown={forceDropdown}
customTrigger={customActionable}
/>
</div>
</div>
</div>
{subtitle && (
<h3 className="inter-small-regular pt-1.5 text-grey-50">
{subtitle}
</h3>
)}
{children && (
<div
className={clsx("flex flex-col", {
"my-large grow": !compact,
})}
>
{children}
</div>
)}
<div className="px-xlarge">
{children && (
<div
className={clsx("flex flex-col", {
"my-large grow": !compact,
})}
>
{children}
</div>
)}
</div>
</div>
{events && events.length > 0 ? (
<div className="pb-large pt-base px-xlarge border-t border-grey-20">
<div className="flex items-center flex-row-reverse">
<div className="pb-large pt-base px-xlarge border-grey-20 border-t">
<div className="flex flex-row-reverse items-center">
{events.map((event, i: React.Key) => {
return (
<Button
@@ -106,7 +122,7 @@ const BodyCard: React.FC<BodyCardProps> = ({
</div>
</div>
) : (
<div className="min-h-[24px]" />
<div className={`min-h-[${footerMinHeight}px]`} />
)}
</div>
)

View File

@@ -1,5 +1,5 @@
import { useAdminStore } from "medusa-react"
import { useState } from "react"
import React, { useState } from "react"
import { useFeatureFlag } from "../../../providers/feature-flag-provider"
import BuildingsIcon from "../../fundamentals/icons/buildings-icon"
import CartIcon from "../../fundamentals/icons/cart-icon"
@@ -8,15 +8,17 @@ import GearIcon from "../../fundamentals/icons/gear-icon"
import GiftIcon from "../../fundamentals/icons/gift-icon"
import SaleIcon from "../../fundamentals/icons/sale-icon"
import TagIcon from "../../fundamentals/icons/tag-icon"
import SwatchIcon from "../../fundamentals/icons/swatch-icon"
import UsersIcon from "../../fundamentals/icons/users-icon"
import SidebarMenuItem from "../../molecules/sidebar-menu-item"
import UserMenu from "../../molecules/user-menu"
const ICON_SIZE = 20
const Sidebar = () => {
const Sidebar: React.FC = () => {
const [currentlyOpen, setCurrentlyOpen] = useState(-1)
const { isFeatureEnabled } = useFeatureFlag()
const { store } = useAdminStore()
const triggerHandler = () => {
@@ -30,8 +32,6 @@ const Sidebar = () => {
// infinite updates, and we do not want the variable to be free floating.
triggerHandler.id = 0
const { isFeatureEnabled } = useFeatureFlag()
const inventoryEnabled =
isFeatureEnabled("inventoryService") &&
isFeatureEnabled("stockLocationService")
@@ -63,6 +63,14 @@ const Sidebar = () => {
text={"Products"}
triggerHandler={triggerHandler}
/>
{isFeatureEnabled("product_categories") && (
<SidebarMenuItem
pageLink={"/a/product-categories"}
icon={<SwatchIcon size={ICON_SIZE} />}
text={"Categories"}
triggerHandler={triggerHandler}
/>
)}
<SidebarMenuItem
pageLink={"/a/customers"}
icon={<UsersIcon size={ICON_SIZE} />}

View File

@@ -0,0 +1,13 @@
import { Route, Routes } from "react-router-dom"
import ProductCategoryIndex from "./pages"
const ProductCategories = () => {
return (
<Routes>
<Route index element={<ProductCategoryIndex />} />
</Routes>
)
}
export default ProductCategories

View File

@@ -0,0 +1,54 @@
import { createContext } from "react"
import BodyCard from "../../../components/organisms/body-card"
/**
* Product categories empty state placeholder.
*/
function ProductCategoriesEmptyState() {
return (
<div className="flex min-h-[600px] items-center justify-center">
<p className="text-grey-40">
No product categories yet, use the above button to create your first
category.
</p>
</div>
)
}
export const ProductCategoriesContext = createContext<{}>({} as any)
/**
* Product category index page container.
*/
function ProductCategoryPage() {
const actions = [
{
label: "Add category",
onClick: () => {},
},
]
const context = {}
return (
<ProductCategoriesContext.Provider value={context}>
<div className="flex h-full grow flex-col">
<div className="flex w-full grow flex-col">
<BodyCard
className="h-full"
title="Product Categories"
subtitle="Helps you to keep your products organized."
actionables={actions}
footerMinHeight={40}
setBorders
>
<ProductCategoriesEmptyState />
</BodyCard>
</div>
</div>
</ProductCategoriesContext.Provider>
)
}
export default ProductCategoryPage

View File

@@ -20,6 +20,7 @@ import PublishableApiKeys from "../domain/publishable-api-keys"
import SalesChannels from "../domain/sales-channels"
import Settings from "../domain/settings"
import { AnalyticsProvider } from "../providers/analytics-provider"
import ProductCategories from "../domain/product-categories"
const IndexPage = () => {
const navigate = useNavigate()
@@ -42,6 +43,10 @@ const DashboardRoutes = () => {
<Routes>
<Route path="oauth/:app_name" element={<Oauth />} />
<Route path="products/*" element={<ProductsRoute />} />
<Route
path="product-categories/*"
element={<ProductCategories />}
/>
<Route path="collections/*" element={<Collections />} />
<Route path="gift-cards/*" element={<GiftCards />} />
<Route path="orders/*" element={<Orders />} />