import React, { useState, useEffect } from 'react';
import { NavLink, Outlet, useLocation, useNavigate, Navigate, Link } from 'react-router-dom';
import {
LayoutDashboard, CheckSquare, ShieldAlert, Tent, Utensils,
Map as MapIcon, LogOut, Sun, Moon, Loader2, Leaf,
ShoppingBag, Menu, X, BarChart2, Gamepad2, Settings,
Palette, Library, RefreshCw, Laptop, MessageCircle,
Lock, Zap, Calendar as CalendarIcon, Bot, ChevronRight, Award
} from 'lucide-react';
import { StorageService } from '../services/storageService';
import { UserProfile } from '../types';
import { useLanguage } from '../contexts/LanguageContext';
import { THEME_REGISTRY } from '../config/themes';
import { Logo } from './ui/Logo';
import RudraAI from './RudraAI'; // Import from components folder
import confetti from 'canvas-confetti';
const getFrameStyle = (id?: string) => {
if (!id || id === 'none') return 'ring-2 ring-white/50 dark:ring-white/20';
if (id === 'unicorn') return 'ring-4 ring-pink-400 shadow-[0_0_15px_#f472b6]';
if (id === 'royal') return 'ring-4 ring-yellow-500 shadow-[0_0_20px_#eab308]';
if (id === 'nature') return 'ring-4 ring-green-500 border-green-300';
if (id === 'dark') return 'ring-4 ring-gray-800 shadow-[0_0_20px_#000]';
if (id === 'frame_gold') return 'ring-4 ring-yellow-400 border-4 border-yellow-600 shadow-[0_0_25px_#eab308]';
return 'ring-2 ring-indigo-400';
};
const BadgeOverlay = () => {
const [badge, setBadge] = useState<{title: string, icon: any} | null>(null);
useEffect(() => {
const handleUnlock = (e: any) => {
const { title, icon } = e.detail;
setBadge({ title, icon });
// Trigger confetti
const duration = 3000;
const animationEnd = Date.now() + duration;
const defaults = { startVelocity: 30, spread: 360, ticks: 60, zIndex: 9999 };
const randomInRange = (min: number, max: number) => Math.random() * (max - min) + min;
const interval: any = setInterval(function() {
const timeLeft = animationEnd - Date.now();
if (timeLeft <= 0) {
return clearInterval(interval);
}
const particleCount = 50 * (timeLeft / duration);
confetti({ ...defaults, particleCount, origin: { x: randomInRange(0.1, 0.3), y: Math.random() - 0.2 } });
confetti({ ...defaults, particleCount, origin: { x: randomInRange(0.7, 0.9), y: Math.random() - 0.2 } });
}, 250);
// Auto dismiss
setTimeout(() => setBadge(null), 4000);
};
window.addEventListener('rudraksha-badge-unlock', handleUnlock);
return () => window.removeEventListener('rudraksha-badge-unlock', handleUnlock);
}, []);
if (!badge) return null;
return (
Achievement Unlocked
{badge.title}
);
};
const Layout: React.FC = () => {
const [isAuthenticated, setIsAuthenticated] = useState(false);
const [loading, setLoading] = useState(true);
const [profile, setProfile] = useState(null);
const [isSidebarOpen, setIsSidebarOpen] = useState(false);
const [isRefreshing, setIsRefreshing] = useState(false);
const [refreshKey, setRefreshKey] = useState(0);
const [isFocusMode, setIsFocusMode] = useState(() => localStorage.getItem('rudraksha_focus_mode') === 'true');
// Easter Egg State
const [logoClicks, setLogoClicks] = useState(0);
const [themeMode, setThemeMode] = useState<'system' | 'light' | 'dark'>(() => {
if (typeof window !== 'undefined') {
const saved = localStorage.getItem('themeMode');
return (saved === 'light' || saved === 'dark' || saved === 'system') ? saved : 'dark';
}
return 'dark';
});
const navigate = useNavigate();
const location = useLocation();
const { t, language, setLanguage } = useLanguage();
useEffect(() => {
checkAuth();
const handleUpdate = () => {
checkAuth();
setIsFocusMode(localStorage.getItem('rudraksha_focus_mode') === 'true');
};
window.addEventListener('rudraksha-profile-update', handleUpdate);
window.addEventListener('rudraksha-focus-update', handleUpdate);
return () => {
window.removeEventListener('rudraksha-profile-update', handleUpdate);
window.removeEventListener('rudraksha-focus-update', handleUpdate);
};
}, []);
useEffect(() => { setIsSidebarOpen(false); }, [location.pathname]);
useEffect(() => {
const root = window.document.documentElement;
const body = document.body;
if (body.getAttribute('data-theme-override')) return;
const currentThemeId = profile?.activeTheme || 'default';
const themeConfig = THEME_REGISTRY[currentThemeId] || THEME_REGISTRY['default'];
let isDark = false;
if (themeConfig.uiMode !== 'auto') {
isDark = themeConfig.uiMode === 'dark';
} else {
isDark = themeMode === 'system' ? window.matchMedia('(prefers-color-scheme: dark)').matches : themeMode === 'dark';
}
if (isDark) root.classList.add('dark');
else root.classList.remove('dark');
Object.entries(themeConfig.colors).forEach(([key, value]) => root.style.setProperty(key, value));
body.setAttribute('data-theme', currentThemeId);
const bgColor = (isDark && themeConfig.darkBgColor) ? themeConfig.darkBgColor : themeConfig.bgColor;
const bgPattern = (isDark && themeConfig.darkBgPattern !== undefined) ? themeConfig.darkBgPattern : (themeConfig.bgPattern || 'none');
body.style.backgroundColor = bgColor;
body.style.backgroundImage = bgPattern;
body.style.backgroundAttachment = 'fixed';
body.style.backgroundSize = 'cover';
body.style.backgroundPosition = themeConfig.bgPosition || 'center';
if (themeConfig.isAnimated) body.classList.add('animate-neon-flow');
else body.classList.remove('animate-neon-flow');
body.style.filter = isFocusMode ? 'saturate(0.7) contrast(1.1)' : 'none';
localStorage.setItem('themeMode', themeMode);
}, [themeMode, profile?.activeTheme, location.pathname, isFocusMode]);
const checkAuth = async () => {
const auth = await StorageService.isAuthenticated();
const user = await StorageService.getProfile();
setIsAuthenticated(auth);
setProfile(user);
setLoading(false);
};
const cycleThemeMode = () => {
const modes: ('system' | 'light' | 'dark')[] = ['system', 'light', 'dark'];
const nextIndex = (modes.indexOf(themeMode) + 1) % modes.length;
setThemeMode(modes[nextIndex]);
};
const handleRefresh = async () => {
setIsRefreshing(true);
window.dispatchEvent(new Event('rudraksha-profile-update'));
await checkAuth();
setRefreshKey(prev => prev + 1);
setTimeout(() => setIsRefreshing(false), 800);
};
const toggleFocusMode = () => {
const newState = !isFocusMode;
localStorage.setItem('rudraksha_focus_mode', String(newState));
setIsFocusMode(newState);
window.dispatchEvent(new Event('rudraksha-focus-update'));
};
const handleLogoClick = async (e: React.MouseEvent) => {
e.preventDefault();
// Only count clicks if authenticated
if (!isAuthenticated || !profile) return;
setLogoClicks(prev => prev + 1);
// Easter Egg Trigger (5 clicks)
if (logoClicks + 1 === 5) {
// STRICT CHECK: Ensure profile data is loaded and badge isn't already owned
if (profile.unlockedItems?.includes('badge_secret')) {
console.log("Easter egg already claimed.");
setLogoClicks(0);
return;
}
// If valid claim:
await StorageService.addPoints(500, 0, 'easter_egg', 'Secret Hunter');
// Manually update unlock list in DB immediately
const currentItems = profile.unlockedItems || [];
const updatedProfile = await StorageService.updateProfile({
unlockedItems: [...currentItems, 'badge_secret']
});
// Update local state to reflect change immediately (prevents double tap)
if(updatedProfile) setProfile(updatedProfile);
// Trigger Visuals
window.dispatchEvent(new CustomEvent('rudraksha-badge-unlock', {
detail: { title: 'Secret Hunter', icon: 'spy' }
}));
setLogoClicks(0);
}
// Reset after 2 seconds of no click
setTimeout(() => setLogoClicks(0), 2000);
};
if (loading) return
;
if (!isAuthenticated && location.pathname !== '/auth' && location.pathname !== '/welcome') return ;
const isTeacher = profile?.role === 'teacher';
const isStudent = profile?.role === 'student';
const navGroups = [
{ items: [{ path: '/', label: t('Dashboard', 'Dashboard'), icon: LayoutDashboard }] },
{
title: t('ACADEMIC', 'ACADEMIC'),
condition: isStudent || isTeacher,
items: [
{ path: '/study-buddy', label: t('Rudra AI', 'Rudra AI'), icon: Bot },
{ path: '/planner', label: t('Assignments', 'Assignments'), icon: CheckSquare },
{ path: '/library', label: t('Library', 'Library'), icon: Library },
]
},
{
title: 'CULTURE',
condition: !isFocusMode,
items: [
{ path: '/culture', label: t('Calendar', 'Calendar'), icon: CalendarIcon },
{ path: '/map', label: t('Map & Provinces', 'Map & Provinces'), icon: MapIcon },
{ path: '/recipes', label: t('Kitchen', 'Kitchen'), icon: Utensils },
]
},
{
title: 'COMMUNITY',
condition: !isFocusMode,
items: [
{ path: '/community-chat', label: t('Network', 'Network'), icon: MessageCircle },
{ path: '/health', label: t('Wellness', 'Wellness'), icon: Leaf },
{ path: '/safety', label: t('FTL Rescue', 'FTL Rescue'), icon: ShieldAlert },
{ path: '/rewards', label: t('Karma Bazaar', 'Karma Bazaar'), icon: ShoppingBag },
{ path: '/arcade', label: t('Arcade', 'Arcade'), icon: Gamepad2 },
]
}
];
const NavContent = ({ onItemClick }: { onItemClick?: () => void }) => (
{navGroups.map((group, idx) => {
if (group.condition === false) return null;
return (
{group.title && (
{group.title}
)}
{group.items.map((item) => (
`
flex items-center justify-between px-4 py-3 rounded-2xl text-sm font-black italic transition-all duration-300 group
${isActive
? 'bg-white/80 dark:bg-white/10 text-indigo-700 dark:text-indigo-400 shadow-lg backdrop-blur-md translate-x-1 border border-indigo-100/50'
: 'text-gray-700 dark:text-gray-300 hover:bg-white/40 dark:hover:bg-white/5 hover:translate-x-1'}
`}
>
{item.label}
))}
);
})}
);
const UserProfileCard = () => (
{profile?.name || 'User'}
🏆 {profile?.points || 0} pts
);
return (
{/* Desktop Sidebar */}
{/* Mobile Header - Visible only on mobile */}
0 ? 'scale-110' : ''} transition-transform`}>
{isFocusMode ? : }
{isFocusMode ? Deep Work : 'Rudraksha'}
{!isFocusMode && (
)}
{/* Global Rudra AI Button */}
{!isFocusMode &&
}
{/* Mobile Sidebar Overlay */}
{isSidebarOpen && (
setIsSidebarOpen(false)}>
)}
{/* Mobile Sidebar Drawer */}
setIsSidebarOpen(false)} className="flex items-center gap-3 font-black text-xl text-red-700 dark:text-red-500 uppercase italic">
{isFocusMode ? : }
Rudraksha
);
};
export default Layout;