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

chore(dashboard): render main layout as home page for v2 #6823

Merged
merged 4 commits into from
Mar 26, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
@@ -0,0 +1 @@
export * from "./main-layout"
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
import {
Buildings,
ChevronDownMini,
CurrencyDollar,
MinusMini,
ReceiptPercent,
ShoppingCart,
SquaresPlus,
Tag,
Users,
} from "@medusajs/icons"
import { Avatar, Text } from "@medusajs/ui"
import * as Collapsible from "@radix-ui/react-collapsible"
import { useTranslation } from "react-i18next"
import { useV2Store } from "../../../lib/api-v2"

import { Skeleton } from "../../common/skeleton"
import { NavItem, NavItemProps } from "../../layout/nav-item"
import { Shell } from "../../layout/shell"

import extensions from "medusa-admin:routes/links"

export const MainLayout = () => {
return (
<Shell>
<MainSidebar />
</Shell>
)
}

const MainSidebar = () => {
return (
<aside className="flex flex-1 flex-col justify-between overflow-y-auto">
<div className="flex flex-1 flex-col">
<div className="bg-ui-bg-subtle sticky top-0">
<Header />
<div className="px-3">
<div className="border-ui-border-strong h-px w-full border-b border-dashed" />
</div>
</div>
<CoreRouteSection />
<ExtensionRouteSection />
</div>
</aside>
)
}

const Header = () => {
const { store, isError, error } = useV2Store({})
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

only thing that changes here is the v2Store call. Lmk if this is the desired approach.


const name = store?.name
const fallback = store?.name?.slice(0, 1).toUpperCase()

if (isError) {
throw error
}

return (
<div className="w-full px-3 py-2">
<div className="flex items-center p-1 md:pr-2">
<div className="flex items-center gap-x-3">
{fallback ? (
<Avatar variant="squared" fallback={fallback} />
) : (
<Skeleton className="h-8 w-8 rounded-md" />
)}
{name ? (
<Text size="small" weight="plus" leading="compact">
{store.name}
</Text>
) : (
<Skeleton className="h-[9px] w-[120px]" />
)}
</div>
</div>
</div>
)
}

const useCoreRoutes = (): Omit<NavItemProps, "pathname">[] => {
const { t } = useTranslation()

return [
{
icon: <ShoppingCart />,
label: t("orders.domain"),
to: "/orders",
items: [
{
label: t("draftOrders.domain"),
to: "/draft-orders",
},
],
},
{
icon: <Tag />,
label: t("products.domain"),
to: "/products",
items: [
{
label: t("collections.domain"),
to: "/collections",
},
{
label: t("categories.domain"),
to: "/categories",
},
{
label: t("giftCards.domain"),
to: "/gift-cards",
},
],
},
{
icon: <Buildings />,
label: t("inventory.domain"),
to: "/inventory",
items: [
{
label: t("reservations.domain"),
to: "/reservations",
},
],
},
{
icon: <Users />,
label: t("customers.domain"),
to: "/customers",
items: [
{
label: t("customerGroups.domain"),
to: "/customer-groups",
},
],
},
{
icon: <ReceiptPercent />,
label: t("discounts.domain"),
to: "/discounts",
},
{
icon: <CurrencyDollar />,
label: t("pricing.domain"),
to: "/pricing",
},
]
}

const CoreRouteSection = () => {
const coreRoutes = useCoreRoutes()

return (
<nav className="flex flex-col gap-y-1 py-2">
{coreRoutes.map((route) => {
return <NavItem key={route.to} {...route} />
})}
</nav>
)
}

const ExtensionRouteSection = () => {
if (!extensions.links || extensions.links.length === 0) {
return null
}

return (
<div>
<div className="px-3">
<div className="border-ui-border-strong h-px w-full border-b border-dashed" />
</div>
<div className="flex flex-col gap-y-1 py-2">
<Collapsible.Root defaultOpen>
<div className="px-4">
<Collapsible.Trigger asChild className="group/trigger">
<button className="text-ui-fg-subtle flex w-full items-center justify-between px-2">
<Text size="xsmall" weight="plus" leading="compact">
Extensions
</Text>
<div className="text-ui-fg-muted">
<ChevronDownMini className="group-data-[state=open]/trigger:hidden" />
<MinusMini className="group-data-[state=closed]/trigger:hidden" />
</div>
</button>
</Collapsible.Trigger>
</div>
<Collapsible.Content>
<div className="flex flex-col gap-y-1 py-1 pb-4">
{extensions.links.map((link) => {
return (
<NavItem
key={link.path}
to={link.path}
label={link.label}
icon={link.icon ? <link.icon /> : <SquaresPlus />}
type="extension"
/>
)
})}
</div>
</Collapsible.Content>
</Collapsible.Root>
</div>
</div>
)
}
2 changes: 1 addition & 1 deletion packages/admin-next/dashboard/src/lib/api-v2/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export const useV2Store = ({ initialData }: { initialData?: any }) => {
{ initialData }
)

const store = data.stores[0]
const store = data?.stores[0]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: not really related to your PR, but make sense to manually set the error in the case where isLoading is false and the stores array is empty, to have the same effect as if the current useAdminStore endpoint fails. Otherwise, you might end up with a false positive, where loading is completed and no error is thrown, but at the same time store is undefined, causing the admin to break.


return { store, isLoading, isError, error }
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { Navigate, RouteObject, useLocation } from "react-router-dom"
import { MainLayout } from "../../components/layout-v2/main-layout"
import { SettingsLayout } from "../../components/layout/settings-layout"

import { Outlet } from "react-router-dom"

import { SidebarProvider } from "../sidebar-provider"
import { SearchProvider } from "../search-provider"
import { ErrorBoundary } from "../../components/error/error-boundary"
import { Spinner } from "@medusajs/icons"
import { ErrorBoundary } from "../../components/error/error-boundary"
import { useV2Session } from "../../lib/api-v2"
import { SearchProvider } from "../search-provider"
import { SidebarProvider } from "../sidebar-provider"

export const ProtectedRoute = () => {
const { user, isLoading } = useV2Session()
Expand Down Expand Up @@ -52,6 +53,30 @@ export const v2Routes: RouteObject[] = [
path: "*",
lazy: () => import("../../routes/no-match"),
},
{
element: <ProtectedRoute />,
errorElement: <ErrorBoundary />,
children: [
{
path: "/",
element: <MainLayout />,
children: [
{
path: "/orders",
handle: {
crumb: () => "Orders",
},
children: [
{
path: "",
lazy: () => import("../../v2-routes/orders/order-list"),
},
],
},
],
},
],
},
{
element: <ProtectedRoute />,
errorElement: <ErrorBoundary />,
Expand Down
3 changes: 1 addition & 2 deletions packages/admin-next/dashboard/src/v2-routes/home/home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@ import { useNavigate } from "react-router-dom"
export const Home = () => {
const navigate = useNavigate()

// Currently, the home page simply redirects to the settings page
useEffect(() => {
navigate("/settings", { replace: true })
navigate("/orders", { replace: true })
}, [navigate])

return <div />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { OrderList as Component } from "./order-list"
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// TODO: This is just a placeholder to render the actual "home" page
// after logging in. Replace this with the actual order components when ready
export const OrderList = () => {
return <div className="flex w-full flex-col gap-y-2"></div>
}
Loading