clean ui
This commit is contained in:
@@ -1,17 +1,27 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { DashboardTab } from './components/DashboardTab';
|
||||
import { ClassesTab } from './components/ClassesTab';
|
||||
import { StudentsTab } from './components/StudentsTab';
|
||||
import { LearningTab } from './components/LearningTab';
|
||||
import { ExamsTab } from './components/ExamsTab';
|
||||
import { ExamRoomWorkspace } from './components/ExamRoomWorkspace';
|
||||
import { NetworkTab } from './components/NetworkTab';
|
||||
import { EmailDomainsTab, MyAccountTab } from './components/AccountsTab';
|
||||
import { SystemTab } from './components/SystemTab';
|
||||
import { MyAccountTab } from './components/AccountsTab';
|
||||
import { ChatWidget } from './components/ChatWidget';
|
||||
import { StaffChatSocket } from './hooks/useStaffChatSocket';
|
||||
import { ClassWorkspace } from './components/ClassWorkspace';
|
||||
import { NavHistoryBar, useRoute } from './components/NavHistoryBar';
|
||||
import { goBack, navigate, parseRoute, pushNav, TAB_LABELS, type TabId } from './navigation';
|
||||
import {
|
||||
goBack,
|
||||
navigate,
|
||||
navigateSystem,
|
||||
parseRoute,
|
||||
pushNav,
|
||||
SYSTEM_SECTION_LABELS,
|
||||
TAB_LABELS,
|
||||
type SystemSection,
|
||||
type TabId,
|
||||
} from './navigation';
|
||||
import { useAuth } from './auth/AuthContext';
|
||||
|
||||
const IconDashboard = () => (
|
||||
@@ -51,36 +61,54 @@ const IconExam = () => (
|
||||
</svg>
|
||||
);
|
||||
|
||||
const IconNetwork = () => (
|
||||
const IconSystem = () => (
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<path d="M5 12.55a11 11 0 0 1 14.08 0" />
|
||||
<path d="M1.42 9a16 16 0 0 1 21.16 0" />
|
||||
<path d="M8.53 16.11a6 6 0 0 1 6.95 0" />
|
||||
<circle cx="12" cy="20" r="1" />
|
||||
<circle cx="12" cy="12" r="3" />
|
||||
<path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42" />
|
||||
</svg>
|
||||
);
|
||||
|
||||
const IconEmail = () => (
|
||||
const IconMenu = () => (
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<rect x="2" y="4" width="20" height="16" rx="2" />
|
||||
<path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7" />
|
||||
<line x1="3" y1="12" x2="21" y2="12" /><line x1="3" y1="6" x2="21" y2="6" /><line x1="3" y1="18" x2="21" y2="18" />
|
||||
</svg>
|
||||
);
|
||||
|
||||
const SYSTEM_NAV: { section: SystemSection }[] = [
|
||||
{ section: 'organization' },
|
||||
{ section: 'network' },
|
||||
{ section: 'templates' },
|
||||
];
|
||||
|
||||
function App() {
|
||||
const route = useRoute();
|
||||
const { staff, logout } = useAuth();
|
||||
const [sidebarOpen, setSidebarOpen] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const initial = parseRoute();
|
||||
if (initial.classId || initial.examId) {
|
||||
return;
|
||||
}
|
||||
pushNav({ kind: 'tab', tab: initial.tab, label: TAB_LABELS[initial.tab] });
|
||||
const label =
|
||||
initial.tab === 'system'
|
||||
? `Hệ thống · ${SYSTEM_SECTION_LABELS[initial.systemSection]}`
|
||||
: TAB_LABELS[initial.tab];
|
||||
pushNav({
|
||||
kind: 'tab',
|
||||
tab: initial.tab,
|
||||
systemSection: initial.tab === 'system' ? initial.systemSection : undefined,
|
||||
label,
|
||||
});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
setSidebarOpen(false);
|
||||
}, [route.tab, route.classId, route.examId, route.systemSection]);
|
||||
|
||||
const setActiveTab = (tab: string) => {
|
||||
navigate(tab as TabId);
|
||||
setSidebarOpen(false);
|
||||
};
|
||||
|
||||
const handleBackFromWorkspace = () => {
|
||||
@@ -89,9 +117,39 @@ function App() {
|
||||
|
||||
const inWorkspace = Boolean(route.classId || route.examId);
|
||||
|
||||
const classesActive = route.tab === 'classes';
|
||||
const learningActive = route.tab === 'learning';
|
||||
const examsActive = route.tab === 'exams' || route.examId != null;
|
||||
const systemActive = route.tab === 'system' && !inWorkspace;
|
||||
|
||||
const goSystem = (section: SystemSection) => {
|
||||
navigateSystem(section);
|
||||
setSidebarOpen(false);
|
||||
};
|
||||
|
||||
const navBtn = (active: boolean) => `nav-btn${active ? ' active' : ''}`;
|
||||
|
||||
return (
|
||||
<>
|
||||
<aside className="sidebar">
|
||||
<button
|
||||
type="button"
|
||||
className="mobile-menu-btn"
|
||||
aria-label="Mở menu"
|
||||
onClick={() => setSidebarOpen(true)}
|
||||
>
|
||||
<IconMenu />
|
||||
</button>
|
||||
|
||||
{sidebarOpen && (
|
||||
<button
|
||||
type="button"
|
||||
className="sidebar-backdrop"
|
||||
aria-label="Đóng menu"
|
||||
onClick={() => setSidebarOpen(false)}
|
||||
/>
|
||||
)}
|
||||
|
||||
<aside className={`sidebar${sidebarOpen ? ' sidebar--open' : ''}`}>
|
||||
<div className="brand">
|
||||
<img src="/logo.jpeg" alt="Simple Care" className="brand-logo-img" />
|
||||
<div className="brand-text">
|
||||
@@ -105,8 +163,8 @@ function App() {
|
||||
<div className="nav-header">Tổng quan</div>
|
||||
<li className="nav-item">
|
||||
<button
|
||||
className={`nav-btn ${route.tab === 'dashboard' && !inWorkspace ? 'active' : ''}`}
|
||||
onClick={() => navigate('dashboard')}
|
||||
className={navBtn(route.tab === 'dashboard' && !inWorkspace)}
|
||||
onClick={() => setActiveTab('dashboard')}
|
||||
>
|
||||
<span className="nav-icon"><IconDashboard /></span>
|
||||
Tổng quan
|
||||
@@ -115,18 +173,15 @@ function App() {
|
||||
|
||||
<div className="nav-header">CSDL liên kết</div>
|
||||
<li className="nav-item">
|
||||
<button
|
||||
className={`nav-btn ${route.tab === 'classes' && !inWorkspace ? 'active' : ''}`}
|
||||
onClick={() => navigate('classes')}
|
||||
>
|
||||
<button className={navBtn(classesActive)} onClick={() => setActiveTab('classes')}>
|
||||
<span className="nav-icon"><IconClass /></span>
|
||||
Lớp học
|
||||
</button>
|
||||
</li>
|
||||
<li className="nav-item">
|
||||
<button
|
||||
className={`nav-btn ${route.tab === 'students' && !inWorkspace ? 'active' : ''}`}
|
||||
onClick={() => navigate('students')}
|
||||
className={navBtn(route.tab === 'students' && !inWorkspace)}
|
||||
onClick={() => setActiveTab('students')}
|
||||
>
|
||||
<span className="nav-icon"><IconStudent /></span>
|
||||
Sinh viên
|
||||
@@ -135,19 +190,13 @@ function App() {
|
||||
|
||||
<div className="nav-header">Quản lý học tập</div>
|
||||
<li className="nav-item">
|
||||
<button
|
||||
className={`nav-btn ${route.tab === 'learning' && !inWorkspace ? 'active' : ''}`}
|
||||
onClick={() => navigate('learning')}
|
||||
>
|
||||
<button className={navBtn(learningActive)} onClick={() => setActiveTab('learning')}>
|
||||
<span className="nav-icon"><IconLearning /></span>
|
||||
Phòng Học
|
||||
</button>
|
||||
</li>
|
||||
<li className="nav-item">
|
||||
<button
|
||||
className={`nav-btn ${route.tab === 'exams' && !inWorkspace ? 'active' : ''}`}
|
||||
onClick={() => navigate('exams')}
|
||||
>
|
||||
<button className={navBtn(examsActive)} onClick={() => setActiveTab('exams')}>
|
||||
<span className="nav-icon"><IconExam /></span>
|
||||
Phòng thi
|
||||
</button>
|
||||
@@ -156,22 +205,25 @@ function App() {
|
||||
<div className="nav-header">Hệ thống</div>
|
||||
<li className="nav-item">
|
||||
<button
|
||||
className={`nav-btn ${route.tab === 'email-domains' && !inWorkspace ? 'active' : ''}`}
|
||||
onClick={() => navigate('email-domains')}
|
||||
className={navBtn(systemActive)}
|
||||
onClick={() => goSystem('organization')}
|
||||
>
|
||||
<span className="nav-icon"><IconEmail /></span>
|
||||
Đuôi email
|
||||
</button>
|
||||
</li>
|
||||
<li className="nav-item">
|
||||
<button
|
||||
className={`nav-btn ${route.tab === 'network' && !inWorkspace ? 'active' : ''}`}
|
||||
onClick={() => navigate('network')}
|
||||
>
|
||||
<span className="nav-icon"><IconNetwork /></span>
|
||||
Quản lý mạng
|
||||
<span className="nav-icon"><IconSystem /></span>
|
||||
Quản lý hệ thống
|
||||
</button>
|
||||
</li>
|
||||
<ul className="nav-sub">
|
||||
{SYSTEM_NAV.map(({ section }) => (
|
||||
<li key={section} className="nav-item">
|
||||
<button
|
||||
className={navBtn(systemActive && route.systemSection === section)}
|
||||
onClick={() => goSystem(section)}
|
||||
>
|
||||
{SYSTEM_SECTION_LABELS[section]}
|
||||
</button>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
@@ -179,7 +231,7 @@ function App() {
|
||||
<button
|
||||
type="button"
|
||||
className={`sidebar-user-btn ${route.tab === 'profile' && !inWorkspace ? 'active' : ''}`}
|
||||
onClick={() => navigate('profile')}
|
||||
onClick={() => setActiveTab('profile')}
|
||||
title="Tài khoản của tôi"
|
||||
>
|
||||
<span className="sidebar-user-name">
|
||||
@@ -213,8 +265,7 @@ function App() {
|
||||
{route.tab === 'students' && <StudentsTab />}
|
||||
{route.tab === 'learning' && <LearningTab />}
|
||||
{route.tab === 'exams' && <ExamsTab />}
|
||||
{route.tab === 'network' && <NetworkTab />}
|
||||
{route.tab === 'email-domains' && <EmailDomainsTab />}
|
||||
{route.tab === 'system' && <SystemTab />}
|
||||
{route.tab === 'profile' && <MyAccountTab />}
|
||||
</>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user