1
This commit is contained in:
parent
cf695efb38
commit
c34f257fd0
@ -28,20 +28,12 @@ import {
|
|||||||
DialogHeader,
|
DialogHeader,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
} from "@/components/ui/dialog";
|
} from "@/components/ui/dialog";
|
||||||
import {
|
|
||||||
Select,
|
|
||||||
SelectContent,
|
|
||||||
SelectItem,
|
|
||||||
SelectTrigger,
|
|
||||||
SelectValue,
|
|
||||||
} from "@/components/ui/select";
|
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
|
|
||||||
export function Header() {
|
export function Header() {
|
||||||
const { user, logout } = useAuth();
|
const { user, logout } = useAuth();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { activeClassId, activeClassName, canSwitchClass, availableClasses, setActiveClassId } =
|
const { activeClassName } = useActiveClass();
|
||||||
useActiveClass();
|
|
||||||
const { toggle } = useSidebar();
|
const { toggle } = useSidebar();
|
||||||
const { unreadCount, notifications, markRead, markAllRead, refresh } = useNotifications();
|
const { unreadCount, notifications, markRead, markAllRead, refresh } = useNotifications();
|
||||||
const [notifOpen, setNotifOpen] = useState(false);
|
const [notifOpen, setNotifOpen] = useState(false);
|
||||||
@ -52,9 +44,7 @@ export function Header() {
|
|||||||
const [newPassword, setNewPassword] = useState("");
|
const [newPassword, setNewPassword] = useState("");
|
||||||
const [confirmPassword, setConfirmPassword] = useState("");
|
const [confirmPassword, setConfirmPassword] = useState("");
|
||||||
const [passwordLoading, setPasswordLoading] = useState(false);
|
const [passwordLoading, setPasswordLoading] = useState(false);
|
||||||
const classDescriptor = activeClassName
|
const classDescriptor = activeClassName || "香港大学中国商业学院";
|
||||||
? activeClassName.split(" ").slice(0, 2).join(" ")
|
|
||||||
: "香港大学中国商业学院";
|
|
||||||
|
|
||||||
const handleChangePassword = async (e: React.FormEvent) => {
|
const handleChangePassword = async (e: React.FormEvent) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@ -99,32 +89,11 @@ export function Header() {
|
|||||||
<p className="text-[11px] uppercase tracking-[0.24em] text-[#94613e]">
|
<p className="text-[11px] uppercase tracking-[0.24em] text-[#94613e]">
|
||||||
HKU ICB
|
HKU ICB
|
||||||
</p>
|
</p>
|
||||||
<h2 className="truncate text-lg font-semibold text-[#4a1f1a]">
|
<h2 className="text-lg font-semibold text-[#4a1f1a]">
|
||||||
{classDescriptor}
|
{classDescriptor}
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
{canSwitchClass ? (
|
{activeClassName ? (
|
||||||
<Select
|
|
||||||
value={activeClassId ? String(activeClassId) : ""}
|
|
||||||
onValueChange={(v) => v && setActiveClassId(parseInt(v))}
|
|
||||||
>
|
|
||||||
<SelectTrigger className="w-56 border-[#d7c0a0] bg-white/75 shadow-none">
|
|
||||||
<SelectValue>
|
|
||||||
{activeClassId
|
|
||||||
? availableClasses.find((c) => c.id === activeClassId)?.name ||
|
|
||||||
"选择班级"
|
|
||||||
: "选择班级"}
|
|
||||||
</SelectValue>
|
|
||||||
</SelectTrigger>
|
|
||||||
<SelectContent>
|
|
||||||
{availableClasses.map((c) => (
|
|
||||||
<SelectItem key={c.id} value={String(c.id)}>
|
|
||||||
{c.name} ({c.cohort_year})
|
|
||||||
</SelectItem>
|
|
||||||
))}
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
) : activeClassName ? (
|
|
||||||
<span className="text-sm text-[#6f4b38] md:hidden">
|
<span className="text-sm text-[#6f4b38] md:hidden">
|
||||||
当前班级:<span className="font-medium text-[#4a1f1a]">{activeClassName}</span>
|
当前班级:<span className="font-medium text-[#4a1f1a]">{activeClassName}</span>
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@ -8,6 +8,13 @@ import { cn } from "@/lib/utils";
|
|||||||
import type { ClassPermission, UserRole } from "@/lib/types";
|
import type { ClassPermission, UserRole } from "@/lib/types";
|
||||||
import { useAuth } from "@/hooks/use-auth";
|
import { useAuth } from "@/hooks/use-auth";
|
||||||
import { hasClassPermission } from "@/lib/permissions";
|
import { hasClassPermission } from "@/lib/permissions";
|
||||||
|
import {
|
||||||
|
Select,
|
||||||
|
SelectContent,
|
||||||
|
SelectItem,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectValue,
|
||||||
|
} from "@/components/ui/select";
|
||||||
|
|
||||||
const navItems = [
|
const navItems = [
|
||||||
{ href: "/dashboard", label: "首页", icon: "M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6", moduleKey: undefined },
|
{ href: "/dashboard", label: "首页", icon: "M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6", moduleKey: undefined },
|
||||||
@ -32,7 +39,14 @@ export function Sidebar() {
|
|||||||
const pathname = usePathname();
|
const pathname = usePathname();
|
||||||
const { isOpen, close } = useSidebar();
|
const { isOpen, close } = useSidebar();
|
||||||
const { user } = useAuth();
|
const { user } = useAuth();
|
||||||
const { enabledModules, activeClassId } = useActiveClass();
|
const {
|
||||||
|
enabledModules,
|
||||||
|
activeClassId,
|
||||||
|
activeClassName,
|
||||||
|
canSwitchClass,
|
||||||
|
availableClasses,
|
||||||
|
setActiveClassId,
|
||||||
|
} = useActiveClass();
|
||||||
const visibleAdminItems = user
|
const visibleAdminItems = user
|
||||||
? adminItems.filter((item) => {
|
? adminItems.filter((item) => {
|
||||||
if (!item.roles.includes(user.role)) return false;
|
if (!item.roles.includes(user.role)) return false;
|
||||||
@ -75,6 +89,39 @@ export function Sidebar() {
|
|||||||
<div className="border-b border-sidebar-border px-6 pb-6 pt-7">
|
<div className="border-b border-sidebar-border px-6 pb-6 pt-7">
|
||||||
<h1 className="text-2xl font-semibold tracking-tight text-white">香港大学中国商业学院</h1>
|
<h1 className="text-2xl font-semibold tracking-tight text-white">香港大学中国商业学院</h1>
|
||||||
<p className="mt-1 text-sm text-white/65">HKU ICB</p>
|
<p className="mt-1 text-sm text-white/65">HKU ICB</p>
|
||||||
|
{activeClassName && (
|
||||||
|
<div className="mt-5 rounded-2xl border border-white/10 bg-white/[0.06] p-4">
|
||||||
|
<p className="text-[11px] uppercase tracking-[0.22em] text-white/38">
|
||||||
|
当前班级
|
||||||
|
</p>
|
||||||
|
<p className="mt-2 text-sm font-medium leading-6 text-white">
|
||||||
|
{activeClassName}
|
||||||
|
</p>
|
||||||
|
{canSwitchClass && availableClasses.length > 1 && (
|
||||||
|
<div className="mt-3">
|
||||||
|
<Select
|
||||||
|
value={activeClassId ? String(activeClassId) : ""}
|
||||||
|
onValueChange={(value) => value && setActiveClassId(Number(value))}
|
||||||
|
>
|
||||||
|
<SelectTrigger className="h-auto w-full rounded-xl border-white/12 bg-white/8 px-3 py-2 text-left text-sm text-white hover:bg-white/12">
|
||||||
|
<SelectValue>
|
||||||
|
{activeClassId
|
||||||
|
? availableClasses.find((item) => item.id === activeClassId)?.name ?? "切换班级"
|
||||||
|
: "切换班级"}
|
||||||
|
</SelectValue>
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent className="border-[#e2ccb0] bg-[#fffaf2]">
|
||||||
|
{availableClasses.map((item) => (
|
||||||
|
<SelectItem key={item.id} value={String(item.id)}>
|
||||||
|
{item.name} ({item.cohort_year})
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<nav className="flex-1 space-y-1 overflow-y-auto px-4 py-5">
|
<nav className="flex-1 space-y-1 overflow-y-auto px-4 py-5">
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user