metis-desk/modules/companies/src/web/components/workspace-sidebar.tsx

142 lines
4.7 KiB
TypeScript
Raw Normal View History

2026-10-08 14:43:34 +00:00
import { Button } from "@repo/shadcn-ui/components/button";
import {
Building2Icon,
ChevronRightIcon,
DatabaseIcon,
HomeIcon,
SettingsIcon,
TicketIcon,
WrenchIcon,
} from "@repo/shadcn-ui/lib/icons";
import type { ComponentProps } from "react";
import { useTranslation } from "react-i18next";
import type { WorkspaceContent } from "./workspace-content";
import type { WorkspaceLocation } from "./workspace-location";
export function WorkspaceSidebar({
companies,
current,
catalog,
onNavigate,
onSelectCompany,
onSelectCatalog,
onSettings,
}: {
companies: readonly { id: string; name: string }[];
onNavigate: (location: WorkspaceLocation) => void;
onSelectCompany: (id: string) => void;
current: WorkspaceLocation;
catalog: ComponentProps<typeof WorkspaceContent>["catalog"];
onSelectCatalog: (catalog: ComponentProps<typeof WorkspaceContent>["catalog"]) => void;
onSettings: () => void;
}) {
const { t } = useTranslation("companies");
const { t: coreTranslation } = useTranslation("core");
const { t: resourceTranslation } = useTranslation("resources");
const { t: assetTranslation } = useTranslation("assets");
const { t: accessTranslation } = useTranslation("access");
return (
<aside className="desk-sidebar">
<div className="desk-brand">
<svg aria-hidden="true" viewBox="0 0 36 30">
<path
d="M5 24 13 7l9 17 9-18"
fill="none"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="7"
/>
</svg>
<span>Metis Desk</span>
</div>
<nav aria-label={t("companySpaces")} className="desk-company-rail">
{(
[
["home", "dashboard.title", HomeIcon],
["directory", "title", Building2Icon],
["catalogs", "shell.catalogs", DatabaseIcon],
["tickets", "shell.tickets", TicketIcon],
["interventions", "shell.interventions", WrenchIcon],
] as const
).map(([area, label, Icon]) => (
<Button
aria-label={t(label)}
aria-pressed={current.area === area}
className="desk-space-button"
key={area}
onClick={() => onNavigate({ area })}
variant="ghost"
>
<Icon aria-hidden="true" />
<span>{t(label)}</span>
{area === "catalogs" && (
<ChevronRightIcon aria-hidden="true" className="desk-nav-chevron" />
)}
</Button>
))}
{current.area === "catalogs" && (
<nav aria-label={t("globalCatalogs")} className="desk-catalog-navigation">
<>
<Button
aria-pressed={catalog === "access"}
onClick={() => onSelectCatalog("access")}
variant="ghost"
>
{accessTranslation("catalogTitle")}
</Button>
<Button
aria-pressed={catalog === "assets"}
onClick={() => onSelectCatalog("assets")}
variant="ghost"
>
{assetTranslation("title")}
</Button>
<Button
aria-pressed={catalog === "intervention-templates"}
onClick={() => onSelectCatalog("intervention-templates")}
variant="ghost"
>
{t("interventionTemplates.title")}
</Button>
<Button
aria-pressed={catalog === "brands"}
onClick={() => onSelectCatalog("brands")}
variant="ghost"
>
{assetTranslation("brands.title")}
</Button>
<Button
aria-pressed={catalog === "resources"}
onClick={() => onSelectCatalog("resources")}
variant="ghost"
>
{resourceTranslation("title")}
</Button>
</>
</nav>
)}
<Button className="desk-space-button" onClick={onSettings} variant="ghost">
<SettingsIcon aria-hidden="true" />
<span>{coreTranslation("shell.settings")}</span>
</Button>
<div className="desk-rail-separator" />
{companies.map((company) => (
<Button
aria-label={company.name}
aria-pressed={current.area === "company" && current.id === company.id}
className="desk-space-button"
key={company.id}
onClick={() => onSelectCompany(company.id)}
title={company.name}
variant="ghost"
>
<Building2Icon aria-hidden="true" />
<span>{company.name}</span>
</Button>
))}
</nav>
</aside>
);
}