Upload folder using huggingface_hub
Browse files- client/src/components/Layout.tsx +25 -1
- client/src/pages/Profile.tsx +21 -1
client/src/components/Layout.tsx
CHANGED
|
@@ -13,6 +13,12 @@ interface User {
|
|
| 13 |
|
| 14 |
const Layout: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
| 15 |
const location = useLocation();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16 |
const [isTransitioning] = useState(false);
|
| 17 |
const userData = localStorage.getItem('user');
|
| 18 |
const user: User | null = userData ? JSON.parse(userData) : null;
|
|
@@ -67,6 +73,18 @@ const Layout: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
|
| 67 |
// eslint-disable-next-line react-hooks/exhaustive-deps
|
| 68 |
}, [location.pathname]);
|
| 69 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 70 |
// Admin unread message badge (non-invasive)
|
| 71 |
useEffect(() => {
|
| 72 |
let timer: any;
|
|
@@ -145,8 +163,14 @@ const Layout: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
|
| 145 |
{ name: 'Feedback', href: '/feedback', icon: ChatBubbleLeftRightIcon },
|
| 146 |
];
|
| 147 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 148 |
// Hide Slides for visitors
|
| 149 |
-
if (!user ||
|
| 150 |
navigation = navigation.filter(item => item.name !== 'Slides');
|
| 151 |
}
|
| 152 |
|
|
|
|
| 13 |
|
| 14 |
const Layout: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
| 15 |
const location = useLocation();
|
| 16 |
+
const [viewMode, setViewMode] = useState<'admin' | 'student' | 'auto'>(() => {
|
| 17 |
+
try {
|
| 18 |
+
const saved = localStorage.getItem('viewMode') as any;
|
| 19 |
+
return saved === 'admin' || saved === 'student' ? saved : 'auto';
|
| 20 |
+
} catch { return 'auto'; }
|
| 21 |
+
});
|
| 22 |
const [isTransitioning] = useState(false);
|
| 23 |
const userData = localStorage.getItem('user');
|
| 24 |
const user: User | null = userData ? JSON.parse(userData) : null;
|
|
|
|
| 73 |
// eslint-disable-next-line react-hooks/exhaustive-deps
|
| 74 |
}, [location.pathname]);
|
| 75 |
|
| 76 |
+
// React to external view mode changes (from Manage toggle)
|
| 77 |
+
useEffect(() => {
|
| 78 |
+
const handler = (e: any) => {
|
| 79 |
+
const mode = e?.detail;
|
| 80 |
+
if (mode === 'admin' || mode === 'student') {
|
| 81 |
+
setViewMode(mode);
|
| 82 |
+
}
|
| 83 |
+
};
|
| 84 |
+
window.addEventListener('view-mode-change', handler as any);
|
| 85 |
+
return () => window.removeEventListener('view-mode-change', handler as any);
|
| 86 |
+
}, []);
|
| 87 |
+
|
| 88 |
// Admin unread message badge (non-invasive)
|
| 89 |
useEffect(() => {
|
| 90 |
let timer: any;
|
|
|
|
| 163 |
{ name: 'Feedback', href: '/feedback', icon: ChatBubbleLeftRightIcon },
|
| 164 |
];
|
| 165 |
|
| 166 |
+
// Effective role based on viewMode
|
| 167 |
+
const effectiveRole = (() => {
|
| 168 |
+
if (viewMode === 'auto') return user?.role;
|
| 169 |
+
return viewMode === 'student' ? 'student' : 'admin';
|
| 170 |
+
})();
|
| 171 |
+
|
| 172 |
// Hide Slides for visitors
|
| 173 |
+
if (!user || effectiveRole === 'visitor') {
|
| 174 |
navigation = navigation.filter(item => item.name !== 'Slides');
|
| 175 |
}
|
| 176 |
|
client/src/pages/Profile.tsx
CHANGED
|
@@ -469,6 +469,26 @@ const Manage: React.FC = () => {
|
|
| 469 |
<span className="text-sm text-gray-500">
|
| 470 |
Admin • {user.email}
|
| 471 |
</span>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 472 |
<button
|
| 473 |
onClick={handleLogout}
|
| 474 |
className="bg-red-600 hover:bg-red-700 text-white px-4 py-2 rounded-md text-sm font-medium"
|
|
@@ -482,7 +502,7 @@ const Manage: React.FC = () => {
|
|
| 482 |
{/* Login Summary removed as requested */}
|
| 483 |
|
| 484 |
{/* Admin Management Sections */}
|
| 485 |
-
<div className="grid grid-cols-1
|
| 486 |
{/* User Management */}
|
| 487 |
<div className="bg-white rounded-lg shadow p-6">
|
| 488 |
<div className="flex items-center mb-4">
|
|
|
|
| 469 |
<span className="text-sm text-gray-500">
|
| 470 |
Admin • {user.email}
|
| 471 |
</span>
|
| 472 |
+
<div className="flex items-center bg-gray-100 rounded-md p-1 text-xs">
|
| 473 |
+
<button
|
| 474 |
+
onClick={() => {
|
| 475 |
+
try { localStorage.setItem('viewMode', 'admin'); } catch {}
|
| 476 |
+
window.dispatchEvent(new CustomEvent('view-mode-change', { detail: 'admin' } as any));
|
| 477 |
+
}}
|
| 478 |
+
className="px-2 py-1 rounded-sm font-medium text-gray-700 hover:bg-white"
|
| 479 |
+
>
|
| 480 |
+
Admin view
|
| 481 |
+
</button>
|
| 482 |
+
<button
|
| 483 |
+
onClick={() => {
|
| 484 |
+
try { localStorage.setItem('viewMode', 'student'); } catch {}
|
| 485 |
+
window.dispatchEvent(new CustomEvent('view-mode-change', { detail: 'student' } as any));
|
| 486 |
+
}}
|
| 487 |
+
className="px-2 py-1 rounded-sm font-medium text-gray-700 hover:bg-white"
|
| 488 |
+
>
|
| 489 |
+
Student view
|
| 490 |
+
</button>
|
| 491 |
+
</div>
|
| 492 |
<button
|
| 493 |
onClick={handleLogout}
|
| 494 |
className="bg-red-600 hover:bg-red-700 text-white px-4 py-2 rounded-md text-sm font-medium"
|
|
|
|
| 502 |
{/* Login Summary removed as requested */}
|
| 503 |
|
| 504 |
{/* Admin Management Sections */}
|
| 505 |
+
<div className="grid grid-cols-1 gap-6 mb-8">
|
| 506 |
{/* User Management */}
|
| 507 |
<div className="bg-white rounded-lg shadow p-6">
|
| 508 |
<div className="flex items-center mb-4">
|