add loading state in layout
This commit is contained in:
11
src/App.tsx
11
src/App.tsx
@@ -28,7 +28,7 @@ import { Toaster } from "./components/ui/sonner";
|
||||
import { Settings } from "lucide-react";
|
||||
|
||||
export default function App() {
|
||||
const [isAuthenticated, setIsAuthenticated] = useState(false);
|
||||
const [isAuthenticated, setIsAuthenticated] = useState<boolean | null>(null); // null = loading
|
||||
const [user, setUser] = useState({
|
||||
name: "Admin User",
|
||||
email: "admin@klc.edu",
|
||||
@@ -41,9 +41,7 @@ export default function App() {
|
||||
|
||||
useEffect(() => {
|
||||
const authToken = localStorage.getItem("klc_auth_token");
|
||||
if (authToken) {
|
||||
setIsAuthenticated(true);
|
||||
}
|
||||
setIsAuthenticated(!!authToken); // true if token exists, false otherwise
|
||||
}, []);
|
||||
|
||||
const login = () => {
|
||||
@@ -58,6 +56,11 @@ export default function App() {
|
||||
navigate("/login");
|
||||
};
|
||||
|
||||
if (isAuthenticated === null) {
|
||||
// while checking localStorage
|
||||
return <div className="flex justify-center items-center h-screen">Loading...</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-background">
|
||||
<Routes>
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Button } from '../ui/button';
|
||||
import {
|
||||
Home,
|
||||
FileText,
|
||||
GraduationCap,
|
||||
Users,
|
||||
Calendar,
|
||||
Globe,
|
||||
BarChart3,
|
||||
Settings,
|
||||
Menu,
|
||||
import {
|
||||
Home,
|
||||
FileText,
|
||||
GraduationCap,
|
||||
Users,
|
||||
Calendar,
|
||||
Globe,
|
||||
BarChart3,
|
||||
Settings,
|
||||
Menu,
|
||||
ChevronLeft,
|
||||
LogOut,
|
||||
User,
|
||||
@@ -20,7 +20,7 @@ import {
|
||||
ClipboardList,
|
||||
Target
|
||||
} from 'lucide-react';
|
||||
import {
|
||||
import {
|
||||
Breadcrumb,
|
||||
BreadcrumbItem,
|
||||
BreadcrumbLink,
|
||||
@@ -29,7 +29,7 @@ import {
|
||||
BreadcrumbSeparator,
|
||||
} from '../ui/breadcrumb';
|
||||
import { Avatar, AvatarFallback } from '../ui/avatar';
|
||||
import {
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
@@ -171,19 +171,19 @@ const navigationItems: NavigationItem[] = [
|
||||
}
|
||||
];
|
||||
|
||||
export function AuthenticatedLayout({
|
||||
children,
|
||||
currentRoute,
|
||||
// onNavigate,
|
||||
onLogout,
|
||||
user,
|
||||
breadcrumbs = []
|
||||
export function AuthenticatedLayout({
|
||||
children,
|
||||
currentRoute,
|
||||
onLogout,
|
||||
user,
|
||||
breadcrumbs = []
|
||||
}: AuthenticatedLayoutProps) {
|
||||
const [sidebarCollapsed, setSidebarCollapsed] = useState(false);
|
||||
const navigate = useNavigate(); // Move useNavigate to the top level
|
||||
|
||||
const isActiveRoute = (route: string) => {
|
||||
return currentRoute === route ||
|
||||
(route === '/users/individual' && currentRoute.startsWith('/users/'));
|
||||
return currentRoute === route ||
|
||||
(route === '/users/individual' && currentRoute.startsWith('/users/'));
|
||||
};
|
||||
|
||||
const getActiveParent = (items: NavigationItem[]): string | null => {
|
||||
@@ -205,27 +205,24 @@ export function AuthenticatedLayout({
|
||||
const isParentActive = activeParent === item.id;
|
||||
const Icon = item.icon;
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
return (
|
||||
<div key={item.id}>
|
||||
<Button
|
||||
variant="ghost"
|
||||
className={`w-full justify-start min-h-[44px] ${
|
||||
isActive
|
||||
? 'bg-primary text-primary-foreground'
|
||||
className={`w-full justify-start min-h-[44px] ${isActive
|
||||
? 'bg-primary text-primary-foreground'
|
||||
: isParentActive && !isChild
|
||||
? 'bg-accent text-accent-foreground'
|
||||
: 'hover:bg-accent hover:text-accent-foreground'
|
||||
} ${isChild ? 'ml-4 text-sm' : ''}`}
|
||||
onClick={() => navigate(item.route)}
|
||||
} ${isChild ? 'ml-4 text-sm' : ''}`}
|
||||
onClick={() => navigate(item.route)} // Use the navigate from the top level
|
||||
>
|
||||
<Icon className={`${sidebarCollapsed ? 'mx-auto' : 'mr-2'} h-4 w-4 flex-shrink-0`} />
|
||||
{!sidebarCollapsed && (
|
||||
<span className="truncate">{item.label}</span>
|
||||
)}
|
||||
</Button>
|
||||
|
||||
|
||||
{/* Render children if parent is active and not collapsed */}
|
||||
{item.children && isParentActive && !sidebarCollapsed && (
|
||||
<div className="mt-1 space-y-1">
|
||||
@@ -235,11 +232,10 @@ export function AuthenticatedLayout({
|
||||
</div>
|
||||
);
|
||||
};
|
||||
const navigate = useNavigate();
|
||||
return (
|
||||
<div className="flex h-screen bg-background">
|
||||
{/* Left Sidebar */}
|
||||
<div
|
||||
<div
|
||||
className={`${sidebarCollapsed ? 'w-[72px]' : 'w-[240px]'} bg-sidebar border-r border-sidebar-border flex flex-col transition-all duration-200`}
|
||||
role="navigation"
|
||||
aria-label="Main navigation"
|
||||
@@ -248,9 +244,9 @@ export function AuthenticatedLayout({
|
||||
<div className="p-4 border-b border-sidebar-border" style={{ backgroundColor: 'var(--color-brand-primary)' }}>
|
||||
<div className="flex items-center justify-between">
|
||||
{!sidebarCollapsed && (
|
||||
<img
|
||||
src={klcLogoDark}
|
||||
alt="Kautilya Leadership Centre"
|
||||
<img
|
||||
src={klcLogoDark}
|
||||
alt="Kautilya Leadership Centre"
|
||||
className="h-8"
|
||||
/>
|
||||
)}
|
||||
@@ -275,7 +271,6 @@ export function AuthenticatedLayout({
|
||||
|
||||
{/* User Section */}
|
||||
<div className="p-4 border-t border-sidebar-border"
|
||||
onClick={() => navigate('/profile')}
|
||||
>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
@@ -324,7 +319,7 @@ export function AuthenticatedLayout({
|
||||
<Breadcrumb>
|
||||
<BreadcrumbList>
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbLink
|
||||
<BreadcrumbLink
|
||||
onClick={() => navigate('/dashboard')}
|
||||
className="cursor-pointer"
|
||||
>
|
||||
@@ -336,7 +331,7 @@ export function AuthenticatedLayout({
|
||||
<BreadcrumbSeparator />
|
||||
<BreadcrumbItem>
|
||||
{crumb.route && index < breadcrumbs.length - 1 ? (
|
||||
<BreadcrumbLink
|
||||
<BreadcrumbLink
|
||||
onClick={() => navigate(crumb.route!)}
|
||||
className="cursor-pointer"
|
||||
>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
"use client";
|
||||
|
||||
import * as React from "react";
|
||||
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu@2.1.6";
|
||||
import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react@0.487.0";
|
||||
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
|
||||
import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react";
|
||||
|
||||
import { cn } from "./utils";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user