fix nav expand

This commit is contained in:
priyanshuvish
2025-11-11 11:57:39 +05:30
parent c08ecf6a4b
commit 7e414207d6
3 changed files with 100 additions and 80 deletions

View File

@@ -271,7 +271,6 @@ export default function App() {
return <NewOrganization {...commonProps} />;
// Updated content routes section
// In App.tsx - Update the content routes section
case "/content":
case "/content/profiler":
case "/content/blogs":

View File

@@ -1,16 +1,16 @@
import React, { useState, useEffect } from 'react';
import { Button } from '../ui/button';
import { NotificationPanel, Notification } from '../NotificationPanel';
import {
Home,
FileText,
GraduationCap,
Users,
Calendar,
Globe,
BarChart3,
Settings,
Menu,
import {
Home,
FileText,
GraduationCap,
Users,
Calendar,
Globe,
BarChart3,
Settings,
Menu,
ChevronLeft,
LogOut,
User,
@@ -28,7 +28,7 @@ import {
ChevronDown,
Target
} from 'lucide-react';
import {
import {
Breadcrumb,
BreadcrumbItem,
BreadcrumbLink,
@@ -37,7 +37,7 @@ import {
BreadcrumbSeparator,
} from '../ui/breadcrumb';
import { Avatar, AvatarFallback } from '../ui/avatar';
import {
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
@@ -112,10 +112,10 @@ const navigationItems: NavigationItem[] = [
route: '/content',
children: [
{
id: 'profiler',
label: 'Profiler',
icon: Target,
route: '/content'
id: 'profiler',
label: 'Profiler',
icon: Target,
route: '/content/profiler'
},
{
id: 'blogs',
@@ -257,7 +257,7 @@ const useAutoSave = (
// Save to localStorage for persistence
localStorage.setItem(`autosave_${userId}_${currentRoute}`, JSON.stringify(autoSaveData));
onAutoSave(formData);
// Show subtle toast notification
toast.success("Draft saved", { duration: 1000 });
}, SESSION_CONFIG.AUTO_SAVE_INTERVAL);
@@ -301,7 +301,7 @@ const useSessionTimeout = (onLogout: () => void) => {
// Activity listeners
const resetOnActivity = () => resetTimers();
// Listen for user activity
const events = ['mousedown', 'mousemove', 'keypress', 'scroll', 'touchstart'];
events.forEach(event => {
@@ -320,12 +320,12 @@ const useSessionTimeout = (onLogout: () => void) => {
}, [onLogout]);
};
export function AuthenticatedLayout({
children,
currentRoute,
onNavigate,
onLogout,
user,
export function AuthenticatedLayout({
children,
currentRoute,
onNavigate,
onLogout,
user,
breadcrumbs = [],
formData,
onAutoSave,
@@ -350,10 +350,10 @@ export function AuthenticatedLayout({
// Auto-expand parent items when on child routes
useEffect(() => {
const newExpandedItems = new Set<string>();
navigationItems.forEach(item => {
if (item.children) {
const isChildActive = item.children.some(child =>
const isChildActive = item.children.some(child =>
isActiveRoute(child.route)
);
if (isChildActive) {
@@ -361,13 +361,14 @@ export function AuthenticatedLayout({
}
}
});
setExpandedItems(newExpandedItems);
}, [currentRoute]);
// Notification handlers
const handleMarkAsRead = (notificationId: string) => {
setLocalNotifications(prev =>
setLocalNotifications(prev =>
prev.map(n => n.id === notificationId ? { ...n, read: true } : n)
);
if (onMarkNotificationAsRead) {
@@ -408,22 +409,32 @@ export function AuthenticatedLayout({
const isActiveRoute = (route: string) => {
if (!currentRoute || !route) return false;
// Exact match
if (currentRoute === route) return true;
// User routes
if (route === '/users/individual' && currentRoute.startsWith('/users/')) return true;
// Content routes - match both parent and children
if (route === '/content' && currentRoute.startsWith('/content/')) return true;
// Content section — highlight both parent and child routes
if (route === '/content') {
return currentRoute.startsWith('/content');
}
// Child route check
if (route.startsWith('/content/')) {
return currentRoute === route || currentRoute.startsWith(route + '/');
}
return false;
};
const getActiveParent = (items: NavigationItem[]): string | null => {
for (const item of items) {
// Check if this item is active
if (isActiveRoute(item.route)) return item.id;
// Check if any children are active
if (item.children) {
for (const child of item.children) {
if (isActiveRoute(child.route)) return item.id;
@@ -453,31 +464,43 @@ export function AuthenticatedLayout({
const expanded = isExpanded(item.id);
const Icon = item.icon;
// const handleItemClick = () => {
// if (hasChildren && !isChild) {
// // Always expand when parent clicked
// const newExpandedItems = new Set(expandedItems);
// newExpandedItems.add(item.id);
// setExpandedItems(newExpandedItems);
// // Navigate to parent route (like /content)
// onNavigate(item.route);
// } else {
// // Navigate directly for child items
// onNavigate(item.route);
// }
// };
const handleItemClick = () => {
if (hasChildren && !isChild) {
// Toggle dropdown for parent items
// Toggle dropdown open/close when clicking parent
toggleExpanded(item.id);
// If not active and has children, navigate to first child
if (!isActive && item.children && item.children.length > 0) {
onNavigate(item.children[0].route);
}
} else {
// Navigate directly for child items or items without children
onNavigate(item.route);
}
};
return (
<div key={item.id}>
<Button
variant="ghost"
className={`w-full justify-start min-h-[44px] ${
isActive
? 'bg-primary text-primary-foreground'
: expanded && !isChild
? 'bg-accent text-accent-foreground'
: 'hover:bg-accent hover:text-accent-foreground'
} ${isChild ? 'ml-4 text-sm' : ''} ${hasChildren ? 'pr-2' : ''}`}
className={`w-full justify-start min-h-[44px] ${isActive
? 'bg-primary text-primary-foreground'
: expanded && !isChild
? 'bg-accent text-accent-foreground'
: 'hover:bg-accent hover:text-accent-foreground'
} ${isChild ? 'ml-4 text-sm' : ''} ${hasChildren ? 'pr-2' : ''}`}
onClick={handleItemClick}
>
<Icon className={`${sidebarCollapsed ? 'mx-auto' : 'mr-2'} h-4 w-4 flex-shrink-0`} />
@@ -485,14 +508,13 @@ export function AuthenticatedLayout({
<>
<span className="truncate flex-1 text-left">{item.label}</span>
{hasChildren && (
<ChevronDown className={`h-4 w-4 ml-auto transition-transform ${
expanded ? 'rotate-180' : ''
}`} />
<ChevronDown className={`h-4 w-4 ml-auto transition-transform ${expanded ? 'rotate-180' : ''
}`} />
)}
</>
)}
</Button>
{/* Render children if dropdown is expanded and not collapsed */}
{item.children && expanded && !sidebarCollapsed && (
<div className="mt-1 space-y-1">
@@ -511,7 +533,7 @@ export function AuthenticatedLayout({
<Breadcrumb>
<BreadcrumbList>
<BreadcrumbItem>
<BreadcrumbLink
<BreadcrumbLink
onClick={() => onNavigate('/dashboard')}
className="cursor-pointer"
>
@@ -523,7 +545,7 @@ export function AuthenticatedLayout({
<BreadcrumbSeparator />
<BreadcrumbItem>
{crumb.href && index < breadcrumbs.length - 1 ? (
<BreadcrumbLink
<BreadcrumbLink
onClick={() => onNavigate(crumb.href!)}
className="cursor-pointer"
>
@@ -537,7 +559,7 @@ export function AuthenticatedLayout({
))}
</BreadcrumbList>
</Breadcrumb>
{/* Notification Bell */}
<NotificationPanel
notifications={localNotifications}
@@ -559,7 +581,7 @@ export function AuthenticatedLayout({
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"
@@ -568,9 +590,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"
/>
)}

View File

@@ -132,25 +132,25 @@ export function ContentManager({
const getCurrentContentType = () => {
console.log('🔄 getCurrentContentType called with currentRoute:', currentRoute);
// Find exact route match first
const exactMatch = contentTypes.find(type => currentRoute === type.route);
if (exactMatch) {
console.log('✅ Exact route match found:', exactMatch.id);
return exactMatch;
}
// Find partial match for nested routes
const partialMatch = contentTypes.find(type =>
currentRoute.startsWith(type.route + '/') ||
const partialMatch = contentTypes.find(type =>
currentRoute.startsWith(type.route + '/') ||
currentRoute.includes(type.id)
);
if (partialMatch) {
console.log('✅ Partial route match found:', partialMatch.id);
return partialMatch;
}
console.log('⚠️ No match found, defaulting to profiler');
return contentTypes[0]; // Default to profiler
};
@@ -159,34 +159,33 @@ export function ContentManager({
console.log('📌 Current content type:', currentContentType.label);
const getBreadcrumbs = () => {
const breadcrumbs = [
{ label: "Content", href: "/content" }
];
const breadcrumbs = [{ label: "Content", href: "/content" }];
// Add specific content type to breadcrumbs if not on the main content page
if (currentRoute !== "/content") {
// Always show current content type
if (currentContentType) {
breadcrumbs.push({ label: currentContentType.label });
}
return breadcrumbs;
};
const renderContent = () => {
console.log('🎨 Rendering content for:', currentContentType.id);
switch (currentContentType.id) {
case "profiler":
return <ProfilerTab onNavigate={onNavigate} user={user} />;
case "blogs":
return <BlogsTab onNavigate={onNavigate} user={user} />;
case "faqs":
return <FAQTab onNavigate={onNavigate} user={user} />;
case "webcasts":
return <WebcastsTab onNavigate={onNavigate} user={user} />;
case "training-materials":
return (
<TrainingMaterialsTab
@@ -196,16 +195,16 @@ export function ContentManager({
setActiveInnerTab={setActiveInnerTab}
/>
);
case "reading-materials":
return <ReadingMaterialsTab onNavigate={onNavigate} user={user} />;
case "podcasts":
return <PodcastsTab onNavigate={onNavigate} user={user} />;
case "case-studies":
return <CaseStudiesTab onNavigate={onNavigate} user={user} />;
case "klc-archives":
return (
<KLCContentArchiveTab
@@ -215,7 +214,7 @@ export function ContentManager({
setActiveInnerTab={setActiveInnerTab}
/>
);
default:
console.log('⚠️ Defaulting to profiler tab');
return <ProfilerTab onNavigate={onNavigate} user={user} />;
@@ -237,7 +236,7 @@ export function ContentManager({
{currentContentType.label}
</h1>
<p className="text-muted-foreground mt-2">
{currentContentType.id === "profiler"
{currentContentType.id === "profiler"
? "Manage all content types and profiler submissions with approval workflow"
: `Manage and organize ${currentContentType.label.toLowerCase()}`
}