Replace src folder with new version

This commit is contained in:
priyanshuvish
2025-09-26 19:35:18 +05:30
parent b156a8fb10
commit 65ea0f4346
20 changed files with 6 additions and 4818 deletions

View File

@@ -1,11 +0,0 @@
import {configureStore} from '@reduxjs/toolkit';
import { demoApi } from './services/demo.service';
export const store = configureStore({
reducer: {
[demoApi.reducerPath]: demoApi.reducer},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat(demoApi.middleware),
});
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;

View File

@@ -1,16 +0,0 @@
// import { createApi } from '@reduxjs/toolkit/query'
import { fetchBaseQuery, createApi } from '@reduxjs/toolkit/query/react'
export const demoApi = createApi({
reducerPath: 'demoApi',
baseQuery: fetchBaseQuery({ baseUrl: "https://jsonplaceholder.typicode.com" }),
endpoints: (builder) => ({
// GET example
getPosts: builder.query<any[], void>({
query: () => "/posts",
}),
}),
})
export const { useGetPostsQuery } = demoApi;

View File

@@ -1,186 +0,0 @@
import React from 'react';
import { Button } from './ui/button';
import { ArrowRight, ChevronLeft, ChevronRight } from 'lucide-react';
import { ImageWithFallback } from './figma/ImageWithFallback';
// import heroBannerImage from 'figma:asset/1bb9c22c86c0892d4716564b7135835f04869298.png';
const heroBannerImage = 'https://images.unsplash.com/photo-1504384308090-c894fdcc538d?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1470&q=80';
interface HeroSectionProps {
showAnnouncementBar?: boolean;
announcementText?: string;
announcementCTA?: string;
title?: string;
subtitle?: string;
ctaText?: string;
onAnnouncementClick?: () => void;
onCTAClick?: () => void;
showFeatures?: boolean;
}
export function HeroSection({
showAnnouncementBar = true,
announcementText = "Join Our Upcoming Leadership Webinars - Transform Your Leadership Journey",
announcementCTA = "Enroll Now",
title = "Empowering Future-Ready Leaders",
subtitle = "Build confidence, agility, and clarity for today's complex challenges.",
ctaText = "Build Your Leadership Pipeline",
onAnnouncementClick,
onCTAClick,
showFeatures = true
}: HeroSectionProps) {
const handleAnnouncementClick = () => {
if (onAnnouncementClick) {
onAnnouncementClick();
} else {
window.location.href = '/webinars?view=individual';
}
};
const handleCTAClick = () => {
if (onCTAClick) {
onCTAClick();
} else {
window.location.href = '/dashboard?view=individual';
}
};
return (
<div className="relative w-full">
{/* Top Announcement Bar */}
{showAnnouncementBar && (
<div className="bg-[#F8C301] text-[#26231A] py-3 px-4">
<div className="container mx-auto px-4 lg:px-8">
<div className="flex items-center justify-center gap-4 text-center">
<span className="text-base font-medium">
{announcementText}
</span>
<Button
onClick={handleAnnouncementClick}
variant="ghost"
size="sm"
className="text-[#26231A] hover:bg-[#26231A]/10 font-medium text-base h-auto py-1 px-3"
>
{announcementCTA}
<ArrowRight className="ml-2 h-4 w-4" />
</Button>
</div>
</div>
</div>
)}
{/* Main Hero Section */}
<div className="relative min-h-[80vh] flex items-center justify-center overflow-hidden">
{/* Background Image */}
<div className="absolute inset-0 z-0">
<ImageWithFallback
src={heroBannerImage}
alt="Leadership workshop with diverse team members collaborating with colorful sticky notes on a wall"
className="w-full h-full object-cover"
/>
{/* Overlay for better text readability */}
<div className="absolute inset-0 bg-black/40"></div>
</div>
{/* Hero Content */}
<div className="relative z-10 container mx-auto px-4 lg:px-8 pt-20 pb-32">
<div className="max-w-4xl">
<div className="text-white space-y-8">
{/* Main Heading */}
<h1 className="text-5xl lg:text-6xl font-bold leading-tight">
{title}
</h1>
{/* Subtext */}
<p className="text-xl lg:text-2xl text-white/90 leading-relaxed max-w-2xl">
{subtitle}
</p>
{/* CTA Button */}
<div className="pt-4">
<Button
onClick={handleCTAClick}
size="lg"
className="bg-[#04045B] hover:bg-[#04045B]/90 text-white text-lg px-8 py-4 min-h-[60px] font-medium"
>
{ctaText}
</Button>
</div>
</div>
</div>
</div>
{/* Bottom Feature Navigation */}
{showFeatures && (
<div className="absolute bottom-0 left-0 right-0 z-10">
<div className="container mx-auto px-4 lg:px-8">
<div className="grid grid-cols-1 md:grid-cols-3 gap-8 py-12">
{/* Feature 01 */}
<div className="text-white space-y-4">
<div className="flex items-center gap-4">
<div className="text-[#F8C301] text-xl font-bold">01</div>
<div className="h-px bg-[#F8C301] flex-1"></div>
</div>
<div>
<h3 className="text-lg font-semibold mb-2">Leadership Is Learning. We Teach It Right.</h3>
<p className="text-white/80 text-base leading-relaxed">
Master proven methodologies and frameworks that transform managers into exceptional leaders.
</p>
</div>
</div>
{/* Feature 02 */}
<div className="text-white space-y-4">
<div className="flex items-center gap-4">
<div className="text-[#F8C301] text-xl font-bold">02</div>
<div className="h-px bg-[#F8C301] flex-1"></div>
</div>
<div>
<h3 className="text-lg font-semibold mb-2">Turn Managers Into Impactful Leaders</h3>
<p className="text-white/80 text-base leading-relaxed">
Develop strategic thinking, emotional intelligence, and decision-making capabilities.
</p>
</div>
</div>
{/* Feature 03 */}
<div className="text-white space-y-4">
<div className="flex items-center gap-4">
<div className="text-[#F8C301] text-xl font-bold">03</div>
<div className="h-px bg-[#F8C301] flex-1"></div>
</div>
<div>
<h3 className="text-lg font-semibold mb-2">Struggling with Managerial Gaps?</h3>
<p className="text-white/80 text-base leading-relaxed">
Bridge the gap between individual contribution and effective team leadership.
</p>
</div>
</div>
</div>
</div>
{/* Navigation Controls */}
<div className="absolute bottom-6 right-6 flex items-center gap-2">
<Button
variant="ghost"
size="icon"
className="w-12 h-12 rounded-full bg-white/10 hover:bg-white/20 text-white border border-white/20"
aria-label="Previous slide"
>
<ChevronLeft className="h-5 w-5" />
</Button>
<Button
variant="ghost"
size="icon"
className="w-12 h-12 rounded-full bg-white/10 hover:bg-white/20 text-white border border-white/20"
aria-label="Next slide"
>
<ChevronRight className="h-5 w-5" />
</Button>
</div>
</div>
)}
</div>
</div>
);
}

View File

@@ -1,712 +0,0 @@
import React, { useState, useEffect } from 'react';
import { Button } from './ui/button';
import { Input } from './ui/input';
import { Avatar, AvatarFallback, AvatarImage } from './ui/avatar';
import { Badge } from './ui/badge';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
DropdownMenuSeparator,
DropdownMenuLabel,
} from './ui/dropdown-menu';
import {
Sheet,
SheetContent,
SheetHeader,
SheetTitle,
SheetTrigger,
} from './ui/sheet';
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from './ui/collapsible';
// import { navigate } from './Router';
import { useAuth } from './AuthContext';
// import klcLogo from 'figma:asset/209958db0c439ec78be82ab4f3e335a6aed5de89.png';
// import exampleImage from 'figma:asset/6cae567b6bf6a44cb03b767e4308c4c705340d08.png';
const klcLogo = 'https://res.cloudinary.com/dt3k2apqd/image/upload/v1697045531/Kautilya_Leadership_Centre_Logo_hor_uxh0v4.png';
const exampleImage = 'https://images.unsplash.com/photo-1508214751196-bcfd4ca60f91?w=150&h=150&fit=crop&crop=face';
import {
Menu,
ChevronDown,
ChevronRight,
ShoppingCart,
Search,
Building2,
User,
Settings,
LogOut,
LayoutDashboard,
Users,
Target,
Award,
Lightbulb,
GraduationCap,
BookOpen,
Video,
FileText,
Eye,
Heart,
MapPin,
Calendar,
Play,
Home,
Check,
ArrowRight
} from 'lucide-react';
import { useNavigate } from 'react-router-dom';
const navigate = useNavigate();
interface NavigationProps {
currentPage?: string;
}
export function Navigation({ currentPage }: NavigationProps) {
const [isScrolled, setIsScrolled] = useState(false);
const [activeDropdown, setActiveDropdown] = useState<string | null>(null);
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
const [expandedMobileSection, setExpandedMobileSection] = useState<string | null>(null);
const { user, login, signOut, isAuthenticated } = useAuth();
// Determine user type from URL or user data
const getQueryParam = (param: string) => {
const urlParams = new URLSearchParams(window.location.search);
return urlParams.get(param);
};
const isIndividualUser = getQueryParam('view') === 'individual' ||
(!getQueryParam('view') && currentPage?.includes('/dashboard')) ||
(!getQueryParam('view') && currentPage?.includes('/library')) ||
(!getQueryParam('view') && currentPage?.includes('/course')) ||
(!getQueryParam('view') && currentPage?.includes('/settings')) ||
(!getQueryParam('view') && currentPage?.includes('/surveys')) ||
(!getQueryParam('view') && currentPage?.includes('/webinars')) ||
(!getQueryParam('view') && currentPage?.includes('/leaderboard'));
const isCorporateUser = getQueryParam('view') === 'corporate';
useEffect(() => {
const handleScroll = () => {
setIsScrolled(window.scrollY > 10);
};
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, []);
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
const target = event.target as Element;
if (!target.closest('[data-dropdown]')) {
setActiveDropdown(null);
}
};
document.addEventListener('click', handleClickOutside);
return () => document.removeEventListener('click', handleClickOutside);
}, []);
const handleDropdownToggle = (dropdown: string) => {
setActiveDropdown(activeDropdown === dropdown ? null : dropdown);
};
const handleMobileToggle = (section: string) => {
setExpandedMobileSection(expandedMobileSection === section ? null : section);
};
const handleLogin = () => {
navigate('/auth'); // Route to login selection page
setIsMobileMenuOpen(false);
};
const handleSignup = () => {
navigate('/signup');
setIsMobileMenuOpen(false);
};
const handleLogout = () => {
signOut();
navigate('/');
setActiveDropdown(null);
setIsMobileMenuOpen(false);
};
const handleAccountSignIn = (accountType: 'individual' | 'corporate') => {
// Navigate to appropriate sign-in page for the account type
if (accountType === 'individual') {
navigate('/login');
} else {
navigate('/corporate/login');
}
setActiveDropdown(null);
setIsMobileMenuOpen(false);
};
const navigationItems = [
{
title: 'About Us',
href: '/about-us/our-vision',
items: [
{ title: 'Our Vision', href: '/about-us/our-vision', icon: Eye },
{ title: 'Our Team', href: '/about-us/our-team', icon: Users },
{ title: 'Our Impact', href: '/about-us/our-impact', icon: Target },
{ title: 'Our Expertise', href: '/about-us/our-expertise', icon: Award }
]
},
{
title: 'Programmes',
href: '/programmes',
items: [
{ title: 'Programme Catalogue', href: '/programmes', icon: BookOpen },
{ title: 'Executive Leadership', href: '/programmes/executive-leadership', icon: Award },
{ title: 'Team Leadership', href: '/programmes/team-leadership', icon: Users },
{ title: 'Innovation Leadership', href: '/programmes/innovation-leadership', icon: Lightbulb },
{ title: 'Leadership Online', href: '/programmes/leadership-online', icon: Play }
]
},
{
title: 'Services',
href: '/services/leadership-development',
items: [
{ title: 'Leadership Development', href: '/services/leadership-development', icon: Target },
{ title: 'Management Development', href: '/services/management-development', icon: Users },
{ title: 'Executive Coaching', href: '/services/executive-coaching', icon: Award },
{ title: 'Culture & Competence', href: '/services/culture-competence', icon: Heart },
{ title: 'Consulting', href: '/services/consulting', icon: Lightbulb },
{ title: 'Learning Facility', href: '/services/learning-facility', icon: MapPin }
]
},
{
title: 'Learning',
href: '/learning/articles',
items: [
{ title: 'Articles', href: '/learning/articles', icon: FileText },
{ title: 'Blog', href: '/learning/blog', icon: BookOpen },
{ title: 'Resources', href: '/learning/resources', icon: BookOpen },
{ title: 'Webinars', href: '/individual-webinars', icon: Video }
]
}
];
const learnerMenuItems = [
{
title: 'Dashboard',
href: isIndividualUser ? '/dashboard?view=individual' : '/dashboard?view=corporate',
icon: LayoutDashboard,
description: isIndividualUser ? 'Your learning overview' : 'Team management hub'
},
{
title: 'Library',
href: isIndividualUser ? '/library?view=individual' : '/library?view=corporate',
icon: BookOpen,
description: isIndividualUser ? 'Browse courses' : 'Assigned courses'
},
{
title: 'Course Timeline',
href: isIndividualUser ? '/course?view=individual' : '/course?view=corporate',
icon: Calendar,
description: isIndividualUser ? 'Your learning path' : 'Team progress'
},
{
title: 'Surveys & Assessments',
href: isIndividualUser ? '/surveys?view=individual' : '/surveys?view=corporate',
icon: FileText,
description: isIndividualUser ? 'Complete assessments' : 'Team evaluations'
},
{
title: 'Live Webinars',
href: isIndividualUser ? '/webinars?view=individual' : '/webinars?view=corporate',
icon: Video,
description: isIndividualUser ? 'Join sessions' : 'Corporate events'
},
{
title: 'Leaderboard',
href: isIndividualUser ? '/leaderboard?view=individual' : '/leaderboard?view=corporate',
icon: Award,
description: isIndividualUser ? 'Your achievements' : 'Team rankings'
},
{
title: 'Settings',
href: isIndividualUser ? '/settings?view=individual' : '/settings?view=corporate',
icon: Settings,
description: isIndividualUser ? 'Account preferences' : 'Admin settings'
}
];
// Mock data for demonstration - replace with actual user data
const currentUser = {
name: 'Priya Sharma',
email: 'priya.sharma@example.com',
avatar: "https://images.unsplash.com/photo-1494790108755-2616b612b786?w=150&h=150&fit=crop&crop=face",
organization: 'TechCorp Inc.',
role: 'Marketing Team Member'
};
const availableAccounts = [
{
type: 'individual',
isActive: isIndividualUser,
title: 'Personal Learning',
subtitle: 'Access your individual learning portal',
icon: User,
user: currentUser
},
{
type: 'corporate',
isActive: isCorporateUser,
title: 'Corporate Learning',
subtitle: 'Enterprise team development portal',
icon: Building2,
user: currentUser,
organization: 'TechCorp Inc.'
}
];
return (
<nav className={`fixed top-0 left-0 right-0 z-50 transition-all duration-300 ${
isScrolled ? 'bg-white/95 backdrop-blur-md shadow-sm' : 'bg-white'
}`}>
<div className="w-full px-4 lg:px-8">
<div className="flex items-center justify-between h-[70px]">
{/* Logo */}
<div className="flex-shrink-0">
<button
onClick={() => navigate('/')}
className="flex items-center space-x-2 focus:outline-none focus:ring-2 focus:ring-primary rounded-lg p-1 hover:bg-gray-50 transition-colors"
aria-label="Go to KLC homepage"
>
<img
src={klcLogo}
alt="Kautilya Leadership Centre"
className="h-12 w-auto object-contain"
/>
</button>
</div>
{/* Desktop Navigation */}
<div className="hidden lg:flex items-center space-x-8">
{navigationItems.map((item) => (
<div key={item.title} className="relative" data-dropdown>
<button
onClick={() => handleDropdownToggle(item.title)}
className="flex items-center space-x-1 text-[16px] text-foreground hover:text-primary transition-colors py-2 px-3 rounded-lg hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-primary"
aria-expanded={activeDropdown === item.title}
aria-haspopup="true"
>
<span>{item.title}</span>
<ChevronDown className={`h-4 w-4 transition-transform ${
activeDropdown === item.title ? 'rotate-180' : ''
}`} />
</button>
{activeDropdown === item.title && (
<div className="absolute top-full left-0 mt-2 w-64 bg-white rounded-lg shadow-lg border border-gray-200 py-2 z-50">
{item.items.map((subItem) => {
const IconComponent = subItem.icon;
return (
<button
key={subItem.title}
onClick={() => {
navigate(subItem.href);
setActiveDropdown(null);
}}
className="w-full flex items-center space-x-3 px-4 py-3 text-[16px] text-gray-700 hover:bg-gray-50 hover:text-primary transition-colors text-left focus:outline-none focus:ring-2 focus:ring-primary"
>
<IconComponent className="h-4 w-4 flex-shrink-0" />
<span>{subItem.title}</span>
</button>
);
})}
</div>
)}
</div>
))}
<button
onClick={() => navigate('/contact')}
className="text-[16px] text-foreground hover:text-primary transition-colors py-2 px-3 rounded-lg hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-primary"
>
Contact
</button>
</div>
{/* Right Section - Desktop */}
<div className="hidden lg:flex items-center space-x-4">
{!isAuthenticated ? (
<>
<Button
variant="ghost"
onClick={handleLogin}
className="text-[16px] min-h-[44px]"
>
Sign In
</Button>
<Button
onClick={handleSignup}
className="text-[16px] min-h-[44px] bg-primary hover:bg-primary/90 text-primary-foreground"
>
Get Started
</Button>
</>
) : (
<div className="flex items-center space-x-4">
{/* Redesigned User Profile Dropdown */}
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
variant="ghost"
className="flex items-center gap-3 h-auto p-2 hover:bg-gray-50 transition-all duration-200 rounded-lg min-h-[44px]"
aria-label="Open user menu"
>
<Avatar className="h-8 w-8">
<AvatarImage
src={currentUser.avatar}
alt={currentUser.name}
/>
<AvatarFallback className="bg-primary/10 text-primary text-sm">
{currentUser.name.split(' ').map(n => n[0]).join('')}
</AvatarFallback>
</Avatar>
<div className="flex flex-col items-start min-w-0">
<span className="text-[16px] font-medium text-gray-900 truncate">
{currentUser.name}
</span>
<span className="text-[14px] text-gray-600 truncate">
{isIndividualUser ? 'Individual Account' : 'Corporate Account'}
</span>
</div>
<ChevronDown className="h-4 w-4 text-gray-500 flex-shrink-0" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="w-80 p-0" align="end" forceMount>
{/* Header Section */}
<div className="p-4 border-b border-gray-100 bg-gray-50">
<div className="flex items-center gap-3">
<Avatar className="h-12 w-12">
<AvatarImage
src={currentUser.avatar}
alt={currentUser.name}
/>
<AvatarFallback className="bg-primary/10 text-primary text-lg">
{currentUser.name.split(' ').map(n => n[0]).join('')}
</AvatarFallback>
</Avatar>
<div className="flex-1 min-w-0">
<div className="flex items-center gap-2">
<p className="text-[16px] font-semibold text-gray-900 truncate">
{currentUser.name}
</p>
<ChevronDown className="h-4 w-4 text-gray-400 flex-shrink-0" />
</div>
<p className="text-[14px] text-gray-600 truncate">
{isIndividualUser ? 'Individual Account' : 'Corporate Account'}
</p>
</div>
</div>
</div>
{/* Account Switching Section */}
<div className="p-4 border-b border-gray-100">
<h4 className="text-[14px] font-medium text-gray-900 mb-3">Switch Account</h4>
<div className="space-y-2">
{availableAccounts.map((account) => {
const IconComponent = account.icon;
return (
<div
key={account.type}
className={`flex items-center gap-3 p-3 rounded-lg border transition-all duration-200 ${
account.isActive
? 'bg-green-50 border-green-200'
: 'bg-gray-50 border-gray-200 hover:bg-gray-100 cursor-pointer'
}`}
onClick={() => !account.isActive && handleAccountSignIn(account.type as 'individual' | 'corporate')}
>
<div className="relative">
{account.type === 'individual' ? (
<Avatar className="h-8 w-8">
<AvatarImage
src={currentUser.avatar}
alt={currentUser.name}
/>
<AvatarFallback className="bg-blue-100 text-blue-700 text-sm">
<User className="h-4 w-4" />
</AvatarFallback>
</Avatar>
) : (
<div className="h-8 w-8 bg-purple-100 rounded-full flex items-center justify-center">
<Building2 className="h-4 w-4 text-purple-700" />
</div>
)}
{account.isActive && (
<div className="absolute -top-1 -right-1 w-4 h-4 bg-green-500 rounded-full flex items-center justify-center">
<Check className="h-2.5 w-2.5 text-white" />
</div>
)}
</div>
<div className="flex-1 min-w-0">
<p className="text-[14px] font-medium text-gray-900 truncate">
{account.title}
</p>
<p className="text-[14px] text-gray-600 truncate">
{account.subtitle}
</p>
</div>
{!account.isActive && (
<ArrowRight className="h-4 w-4 text-gray-400 flex-shrink-0" />
)}
</div>
);
})}
</div>
</div>
<DropdownMenuSeparator />
{/* Settings and Logout */}
<div className="p-2">
<DropdownMenuItem
className="flex items-center gap-3 px-3 py-2 cursor-pointer rounded-md hover:bg-gray-50 focus:bg-gray-50 min-h-[44px]"
onClick={() => navigate(learnerMenuItems[learnerMenuItems.length - 1].href)}
>
<Settings className="h-5 w-5 text-gray-500" />
<span className="text-[16px] font-medium text-gray-900">Settings</span>
</DropdownMenuItem>
<DropdownMenuItem
className="flex items-center gap-3 px-3 py-2 cursor-pointer rounded-md text-red-600 hover:bg-red-50 focus:bg-red-50 min-h-[44px]"
onClick={handleLogout}
>
<LogOut className="h-5 w-5" />
<span className="text-[16px] font-medium">Sign Out</span>
</DropdownMenuItem>
</div>
</DropdownMenuContent>
</DropdownMenu>
</div>
)}
</div>
{/* Mobile Menu Button */}
<div className="lg:hidden">
<Sheet open={isMobileMenuOpen} onOpenChange={setIsMobileMenuOpen}>
<SheetTrigger asChild>
<Button
variant="ghost"
size="icon"
className="h-10 w-10"
aria-label="Open mobile menu"
>
<Menu className="h-6 w-6" />
</Button>
</SheetTrigger>
<SheetContent side="right" className="w-full sm:w-96 p-0">
<SheetHeader className="p-6 border-b border-gray-200">
<SheetTitle className="text-left flex items-center gap-3">
<img
src={klcLogo}
alt="KLC"
className="h-8 w-auto object-contain"
/>
<span className="text-lg font-semibold">Menu</span>
</SheetTitle>
</SheetHeader>
<div className="flex flex-col h-full">
{/* User Section for Mobile */}
{isAuthenticated && (
<div className="p-4 border-b border-gray-200">
<div className="flex items-center gap-3 mb-4">
<Avatar className="h-12 w-12">
<AvatarImage
src={currentUser.avatar}
alt={currentUser.name}
/>
<AvatarFallback className="bg-primary/10 text-primary">
{currentUser.name.split(' ').map(n => n[0]).join('')}
</AvatarFallback>
</Avatar>
<div className="flex-1 min-w-0">
<p className="text-[16px] font-semibold text-gray-900 truncate">
{currentUser.name}
</p>
<p className="text-[14px] text-gray-600 truncate">
{isIndividualUser ? 'Individual Account' : 'Corporate Account'}
</p>
</div>
</div>
{/* Mobile Account Switching */}
<div className="space-y-3">
<h4 className="text-[14px] font-medium text-gray-900">Switch Account</h4>
<div className="space-y-2">
{availableAccounts.map((account) => (
<button
key={account.type}
onClick={() => !account.isActive && handleAccountSignIn(account.type as 'individual' | 'corporate')}
disabled={account.isActive}
className={`w-full flex items-center gap-3 p-3 rounded-lg border text-left transition-all duration-200 ${
account.isActive
? 'bg-green-50 border-green-200'
: 'bg-gray-50 border-gray-200 hover:bg-gray-100'
}`}
>
<div className="relative">
{account.type === 'individual' ? (
<Avatar className="h-8 w-8">
<AvatarImage
src={currentUser.avatar}
alt={currentUser.name}
/>
<AvatarFallback className="bg-blue-100 text-blue-700 text-sm">
<User className="h-4 w-4" />
</AvatarFallback>
</Avatar>
) : (
<div className="h-8 w-8 bg-purple-100 rounded-full flex items-center justify-center">
<Building2 className="h-4 w-4 text-purple-700" />
</div>
)}
{account.isActive && (
<div className="absolute -top-1 -right-1 w-4 h-4 bg-green-500 rounded-full flex items-center justify-center">
<Check className="h-2.5 w-2.5 text-white" />
</div>
)}
</div>
<div className="flex-1 min-w-0">
<p className="text-[14px] font-medium text-gray-900 truncate">
{account.title}
</p>
<p className="text-[14px] text-gray-600 truncate">
{account.subtitle}
</p>
</div>
{!account.isActive && (
<ArrowRight className="h-4 w-4 text-gray-400 flex-shrink-0" />
)}
</button>
))}
</div>
</div>
</div>
)}
{/* Navigation Items */}
<div className="flex-1 overflow-y-auto py-4">
{/* Learner Portal Items (if authenticated) */}
{isAuthenticated && (isIndividualUser || isCorporateUser) && (
<div className="px-4 mb-6">
<h3 className="text-[14px] font-medium text-gray-900 mb-3">
{isIndividualUser ? 'Personal Learning' : 'Corporate Learning'}
</h3>
<div className="space-y-1">
{learnerMenuItems.map((item) => {
const IconComponent = item.icon;
return (
<button
key={item.title}
onClick={() => {
navigate(item.href);
setIsMobileMenuOpen(false);
}}
className="w-full flex items-center gap-3 px-3 py-2 text-left text-[16px] text-gray-700 hover:bg-gray-50 hover:text-primary rounded-lg transition-colors focus:outline-none focus:ring-2 focus:ring-primary min-h-[44px]"
>
<IconComponent className="h-5 w-5 flex-shrink-0" />
<div className="flex-1 min-w-0">
<div className="font-medium">{item.title}</div>
<div className="text-[14px] text-gray-500 truncate">{item.description}</div>
</div>
</button>
);
})}
</div>
</div>
)}
{/* Public Navigation Items */}
<div className="px-4">
{navigationItems.map((item) => (
<Collapsible key={item.title}>
<CollapsibleTrigger
onClick={() => handleMobileToggle(item.title)}
className="w-full flex items-center justify-between p-3 text-[16px] text-gray-900 hover:bg-gray-50 rounded-lg transition-colors focus:outline-none focus:ring-2 focus:ring-primary min-h-[44px]"
>
<span className="font-medium">{item.title}</span>
<ChevronRight className={`h-4 w-4 transition-transform ${
expandedMobileSection === item.title ? 'rotate-90' : ''
}`} />
</CollapsibleTrigger>
<CollapsibleContent className="px-4 pb-2">
<div className="space-y-1">
{item.items.map((subItem) => {
const IconComponent = subItem.icon;
return (
<button
key={subItem.title}
onClick={() => {
navigate(subItem.href);
setIsMobileMenuOpen(false);
}}
className="w-full flex items-center gap-3 px-3 py-2 text-left text-[16px] text-gray-600 hover:bg-gray-50 hover:text-primary rounded-lg transition-colors focus:outline-none focus:ring-2 focus:ring-primary min-h-[44px]"
>
<IconComponent className="h-4 w-4 flex-shrink-0" />
<span>{subItem.title}</span>
</button>
);
})}
</div>
</CollapsibleContent>
</Collapsible>
))}
<button
onClick={() => {
navigate('/contact');
setIsMobileMenuOpen(false);
}}
className="w-full flex items-center p-3 text-[16px] text-gray-900 hover:bg-gray-50 rounded-lg transition-colors text-left focus:outline-none focus:ring-2 focus:ring-primary min-h-[44px]"
>
<span className="font-medium">Contact</span>
</button>
</div>
</div>
{/* Mobile Authentication Actions */}
{!isAuthenticated && (
<div className="p-4 border-t border-gray-200 space-y-2">
<Button
onClick={handleLogin}
variant="outline"
className="w-full text-[16px] min-h-[44px]"
>
Sign In
</Button>
<Button
onClick={handleSignup}
className="w-full text-[16px] min-h-[44px] bg-primary hover:bg-primary/90 text-primary-foreground"
>
Get Started
</Button>
</div>
)}
{/* Mobile Logout */}
{isAuthenticated && (
<div className="p-4 border-t border-gray-200">
<Button
onClick={handleLogout}
variant="outline"
className="w-full text-[16px] min-h-[44px] text-red-600 border-red-200 hover:bg-red-50"
>
<LogOut className="h-4 w-4 mr-2" />
Sign Out
</Button>
</div>
)}
</div>
</SheetContent>
</Sheet>
</div>
</div>
</div>
</nav>
);
}

View File

@@ -1,595 +0,0 @@
import React, { useState, useEffect } from 'react';
import { Card, CardContent, CardHeader, CardTitle } from '../ui/card';
// import { Progress } from '../ui/progress';
import { Badge } from '../ui/badge';
import { Button } from '../ui/button';
import {
BookOpen,
Clock,
Trophy,
Target,
TrendingUp,
Award,
CheckCircle,
Calendar,
Users,
Star,
Play,
Bookmark,
Search,
Zap,
ArrowRight,
BarChart3,
Brain,
Sparkles,
Flame,
ChevronRight,
Gauge,
Activity,
ChevronLeft,
ChevronDown,
MoreHorizontal
} from 'lucide-react';
import {
BarChart,
Bar,
XAxis,
YAxis,
CartesianGrid,
ResponsiveContainer,
Tooltip,
PieChart,
Pie,
Cell,
Legend
} from 'recharts';
import { Course } from '../../pages/learner/data/libraryData';
interface LibraryStatsProps {
courses: Course[];
userType: 'individual' | 'corporate';
}
export function LibraryStats({ courses, userType }: LibraryStatsProps) {
const [isVisible, setIsVisible] = useState(false);
const [selectedTimeRange, setSelectedTimeRange] = useState('December');
// Calculate statistics
const stats = {
totalCourses: courses.length,
completedCourses: courses.filter(c => c.status === 'completed').length,
inProgressCourses: courses.filter(c => c.status === 'in-progress').length,
bookmarkedCourses: courses.filter(c => c.status === 'bookmarked').length,
assignedCourses: userType === 'corporate' ? courses.filter(c => c.organizationAssigned).length : 0,
overdueCourses: userType === 'corporate' ? courses.filter(c => c.status === 'not-started').length : undefined,
completionRate: courses.length > 0 ? (courses.filter(c => c.status === 'completed').length / courses.length) * 100 : 0,
averageRating: courses.length > 0 ? courses.reduce((sum, c) => sum + c.rating, 0) / courses.length : 0,
totalHours: courses.reduce((sum, c) => sum + parseFloat(c.duration.replace(/[^\d.]/g, '')), 0),
certificatesEarned: courses.filter(c => c.status === 'completed').length
};
useEffect(() => {
const timer = setTimeout(() => setIsVisible(true), 100);
return () => clearTimeout(timer);
}, []);
// Performance chart data (bar chart showing progress over time)
const performanceData = [
{ name: 'Jan', value: 1, color: '#04045B' },
{ name: 'Feb', value: 2, color: '#04045B' },
{ name: 'Mar', value: 4, color: '#04045B' },
{ name: 'Apr', value: 6, color: '#04045B' },
{ name: 'May', value: 7, color: '#04045B' },
{ name: 'Jun', value: 8, color: '#04045B' }
];
// Time learning data (stacked bar chart)
const timeLearningData = [
{ date: 'Apr 18', performance: 2, consistency: 1, unknown: 0.5 },
{ date: 'Apr 19', performance: 3, consistency: 2, unknown: 1 },
{ date: 'Apr 20', performance: 1.5, consistency: 2.5, unknown: 0.5 },
{ date: 'Apr 21', performance: 4, consistency: 1, unknown: 1 },
{ date: 'Apr 22', performance: 2, consistency: 3, unknown: 0.5 },
{ date: 'Apr 23', performance: 3.5, consistency: 1.5, unknown: 1 },
{ date: 'Apr 24', performance: 2.5, consistency: 2, unknown: 1.5 }
];
// Course list with progress
const courseList = [
{ name: 'Introduction to Strategic Leadership', lessons: '24/30 Lessons', progress: 80, color: '#04045B' },
{ name: 'English for Effective Communication', lessons: '18/25 Lessons', progress: 72, color: '#10B981' },
{ name: 'Introduction to Team Management', lessons: '14/20 Lessons', progress: 70, color: '#F8C301' },
{ name: 'Introduction to Digital Leadership', lessons: '8/15 Lessons', progress: 53, color: '#6366F1' }
];
// Daily activity timeline
const dailyActivities = [
{ time: '07:00', course: 'Introduction to Strategic Leadership', type: 'Google Meeting', color: '#F8C301', instructor: 'A' },
{ time: '08:00', course: '', type: '', color: '', instructor: '' },
{ time: '09:00', course: 'English for Effective Communication', type: 'Google Meeting', color: '#3B82F6', instructor: 'E' },
{ time: '10:00', course: '', type: '', color: '', instructor: '' },
{ time: '11:00', course: '', type: '', color: '', instructor: '' },
{ time: '12:00', course: 'Introduction to Digital Leadership', type: 'Google Meeting', color: '#6366F1', instructor: 'I' },
{ time: '01:00', course: '', type: '', color: '', instructor: '' }
];
// Month navigation functionality
const months = [
'January', 'February', 'March', 'April', 'May', 'June',
'July', 'August', 'September', 'October', 'November', 'December'
];
const navigateMonth = (direction: 'prev' | 'next') => {
const currentIndex = months.findIndex(month => month === selectedTimeRange);
let newIndex;
if (direction === 'prev') {
newIndex = currentIndex <= 0 ? months.length - 1 : currentIndex - 1;
} else {
newIndex = currentIndex >= months.length - 1 ? 0 : currentIndex + 1;
}
setSelectedTimeRange(months[newIndex]);
};
const handleWheel = (e: React.WheelEvent) => {
e.preventDefault();
// Throttle wheel events to prevent rapid scrolling
const now = Date.now();
const lastWheelTime = (e.currentTarget as any)._lastWheelTime || 0;
if (now - lastWheelTime < 200) return; // 200ms throttle
(e.currentTarget as any)._lastWheelTime = now;
if (e.deltaY > 0) {
navigateMonth('next');
} else {
navigateMonth('prev');
}
};
return (
<div className={`space-y-4 transition-all duration-500 ${isVisible ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-4'}`}>
{/* Dashboard Grid Layout - Matching Reference Image */}
<div className="grid grid-cols-12 gap-4">
{/* Top Row */}
{/* Simplified Performance Chart */}
<div className="col-span-12 lg:col-span-6">
<Card className="border-0 shadow-md bg-white h-full">
<CardHeader className="pb-3">
<div className="flex items-center justify-between">
<CardTitle className="text-[16px] font-semibold text-[#111827]">
Performance
</CardTitle>
<MoreHorizontal className="h-4 w-4 text-[#6B7280]" />
</div>
<div className="text-[14px] text-[#6B7280]">
{stats.completedCourses} Course Completed
</div>
</CardHeader>
<CardContent className="pt-0 pb-4">
<ResponsiveContainer width="100%" height={140}>
<BarChart data={performanceData} margin={{ top: 15, right: 15, left: 15, bottom: 15 }}>
<defs>
<filter id="performanceShadow" x="-50%" y="-50%" width="200%" height="200%">
<feDropShadow dx="0" dy="2" stdDeviation="2" floodColor="#04045B" floodOpacity="0.3"/>
</filter>
</defs>
<CartesianGrid strokeDasharray="3 3" stroke="#E5E7EB" opacity={0.4} />
<Bar
dataKey="value"
fill="#04045B"
radius={[4, 4, 0, 0]}
maxBarSize={24}
filter="url(#performanceShadow)"
className="hover:opacity-80 transition-opacity duration-200"
/>
<XAxis
dataKey="name"
axisLine={false}
tickLine={false}
tick={{ fontSize: 13, fill: '#6B7280', fontWeight: 500 }}
/>
<YAxis
axisLine={false}
tickLine={false}
tick={{ fontSize: 11, fill: '#9CA3AF' }}
width={25}
/>
<Tooltip
cursor={false}
contentStyle={{
backgroundColor: 'white',
border: '1px solid #E5E7EB',
borderRadius: '8px',
fontSize: '14px',
boxShadow: '0 4px 12px rgba(0,0,0,0.15)',
padding: '12px'
}}
formatter={(value) => [`${value} courses`, 'Completed']}
labelStyle={{ color: '#111827', fontWeight: 600, marginBottom: '4px' }}
/>
</BarChart>
</ResponsiveContainer>
</CardContent>
</Card>
</div>
{/* Simplified Time Learning Chart */}
<div className="col-span-12 lg:col-span-6">
<Card className="border-0 shadow-md bg-white h-full">
<CardHeader className="pb-3">
<div className="flex items-center justify-between">
<div>
<CardTitle className="text-[16px] font-semibold text-[#111827] mb-1">
Time spend on learning
</CardTitle>
<div className="text-[14px] text-[#6B7280]">
4 Course Completed
</div>
</div>
<div className="flex items-center gap-2">
<div
className="flex items-center gap-2 cursor-pointer select-none hover:bg-gray-50 rounded-lg px-3 py-2 transition-colors duration-200"
onWheel={handleWheel}
title="Scroll to change month or click arrows"
>
<button
onClick={() => navigateMonth('prev')}
className="h-4 w-4 text-[#6B7280] hover:text-[#04045B] transition-colors duration-200 flex items-center justify-center"
aria-label="Previous month"
>
<ChevronLeft className="h-4 w-4" />
</button>
<span className="text-[14px] font-medium text-[#111827] min-w-[70px] text-center transition-all duration-200">
{selectedTimeRange}
</span>
<button
onClick={() => navigateMonth('next')}
className="h-4 w-4 text-[#6B7280] hover:text-[#04045B] transition-colors duration-200 flex items-center justify-center"
aria-label="Next month"
>
<ChevronRight className="h-4 w-4" />
</button>
</div>
</div>
</div>
</CardHeader>
<CardContent className="pt-0 pb-4">
<div className="mb-4">
<ResponsiveContainer width="100%" height={120}>
<BarChart data={timeLearningData} margin={{ top: 10, right: 10, left: 10, bottom: 10 }}>
<defs>
<filter id="stackShadow" x="-20%" y="-20%" width="140%" height="140%">
<feDropShadow dx="0" dy="1" stdDeviation="1" floodColor="#000000" floodOpacity="0.2"/>
</filter>
</defs>
<CartesianGrid strokeDasharray="3 3" stroke="#E5E7EB" opacity={0.3} />
<Bar
dataKey="performance"
stackId="a"
fill="#04045B"
radius={[0, 0, 0, 0]}
maxBarSize={28}
filter="url(#stackShadow)"
/>
<Bar
dataKey="consistency"
stackId="a"
fill="#6366F1"
radius={[0, 0, 0, 0]}
maxBarSize={28}
/>
<Bar
dataKey="unknown"
stackId="a"
fill="#E5E7EB"
radius={[3, 3, 0, 0]}
maxBarSize={28}
/>
<XAxis
dataKey="date"
axisLine={false}
tickLine={false}
tick={{ fontSize: 12, fill: '#6B7280', fontWeight: 500 }}
/>
<YAxis
axisLine={false}
tickLine={false}
tick={{ fontSize: 10, fill: '#9CA3AF' }}
width={25}
/>
<Tooltip
cursor={false}
contentStyle={{
backgroundColor: 'white',
border: '1px solid #E5E7EB',
borderRadius: '8px',
fontSize: '14px',
boxShadow: '0 4px 12px rgba(0,0,0,0.15)',
padding: '12px'
}}
labelStyle={{ color: '#111827', fontWeight: 600, marginBottom: '4px' }}
/>
</BarChart>
</ResponsiveContainer>
</div>
{/* Enhanced Legend */}
<div className="flex items-center justify-center gap-6 text-[14px]">
<div className="flex items-center gap-2">
<div className="w-3 h-3 rounded-sm bg-[#04045B] shadow-sm"></div>
<span className="text-[#6B7280] font-medium">Performance</span>
</div>
<div className="flex items-center gap-2">
<div className="w-3 h-3 rounded-sm bg-[#6366F1] shadow-sm"></div>
<span className="text-[#6B7280] font-medium">Consistency</span>
</div>
<div className="flex items-center gap-2">
<div className="w-3 h-3 rounded-sm bg-[#E5E7EB] shadow-sm"></div>
<span className="text-[#6B7280] font-medium">Other</span>
</div>
</div>
</CardContent>
</Card>
</div>
{/* Bottom Row */}
{/* Enhanced Your Courses (7 columns) */}
<div className="col-span-12 lg:col-span-7">
<Card className="border-0 shadow-md bg-white h-full">
<CardHeader className="pb-3">
<div className="flex items-center justify-between">
<div>
<CardTitle className="text-[16px] font-semibold text-[#111827]">
Your Courses
</CardTitle>
<div className="text-[14px] text-[#6B7280]">
{courseList.length} Course{courseList.length !== 1 ? 's' : ''} {courseList.filter(c => c.progress === 100).length} Completed
</div>
</div>
<Button
variant="ghost"
className="text-[14px] text-[#6B7280] hover:text-[#04045B] h-auto p-2 rounded-lg transition-colors"
onClick={() => window.location.href = '/library?view=individual'}
>
<span className="mr-1">View All</span>
<ArrowRight className="h-3 w-3" />
</Button>
</div>
</CardHeader>
<CardContent className="pt-0 pb-4">
<div className="space-y-3">
{courseList.map((course, index) => {
const isCompleted = course.progress === 100;
const isInProgress = course.progress > 0 && course.progress < 100;
const isNotStarted = course.progress === 0;
return (
<div
key={index}
className="group relative flex items-center gap-4 p-3 hover:bg-gray-50 hover:shadow-sm rounded-lg transition-all duration-200 cursor-pointer border border-transparent hover:border-gray-200"
onClick={() => window.location.href = '/course?view=individual'}
>
{/* Enhanced Course Avatar */}
<div className="relative flex-shrink-0">
<div
className="w-8 h-8 rounded-lg flex items-center justify-center text-white text-[14px] font-semibold shadow-sm"
style={{ backgroundColor: course.color }}
>
{course.name.charAt(0)}
</div>
{/* Status Indicator */}
{isCompleted && (
<div className="absolute -top-1 -right-1 w-3 h-3 bg-[#21A36A] rounded-full flex items-center justify-center">
<CheckCircle className="w-2 h-2 text-white" />
</div>
)}
{isInProgress && (
<div className="absolute -top-1 -right-1 w-3 h-3 bg-[#F8C301] rounded-full animate-pulse"></div>
)}
</div>
{/* Course Information */}
<div className="flex-1 min-w-0">
<div className="flex items-start justify-between gap-2 mb-1">
<h4 className="text-[16px] font-medium text-[#111827] truncate group-hover:text-[#04045B] transition-colors">
{course.name}
</h4>
<div className="flex items-center gap-1 flex-shrink-0">
<span className="text-[14px] font-medium text-[#111827]">
{course.progress}%
</span>
{isCompleted && (
<Badge variant="outline" className="text-[12px] bg-[#21A36A]/10 text-[#21A36A] border-[#21A36A]/20 px-2 py-0.5">
Complete
</Badge>
)}
</div>
</div>
<div className="flex items-center gap-4 mb-2">
<span className="text-[14px] text-[#6B7280]">
{course.lessons}
</span>
<span className="text-[14px] text-[#6B7280]">
{isCompleted ? 'Completed' : isInProgress ? 'In Progress' : 'Not Started'}
</span>
{isInProgress && (
<span className="text-[14px] text-[#F8C301] font-medium">
Continue Learning
</span>
)}
</div>
{/* Enhanced Progress Bar */}
<div className="flex items-center gap-3">
<div className="flex-1 bg-gray-100 rounded-full h-2 overflow-hidden">
<div
className="h-2 rounded-full transition-all duration-700 ease-out relative"
style={{
width: `${course.progress}%`,
backgroundColor: course.color
}}
>
{/* Progress bar shine effect */}
<div className="absolute inset-0 bg-gradient-to-r from-transparent via-white/30 to-transparent animate-pulse"></div>
</div>
</div>
{/* Action Button */}
<div className="flex-shrink-0">
{isCompleted ? (
<Button
variant="outline"
size="sm"
className="h-8 px-3 text-[14px] border-[#21A36A]/20 text-[#21A36A] hover:bg-[#21A36A]/10"
onClick={(e) => {
e.stopPropagation();
window.location.href = '/course?view=individual';
}}
>
<Award className="w-3 h-3 mr-1" />
Review
</Button>
) : isInProgress ? (
<Button
variant="outline"
size="sm"
className="h-8 px-3 text-[14px] border-[#F8C301]/30 text-[#04045B] hover:bg-[#F8C301]/10"
onClick={(e) => {
e.stopPropagation();
window.location.href = '/course?view=individual';
}}
>
<Play className="w-3 h-3 mr-1 stroke-[#04045B]" />
Continue
</Button>
) : (
<Button
variant="outline"
size="sm"
className="h-8 px-3 text-[14px] border-[#04045B]/20 text-[#04045B] hover:bg-[#04045B]/10"
onClick={(e) => {
e.stopPropagation();
window.location.href = '/course?view=individual';
}}
>
<BookOpen className="w-3 h-3 mr-1" />
Start
</Button>
)}
</div>
</div>
</div>
{/* Hover Arrow */}
<div className="flex-shrink-0 opacity-0 group-hover:opacity-100 transition-opacity duration-200">
<ArrowRight className="h-4 w-4 text-[#6B7280]" />
</div>
</div>
);
})}
{/* Quick Action Footer */}
<div className="pt-2 mt-4 border-t border-gray-100">
<div className="flex items-center justify-between text-[14px]">
<div className="flex items-center gap-4">
<div className="flex items-center gap-2">
<div className="w-2 h-2 bg-[#21A36A] rounded-full"></div>
<span className="text-[#6B7280]">Completed</span>
</div>
<div className="flex items-center gap-2">
<div className="w-2 h-2 bg-[#F8C301] rounded-full"></div>
<span className="text-[#6B7280]">In Progress</span>
</div>
<div className="flex items-center gap-2">
<div className="w-2 h-2 bg-gray-300 rounded-full"></div>
<span className="text-[#6B7280]">Not Started</span>
</div>
</div>
<Button
variant="ghost"
size="sm"
className="text-[14px] text-[#6B7280] hover:text-[#04045B] h-auto p-1"
onClick={() => window.location.href = '/library?view=individual'}
>
<Target className="w-3 h-3 mr-1" />
Browse Library
</Button>
</div>
</div>
</div>
</CardContent>
</Card>
</div>
{/* Daily Activity (5 columns) */}
<div className="col-span-12 lg:col-span-5">
<Card className="border-0 shadow-md bg-white h-full">
<CardHeader className="pb-3">
<div className="flex items-center justify-between">
<div>
<CardTitle className="text-[16px] font-semibold text-[#111827]">
Daily activity
</CardTitle>
<div className="text-[14px] text-[#6B7280]">
Today Apr 24
</div>
</div>
</div>
</CardHeader>
<CardContent className="pt-0 pb-4">
<div className="space-y-2">
{dailyActivities.map((activity, index) => (
<div key={index} className="flex items-center gap-3">
<div className="text-[12px] text-[#6B7280] w-10 text-right">
{activity.time}
</div>
<div className="w-px h-8 bg-gray-200 relative">
{activity.course && (
<div className="absolute -left-1 top-1/2 transform -translate-y-1/2 w-2 h-2 rounded-full" style={{ backgroundColor: activity.color }}></div>
)}
</div>
<div className="flex-1 min-w-0">
{activity.course ? (
<div className="flex items-center gap-2">
<div className="flex-1 min-w-0">
<div className="text-[14px] font-medium text-[#111827] truncate">
{activity.course}
</div>
<div className="text-[12px] text-[#6B7280]">
{activity.type}
</div>
</div>
<div className="w-6 h-6 rounded-full flex items-center justify-center text-white text-[10px] font-semibold flex-shrink-0" style={{ backgroundColor: activity.color }}>
{activity.instructor}
</div>
</div>
) : (
<div className="h-8"></div>
)}
</div>
</div>
))}
</div>
</CardContent>
</Card>
</div>
</div>
</div>
);
}

View File

@@ -1,12 +1,7 @@
import { createRoot } from "react-dom/client";
import { BrowserRouter } from "react-router-dom";
import App from "./App.tsx";
import "./styles/globals.css";
import { Provider } from "react-redux";
import { store } from "./Redux/Store.tsx";
createRoot(document.getElementById("root")!).render(
<BrowserRouter>
<App />
</BrowserRouter>
);
import { createRoot } from "react-dom/client";
import App from "./App.tsx";
import "./index.css";
createRoot(document.getElementById("root")!).render(<App />);

View File

@@ -1,794 +0,0 @@
import React, { useState, useEffect } from 'react';
import { LearnerLayout } from '../components/learner/LearnerLayout';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '../components/ui/card';
import { Button } from '../components/ui/button';
import { Input } from '../components/ui/input';
import { Badge } from '../components/ui/badge';
import { Avatar, AvatarFallback, AvatarImage } from '../components/ui/avatar';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '../components/ui/tabs';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../components/ui/select';
import { Progress } from '../components/ui/progress';
import { Separator } from '../components/ui/separator';
import { motion } from 'motion/react';
import {
ArrowLeft,
Trophy,
Medal,
Award,
Target,
TrendingUp,
Users,
Download,
Filter,
Search,
Crown,
Star,
Gift,
Zap,
ChevronRight,
Calendar,
Clock,
BookOpen,
CheckCircle,
BarChart3,
PieChart,
ArrowUp,
ArrowDown,
Minus,
Settings,
Flag,
Sparkles
} from 'lucide-react';
import { useNavigate } from 'react-router-dom';
const navigate = useNavigate();
// Mock data for leaderboard
const mockLeaderboard = [
{
id: 1,
rank: 1,
name: "Alexandra Chen",
title: "Senior Director",
department: "Operations",
avatar: "https://images.unsplash.com/photo-1494790108755-2616b612b786?w=150&h=150&fit=crop&crop=face",
totalPoints: 2847,
monthlyPoints: 485,
coursesCompleted: 12,
streakDays: 28,
level: "Expert",
progress: 85,
trend: "up",
badges: ["Leadership Excellence", "Team Builder", "Innovation Champion"],
lastActive: "2 hours ago",
completionRate: 94
},
{
id: 2,
rank: 2,
name: "Michael Rodriguez",
title: "VP Engineering",
department: "Technology",
avatar: "https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=150&h=150&fit=crop&crop=face",
totalPoints: 2756,
monthlyPoints: 423,
coursesCompleted: 11,
streakDays: 22,
level: "Expert",
progress: 76,
trend: "up",
badges: ["Tech Leader", "Mentor", "Strategic Thinker"],
lastActive: "4 hours ago",
completionRate: 89
},
{
id: 3,
rank: 3,
name: "Sarah Johnson",
title: "Director of Sales",
department: "Sales",
avatar: "https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=150&h=150&fit=crop&crop=face",
totalPoints: 2634,
monthlyPoints: 398,
coursesCompleted: 10,
streakDays: 19,
level: "Advanced",
progress: 68,
trend: "up",
badges: ["Sales Champion", "Customer Focus", "Results Driver"],
lastActive: "1 hour ago",
completionRate: 91
},
{
id: 4,
rank: 4,
name: "David Kim",
title: "Marketing Manager",
department: "Marketing",
avatar: "https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=150&h=150&fit=crop&crop=face",
totalPoints: 2521,
monthlyPoints: 367,
coursesCompleted: 9,
streakDays: 15,
level: "Advanced",
progress: 52,
trend: "stable",
badges: ["Creative Leader", "Brand Builder", "Analytics Pro"],
lastActive: "6 hours ago",
completionRate: 87
},
{
id: 5,
rank: 5,
name: "Emily Watson",
title: "HR Director",
department: "Human Resources",
avatar: "https://images.unsplash.com/photo-1573496359142-b8d87734a5a2?w=150&h=150&fit=crop&crop=face",
totalPoints: 2398,
monthlyPoints: 334,
coursesCompleted: 8,
streakDays: 12,
level: "Advanced",
progress: 45,
trend: "down",
badges: ["People Leader", "Culture Champion", "Diversity Advocate"],
lastActive: "3 hours ago",
completionRate: 92
},
{
id: 6,
rank: 6,
name: "James Thompson",
title: "Finance Manager",
department: "Finance",
avatar: "https://images.unsplash.com/photo-1556157382-97eda2d62296?w=150&h=150&fit=crop&crop=face",
totalPoints: 2267,
monthlyPoints: 298,
coursesCompleted: 7,
streakDays: 8,
level: "Intermediate",
progress: 34,
trend: "up",
badges: ["Financial Acumen", "Risk Manager", "Process Optimizer"],
lastActive: "5 hours ago",
completionRate: 85
}
];
// Animated number counter component
const AnimatedNumber = ({ value, duration = 1000 }: { value: number; duration?: number }) => {
const [displayValue, setDisplayValue] = useState(0);
useEffect(() => {
let startTime: number;
let animationFrame: number;
const animate = (timestamp: number) => {
if (!startTime) startTime = timestamp;
const progress = Math.min((timestamp - startTime) / duration, 1);
// Easing function for smooth animation
const easeOut = 1 - Math.pow(1 - progress, 3);
setDisplayValue(Math.floor(value * easeOut));
if (progress < 1) {
animationFrame = requestAnimationFrame(animate);
}
};
animationFrame = requestAnimationFrame(animate);
return () => {
if (animationFrame) {
cancelAnimationFrame(animationFrame);
}
};
}, [value, duration]);
return <span>{displayValue.toLocaleString()}</span>;
};
export function CorporateLeaderboard() {
const [searchQuery, setSearchQuery] = useState('');
const [selectedDepartment, setSelectedDepartment] = useState('all');
const [selectedLevel, setSelectedLevel] = useState('all');
const [sortBy, setSortBy] = useState('rank');
const [timeFilter, setTimeFilter] = useState('month');
// Mock corporate user data matching dashboard pattern
const user = {
name: "Sarah Johnson",
email: "sarah.johnson@company.com",
avatar: "https://images.unsplash.com/photo-1494790108755-2616b612b786?w=150&h=150&fit=crop&crop=face",
organization: "TCS",
orgLogo: "https://images.unsplash.com/photo-1560179707-f14e90ef3623?w=32&h=32&fit=crop",
role: "Senior Manager",
cohort: "Leadership 2024"
};
const getRankIcon = (rank: number) => {
switch (rank) {
case 1:
return <Trophy className="h-8 w-8 text-[#F8C301]" />;
case 2:
return <Medal className="h-8 w-8 text-primary" />;
case 3:
return <Award className="h-8 w-8 text-[#26231A]" />;
default:
return <Target className="h-8 w-8 text-muted-foreground" />;
}
};
const getTrendIcon = (trend: string) => {
switch (trend) {
case 'up':
return <ArrowUp className="h-4 w-4 text-success" />;
case 'down':
return <ArrowDown className="h-4 w-4 text-destructive" />;
default:
return <Minus className="h-4 w-4 text-muted-foreground" />;
}
};
// Filter leaderboard data
const filteredLeaderboard = mockLeaderboard.filter(user => {
const matchesSearch = user.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
user.department.toLowerCase().includes(searchQuery.toLowerCase()) ||
user.title.toLowerCase().includes(searchQuery.toLowerCase());
const matchesDepartment = selectedDepartment === 'all' || user.department === selectedDepartment;
const matchesLevel = selectedLevel === 'all' || user.level === selectedLevel;
return matchesSearch && matchesDepartment && matchesLevel;
});
// Get unique departments and levels for filters
const departments = Array.from(new Set(mockLeaderboard.map(user => user.department)));
const levels = Array.from(new Set(mockLeaderboard.map(user => user.level)));
return (
<LearnerLayout currentPage="/leaderboard" userType="corporate" user={user}>
<div className="p-6 space-y-8">
{/* KPI Cards - Matching Dashboard Design with Brand Colors */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
<Card className="hover:shadow-lg transition-shadow duration-200">
<CardContent className="p-6 text-center">
<div className="w-12 h-12 bg-primary/10 rounded-full flex items-center justify-center mx-auto mb-3">
<Users className="h-6 w-6 text-primary" />
</div>
<p className="text-2xl font-bold text-foreground mb-1">128</p>
<p className="text-base text-muted-foreground">Active Learners</p>
</CardContent>
</Card>
<Card className="hover:shadow-lg transition-shadow duration-200">
<CardContent className="p-6 text-center">
<div className="w-12 h-12 bg-success/10 rounded-full flex items-center justify-center mx-auto mb-3">
<BookOpen className="h-6 w-6 text-success" />
</div>
<p className="text-2xl font-bold text-foreground mb-1">1,247</p>
<p className="text-base text-muted-foreground">Courses Completed</p>
</CardContent>
</Card>
<Card className="hover:shadow-lg transition-shadow duration-200">
<CardContent className="p-6 text-center">
<div className="w-12 h-12 bg-[#F8C301]/10 rounded-full flex items-center justify-center mx-auto mb-3">
<Trophy className="h-6 w-6 text-[#26231A]" />
</div>
<p className="text-2xl font-bold text-foreground mb-1">89%</p>
<p className="text-base text-muted-foreground">Avg Completion</p>
</CardContent>
</Card>
<Card className="hover:shadow-lg transition-shadow duration-200">
<CardContent className="p-6 text-center">
<div className="w-12 h-12 bg-[#26231A]/10 rounded-full flex items-center justify-center mx-auto mb-3">
<TrendingUp className="h-6 w-6 text-[#26231A]" />
</div>
<p className="text-2xl font-bold text-foreground mb-1">+23%</p>
<p className="text-base text-muted-foreground">This Month</p>
</CardContent>
</Card>
</div>
{/* Time Period Filter - Enhanced Design */}
<Card>
<CardContent className="p-6">
<div className="flex flex-col sm:flex-row gap-4 items-start sm:items-center justify-between">
<div>
<h2 className="text-xl font-semibold mb-1 text-foreground">Performance Tracking</h2>
<p className="text-base text-muted-foreground">View leaderboard data across different time periods</p>
</div>
<div className="flex gap-2">
<Button
variant={timeFilter === 'week' ? 'default' : 'outline'}
onClick={() => setTimeFilter('week')}
className="text-base h-11"
>
This Week
</Button>
<Button
variant={timeFilter === 'month' ? 'default' : 'outline'}
onClick={() => setTimeFilter('month')}
className="text-base h-11"
>
This Month
</Button>
<Button
variant={timeFilter === 'quarter' ? 'default' : 'outline'}
onClick={() => setTimeFilter('quarter')}
className="text-base h-11"
>
This Quarter
</Button>
</div>
</div>
</CardContent>
</Card>
{/* Top Performers - Enhanced with KLC Branding */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5 }}
>
<Card>
<CardHeader>
<div className="flex items-center gap-3">
<div className="w-10 h-10 bg-[#F8C301]/10 rounded-full flex items-center justify-center">
<Crown className="h-5 w-5 text-[#26231A]" />
</div>
<div>
<CardTitle className="text-xl text-foreground">Top Performers This Month</CardTitle>
<CardDescription className="text-base">
Celebrating our highest achievers and their outstanding dedication
</CardDescription>
</div>
</div>
</CardHeader>
<CardContent className="p-6">
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
{filteredLeaderboard.slice(0, 3).map((user, index) => {
const isFirst = index === 0;
const isSecond = index === 1;
const isThird = index === 2;
return (
<motion.div
key={user.id}
initial={{ opacity: 0, y: 30, scale: 0.95 }}
animate={{ opacity: 1, y: 0, scale: 1 }}
transition={{
duration: 0.6,
delay: index * 0.15,
ease: "easeOut"
}}
whileHover={{
scale: 1.02,
y: -5,
transition: { duration: 0.2 }
}}
className="w-full"
>
<Card
className={`relative overflow-hidden transition-all duration-300 hover:shadow-xl cursor-pointer group ${
isFirst ? 'border-2 border-[#F8C301] bg-gradient-to-br from-[#F8C301]/5 to-[#F8C301]/10' :
isSecond ? 'border-2 border-primary bg-gradient-to-br from-primary/5 to-primary/10' :
'border-2 border-[#26231A] bg-gradient-to-br from-[#26231A]/5 to-[#26231A]/10'
} ${isFirst ? 'lg:scale-105 lg:-translate-y-2' : ''}`}
>
{/* Subtle Metallic Shimmer Effect for Top 3 */}
<div
className={`absolute inset-0 opacity-0 group-hover:opacity-60 transition-opacity duration-1000 pointer-events-none shimmer-effect ${
isFirst ? 'shimmer-gold' : isSecond ? 'shimmer-silver' : 'shimmer-bronze'
}`}
/>
{/* Rank Ribbon with KLC Colors */}
<motion.div
className={`absolute top-0 right-0 px-3 py-1 rounded-bl-lg text-white text-sm font-medium ${
isFirst ? 'bg-[#F8C301] text-[#26231A]' :
isSecond ? 'bg-primary text-white' :
'bg-[#26231A] text-white'
}`}
initial={{ x: 20, opacity: 0 }}
animate={{ x: 0, opacity: 1 }}
transition={{ delay: index * 0.15 + 0.3 }}
>
#{user.rank}
</motion.div>
{/* Winner Crown for First Place */}
{isFirst && (
<motion.div
className="absolute top-4 left-4"
initial={{ rotate: -10, scale: 0 }}
animate={{
rotate: 0,
scale: 1,
y: [0, -2, 0],
rotateZ: [0, 2, -2, 0]
}}
transition={{
delay: 0.5,
type: "spring",
stiffness: 200,
damping: 10,
y: {
duration: 2,
repeat: Infinity,
ease: "easeInOut"
},
rotateZ: {
duration: 4,
repeat: Infinity,
ease: "easeInOut"
}
}}
>
<Crown className="h-6 w-6 text-[#F8C301]" />
</motion.div>
)}
<CardContent className="p-8 text-center">
{/* Rank Icon */}
<motion.div
className="flex justify-center mb-6"
initial={{ scale: 0, rotate: -180 }}
animate={{ scale: 1, rotate: 0 }}
transition={{
delay: index * 0.15 + 0.2,
type: "spring",
stiffness: 150
}}
>
<div className={`p-4 rounded-full ${
isFirst ? 'bg-[#F8C301]/10' : isSecond ? 'bg-primary/10' : 'bg-[#26231A]/10'
}`}>
{getRankIcon(user.rank)}
</div>
</motion.div>
{/* User Avatar with Enhanced Styling */}
<motion.div
className="relative mb-6"
initial={{ scale: 0 }}
animate={{ scale: 1 }}
transition={{
delay: index * 0.15 + 0.4,
type: "spring",
stiffness: 200
}}
whileHover={{ scale: 1.05 }}
>
<Avatar className="w-24 h-24 mx-auto border-4 border-white shadow-lg">
<AvatarImage src={user.avatar} alt={user.name} />
<AvatarFallback className="text-xl">
{user.name.split(' ').map(n => n[0]).join('')}
</AvatarFallback>
</Avatar>
{/* Trend Indicator */}
<motion.div
className="absolute -bottom-2 -right-2 p-1 bg-white rounded-full shadow-md"
initial={{ scale: 0 }}
animate={{
scale: [1, 1.1, 1]
}}
transition={{
delay: index * 0.15 + 0.6,
scale: {
duration: 2,
repeat: Infinity,
ease: "easeInOut"
}
}}
>
{getTrendIcon(user.trend)}
</motion.div>
</motion.div>
{/* User Information */}
<motion.div
className="mb-6"
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: index * 0.15 + 0.5 }}
>
<h3 className="text-xl mb-2 text-foreground">{user.name}</h3>
<p className="text-base text-muted-foreground mb-1">{user.title}</p>
<p className="text-base text-muted-foreground">{user.department}</p>
</motion.div>
{/* Performance Stats */}
<motion.div
className="grid grid-cols-3 gap-4 mb-6 p-4 bg-white/50 rounded-lg backdrop-blur-sm"
initial={{ opacity: 0, scale: 0.9 }}
animate={{ opacity: 1, scale: 1 }}
transition={{ delay: index * 0.15 + 0.7 }}
>
<div className="text-center">
<p className="text-2xl font-bold text-foreground">
<AnimatedNumber value={user.totalPoints} duration={1500} />
</p>
<p className="text-sm text-muted-foreground">Points</p>
</div>
<div className="text-center border-x border-border/50">
<p className="text-2xl font-bold text-foreground">
<AnimatedNumber value={user.coursesCompleted} duration={1200} />
</p>
<p className="text-sm text-muted-foreground">Courses</p>
</div>
<div className="text-center">
<p className="text-2xl font-bold text-foreground">
<AnimatedNumber value={user.streakDays} duration={1000} />
</p>
<p className="text-sm text-muted-foreground">Day Streak</p>
</div>
</motion.div>
{/* Level Progress */}
<motion.div
className="mb-6"
initial={{ opacity: 0, x: -20 }}
animate={{ opacity: 1, x: 0 }}
transition={{ delay: index * 0.15 + 0.8 }}
>
<div className="flex items-center justify-between mb-2">
<span className="text-base text-muted-foreground">Level Progress</span>
<Badge variant="outline" className="text-sm font-medium">
{user.level}
</Badge>
</div>
<Progress value={user.progress} className="h-2" />
<p className="text-sm text-muted-foreground mt-1">{user.progress}% to next level</p>
</motion.div>
{/* Achievement Badges */}
<motion.div
className="space-y-3"
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: index * 0.15 + 0.9 }}
>
<p className="text-base text-muted-foreground">Recent Achievements</p>
<div className="flex flex-wrap justify-center gap-2">
{user.badges.slice(0, 3).map((badge, badgeIndex) => (
<motion.div
key={badge}
initial={{ opacity: 0, scale: 0.8 }}
animate={{ opacity: 1, scale: 1 }}
transition={{
delay: index * 0.15 + 1 + (badgeIndex * 0.1)
}}
whileHover={{ scale: 1.05 }}
>
<Badge
variant="outline"
className={`text-sm px-3 py-1 ${
badgeIndex === 0 ? 'border-[#F8C301]/30 bg-[#F8C301]/5 text-[#26231A]' :
badgeIndex === 1 ? 'border-primary/30 bg-primary/5 text-primary' :
'border-success/30 bg-success/5 text-success'
}`}
>
{badge}
</Badge>
</motion.div>
))}
</div>
</motion.div>
{/* Monthly Performance Indicator */}
<motion.div
className="mt-6 pt-4 border-t border-border/50"
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: index * 0.15 + 1.1 }}
>
<div className="flex items-center justify-center gap-2">
<TrendingUp className="h-4 w-4 text-success" />
<span className="text-base text-success font-medium">
+<AnimatedNumber value={user.monthlyPoints} duration={1800} /> this month
</span>
</div>
</motion.div>
</CardContent>
</Card>
</motion.div>
);
})}
</div>
</CardContent>
</Card>
</motion.div>
{/* Search and Filters - Matching Dashboard Design */}
<Card>
<CardContent className="p-6">
<div className="space-y-4">
{/* Search Bar */}
<div className="relative">
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-muted-foreground" />
<Input
placeholder="Search by name, department, or title..."
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="pl-10 text-base h-11"
/>
</div>
{/* Filters Row */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
<Select value={selectedDepartment} onValueChange={setSelectedDepartment}>
<SelectTrigger className="text-base h-11">
<SelectValue placeholder="All Departments" />
</SelectTrigger>
<SelectContent>
<SelectItem value="all">All Departments</SelectItem>
{departments.map(dept => (
<SelectItem key={dept} value={dept}>{dept}</SelectItem>
))}
</SelectContent>
</Select>
<Select value={selectedLevel} onValueChange={setSelectedLevel}>
<SelectTrigger className="text-base h-11">
<SelectValue placeholder="All Levels" />
</SelectTrigger>
<SelectContent>
<SelectItem value="all">All Levels</SelectItem>
{levels.map(level => (
<SelectItem key={level} value={level}>{level}</SelectItem>
))}
</SelectContent>
</Select>
<Select value={sortBy} onValueChange={setSortBy}>
<SelectTrigger className="text-base h-11">
<SelectValue placeholder="Sort By" />
</SelectTrigger>
<SelectContent>
<SelectItem value="rank">Rank</SelectItem>
<SelectItem value="points">Total Points</SelectItem>
<SelectItem value="courses">Courses Completed</SelectItem>
<SelectItem value="streak">Learning Streak</SelectItem>
</SelectContent>
</Select>
<Button
variant="outline"
className="text-base h-11"
onClick={() => {
setSearchQuery('');
setSelectedDepartment('all');
setSelectedLevel('all');
}}
>
Clear Filters
</Button>
</div>
</div>
</CardContent>
</Card>
{/* Full Leaderboard Table - Enhanced Design */}
<Card>
<CardHeader>
<div className="flex items-center justify-between">
<div className="flex items-center gap-3">
<div className="w-10 h-10 bg-primary/10 rounded-full flex items-center justify-center">
<Trophy className="h-5 w-5 text-primary" />
</div>
<div>
<CardTitle className="text-xl text-foreground">Complete Leaderboard</CardTitle>
<p className="text-base text-muted-foreground mt-1">
View all team members and their performance metrics
</p>
</div>
</div>
<Badge variant="outline" className="text-base">
{filteredLeaderboard.length} {filteredLeaderboard.length === 1 ? 'learner' : 'learners'}
</Badge>
</div>
</CardHeader>
<CardContent className="p-6">
<div className="space-y-4 !mt-0 !pt-0">
{filteredLeaderboard.map((user, index) => (
<motion.div
key={user.id}
initial={{ opacity: 0, x: -20 }}
animate={{ opacity: 1, x: 0 }}
transition={{ delay: index * 0.05 }}
className="group cursor-pointer p-4 rounded-lg border border-border hover:border-primary/30 hover:bg-muted/30 transition-all duration-200"
>
<div className="flex items-center gap-4">
{/* Rank */}
<div className="flex items-center justify-center w-12 h-12 rounded-full bg-muted flex-shrink-0">
<div className="flex items-center justify-center w-8 h-8">
{user.rank <= 3 ? getRankIcon(user.rank) : (
<span className="text-lg font-bold text-foreground">#{user.rank}</span>
)}
</div>
</div>
{/* Avatar and User Info */}
<div className="flex items-center gap-3 flex-1 min-w-0">
<Avatar className="w-10 h-10 flex-shrink-0">
<AvatarImage src={user.avatar} alt={user.name} />
<AvatarFallback className="text-sm bg-primary/10 text-primary">
{user.name.split(' ').map(n => n[0]).join('')}
</AvatarFallback>
</Avatar>
<div className="flex-1 min-w-0">
<div className="flex items-center gap-2">
<p className="text-base font-medium text-foreground group-hover:text-primary transition-colors truncate">
{user.name}
</p>
{getTrendIcon(user.trend)}
</div>
<div className="flex items-center gap-2 text-sm text-muted-foreground">
<span>{user.title}</span>
<span></span>
<span>{user.department}</span>
<span></span>
<Badge variant="outline" className="text-sm">
{user.level}
</Badge>
</div>
</div>
</div>
{/* Performance Stats */}
<div className="hidden md:flex items-center gap-6 text-sm">
<div className="text-center">
<p className="font-bold text-foreground">{user.totalPoints.toLocaleString()}</p>
<p className="text-muted-foreground">Points</p>
</div>
<div className="text-center">
<p className="font-bold text-foreground">{user.coursesCompleted}</p>
<p className="text-muted-foreground">Courses</p>
</div>
<div className="text-center">
<p className="font-bold text-foreground">{user.streakDays}</p>
<p className="text-muted-foreground">Streak</p>
</div>
<div className="text-center">
<p className="font-bold text-foreground">{user.completionRate}%</p>
<p className="text-muted-foreground">Complete</p>
</div>
</div>
{/* Action */}
<ChevronRight className="h-4 w-4 text-muted-foreground group-hover:text-primary group-hover:translate-x-1 transition-all flex-shrink-0" />
</div>
{/* Mobile Stats */}
<div className="md:hidden mt-4 grid grid-cols-4 gap-3 text-sm">
<div className="text-center">
<p className="font-bold text-foreground">{user.totalPoints.toLocaleString()}</p>
<p className="text-muted-foreground">Points</p>
</div>
<div className="text-center">
<p className="font-bold text-foreground">{user.coursesCompleted}</p>
<p className="text-muted-foreground">Courses</p>
</div>
<div className="text-center">
<p className="font-bold text-foreground">{user.streakDays}</p>
<p className="text-muted-foreground">Streak</p>
</div>
<div className="text-center">
<p className="font-bold text-foreground">{user.completionRate}%</p>
<p className="text-muted-foreground">Complete</p>
</div>
</div>
</motion.div>
))}
</div>
</CardContent>
</Card>
</div>
</LearnerLayout>
);
}

View File

@@ -1,954 +0,0 @@
import React, { useState, useEffect, useRef } from 'react';
import { LearnerLayout } from '../components/learner/LearnerLayout';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '../components/ui/card';
import { Button } from '../components/ui/button';
import { Input } from '../components/ui/input';
import { Label } from '../components/ui/label';
import { Textarea } from '../components/ui/textarea';
import { RadioGroup, RadioGroupItem } from '../components/ui/radio-group';
import { Checkbox } from '../components/ui/checkbox';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../components/ui/select';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '../components/ui/tabs';
import { Badge } from '../components/ui/badge';
import { Progress } from '../components/ui/progress';
import { Alert, AlertDescription } from '../components/ui/alert';
import { Separator } from '../components/ui/separator';
import {
FileText,
Clock,
Users,
ChevronRight,
Star,
TrendingUp,
BarChart3,
MessageSquare,
AlertCircle,
CheckCircle,
Calendar,
Target,
Zap,
ThumbsUp,
ThumbsDown,
Send,
Eye,
Award,
Lightbulb,
ArrowUp,
ArrowDown,
MapPin,
Globe,
ExternalLink
} from 'lucide-react';
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, PieChart, Pie, Cell } from 'recharts';
// import exampleImage from 'figma:asset/c501c3d3f3a828828d4cb2dadb9558b43986718f.png';
import { useNavigate } from 'react-router-dom';
const exampleImage = 'https://via.placeholder.com/600x400?text=Example+Image';
interface SurveyProps {
userType: 'individual' | 'corporate';
}
interface Survey {
id: string;
title: string;
description: string;
category: string;
type: 'self-assessment' | 'feedback' | 'evaluation';
duration: string;
questions: number;
status: 'available' | 'in-progress' | 'completed' | 'pending';
dueDate?: string;
completedDate?: string;
score?: number;
feedback?: string;
participants?: number;
responses?: number;
certificateEarned?: boolean;
}
interface LearningInsights {
averageScore: number;
totalSurveys: number;
completedSurveys: number;
strengths: string[];
developmentAreas: string[];
nextRecommendations: string[];
progressTrend: 'improving' | 'stable' | 'needs-attention';
}
// Mock data for academic dashboard
const dashboardData = {
satisfactionScore: {
current: 78,
previous: 74,
trend: 5.4,
data: [
{ date: 'Week 2', score: 70, previousScore: 68 },
{ date: 'Week 4', score: 75, previousScore: 72 },
{ date: 'Week 6', score: 78, previousScore: 74 },
{ date: 'Week 8', score: 82, previousScore: 77 },
{ date: 'Week 10', score: 80, previousScore: 76 },
{ date: 'Week 12', score: 78, previousScore: 74 }
]
},
netPromoterScore: {
current: 82,
previous: 78,
trend: 5.1,
promoters: 85,
passives: 12,
detractors: 8,
data: [
{ date: 'Week 2', promoters: 78, passives: 15, detractors: 12 },
{ date: 'Week 4', promoters: 80, passives: 14, detractors: 10 },
{ date: 'Week 6', promoters: 82, passives: 13, detractors: 9 },
{ date: 'Week 8', promoters: 85, passives: 12, detractors: 8 },
{ date: 'Week 10', promoters: 87, passives: 11, detractors: 7 },
{ date: 'Week 12', promoters: 85, passives: 12, detractors: 8 }
]
},
responsesFeedback: [
{
id: 1,
user: 'Jennifer Schmidt',
avatar: 'https://images.unsplash.com/photo-1494790108755-2616b612b786?w=40&h=40&fit=crop&crop=face',
feedback: 'The midterm exam format was fair and comprehensive. The case study questions really tested our understanding.',
timeAgo: '2 days ago',
rating: 5
},
{
id: 2,
user: 'Michael Kim',
avatar: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=40&h=40&fit=crop&crop=face',
feedback: 'Appreciate the detailed feedback on my leadership assessment. The rubric was clearly explained.',
timeAgo: '1 week ago',
rating: 4
},
{
id: 3,
user: 'Maria Rodriguez',
avatar: 'https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=40&h=40&fit=crop&crop=face',
feedback: 'The group project evaluation process was transparent. Would like more peer review opportunities.',
timeAgo: '1 week ago',
rating: 4
},
{
id: 4,
user: 'David Thompson',
avatar: 'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=40&h=40&fit=crop&crop=face',
feedback: 'Research paper guidelines were comprehensive. The academic writing workshop really helped prepare us.',
timeAgo: '2 weeks ago',
rating: 5
}
],
learnersByLocation: [
{ country: 'United States', count: 145, flag: '🇺🇸', activity: 'Taking Assessment', coords: { x: 25, y: 35 }, status: 'active' },
{ country: 'United Kingdom', count: 98, flag: '🇬🇧', activity: 'Reviewing Results', coords: { x: 48, y: 28 }, status: 'active' },
{ country: 'Germany', count: 87, flag: '🇩🇪', activity: 'Course Progress', coords: { x: 52, y: 30 }, status: 'studying' },
{ country: 'Singapore', count: 76, flag: '🇸🇬', activity: 'Live Session', coords: { x: 75, y: 52 }, status: 'online' },
{ country: 'Australia', count: 65, flag: '🇦🇺', activity: 'Assignment Due', coords: { x: 82, y: 72 }, status: 'pending' },
{ country: 'Canada', count: 54, flag: '🇨🇦', activity: 'Group Project', coords: { x: 22, y: 25 }, status: 'collaboration' },
{ country: 'India', count: 43, flag: '🇮🇳', activity: 'Webinar Prep', coords: { x: 68, y: 45 }, status: 'preparing' },
{ country: 'Japan', count: 38, flag: '🇯🇵', activity: 'Peer Review', coords: { x: 82, y: 40 }, status: 'reviewing' }
]
};
// Mock data for academic assessments and insights
const mockData = {
insights: {
averageScore: 81,
totalSurveys: 8,
completedSurveys: 5,
strengths: [
'Theoretical Understanding',
'Case Study Analysis',
'Academic Writing',
'Critical Thinking'
],
developmentAreas: [
'Quantitative Analysis',
'Research Methodology',
'Group Presentation Skills'
],
nextRecommendations: [
'Focus on statistical analysis methods for your final research paper',
'Attend the academic writing workshop to improve citation and structure',
'Review leadership frameworks for the comprehensive final examination'
],
progressTrend: 'improving' as const
},
availableSurveys: [
{
id: 'exam-1',
title: 'Midterm Examination',
description: 'Comprehensive examination covering weeks 1-7 course material including leadership theories and frameworks',
category: 'Formal Assessment',
type: 'evaluation' as const,
duration: '120 min',
questions: 60,
status: 'available' as const,
dueDate: '2024-03-15'
},
{
id: 'assignment-2',
title: 'Research Paper Draft Submission',
description: 'Submit first draft of your 3000-word research paper on organizational leadership challenges',
category: 'Research Assignment',
type: 'self-assessment' as const,
duration: '2-3 weeks',
questions: 1,
status: 'in-progress' as const,
dueDate: '2024-03-22'
},
{
id: 'quiz-3',
title: 'Weekly Quiz: Communication Theory',
description: 'Assessment on communication models and leadership communication strategies from Week 8',
category: 'Weekly Assessment',
type: 'evaluation' as const,
duration: '30 min',
questions: 25,
status: 'pending' as const,
dueDate: '2024-03-18'
}
],
completedSurveys: [
{
id: 'completed-1',
title: 'Leadership Theory Examination',
description: 'Comprehensive assessment of foundational leadership theories and their practical applications',
category: 'Course Examination',
type: 'evaluation' as const,
duration: '90 min',
questions: 45,
status: 'completed' as const,
completedDate: '2024-02-20',
score: 87,
feedback: 'Excellent grasp of theoretical concepts. Strong application to case studies. Consider exploring modern leadership paradigms.',
participants: 32,
responses: 32,
certificateEarned: false
},
{
id: 'completed-2',
title: 'Group Project Evaluation',
description: 'Collaborative assessment of team leadership dynamics and strategic planning exercise',
category: 'Group Assignment',
type: 'evaluation' as const,
duration: '3 weeks',
questions: 5,
status: 'completed' as const,
completedDate: '2024-02-28',
score: 83,
feedback: 'Strong collaborative approach and well-structured presentation. Peer evaluations were consistently positive.',
participants: 6,
responses: 6,
certificateEarned: false
}
]
};
// Survey Card Component (Enhanced)
function SurveyCard({
survey,
userType,
onStart,
onContinue,
onView
}: {
survey: Survey;
userType: 'individual' | 'corporate';
onStart: (id: string) => void;
onContinue: (id: string) => void;
onView: (id: string) => void;
}) {
const getStatusInfo = (status: string) => {
switch (status) {
case 'available':
return {
label: 'AVAILABLE',
className: 'inline-flex items-center px-2 py-1 text-[12px] bg-primary/10 text-primary rounded-md border border-primary/20'
};
case 'in-progress':
return {
label: 'IN PROGRESS',
className: 'inline-flex items-center px-2 py-1 text-[12px] bg-orange-100 text-orange-700 rounded-md border border-orange-200'
};
case 'pending':
return {
label: 'PENDING',
className: 'inline-flex items-center px-2 py-1 text-[12px] bg-yellow-100 text-yellow-700 rounded-md border border-yellow-200'
};
default:
return null;
}
};
const getActionButton = () => {
switch (survey.status) {
case 'available':
return (
<Button
onClick={() => onStart(survey.id)}
className="text-[16px] min-h-[44px] w-full transition-colors duration-200"
>
Begin Assessment
<ChevronRight className="h-4 w-4 ml-1" />
</Button>
);
case 'in-progress':
return (
<Button
onClick={() => onContinue(survey.id)}
variant="outline"
className="text-[16px] min-h-[44px] w-full transition-colors duration-200"
>
Continue
<ChevronRight className="h-4 w-4 ml-1" />
</Button>
);
case 'pending':
return (
<Button
disabled
variant="outline"
className="text-[16px] min-h-[44px] w-full"
>
Pending Approval
</Button>
);
default:
return null;
}
};
const statusInfo = getStatusInfo(survey.status);
return (
<Card className="flex flex-col h-full hover:shadow-lg transition-all duration-300 border-gray-200 shadow-md">
<CardHeader className="flex-shrink-0 pb-3">
<div className="space-y-3">
<div className="flex flex-wrap gap-1">
{statusInfo && (
<span className={statusInfo.className}>
{statusInfo.label}
</span>
)}
<span className="inline-flex items-center px-2 py-1 text-[12px] bg-muted text-muted-foreground rounded-md">
{survey.type.replace('-', ' ').toUpperCase()}
</span>
</div>
<div>
<CardTitle className="text-[18px] leading-tight mb-2">{survey.title}</CardTitle>
<CardDescription className="text-[16px] line-clamp-2">
{survey.description}
</CardDescription>
</div>
</div>
</CardHeader>
<CardContent className="flex-1 flex flex-col justify-between pt-0 space-y-3">
<div className="space-y-2">
<div className="grid grid-cols-1 gap-2 text-[16px]">
<div className="flex items-center gap-2">
<Clock className="h-4 w-4 text-muted-foreground flex-shrink-0" />
<span className="truncate">{survey.duration}</span>
</div>
<div className="flex items-center gap-2">
<MessageSquare className="h-4 w-4 text-muted-foreground flex-shrink-0" />
<span className="truncate">{survey.questions} questions</span>
</div>
<div className="flex items-center gap-2">
<Target className="h-4 w-4 text-muted-foreground flex-shrink-0" />
<span className="truncate">{survey.category}</span>
</div>
{survey.dueDate && (
<div className="flex items-center gap-2">
<Calendar className="h-4 w-4 text-muted-foreground flex-shrink-0" />
<span className="truncate">Due {new Date(survey.dueDate).toLocaleDateString()}</span>
</div>
)}
</div>
</div>
<div className="pt-2">
{getActionButton()}
</div>
</CardContent>
</Card>
);
}
export function Surveys({ userType = 'individual' }: SurveyProps) {
const [activeTab, setActiveTab] = useState<'available' | 'completed'>('available');
const navigate = useNavigate();
// Mock user data for LearnerLayout - matching Library page pattern
const user = {
name: "Priya Sharma",
email: userType === 'corporate' ? "priya.sharma@company.com" : "priya.sharma@example.com",
avatar: "https://images.unsplash.com/photo-1494790108755-2616b612b786?w=150&h=150&fit=crop&crop=face",
...(userType === 'corporate' && {
organization: "TCS",
orgLogo: "https://images.unsplash.com/photo-1560179707-f14e90ef3623?w=32&h=32&fit=crop",
role: "Senior Manager",
cohort: "Leadership 2024"
})
};
const handleStartSurvey = (surveyId: string) => {
console.log('Starting survey:', surveyId);
// Implementation for starting survey
};
const handleContinueSurvey = (surveyId: string) => {
console.log('Continuing survey:', surveyId);
// Implementation for continuing survey
};
const handleViewResults = (surveyId: string) => {
console.log('Viewing results for survey:', surveyId);
// Implementation for viewing survey results
};
return (
<LearnerLayout
userType={userType}
currentPage="/surveys"
user={user}
>
{/* Enhanced Page Header */}
<div className="bg-background border-b border-border mb-3">
<div className="w-full max-w-none px-2 sm:px-4 lg:px-6">
<div className="py-8">
<div className="animate-fade-in" style={{ animationDelay: '0.1s' }}>
<h1 className="text-[36px] mb-4 relative">
Course Assessments & Examinations
<div className="absolute -bottom-2 left-0 w-32 h-1 bg-gradient-to-r from-brand-gold to-yellow-400 rounded-full opacity-60"></div>
</h1>
</div>
<p className="text-[16px] text-neutral-700 leading-relaxed animate-fade-in" style={{ animationDelay: '0.2s' }}>
{userType === 'corporate'
? 'Complete course examinations, assignments, and academic assessments for your leadership development program'
: 'Complete course examinations, assignments, and academic assessments for your leadership studies'
}
</p>
</div>
</div>
</div>
{/* Main Content with Dashboard Layout */}
<div className="w-full max-w-none px-2 sm:px-4 lg:px-6 pb-8">
<div className="space-y-6">
{/* Dashboard Layout - 2x2 Grid */}
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
{/* Satisfaction Score Chart - Top Left */}
<Card className="bg-white border-gray-200 shadow-lg hover:shadow-xl transition-all duration-300 rounded-lg">
<CardHeader className="pb-4 border-b border-gray-100">
<div className="flex items-center justify-between">
<CardTitle className="text-[16px] font-semibold text-[#111827]">
Course Performance Average
</CardTitle>
<div className="flex items-center gap-2">
<span className="text-[14px] text-[#6B7280]">Last 30 days</span>
</div>
</div>
</CardHeader>
<CardContent>
<div className="mb-4">
<div className="flex items-center gap-2 mb-2">
<span className="text-[32px] font-bold text-[#111827]">
{dashboardData.satisfactionScore.current}%
</span>
<div className="flex items-center gap-1">
<ArrowUp className="h-4 w-4 text-green-500" />
<span className="text-[14px] text-red-500 font-medium">
{Math.abs(dashboardData.satisfactionScore.trend)}%
</span>
</div>
</div>
<p className="text-[14px] text-[#6B7280] mb-4">
Previous semester average
</p>
</div>
<div className="h-48">
<ResponsiveContainer width="100%" height="100%">
<LineChart data={dashboardData.satisfactionScore.data}>
<CartesianGrid strokeDasharray="3 3" stroke="#f0f0f0" />
<XAxis
dataKey="date"
tick={{ fontSize: 12, fill: '#6B7280' }}
axisLine={false}
tickLine={false}
/>
<YAxis
domain={[0, 100]}
tick={{ fontSize: 12, fill: '#6B7280' }}
axisLine={false}
tickLine={false}
/>
<Tooltip
contentStyle={{
backgroundColor: 'white',
border: '1px solid #e5e7eb',
borderRadius: '8px',
fontSize: '14px'
}}
/>
<Line
type="monotone"
dataKey="score"
stroke="#3b82f6"
strokeWidth={2}
dot={{ fill: '#3b82f6', strokeWidth: 2, r: 4 }}
activeDot={{ r: 6 }}
/>
<Line
type="monotone"
dataKey="previousScore"
stroke="#9ca3af"
strokeWidth={2}
strokeDasharray="5 5"
dot={false}
/>
</LineChart>
</ResponsiveContainer>
</div>
</CardContent>
</Card>
{/* Net Promoter Score Chart - Top Right */}
<Card className="bg-white border-gray-200 shadow-lg hover:shadow-xl transition-all duration-300 rounded-lg">
<CardHeader className="pb-4 border-b border-gray-100">
<div className="flex items-center justify-between">
<CardTitle className="text-[16px] font-semibold text-[#111827]">
Academic Progress Tracking
</CardTitle>
<div className="flex items-center gap-2">
<div className="flex items-center gap-2">
<div className="w-3 h-3 bg-[#10b981] rounded-full"></div>
<span className="text-[12px] text-[#6B7280]">Excellent (A)</span>
</div>
<div className="flex items-center gap-2">
<div className="w-3 h-3 bg-[#f59e0b] rounded-full"></div>
<span className="text-[12px] text-[#6B7280]">Good (B)</span>
</div>
<div className="flex items-center gap-2">
<div className="w-3 h-3 bg-[#ef4444] rounded-full"></div>
<span className="text-[12px] text-[#6B7280]">Needs Improvement</span>
</div>
</div>
</div>
</CardHeader>
<CardContent>
<div className="mb-4">
<div className="flex items-center gap-2 mb-2">
<span className="text-[32px] font-bold text-[#111827]">
{dashboardData.netPromoterScore.current}
</span>
<div className="flex items-center gap-1">
<ArrowUp className="h-4 w-4 text-green-500" />
<span className="text-[14px] text-green-500 font-medium">
{dashboardData.netPromoterScore.trend}%
</span>
</div>
</div>
<p className="text-[14px] text-[#6B7280] mb-4">
Current semester
</p>
</div>
<div className="h-48">
<ResponsiveContainer width="100%" height="100%">
<LineChart data={dashboardData.netPromoterScore.data}>
<CartesianGrid strokeDasharray="3 3" stroke="#f0f0f0" />
<XAxis
dataKey="date"
tick={{ fontSize: 12, fill: '#6B7280' }}
axisLine={false}
tickLine={false}
/>
<YAxis
domain={[0, 100]}
tick={{ fontSize: 12, fill: '#6B7280' }}
axisLine={false}
tickLine={false}
/>
<Tooltip
contentStyle={{
backgroundColor: 'white',
border: '1px solid #e5e7eb',
borderRadius: '8px',
fontSize: '14px'
}}
/>
<Line
type="monotone"
dataKey="promoters"
stroke="#10b981"
strokeWidth={2}
dot={{ fill: '#10b981', strokeWidth: 2, r: 4 }}
/>
<Line
type="monotone"
dataKey="passives"
stroke="#f59e0b"
strokeWidth={2}
dot={{ fill: '#f59e0b', strokeWidth: 2, r: 4 }}
/>
<Line
type="monotone"
dataKey="detractors"
stroke="#ef4444"
strokeWidth={2}
dot={{ fill: '#ef4444', strokeWidth: 2, r: 4 }}
/>
</LineChart>
</ResponsiveContainer>
</div>
</CardContent>
</Card>
{/* Responses from Users - Bottom Left */}
<Card className="bg-white border-gray-200 shadow-lg hover:shadow-xl transition-all duration-300 rounded-lg">
<CardHeader className="pb-4 border-b border-gray-100">
<div className="flex items-center justify-between">
<CardTitle className="text-[16px] font-semibold text-[#111827]">
Academic Feedback & Reviews
</CardTitle>
<Button
variant="ghost"
size="sm"
className="text-[14px] text-[#6B7280] hover:text-[#111827] hover:bg-gray-100 rounded-md h-8 px-2"
>
View All
<ExternalLink className="h-3 w-3 ml-1" />
</Button>
</div>
</CardHeader>
<CardContent className="pt-4">
<div className="space-y-4">
{dashboardData.responsesFeedback.map((response) => (
<div key={response.id} className="flex items-start gap-3">
<img
src={response.avatar}
alt={response.user}
className="w-8 h-8 rounded-full object-cover"
/>
<div className="flex-1 min-w-0">
<div className="flex items-center gap-2 mb-1">
<span className="text-[14px] font-medium text-[#111827]">{response.user}</span>
<div className="flex items-center gap-1">
{Array.from({ length: response.rating }).map((_, i) => (
<Star key={i} className="h-3 w-3 fill-yellow-400 text-yellow-400" />
))}
</div>
</div>
<p className="text-[14px] text-[#6B7280] line-clamp-2 mb-1">
{response.feedback}
</p>
<span className="text-[12px] text-[#9CA3AF]">{response.timeAgo}</span>
</div>
</div>
))}
</div>
</CardContent>
</Card>
{/* Global Learning Activity Heatmap - Bottom Right */}
<Card className="bg-white border-gray-200 shadow-lg hover:shadow-xl transition-all duration-300 rounded-lg">
<CardHeader className="pb-4 border-b border-gray-100">
<div className="flex items-center justify-between">
<CardTitle className="text-[16px] font-semibold text-[#111827]">
Global Learning Activity
</CardTitle>
<Button
variant="ghost"
size="sm"
className="text-[14px] text-[#6B7280] hover:text-[#111827] hover:bg-gray-100 rounded-md h-8 px-2"
>
View All
<ExternalLink className="h-3 w-3 ml-1" />
</Button>
</div>
</CardHeader>
<CardContent className="pt-4">
{/* Interactive World Map Heatmap */}
<div className="mb-6">
<div className="relative w-full h-40 bg-gradient-to-br from-slate-50 to-blue-50 rounded-lg border border-gray-200 overflow-hidden">
{/* World map background */}
<div className="absolute inset-0 opacity-20">
<svg viewBox="0 0 100 60" className="w-full h-full">
{/* Simplified world continents */}
<path d="M15 25 L35 20 L40 35 L25 40 Z" fill="#94a3b8" opacity="0.3" />
<path d="M45 20 L65 18 L70 35 L50 38 Z" fill="#94a3b8" opacity="0.3" />
<path d="M70 25 L85 22 L90 45 L75 48 Z" fill="#94a3b8" opacity="0.3" />
<path d="M20 45 L35 42 L40 55 L25 58 Z" fill="#94a3b8" opacity="0.3" />
<path d="M75 50 L88 48 L92 58 L78 60 Z" fill="#94a3b8" opacity="0.3" />
</svg>
</div>
{/* Activity points on map */}
{dashboardData.learnersByLocation.map((location, index) => {
const getStatusColor = (status: string) => {
switch (status) {
case 'active': return 'bg-green-500';
case 'studying': return 'bg-blue-500';
case 'online': return 'bg-purple-500';
case 'pending': return 'bg-orange-500';
case 'collaboration': return 'bg-yellow-500';
case 'preparing': return 'bg-indigo-500';
case 'reviewing': return 'bg-pink-500';
default: return 'bg-gray-500';
}
};
const getActivitySize = (count: number) => {
if (count > 100) return 'w-4 h-4';
if (count > 50) return 'w-3 h-3';
return 'w-2 h-2';
};
return (
<div
key={location.country}
className={`absolute ${getStatusColor(location.status)} ${getActivitySize(location.count)} rounded-full animate-pulse cursor-pointer group`}
style={{
left: `${location.coords.x}%`,
top: `${location.coords.y}%`,
transform: 'translate(-50%, -50%)'
}}
title={`${location.country}: ${location.count} students - ${location.activity}`}
>
{/* Pulse ring */}
<div className={`absolute inset-0 ${getStatusColor(location.status)} rounded-full animate-ping opacity-30`}></div>
{/* Hover tooltip */}
<div className="absolute bottom-full left-1/2 transform -translate-x-1/2 mb-2 px-2 py-1 bg-black text-white text-[10px] rounded opacity-0 group-hover:opacity-100 transition-opacity whitespace-nowrap z-10">
<div className="font-medium">{location.country}</div>
<div className="text-white/80">{location.count} students</div>
<div className="text-white/80">{location.activity}</div>
<div className="absolute top-full left-1/2 transform -translate-x-1/2 border-2 border-transparent border-t-black"></div>
</div>
</div>
);
})}
</div>
</div>
{/* Activity Legend */}
<div className="mb-4">
<h4 className="text-[14px] font-medium text-[#111827] mb-3">Live Activity Status</h4>
<div className="grid grid-cols-2 gap-2 text-[12px]">
<div className="flex items-center gap-2">
<div className="w-2 h-2 bg-green-500 rounded-full"></div>
<span className="text-[#6B7280]">Taking Assessment</span>
</div>
<div className="flex items-center gap-2">
<div className="w-2 h-2 bg-blue-500 rounded-full"></div>
<span className="text-[#6B7280]">Course Progress</span>
</div>
<div className="flex items-center gap-2">
<div className="w-2 h-2 bg-purple-500 rounded-full"></div>
<span className="text-[#6B7280]">Live Session</span>
</div>
<div className="flex items-center gap-2">
<div className="w-2 h-2 bg-orange-500 rounded-full"></div>
<span className="text-[#6B7280]">Assignment Due</span>
</div>
</div>
</div>
{/* Top Countries List */}
<div className="space-y-2">
<h4 className="text-[14px] font-medium text-[#111827] mb-2">Top Active Regions</h4>
{dashboardData.learnersByLocation.slice(0, 4).map((country, index) => (
<div key={country.country} className="flex items-center justify-between py-1">
<div className="flex items-center gap-3">
<span className="text-[14px]">{country.flag}</span>
<div className="flex flex-col">
<span className="text-[13px] font-medium text-[#111827]">{country.country}</span>
<span className="text-[11px] text-[#6B7280]">{country.activity}</span>
</div>
</div>
<div className="text-right">
<div className="text-[13px] font-semibold text-[#111827]">{country.count}</div>
<div className={`text-[10px] px-1.5 py-0.5 rounded-full text-white ${
country.status === 'active' ? 'bg-green-500' :
country.status === 'studying' ? 'bg-blue-500' :
country.status === 'online' ? 'bg-purple-500' :
country.status === 'pending' ? 'bg-orange-500' :
'bg-gray-500'
}`}>
{country.status}
</div>
</div>
</div>
))}
</div>
</CardContent>
</Card>
</div>
{/* Enhanced Survey Tabs */}
<Tabs value={activeTab} onValueChange={setActiveTab} className="space-y-6">
{/* Enhanced Segmented Control */}
<div className="w-full bg-gradient-to-r from-yellow-50 to-amber-50 rounded-full p-1.5 shadow-sm">
<div className="flex items-center space-x-1">
{[
{
value: 'available',
label: `Available Surveys (${mockData.availableSurveys.filter(s => ['available', 'in-progress', 'pending'].includes(s.status)).length})`,
icon: FileText
},
{
value: 'completed',
label: `Completed (${mockData.completedSurveys.length})`,
icon: CheckCircle
}
].map((tab) => {
const Icon = tab.icon;
return (
<button
key={tab.value}
onClick={() => setActiveTab(tab.value as 'available' | 'completed')}
className={`flex-1 px-4 py-2.5 text-[16px] font-medium rounded-full transition-all duration-300 ease-in-out focus:outline-none focus:ring-0 active:outline-none flex items-center justify-center gap-2 hover:scale-105 ${
activeTab === tab.value
? 'bg-white text-gray-900 shadow-lg transform'
: 'text-gray-700 hover:text-gray-900 hover:bg-white/60'
}`}
>
<Icon className="h-5 w-5" />
<span>{tab.label}</span>
</button>
);
})}
</div>
</div>
{/* Available Surveys */}
<TabsContent value="available" className="space-y-6">
{mockData.availableSurveys.filter(s => ['available', 'in-progress', 'pending'].includes(s.status)).length === 0 ? (
<Card className="shadow-lg border-gray-200">
<CardContent className="p-12 text-center">
<MessageSquare className="h-16 w-16 text-muted-foreground mx-auto mb-4" />
<h3 className="text-[20px] font-medium mb-2">No Available Surveys</h3>
<p className="text-[16px] text-muted-foreground">
All surveys have been completed. Check back later for new assessments.
</p>
</CardContent>
</Card>
) : (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 lg:gap-6">
{mockData.availableSurveys
.filter(s => ['available', 'in-progress', 'pending'].includes(s.status))
.map((survey) => (
<SurveyCard
key={survey.id}
survey={survey}
userType={userType}
onStart={handleStartSurvey}
onContinue={handleContinueSurvey}
onView={handleViewResults}
/>
))}
</div>
)}
</TabsContent>
{/* Completed Surveys */}
<TabsContent value="completed" className="space-y-6">
{mockData.completedSurveys.length === 0 ? (
<Card className="shadow-lg border-gray-200">
<CardContent className="p-12 text-center">
<CheckCircle className="h-16 w-16 text-muted-foreground mx-auto mb-4" />
<h3 className="text-[20px] font-medium mb-2">No Completed Surveys</h3>
<p className="text-[16px] text-muted-foreground">
Complete your first survey to see results and insights here.
</p>
</CardContent>
</Card>
) : (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 lg:gap-6">
{mockData.completedSurveys.map((survey) => (
<Card key={survey.id} className="flex flex-col shadow-lg border-gray-200 hover:shadow-xl transition-all duration-300 transform hover:scale-[1.02]">
<CardHeader className="flex-shrink-0 pb-3">
<div className="space-y-3">
<div className="flex items-start justify-between">
<div className="flex flex-wrap gap-1">
<Badge variant="outline" className="text-[12px] bg-green-50 text-green-700 border-green-200">
COMPLETED
</Badge>
<Badge variant="outline" className="text-[12px] bg-muted text-muted-foreground">
{survey.type.replace('-', ' ').toUpperCase()}
</Badge>
</div>
{survey.certificateEarned && (
<Award className="h-5 w-5 text-yellow-500" />
)}
</div>
<div>
<CardTitle className="text-[18px] leading-tight mb-2">{survey.title}</CardTitle>
<CardDescription className="text-[16px] line-clamp-2">
{survey.description}
</CardDescription>
</div>
</div>
</CardHeader>
<CardContent className="flex-1 flex flex-col justify-between pt-0 space-y-3">
<div className="space-y-3">
<div className="grid grid-cols-2 gap-4">
<div className="text-center p-3 bg-gray-50 rounded-lg">
<div className="text-[20px] font-bold text-primary">{survey.score}%</div>
<div className="text-[12px] text-muted-foreground">Score</div>
</div>
<div className="text-center p-3 bg-gray-50 rounded-lg">
<div className="text-[20px] font-bold text-primary">{survey.questions}</div>
<div className="text-[12px] text-muted-foreground">Questions</div>
</div>
</div>
<div className="space-y-2 text-[14px]">
<div className="flex items-center gap-2">
<Clock className="h-4 w-4 text-muted-foreground" />
<span>Completed on {survey.completedDate ? new Date(survey.completedDate).toLocaleDateString() : 'N/A'}</span>
</div>
<div className="flex items-center gap-2">
<Users className="h-4 w-4 text-muted-foreground" />
<span>{survey.participants} participants</span>
</div>
<div className="flex items-center gap-2">
<Target className="h-4 w-4 text-muted-foreground" />
<span>{survey.category}</span>
</div>
</div>
{survey.feedback && (
<div className="p-3 bg-blue-50 rounded-lg">
<p className="text-[14px] text-blue-800 italic">"{survey.feedback}"</p>
</div>
)}
</div>
<Button
onClick={() => handleViewResults(survey.id)}
variant="outline"
className="text-[16px] min-h-[44px] w-full"
>
<Eye className="h-4 w-4 mr-2" />
View Results
</Button>
</CardContent>
</Card>
))}
</div>
)}
</TabsContent>
</Tabs>
</div>
</div>
</LearnerLayout>
);
}

View File

@@ -1,150 +0,0 @@
import React from "react";
import { Card, CardHeader, CardTitle, CardContent } from "../../components/ui/card";
import { Trophy } from "lucide-react";
import { ImageWithFallback } from "../../components/figma/ImageWithFallback";
const platinumTrophy = 'https://via.placeholder.com/150?text=Platinum+Trophy';
const goldTrophy = 'https://via.placeholder.com/150?text=Gold+Trophy';
const silverTrophy = 'https://via.placeholder.com/150?text=Silver+Trophy';
const bronzeTrophy = 'https://via.placeholder.com/150?text=Bronze+Trophy';
// Achievement Badges component
export function AchievementBadges() {
const badges = [
{
id: 'bronze',
title: 'Bronze Trophy',
description: 'Complete 3 foundational leadership courses and score 80%+ in all assessments',
exp: 20,
unlocked: true,
bgColor: 'from-orange-50 to-orange-100',
borderColor: 'border-orange-200',
trophyImage: bronzeTrophy
},
{
id: 'silver',
title: 'Silver Trophy',
description: 'Master 5 advanced leadership modules and lead a successful team project',
exp: 40,
unlocked: true,
bgColor: 'from-gray-50 to-gray-100',
borderColor: 'border-gray-300',
trophyImage: silverTrophy
},
{
id: 'gold',
title: 'Gold Trophy',
description: 'Achieve executive leadership certification and mentor 3 junior leaders',
exp: 60,
unlocked: true,
bgColor: 'from-yellow-50 to-yellow-100',
borderColor: 'border-yellow-300',
trophyImage: goldTrophy
},
{
id: 'platinum',
title: 'Platinum Trophy',
description: 'Complete all specialization tracks and become a certified KLC ambassador',
exp: 100,
unlocked: false,
bgColor: 'from-gray-50 to-gray-100',
borderColor: 'border-gray-200',
trophyImage: platinumTrophy
}
];
const unlockedCount = badges.filter(badge => badge.unlocked).length;
const totalCount = badges.length;
return (
<Card className="border-0 shadow-xl bg-gradient-to-br from-white to-gray-50/50">
<CardHeader className="pb-4">
<div className="flex items-center justify-between mb-3">
<div className="flex items-center gap-3">
<div className="w-8 h-8 bg-gradient-to-br from-brand-gold to-amber-500 rounded-lg flex items-center justify-center">
<Trophy className="h-4 w-4 text-white" />
</div>
<CardTitle className="text-xl font-semibold text-gray-900">
Achievement Badges
</CardTitle>
</div>
<div className="inline-flex items-center gap-2 bg-gray-50 border border-gray-200 rounded-full px-3 py-1">
<Trophy className="h-3 w-3 text-gray-600" />
<span className="text-sm font-semibold text-gray-900">
{unlockedCount}/{totalCount}
</span>
</div>
</div>
<p className="text-sm text-gray-600 mb-3">
Unlock trophies by completing challenges and competitions
</p>
<div className="max-w-full">
<div className="h-2 bg-gray-200 rounded-full overflow-hidden">
<div
className="h-full bg-gradient-to-r from-brand-gold to-amber-500 rounded-full transition-all duration-700 ease-out"
style={{ width: `${(unlockedCount / totalCount) * 100}%` }}
></div>
</div>
</div>
</CardHeader>
<CardContent className="px-4 pb-4">
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
{badges.map((badge) => (
<div
key={badge.id}
className={`relative flex flex-col h-[18rem] p-4 rounded-lg border-2 ${badge.borderColor} bg-gradient-to-br ${badge.bgColor} transition-all duration-300 hover:shadow-lg hover:scale-[1.02] ${
badge.unlocked ? 'hover:border-brand-gold/50 ring-2 ring-white shadow-md' : ''
}`}
>
<div className="absolute top-3 right-3">
<div className={`px-2 py-1 rounded-full text-xs font-semibold ${
badge.unlocked
? 'bg-green-100 text-green-800 border-2 border-green-700'
: 'bg-gray-100 text-gray-500 border border-gray-200'
}`}>
+{badge.exp} EXP
</div>
</div>
<div className="flex justify-center mb-4 mt-2">
<div className="relative">
<div className="w-24 h-24 flex items-center justify-center">
<ImageWithFallback
src={badge.trophyImage}
alt={`${badge.title} trophy`}
className={`w-full h-full object-contain drop-shadow-lg ${
!badge.unlocked ? 'opacity-40' : ''
}`}
/>
</div>
</div>
</div>
<div className="text-center flex-grow flex flex-col justify-center mb-4">
<h3 className="text-base font-semibold text-gray-900 mb-2">
{badge.title}
</h3>
<p className="text-sm text-gray-600 leading-relaxed">
{badge.description}
</p>
</div>
<div className="flex justify-center mt-auto mb-3">
<div className={`px-3 py-1 rounded-full text-xs font-semibold min-w-[80px] text-center flex items-center justify-center ${
badge.unlocked
? 'bg-green-100 text-green-800 border-2 border-green-700'
: 'bg-gray-100 text-gray-500 border border-gray-200'
}`}>
{badge.unlocked ? 'UNLOCKED' : 'LOCKED'}
</div>
</div>
</div>
))}
</div>
</CardContent>
</Card>
);
}

View File

@@ -1,139 +0,0 @@
import React from "react";
import { useNavigate } from "react-router-dom";
import { Clock, Users } from "lucide-react";
import { Card, CardContent } from "../../components/ui/card";
import { Button } from "../../components/ui/button";
import { Badge } from "../../components/ui/badge";
import { ImageWithFallback } from "../../components/figma/ImageWithFallback";
// Based on your recent activity recommendations component - redesigned to match provided image
export function ActivityRecommendations({ userType = 'individual' }: { userType?: 'individual' | 'corporate' }) {
const recommendations = [
{
id: 1,
title: "Emotional Intelligence Mastery",
description: "Develop self-awareness and interpersonal skills to become a more effective leader.",
duration: "5 hours",
difficulty: "Intermediate",
badgeText: "Intermediate",
badgeColor: "bg-yellow-100 text-yellow-800",
thumbnail: "https://images.unsplash.com/photo-1552664730-d307ca884978?w=400&h=240&fit=crop",
recentLearners: 248
},
{
id: 2,
title: "Strategic Thinking Framework",
description: "Learn to analyze complex business scenarios and make data-driven decisions.",
duration: "4 hours",
difficulty: "Advanced",
badgeText: "Advanced",
badgeColor: "bg-red-100 text-red-800",
thumbnail: "https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=400&h=240&fit=crop",
recentLearners: 189
},
{
id: 3,
title: "Team Leadership Excellence",
description: "Master the art of motivating and guiding high-performance teams.",
duration: "8 hours",
difficulty: "Intermediate",
badgeText: "Intermediate",
badgeColor: "bg-yellow-100 text-yellow-800",
thumbnail: "https://images.unsplash.com/photo-1600880292203-757bb62b4baf?w=400&h=240&fit=crop",
recentLearners: 156
},
{
id: 4,
title: "Change Management Strategies",
description: "Navigate organizational transformation with confidence and clarity.",
duration: "3 hours",
difficulty: "Beginner",
badgeText: "Beginner",
badgeColor: "bg-green-100 text-green-800",
thumbnail: "https://images.unsplash.com/photo-1542744173-8e7e53415bb0?w=400&h=240&fit=crop",
recentLearners: 134
}
];
const navigate = useNavigate();
return (
<div className="bg-white">
<div className="flex items-center justify-between mb-6">
<div>
<h2 className="text-2xl font-semibold text-gray-900 mb-2">
Based on your recent activity, here are your recommendations
</h2>
<p className="text-base text-gray-600">
Personalized course suggestions to accelerate your leadership journey
</p>
</div>
<Button
variant="outline"
onClick={() => navigate(`/library?view=${userType}`)}
className="text-brand-navy hover:bg-brand-navy/10 border-brand-navy/20 text-base px-4 py-2 h-auto font-medium"
>
View All Courses
</Button>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
{recommendations.map((course) => (
<Card
key={course.id}
className="group cursor-pointer hover:shadow-lg transition-all duration-300 border border-gray-200 overflow-hidden"
>
{/* Course Thumbnail */}
<div className="relative h-40 bg-gray-200 overflow-hidden">
<ImageWithFallback
src={course.thumbnail}
alt={course.title}
className="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300"
/>
<div className="absolute top-3 left-3">
<Badge className={`${course.badgeColor} text-xs font-medium`}>
{course.badgeText}
</Badge>
</div>
</div>
<CardContent className="px-4 pb-4">
{/* Course Title */}
<h3 className="text-base font-semibold text-gray-900 mb-2 line-clamp-2 group-hover:text-brand-navy transition-colors">
{course.title}
</h3>
{/* Course Description */}
<p className="text-sm text-gray-600 leading-relaxed mb-4 line-clamp-2">
{course.description}
</p>
{/* Duration and Recent Learners (Balanced) */}
<div className="flex justify-between items-center mb-4">
{/* Duration */}
<div className="flex items-center gap-2 w-1/2">
<Clock className="h-4 w-4 text-gray-500 flex-shrink-0" />
<span className="text-sm text-gray-600">{course.duration}</span>
</div>
{/* Recent Learners */}
<div className="flex items-center gap-2 w-1/2 justify-end">
<Users className="h-4 w-4 text-gray-500 flex-shrink-0" />
<span className="text-sm text-gray-600">{course.recentLearners}</span>
</div>
</div>
{/* Enroll Button */}
<Button
onClick={() => navigate(`/course?view=${userType}&courseId=${course.id}`)}
className="w-full text-base min-h-[48px] bg-brand-navy hover:bg-brand-navy/90 text-white font-medium"
>
Enroll Now
</Button>
</CardContent>
</Card>
))}
</div>
</div>
);
}

View File

@@ -1,56 +0,0 @@
import React, { useEffect, useState } from "react";
import { WifiOff, Wifi, RefreshCw } from "lucide-react";
import { Alert, AlertDescription } from "../../components/ui/alert";
import { Button } from "../../components/ui/button";
// Connection status component
export function ConnectionStatus() {
const [isOnline, setIsOnline] = useState(navigator.onLine);
const [isLoading, setIsLoading] = useState(false);
useEffect(() => {
const handleOnline = () => setIsOnline(true);
const handleOffline = () => setIsOnline(false);
window.addEventListener('online', handleOnline);
window.addEventListener('offline', handleOffline);
return () => {
window.removeEventListener('online', handleOnline);
window.removeEventListener('offline', handleOffline);
};
}, []);
const handleRetry = async () => {
setIsLoading(true);
await new Promise(resolve => setTimeout(resolve, 1000));
setIsLoading(false);
window.location.reload();
};
if (isOnline) return null;
return (
<Alert className="mb-8 border-destructive/30 bg-gradient-to-r from-destructive/5 to-destructive/10 backdrop-blur-sm shadow-lg">
<WifiOff className="h-5 w-5 text-destructive" />
<AlertDescription className="flex items-center justify-between text-base">
<span className="font-medium">You're currently offline. Some features may not be available.</span>
<Button
onClick={handleRetry}
disabled={isLoading}
size="sm"
variant="outline"
className="ml-4 text-base min-h-[44px] border-destructive/30 text-destructive hover:bg-destructive hover:text-destructive-foreground transition-all duration-200"
>
{isLoading ? (
<RefreshCw className="h-4 w-4 animate-spin mr-2" />
) : (
<Wifi className="h-4 w-4 mr-2" />
)}
Retry
</Button>
</AlertDescription>
</Alert>
);
}

View File

@@ -1,206 +0,0 @@
import React from "react";
import { useNavigate } from "react-router-dom";
import { Play, FastForward, CheckCircle, ChevronRight, BookOpen } from "lucide-react";
import { Card, CardContent, CardHeader, CardTitle } from "../../components/ui/card";
import CurrentLearningHeaderIcon from "../../imports/CurrentLearningHeaderIcon-4285-106";
import { Badge } from "../../components/ui/badge";
import { Button } from "../../components/ui/button";
export function CurrentLearningProgress({ userType = 'individual' }: { userType?: 'individual' | 'corporate' }) {
const currentCourse = {
title: "Strategic Leadership Excellence Program",
rating: 4.9,
provider: "Dr. Rajesh Sharma, KLC",
dueDate: "Aug 30, 2025",
totalModules: 8,
currentModule: {
title: "Building High-Performance Teams",
number: 6,
progress: 65,
lessonsRemaining: 3
},
nextModule: {
title: "Leadership Communication Mastery",
number: 7
}
};
// Sample module data to match the image layout
const moduleList = [
{ title: "Leadership Fundamentals", duration: "1h 15m", completed: true },
{ title: "Emotional Intelligence for Leaders", duration: "1h 30m", completed: true },
{ title: "Strategic Decision Making", duration: "1h", completed: true },
{ title: "Conflict Resolution & Negotiation", duration: "50m", completed: true },
{ title: "Change Management Principles", duration: "40m", completed: true },
{ title: "Building High-Performance Teams", duration: "1h 20m", completed: false, current: true },
{ title: "Leadership Communication Mastery", duration: "1h 45m", completed: false, upcoming: true },
{ title: "Innovation & Strategic Thinking", duration: "2h", completed: false }
];
const completedModules = moduleList.filter(module => module.completed).length;
const totalModules = moduleList.length;
const overallProgress = Math.round((completedModules / totalModules) * 100);
const navigate = useNavigate();
return (
<Card className="h-fit bg-white shadow-md border border-gray-200 rounded-lg overflow-hidden">
<CardHeader>
<div className="flex items-center justify-between mb-3">
<div className="flex items-center gap-3">
<div className="p-3 bg-gradient-to-br from-brand-navy to-brand-navy/90 rounded-lg shadow-lg">
<div className="h-6 w-6">
<CurrentLearningHeaderIcon />
</div>
</div>
<CardTitle className="text-xl font-semibold text-gray-900">
Current Learning Progress
</CardTitle>
</div>
</div>
</CardHeader>
<CardContent className="px-6 pb-6">
{/* Course Header */}
<div className="flex items-start justify-between mb-4">
<div className="flex-1">
<h2 className="text-xl font-semibold text-gray-900 mb-2">
{currentCourse.title}
</h2>
<p className="text-base text-gray-600">
with {currentCourse.provider}
</p>
</div>
<div className="text-right">
<Badge className="bg-brand-navy/5 text-brand-navy border border-brand-navy px-3 py-1.5 text-sm font-medium mb-2">
In Progress
</Badge>
<p className="text-sm text-gray-600">2h 30m remaining</p>
</div>
</div>
{/* Overall Progress */}
<div className="mb-4">
<div className="flex items-center justify-between mb-3">
<span className="text-sm font-medium text-gray-700">Overall Progress</span>
<span className="text-sm font-medium text-gray-700">Modules</span>
</div>
<div className="flex items-center justify-between mb-2">
<span className="text-2xl font-bold text-gray-900">{overallProgress}%</span>
<span className="text-2xl font-bold text-gray-900">{completedModules}/{totalModules}</span>
</div>
<div className="flex items-center justify-between mb-4">
<span className="text-sm text-gray-500">Started</span>
<span className="text-sm text-gray-500">Completed</span>
</div>
{/* Progress Bar */}
<div className="w-full bg-gray-200 rounded-full h-3 mb-2">
<div
className="bg-brand-navy h-3 rounded-full transition-all duration-300"
style={{ width: `${overallProgress}%` }}
></div>
</div>
</div>
{/* Current and Up Next Modules */}
<div className="grid grid-cols-2 gap-6 mb-4">
{/* Current Module */}
<div className="bg-brand-gold/10 border border-brand-gold/30 rounded-lg p-4">
<div className="flex items-center gap-2 mb-3">
<div className="w-6 h-6 bg-brand-gold rounded flex items-center justify-center">
<Play className="h-3 w-3 text-brand-charcoal" />
</div>
<span className="text-sm font-medium text-brand-charcoal uppercase tracking-wide">Current</span>
</div>
<h3 className="text-base font-semibold text-gray-900 mb-3">
{currentCourse.currentModule.title}
</h3>
<Button
onClick={() => navigate(`/course?view=${userType}&courseId=strategic-leadership&module=${currentCourse.currentModule.number}`)}
className="w-full text-base min-h-[48px] bg-brand-gold hover:bg-brand-gold/90 text-brand-charcoal font-medium"
>
Continue Module
</Button>
</div>
{/* Up Next Module */}
<div className="bg-brand-navy/10 border border-brand-navy/30 rounded-lg p-4">
<div className="flex items-center gap-2 mb-3">
<div className="w-6 h-6 bg-brand-navy rounded flex items-center justify-center">
<FastForward className="h-3 w-3 text-white" />
</div>
<span className="text-sm font-medium text-brand-navy uppercase tracking-wide">Up Next</span>
</div>
<h3 className="text-base font-semibold text-gray-900 mb-3">
{currentCourse.nextModule.title}
</h3>
<Button
variant="outline"
onClick={() => navigate(`/course?view=${userType}&courseId=strategic-leadership&module=${currentCourse.nextModule.number}`)}
className="w-full text-base min-h-[48px] border-brand-navy text-brand-navy hover:bg-brand-navy/10 font-medium"
>
Preview Module
</Button>
</div>
</div>
{/* Course Modules List */}
<div className="mb-4">
<div className="flex items-center justify-between mb-4">
<h3 className="text-base font-semibold text-gray-900">Course Modules</h3>
<Button
variant="ghost"
onClick={() => navigate(`/course?view=${userType}&courseId=strategic-leadership`)}
className="text-sm text-brand-navy hover:text-brand-navy hover:bg-brand-navy/10 p-0 h-auto font-medium"
>
View All
</Button>
</div>
<div className="space-y-3">
{moduleList.slice(0, 5).map((module, index) => (
<div key={index} className="flex items-center justify-between py-2">
<div className="flex items-center gap-3">
<div className="w-5 h-5 flex items-center justify-center">
{module.completed ? (
<CheckCircle className="h-5 w-5 text-brand-gold" />
) : (
<div className="w-4 h-4 border-2 border-gray-300 rounded-full"></div>
)}
</div>
<span className={`text-sm ${module.completed ? 'text-gray-900' : 'text-gray-600'}`}>
{module.title}
</span>
</div>
<div className="flex items-center gap-2">
<span className="text-sm text-gray-500">{module.duration}</span>
<ChevronRight className="h-4 w-4 text-gray-400" />
</div>
</div>
))}
</div>
</div>
{/* Action Buttons */}
<div className="flex items-center justify-between">
<Button
variant="ghost"
onClick={() => navigate(`/course?view=${userType}&courseId=strategic-leadership`)}
className="text-base text-gray-600 hover:text-gray-900 hover:bg-gray-50 p-0 min-h-[48px] font-medium flex items-center gap-1"
>
<BookOpen className="h-4 w-4" />
View Full Course
</Button>
<Button
onClick={() => navigate(`/course?view=${userType}&courseId=strategic-leadership&module=${currentCourse.currentModule.number}`)}
className="text-base min-h-[48px] bg-brand-navy hover:bg-brand-navy/90 text-white font-medium px-6"
>
<Play className="h-4 w-4 mr-2" />
Continue Learning
</Button>
</div>
</CardContent>
</Card>
);
}

View File

@@ -1,72 +0,0 @@
import { LearnerLayout } from '../../components/learner/LearnerLayout';
import { RecentActivity } from './RecentActivity';
import { WelcomeMessage } from './WelcomeMessage';
import { CurrentLearningProgress } from './CurrentLearningProgress';
import { ConnectionStatus } from './ConnectionStatus';
import { WeeklyProgressTracker } from './WeeklyProgressTracker';
import { AchievementBadges } from './AchievementBadges';
import { GlobalLeaderboard } from './GlobalLeaderboard';
import { ActivityRecommendations } from './ActivityRecommendations';
import { RecentlyViewed } from './RecentlyViewed';
import { WhatOthersLearning } from './WhatOthersLearning';
interface DashboardProps {
userType?: 'individual' | 'corporate';
}
// Main Dashboard component
export default function Dashboard({ userType = 'individual' }: DashboardProps) {
const user = { name: 'Alex', email: 'alex@example.com' };
return (
<LearnerLayout currentPage="/dashboard" userType={userType}>
<div className="container mx-auto px-4 lg:px-8 py-8 space-y-8">
<ConnectionStatus />
{/* Welcome Section */}
<div className="mb-8">
<WelcomeMessage user={user} />
<p className="text-lg text-gray-600 leading-relaxed">
Continue your leadership development journey with our personalized recommendations and track your progress
</p>
</div>
{/* Weekly Progress Tracker */}
<WeeklyProgressTracker />
{/* Current Learning Progress */}
<CurrentLearningProgress userType={userType} />
{/* Achievement Badges */}
<AchievementBadges />
{/* Global Leaderboard (left, prominent) and Recent Activity (right) Grid */}
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
<div className="lg:col-span-2">
<GlobalLeaderboard />
</div>
<div className="lg:col-span-1">
<RecentActivity />
</div>
</div>
{/* Based on your activity recommendations - NO TOP PADDING */}
<div>
<ActivityRecommendations userType={userType} />
</div>
{/* Recently Viewed section - NO TOP PADDING */}
<div>
<RecentlyViewed userType={userType} />
</div>
{/* What are others learning section - NO TOP PADDING */}
<div>
<WhatOthersLearning userType={userType} />
</div>
</div>
</LearnerLayout>
);
}

View File

@@ -1,163 +0,0 @@
import React from "react";
import { useNavigate } from "react-router-dom";
import { Trophy } from "lucide-react";
import { Card, CardHeader, CardTitle, CardContent } from "../../components/ui/card";
import { Button } from "../../components/ui/button";
import { ScrollArea } from "../../components/ui/scroll-area";
import { Avatar, AvatarImage, AvatarFallback } from "../../components/ui/avatar";
// Global Leaderboard component - increased height to match Recent Activity
export function GlobalLeaderboard() {
const leaderboardData = [
{
rank: 1,
name: "Sarah Chen",
points: 2450,
avatar: "https://images.unsplash.com/photo-1494790108755-2616b612b5c8?w=80&h=80&fit=crop&crop=face",
badge: "gold",
change: "+15"
},
{
rank: 2,
name: "Marcus Johnson",
points: 2380,
avatar: "https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=80&h=80&fit=crop&crop=face",
badge: "silver",
change: "+8"
},
{
rank: 3,
name: "Emily Rodriguez",
points: 2320,
avatar: "https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=80&h=80&fit=crop&crop=face",
badge: "bronze",
change: "+12"
},
{
rank: 4,
name: "David Kim",
points: 2180,
avatar: "https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=80&h=80&fit=crop&crop=face",
badge: "regular",
change: "+5"
},
{
rank: 5,
name: "Lisa Thompson",
points: 2140,
avatar: "https://images.unsplash.com/photo-1517841905240-472988babdf9?w=80&h=80&fit=crop&crop=face",
badge: "regular",
change: "+20"
},
{
rank: 6,
name: "Alex Patel",
points: 2090,
avatar: "https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=80&h=80&fit=crop&crop=face",
badge: "regular",
change: "+3"
},
{
rank: 7,
name: "Your Position",
points: 1950,
avatar: "https://images.unsplash.com/photo-1535713875002-d1d0cf377fde?w=80&h=80&fit=crop&crop=face",
badge: "user",
change: "+18",
isCurrentUser: true
},
{
rank: 8,
name: "Jennifer Lee",
points: 1890,
avatar: "https://images.unsplash.com/photo-1534528741775-53994a69daeb?w=80&h=80&fit=crop&crop=face",
badge: "regular",
change: "+7"
}
];
const getBadgeColor = (badge: string) => {
switch (badge) {
case 'gold': return 'bg-gradient-to-r from-yellow-400 to-yellow-500 text-white';
case 'silver': return 'bg-gradient-to-r from-gray-300 to-gray-400 text-gray-800';
case 'bronze': return 'bg-gradient-to-r from-orange-400 to-orange-500 text-white';
case 'user': return 'bg-gradient-to-r from-brand-navy to-brand-navy/90 text-white';
default: return 'bg-gray-100 text-gray-600';
}
};
const navigate = useNavigate();
return (
<Card className="h-96 flex flex-col border-0 shadow-lg bg-white">
<CardHeader className="pb-3 flex-shrink-0">
<div className="flex items-center justify-between">
<div className="flex items-center gap-3">
<div className="w-8 h-8 bg-gradient-to-br from-brand-gold to-amber-500 rounded-lg flex items-center justify-center">
<Trophy className="h-4 w-4 text-white" />
</div>
<CardTitle className="text-lg font-semibold text-gray-900">
Global Leaderboard
</CardTitle>
</div>
<Button
variant="outline"
size="sm"
onClick={() => navigate('/leaderboard?view=individual')}
className="text-brand-navy hover:bg-brand-navy/10 border-brand-navy/20 text-sm px-3 py-1.5 h-auto font-medium"
>
View All
</Button>
</div>
<p className="text-sm text-gray-600 mt-1">
Top learners this month
</p>
</CardHeader>
<CardContent className="px-6 pb-4 flex-1 min-h-0">
<ScrollArea className="h-full">
<div className="space-y-2 pr-2">
{leaderboardData.map((user) => (
<div
key={user.rank}
className={`flex items-center gap-3 p-3 rounded-lg transition-all duration-200 hover:shadow-sm ${
user.isCurrentUser
? 'bg-gradient-to-r from-brand-navy/5 to-brand-navy/10 border border-brand-navy/20'
: 'bg-gray-50 hover:bg-gray-100'
}`}
>
{/* Rank */}
<div className={`w-8 h-8 rounded-full flex items-center justify-center text-xs font-bold flex-shrink-0 ${getBadgeColor(user.badge)}`}>
{user.rank}
</div>
{/* Avatar */}
<Avatar className="h-8 w-8 flex-shrink-0">
<AvatarImage src={user.avatar} alt={user.name} />
<AvatarFallback className="text-xs">{user.name.split(' ').map(n => n[0]).join('')}</AvatarFallback>
</Avatar>
{/* User Info */}
<div className="flex-1 min-w-0">
<h4 className={`text-sm font-semibold leading-tight ${
user.isCurrentUser ? 'text-brand-navy' : 'text-gray-900'
}`}>
{user.name}
</h4>
<p className="text-xs text-gray-600 font-medium">
{user.points.toLocaleString()} points
</p>
</div>
{/* Change */}
<div className="text-xs font-semibold text-green-600 flex-shrink-0">
{user.change}
</div>
</div>
))}
</div>
</ScrollArea>
</CardContent>
</Card>
);
}

View File

@@ -1,167 +0,0 @@
import {
CheckCircle,
Video,
FileText,
Award,
PlayCircle,
MessageSquare,
BookOpen,
Users,
Activity
} from "lucide-react";
import { useNavigate } from "react-router-dom";
import { Card, CardContent, CardHeader, CardTitle } from "../../components/ui/card";
import { Button } from "../../components/ui/button";
import { ScrollArea } from "../../components/ui/scroll-area";
// import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
// import { Button } from "@/components/ui/button";
// import { ScrollArea } from "@/components/ui/scroll-area";
// Recent Activity component - increased height to match Global Leaderboard
export function RecentActivity() {
const activities = [
{
id: 1,
type: 'course_completed',
title: 'Completed "Strategic Decision Making"',
description: 'Module 3 of 4 • Leadership Fundamentals',
timestamp: '2 hours ago',
icon: CheckCircle,
iconColor: 'text-green-600',
iconBg: 'bg-green-100'
},
{
id: 2,
type: 'webinar_joined',
title: 'Attended Live Webinar',
description: 'Digital Transformation for Leaders',
timestamp: '5 hours ago',
icon: Video,
iconColor: 'text-blue-600',
iconBg: 'bg-blue-100'
},
{
id: 3,
type: 'assessment_completed',
title: 'Assessment Completed',
description: 'Leadership Style Assessment • Score: 92%',
timestamp: '1 day ago',
icon: FileText,
iconColor: 'text-purple-600',
iconBg: 'bg-purple-100'
},
{
id: 4,
type: 'certificate_earned',
title: 'Certificate Earned',
description: 'Leadership Foundation Certification',
timestamp: '2 days ago',
icon: Award,
iconColor: 'text-brand-gold',
iconBg: 'bg-yellow-100'
},
{
id: 5,
type: 'course_started',
title: 'Started New Course',
description: 'Innovation Leadership Track',
timestamp: '3 days ago',
icon: PlayCircle,
iconColor: 'text-green-600',
iconBg: 'bg-green-100'
},
{
id: 6,
type: 'discussion_posted',
title: 'Discussion Contribution',
description: 'Team Management Best Practices',
timestamp: '4 days ago',
icon: MessageSquare,
iconColor: 'text-orange-600',
iconBg: 'bg-orange-100'
},
{
id: 7,
type: 'resource_downloaded',
title: 'Resource Downloaded',
description: 'Leadership Skills Handbook PDF',
timestamp: '5 days ago',
icon: BookOpen,
iconColor: 'text-gray-600',
iconBg: 'bg-gray-100'
},
{
id: 8,
type: 'peer_connection',
title: 'New Connection',
description: 'Connected with 3 peer learners',
timestamp: '1 week ago',
icon: Users,
iconColor: 'text-brand-navy',
iconBg: 'bg-blue-100'
}
];
const navigate = useNavigate();
return (
<Card className="h-96 flex flex-col border-0 shadow-lg bg-white">
<CardHeader className="pb-3 flex-shrink-0">
<div className="flex items-center justify-between">
<div className="flex items-center gap-3">
<div className="w-8 h-8 bg-gradient-to-br from-brand-navy to-brand-navy/90 rounded-lg flex items-center justify-center">
<Activity className="h-4 w-4 text-white" />
</div>
<CardTitle className="text-lg font-semibold text-gray-900">
Recent Activity
</CardTitle>
</div>
<Button
variant="outline"
size="sm"
onClick={() => navigate('/dashboard?view=individual&tab=activity')}
className="text-brand-navy hover:bg-brand-navy/10 border-brand-navy/20 text-base px-3 py-1.5 min-h-[48px] font-medium"
>
View All
</Button>
</div>
<p className="text-sm text-gray-600 mt-1">
Your recent learning activities
</p>
</CardHeader>
<CardContent className="px-6 pb-4 flex-1 min-h-0">
<ScrollArea className="h-full">
<div className="space-y-2 pr-2">
{activities.map((activity) => {
const Icon = activity.icon;
return (
<div
key={activity.id}
className="flex items-start gap-3 p-3 rounded-lg bg-gray-50 hover:bg-gray-100 transition-all duration-200"
>
{/* Activity Icon */}
<div className={`p-2 rounded-lg ${activity.iconBg} flex-shrink-0`}>
<Icon className={`h-3 w-3 ${activity.iconColor}`} />
</div>
{/* Activity Content */}
<div className="flex-1 min-w-0">
<h4 className="text-sm font-semibold text-gray-900 mb-1 leading-tight">
{activity.title}
</h4>
<p className="text-xs text-gray-600 mb-1 leading-relaxed">
{activity.description}
</p>
<p className="text-xs text-gray-500 font-medium">
{activity.timestamp}
</p>
</div>
</div>
);
})}
</div>
</ScrollArea>
</CardContent>
</Card>
);
}

View File

@@ -1,155 +0,0 @@
import React from "react";
import { useNavigate } from "react-router-dom";
import { Box, Clock, Users } from "lucide-react";
import { Card, CardContent } from "../../components/ui/card";
import { Button } from "../../components/ui/button";
import { Badge } from "../../components/ui/badge";
import { ImageWithFallback } from "../../components/figma/ImageWithFallback";
// Recently Viewed component - redesigned to match course card layout
export function RecentlyViewed({ userType = 'individual' }: { userType?: 'individual' | 'corporate' }) {
const recentItems = [
{
id: 1,
title: "Strategic Decision Making",
description: "Master critical thinking and decision-making frameworks for effective leadership.",
type: "Course",
progress: 75,
lastAccessed: "2 hours ago",
thumbnail: "https://images.unsplash.com/photo-1664575602276-acd073f104c1?w=400&h=240&fit=crop",
duration: "4.2 hours",
badgeText: "In Progress",
badgeColor: "bg-blue-100 text-blue-800",
recentLearners: 312
},
{
id: 2,
title: "Digital Transformation for Leaders",
description: "Navigate the digital landscape and lead technological change in organizations.",
type: "Webinar",
progress: 100,
lastAccessed: "5 hours ago",
thumbnail: "https://images.unsplash.com/photo-1551434678-e076c223a692?w=400&h=240&fit=crop",
duration: "1.5 hours",
badgeText: "Completed",
badgeColor: "bg-green-100 text-green-800",
recentLearners: 189
},
{
id: 3,
title: "Leadership Style Assessment",
description: "Discover your leadership style and develop targeted improvement strategies.",
type: "Assessment",
progress: 100,
lastAccessed: "1 day ago",
thumbnail: "https://images.unsplash.com/photo-1450101499163-c8848c66ca85?w=400&h=240&fit=crop",
duration: "30 minutes",
badgeText: "Completed",
badgeColor: "bg-green-100 text-green-800",
recentLearners: 276
},
{
id: 4,
title: "Team Management Fundamentals",
description: "Build essential skills for managing and developing high-performing teams.",
type: "Course",
progress: 45,
lastAccessed: "2 days ago",
thumbnail: "https://images.unsplash.com/photo-1522202176988-66273c2fd55f?w=400&h=240&fit=crop",
duration: "6.1 hours",
badgeText: "In Progress",
badgeColor: "bg-blue-100 text-blue-800",
recentLearners: 198
}
];
const navigate = useNavigate();
return (
<div className="bg-white">
<div className="flex items-center justify-between mb-6">
<div>
<h2 className="text-2xl font-semibold text-gray-900 mb-2">
Recently Viewed
</h2>
<p className="text-base text-gray-600">
Continue where you left off or revisit completed content
</p>
</div>
<Button
variant="outline"
onClick={() => navigate(`/library?view=${userType}&filter=recent`)}
className="text-brand-navy hover:bg-brand-navy/10 border-brand-navy/20 text-base px-4 py-2 h-auto font-medium"
>
View History
</Button>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
{recentItems.map((item) => (
<Card
key={item.id}
className="group cursor-pointer hover:shadow-lg transition-all duration-300 border border-gray-200 overflow-hidden flex flex-col"
>
{/* Course Thumbnail */}
<div className="relative h-40 bg-gray-200 overflow-hidden">
<ImageWithFallback
src={item.thumbnail}
alt={item.title}
className="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300"
/>
<div className="absolute top-3 left-3">
<Badge className={`${item.badgeColor} text-xs font-medium`}>
{item.badgeText}
</Badge>
</div>
{/* Progress overlay for in-progress items */}
{item.progress > 0 && item.progress < 100 && (
<div className="absolute bottom-0 left-0 right-0 bg-black/50 text-white text-xs p-2">
Progress: {item.progress}%
</div>
)}
</div>
{/* Make content take full space and push button down */}
<CardContent className="px-4 pb-4 flex flex-col flex-1 justify-between">
<div>
{/* Course Title */}
<h3 className="text-base font-semibold text-gray-900 mb-2 line-clamp-2 group-hover:text-brand-navy transition-colors">
{item.title}
</h3>
{/* Course Description */}
<p className="text-sm text-gray-600 leading-relaxed mb-4 line-clamp-2">
{item.description}
</p>
{/* Duration and Recent Learners */}
<div className="flex items-center justify-between mb-4">
<div className="flex items-center gap-1">
<Clock className="h-4 w-4 text-gray-500" />
<span className="text-sm text-gray-600">{item.duration}</span>
</div>
<div className="flex items-center gap-1">
<Users className="h-4 w-4 text-gray-500" />
<span className="text-sm text-gray-600">{item.recentLearners}</span>
</div>
</div>
</div>
{/* Action Button fixed at bottom */}
<Button
onClick={() => navigate(`/course?view=${userType}&courseId=${item.id}`)}
className="w-full text-base min-h-[48px] bg-brand-navy hover:bg-brand-navy/90 text-white font-medium mt-auto"
>
{item.progress === 100 ? 'Review' : item.progress > 0 ? 'Continue' : 'Start'}
</Button>
</CardContent>
</Card>
))}
</div>
</div>
);
}

View File

@@ -1,121 +0,0 @@
import React, { useState } from "react";
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
} from "../../components/ui/dialog";
import { Checkbox } from "../../components/ui/checkbox";
import { Button } from "../../components/ui/button";
// Weekly Progress Goal Setting Modal component
export function WeeklyProgressModal({
isOpen,
onClose,
weeklyGoal,
setWeeklyGoal,
completedDays,
setCompletedDays,
}: {
isOpen?: boolean;
onClose?: () => void;
weeklyGoal?: number;
setWeeklyGoal?: (goal: number) => void;
completedDays?: number[];
setCompletedDays?: (days: number[]) => void;
}) {
const [selectedDays, setSelectedDays] = useState<number[]>(completedDays ?? []);
const daysOfWeek = [
{ label: "Monday", index: 0 },
{ label: "Tuesday", index: 1 },
{ label: "Wednesday", index: 2 },
{ label: "Thursday", index: 3 },
{ label: "Friday", index: 4 },
{ label: "Saturday", index: 5 },
{ label: "Sunday", index: 6 },
];
const toggleDay = (dayIndex: number) => {
setSelectedDays((prev) =>
prev.includes(dayIndex)
? prev.filter((d) => d !== dayIndex)
: [...prev, dayIndex]
);
};
const handleSave = () => {
setCompletedDays?.(selectedDays);
setWeeklyGoal?.(selectedDays.length);
onClose?.();
};
const handleCancel = () => {
setSelectedDays(completedDays ?? []);
onClose?.();
};
return (
<Dialog open={isOpen} onOpenChange={onClose}>
<DialogContent className="max-w-sm">
<DialogHeader className="text-left">
<DialogTitle className="text-xl font-semibold text-gray-900">
Set your weekly learning goal
</DialogTitle>
<DialogDescription className="text-base text-gray-600 leading-relaxed mt-2">
Consistency is key to success! Choose your learning days so we can
estimate your course completion dates and schedule assignment
deadlines, helping you stay on track.
</DialogDescription>
</DialogHeader>
<div className="py-4">
<div>
<h3 className="text-base font-medium text-gray-700 mb-4">
Choose your learning days
</h3>
<p className="text-sm text-gray-500 mb-4">
The days you select will apply to all your courses on KLC
</p>
<div className="space-y-3">
{daysOfWeek.map((day) => (
<div key={day.index} className="flex items-center space-x-3">
<Checkbox
id={`day-${day.index}`}
checked={selectedDays.includes(day.index)}
onCheckedChange={() => toggleDay(day.index)}
className="h-5 w-5"
/>
<label
htmlFor={`day-${day.index}`}
className="text-base text-gray-700 cursor-pointer flex-1"
>
{day.label}
</label>
</div>
))}
</div>
</div>
</div>
<div className="flex gap-3 pt-4 border-t border-gray-200">
<Button
onClick={handleSave}
className="flex-1 text-base min-h-[48px] bg-brand-navy hover:bg-brand-navy/90 text-white font-medium"
>
Save
</Button>
<Button
variant="outline"
onClick={handleCancel}
className="flex-1 text-base min-h-[48px] border-gray-300 text-gray-700 hover:bg-gray-50 font-medium"
>
Cancel
</Button>
</div>
</DialogContent>
</Dialog>
);
}

View File

@@ -1,133 +0,0 @@
import React, { useState } from "react";
import { BookOpen, Clock } from "lucide-react";
import {
Card,
CardContent,
CardHeader,
CardTitle,
} from "../../components/ui/card";
import { Button } from "../../components/ui/button";
import { WeeklyProgressModal } from "./WeeklyProgressModal";
// Weekly Progress component based on the provided design
export function WeeklyProgressTracker() {
const [weeklyGoal, setWeeklyGoal] = useState("Learn 1 day a week on KLC");
const [completedDays, setCompletedDays] = useState([0, 1, 2]);
const [isModalOpen, setIsModalOpen] = useState(false);
const kpiData = [
{
id: 'courses',
value: 8,
label: "Courses Completed",
change: "+2 this month",
icon: BookOpen,
iconBg: "bg-gradient-to-br from-emerald-500 to-emerald-600"
},
{
id: 'hours',
value: 47,
label: "Learning Hours",
change: "+8 this week",
icon: Clock,
iconBg: "bg-gradient-to-br from-blue-500 to-blue-600"
}
];
const daysOfWeek = [
{ label: 'M', full: 'Monday', index: 0 },
{ label: 'T', full: 'Tuesday', index: 1 },
{ label: 'W', full: 'Wednesday', index: 2 },
{ label: 'T', full: 'Thursday', index: 3 },
{ label: 'F', full: 'Friday', index: 4 },
{ label: 'S', full: 'Saturday', index: 5 },
{ label: 'S', full: 'Sunday', index: 6 }
];
return (
<>
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6 items-stretch">
{kpiData.map((data) => {
const Icon = data.icon;
return (
<Card key={data.id} className="border-0 shadow-xl bg-gradient-to-br from-brand-navy/3 to-brand-navy/8 backdrop-blur-sm flex flex-col h-full">
<CardContent className="p-6 pb-0 flex-1 flex flex-col justify-between">
<div className="space-y-4">
<div className="flex items-center justify-between">
<div className="text-base font-semibold text-gray-700">
{data.label}
</div>
<div className={`p-3 ${data.iconBg} rounded-lg shadow-lg`}>
<Icon className="h-6 w-6 text-white" strokeWidth={2.5} />
</div>
</div>
<div className="text-4xl font-bold bg-gradient-to-r from-gray-800 to-gray-600 bg-clip-text text-transparent">
{data.value}{data.id === 'hours' ? 'h' : ''}
</div>
</div>
<div className="text-base text-gray-600 font-medium mt-auto">
{data.change}
</div>
</CardContent>
</Card>
);
})}
<Card className="border-0 shadow-xl bg-gradient-to-br from-white via-brand-navy/3 to-brand-navy/8 backdrop-blur-sm flex flex-col h-full">
<CardHeader className="pb-0 flex-shrink-0">
<div className="flex items-center justify-between">
<CardTitle className="text-base font-semibold text-gray-900">
Weekly Learning Goal
</CardTitle>
<Button
variant="ghost"
size="sm"
onClick={() => setIsModalOpen(true)}
className="text-brand-navy hover:bg-brand-navy/10 text-base font-medium px-3 py-1 min-h-[48px]"
>
Update goal
</Button>
</div>
</CardHeader>
<CardContent className="pt-2 pb-4 px-6 flex-1 flex flex-col justify-between">
<div className="space-y-3">
<p className="text-sm text-gray-600">
{weeklyGoal}
</p>
<div className="flex justify-between items-center">
{daysOfWeek.map((day) => (
<div key={day.index} className="flex flex-col items-center">
<div className={`w-8 h-8 rounded-full flex items-center justify-center text-sm font-medium transition-all duration-200 ${
completedDays.includes(day.index)
? 'bg-green-500 text-white shadow-md'
: 'bg-gray-200 text-gray-600'
}`}>
{day.label}
</div>
</div>
))}
</div>
</div>
<p className="text-sm text-gray-500">
{completedDays.length} days completed
</p>
</CardContent>
</Card>
</div>
<WeeklyProgressModal
isOpen={isModalOpen}
onClose={() => setIsModalOpen(false)}
weeklyGoal={1}
setWeeklyGoal={() => {}}
completedDays={completedDays}
setCompletedDays={setCompletedDays}
/>
</>
);
}

View File

@@ -1,36 +0,0 @@
import React, { useState, useEffect } from "react";
// Welcome Message component with simple visible emoji
export function WelcomeMessage({ user }: { user: any }) {
const [showEmoji, setShowEmoji] = useState(true);
const emojiChar = '👋';
useEffect(() => {
const timer = setTimeout(() => {
setShowEmoji(false);
}, 5000);
return () => clearTimeout(timer);
}, []);
return (
<div className="text-4xl font-bold mb-3">
<span className="bg-gradient-to-r from-gray-800 via-gray-700 to-gray-600 bg-clip-text text-transparent">
Welcome back, Priya Sharma!
</span>
{showEmoji && (
<span
className="text-yellow-500 ml-2 inline-block animate-wave-emoji"
style={{
fontSize: '2.5rem',
fontFamily: 'Apple Color Emoji, Segoe UI Emoji, Noto Color Emoji, sans-serif',
backgroundColor: 'transparent',
color: '#EAB308'
}}
>
{emojiChar}
</span>
)}
</div>
);
}

View File

@@ -1,141 +0,0 @@
import React from "react";
import { useNavigate } from "react-router-dom";
import { Clock, Users } from "lucide-react";
import { Card, CardContent } from "../../components/ui/card";
import { Button } from "../../components/ui/button";
import { Badge } from "../../components/ui/badge";
import { ImageWithFallback } from "../../components/figma/ImageWithFallback";
// What are others learning component - redesigned to match course card layout
export function WhatOthersLearning({ userType = 'individual' }: { userType?: 'individual' | 'corporate' }) {
const trendingContent = [
{
id: 1,
title: "AI in Leadership Decision Making",
description: "Explore how artificial intelligence is reshaping leadership strategies and decision-making processes.",
trend: "Hot",
enrollments: 2340,
duration: "5.2 hours",
badgeColor: "bg-red-100 text-red-800",
thumbnail: "https://images.unsplash.com/photo-1485827404703-89b55fcc595e?w=400&h=240&fit=crop",
recentLearners: 423
},
{
id: 2,
title: "Remote Team Management",
description: "Master the art of leading distributed teams effectively in the modern workplace.",
trend: "Trending",
enrollments: 1890,
duration: "3 sessions",
badgeColor: "bg-orange-100 text-orange-800",
thumbnail: "https://images.unsplash.com/photo-1556761175-b413da4baf72?w=400&h=240&fit=crop",
recentLearners: 267
},
{
id: 3,
title: "Sustainable Leadership Practices",
description: "Build leadership approaches that create lasting organizational change and impact.",
trend: "Rising",
enrollments: 1560,
duration: "1 day",
badgeColor: "bg-green-100 text-green-800",
thumbnail: "https://images.unsplash.com/photo-1542744094-3a31f272c490?w=400&h=240&fit=crop",
recentLearners: 198
},
{
id: 4,
title: "Data-Driven Leadership",
description: "Learn to make strategic decisions using data analytics and business insights.",
trend: "Popular",
enrollments: 2100,
duration: "4.8 hours",
badgeColor: "bg-blue-100 text-blue-800",
thumbnail: "https://images.unsplash.com/photo-1551288049-bebda4e38f71?w=400&h=240&fit=crop",
recentLearners: 356
}
];
const navigate = useNavigate();
return (
<div className="bg-white">
<div className="flex items-center justify-between mb-6">
<div>
<h2 className="text-2xl font-semibold text-gray-900 mb-2">
What are others learning
</h2>
<p className="text-base text-gray-600">
Trending courses and popular content among your peers
</p>
</div>
<Button
variant="outline"
onClick={() => navigate(`/library?view=${userType}&filter=trending`)}
className="text-brand-navy hover:bg-brand-navy/10 border-brand-navy/20 text-base px-4 py-2 h-auto font-medium"
>
View Trending
</Button>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
{trendingContent.map((content) => (
<Card
key={content.id}
className="group cursor-pointer hover:shadow-lg transition-all duration-300 border border-gray-200 overflow-hidden flex flex-col"
>
{/* Course Thumbnail */}
<div className="relative h-40 bg-gray-200 overflow-hidden">
<ImageWithFallback
src={content.thumbnail}
alt={content.title}
className="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300"
/>
<div className="absolute top-3 left-3">
<Badge className={`${content.badgeColor} text-xs font-medium`}>
{content.trend}
</Badge>
</div>
</div>
{/* Make content flex column so button sticks to bottom */}
<CardContent className="px-4 pb-4 flex flex-col flex-1 justify-between">
<div>
{/* Course Title */}
<h3 className="text-base font-semibold text-gray-900 mb-2 line-clamp-2 group-hover:text-brand-navy transition-colors">
{content.title}
</h3>
{/* Course Description */}
<p className="text-sm text-gray-600 leading-relaxed mb-4 line-clamp-2">
{content.description}
</p>
{/* Duration and Recent Learners */}
<div className="flex items-center justify-between mb-4">
<div className="flex items-center gap-1">
<Clock className="h-4 w-4 text-gray-500" />
<span className="text-sm text-gray-600">{content.duration}</span>
</div>
<div className="flex items-center gap-1">
<Users className="h-4 w-4 text-gray-500" />
<span className="text-sm text-gray-600">{content.recentLearners}</span>
</div>
</div>
</div>
{/* Enroll Button at bottom */}
<Button
onClick={() => navigate(`/course?view=${userType}&courseId=${content.id}`)}
className="w-full text-base min-h-[48px] bg-brand-navy hover:bg-brand-navy/90 text-white font-medium mt-auto"
>
Enroll Now
</Button>
</CardContent>
</Card>
))}
</div>
</div>
);
}