Files
ihasmail/web/src/views/admin/AdminNav.tsx
T
jcoffey-dev 7c0e278ee8 Move Administration's section list into the folder pane
Administration's pages are tables, and the Settings-style second column
took width they need. The list of sections -- Directory > Accounts,
Mail > Domains -- now sits in the folder pane where Mail keeps its folders,
and the page is the open section alone, up to 1120px wide.

On a phone the list is in the drawer like every other section's, so a bare
/admin opens the first section rather than a page that is only a list. The
back link it needed is gone.
2026-09-13 16:27:30 -07:00

49 lines
2.0 KiB
TypeScript

import type { ReactNode } from "react";
import { Link, useLocation } from "wouter";
import { Globe, User } from "lucide-react";
import { adminSections, type AdminSection } from "@/lib/adminAccess";
import { t } from "@/lib/i18n";
import { usePermissions } from "./usePermissions";
export const ADMIN_SECTIONS: Record<AdminSection, { group: string; label: string; icon: ReactNode }> = {
accounts: { group: "Directory", label: "Accounts", icon: <User size={20} /> },
domains: { group: "Mail", label: "Domains", icon: <Globe size={20} /> },
};
/** The section the address names, or the first the role can open. */
export function currentAdminSection(allowed: AdminSection[], requested: string | undefined): AdminSection | undefined {
return allowed.find((s) => s === requested) ?? allowed[0];
}
/**
* Administration's sections, in the folder pane.
*
* Settings keeps its list inside the page; Administration's pages are tables
* that want the width, so the list lives where Mail keeps its folders. On a
* phone that puts it in the drawer, which is where every other section's list
* already is. Only sections the role can read are listed.
*/
export function AdminNav() {
const [location] = useLocation();
const allowed = adminSections(usePermissions());
const current = currentAdminSection(allowed, location.split("/")[2]);
const groups = [...new Set(allowed.map((s) => ADMIN_SECTIONS[s].group))];
return (
<nav aria-label={t("Administration")}>
{groups.map((group) => (
<div key={group}>
<div className="nav-section"><span>{t(group)}</span></div>
{allowed
.filter((s) => ADMIN_SECTIONS[s].group === group)
.map((s) => (
<Link key={s} href={`/admin/${s}`} className={`nav-item ${current === s ? "active" : ""}`} title={t(ADMIN_SECTIONS[s].label)} aria-current={current === s ? "page" : undefined}>
{ADMIN_SECTIONS[s].icon}
<span className="nav-label">{t(ADMIN_SECTIONS[s].label)}</span>
</Link>
))}
</div>
))}
</nav>
);
}