import React, { useEffect, useState } from 'react';
import { Link, useNavigate } from 'react-router-dom';
import { StorageService } from '../services/storageService';
import { UserProfile, Task, TaskStatus, Priority, FTLMission } from '../types';
import { useLanguage } from '../contexts/LanguageContext';
import {
ArrowRight, CheckSquare, Loader2,
Calendar as CalendarIcon, Zap,
Coins,
Library as LibraryIcon, MessageCircle, MapPin, Activity,
Gamepad2, CheckCircle2, Camera,
ListTodo, Siren, Utensils, Bot, Shield, ChevronRight
} from 'lucide-react';
import confetti from 'canvas-confetti';
// --- COMPONENTS ---
const XPToast = ({ amount, onComplete }: { amount: number, onComplete: () => void }) => {
useEffect(() => {
const timer = setTimeout(onComplete, 2000);
return () => clearTimeout(timer);
}, [onComplete]);
return (
);
};
const CountUp = ({ end, duration = 1500 }: { end: number, duration?: number }) => {
const [count, setCount] = useState(0);
useEffect(() => {
let startTime: number;
let animationFrame: number;
const update = (currentTime: number) => {
if (!startTime) startTime = currentTime;
const progress = Math.min((currentTime - startTime) / duration, 1);
const ease = 1 - Math.pow(1 - progress, 4);
setCount(Math.floor(ease * end));
if (progress < 1) animationFrame = requestAnimationFrame(update);
};
animationFrame = requestAnimationFrame(update);
return () => cancelAnimationFrame(animationFrame);
}, [end, duration]);
return <>{count}>;
};
const getFrameStyle = (id?: string) => {
if (!id || id === 'none') return 'ring-2 ring-white/30';
if (id === 'unicorn') return 'ring-2 ring-pink-400 shadow-[0_0_15px_#f472b6]';
if (id === 'royal') return 'ring-2 ring-yellow-500 shadow-[0_0_20px_#eab308]';
if (id === 'nature') return 'ring-2 ring-green-500 border-green-300';
if (id === 'dark') return 'ring-2 ring-gray-800 shadow-[0_0_15px_#000]';
return 'ring-2 ring-white/30';
};
// --- DATA ---
const SLOGANS = [
{ en: "Small Country, Big Thinking", ne: "सानो देश, ठूलो सोच" },
{ en: "Heritage is Identity", ne: "सम्पदा नै पहिचान हो" },
{ en: "Unity in Diversity", ne: "विविधतामा एकता" },
{ en: "Digital Nepal, Smart Future", ne: "डिजिटल नेपाल, स्मार्ट भविष्य" },
];
// --- RENDERERS ---
interface TaskItemProps {
task: Task;
onComplete: (task: Task) => void | Promise;
}
const TaskItem: React.FC = ({ task, onComplete }) => (
{task.subject}
{task.title}
);
const Dashboard: React.FC = () => {
const { t, language } = useLanguage();
const navigate = useNavigate();
// Data State
const [profile, setProfile] = useState(null);
const [tasks, setTasks] = useState([]);
const [missions, setMissions] = useState([]);
const [loading, setLoading] = useState(true);
const [currentDate, setCurrentDate] = useState(new Date());
// UI State
const [xpGain, setXpGain] = useState(null);
const [sloganIndex, setSloganIndex] = useState(0);
useEffect(() => {
const timer = setInterval(() => setCurrentDate(new Date()), 60000);
const sloganTimer = setInterval(() => setSloganIndex(prev => (prev + 1) % SLOGANS.length), 4000);
const fetchData = async () => {
setLoading(true);
const [p, t_data, m] = await Promise.all([
StorageService.getProfile(),
StorageService.getTasks(),
StorageService.getMissions()
]);
setProfile(p);
setTasks(t_data);
setMissions(m);
setLoading(false);
};
fetchData();
const handleUpdate = async () => {
const [p, t_data, m] = await Promise.all([
StorageService.getProfile(),
StorageService.getTasks(),
StorageService.getMissions()
]);
if (p && profile && p.xp > profile.xp) {
setXpGain(p.xp - profile.xp);
}
setProfile(p);
setTasks(t_data);
setMissions(m);
};
window.addEventListener('rudraksha-profile-update', handleUpdate);
return () => {
clearInterval(timer);
clearInterval(sloganTimer);
window.removeEventListener('rudraksha-profile-update', handleUpdate);
};
}, [profile?.xp]);
const handleQuickCompleteTask = async (task: Task) => {
const updatedStatus = TaskStatus.COMPLETED;
await StorageService.saveTask({ ...task, status: updatedStatus });
await StorageService.addPoints(10, 50);
confetti({ particleCount: 50, spread: 60, origin: { y: 0.8 } });
window.dispatchEvent(new Event('rudraksha-profile-update'));
};
if (loading && !profile) return
;
const dateString = currentDate.toLocaleDateString(language === 'ne' ? 'ne-NP' : 'en-US', { weekday: 'long', month: 'long', day: 'numeric' });
const currentXP = profile?.xp || 0;
const userLevel = Math.floor(currentXP / 500) + 1;
const xpProgress = Math.min(100, Math.round(((currentXP - ((userLevel - 1) * 500)) / 500) * 100));
const pendingTasks = tasks.filter(t => t.status !== TaskStatus.COMPLETED).slice(0, 3);
const activeFTL = missions.filter(m => m.status === 'active');
const currentSlogan = SLOGANS[sloganIndex];
// Define Sections Logic
const SECTIONS = [
{
title: 'ACADEMICS',
color: 'text-indigo-500',
items: [
{ to: '/study-buddy', label: 'Rudra AI', icon: Bot, color: 'text-indigo-400', bg: 'bg-indigo-500/10', desc: 'Your Personal AI Tutor' },
{ to: '/planner', label: 'Planner', icon: CheckSquare, color: 'text-emerald-400', bg: 'bg-emerald-500/10', desc: `${pendingTasks.length} Pending Tasks` },
{ to: '/library', label: 'Library', icon: LibraryIcon, color: 'text-amber-400', bg: 'bg-amber-500/10', desc: 'Curriculum Resources' },
]
},
{
title: 'CULTURE & LIFESTYLE',
color: 'text-rose-500',
items: [
{ to: '/culture', label: 'Calendar', icon: CalendarIcon, color: 'text-rose-400', bg: 'bg-rose-500/10', desc: dateString },
{ to: '/map', label: 'Heritage Map', icon: MapPin, color: 'text-red-400', bg: 'bg-red-500/10', desc: 'Explore Nepal' },
{ to: '/recipes', label: 'Kitchen', icon: Utensils, color: 'text-orange-400', bg: 'bg-orange-500/10', desc: 'Traditional Recipes' },
]
},
{
title: 'COMMUNITY & UTILITIES',
color: 'text-blue-500',
items: [
{ to: '/community-chat', label: 'Community', icon: MessageCircle, color: 'text-blue-400', bg: 'bg-blue-500/10', desc: 'Global Chat' },
{ to: '/safety', label: 'Safety', icon: Siren, color: 'text-red-500', bg: 'bg-red-500/10', desc: activeFTL.length > 0 ? `${activeFTL.length} Active Alerts` : 'System Secure' },
{ to: '/health', label: 'Wellness', icon: Activity, color: 'text-teal-400', bg: 'bg-teal-500/10', desc: 'Health Tracker' },
{ to: '/arcade', label: 'Arcade', icon: Gamepad2, color: 'text-fuchsia-400', bg: 'bg-fuchsia-500/10', desc: 'Play & Earn' },
{ to: '/rewards', label: 'Karma Bazaar', icon: Coins, color: 'text-yellow-400', bg: 'bg-yellow-500/10', desc: 'Redeem Points' },
]
}
];
return (
{/* 1. HERO SECTION */}
navigate('/profile', { state: { action: 'avatar' } })} className="relative cursor-pointer group/avatar">
{dateString}
ID Verified
Namaste, {profile?.name.split(' ')[0]}
{language === 'ne' ? currentSlogan.ne : currentSlogan.en}
Progress to Level {userLevel + 1}
{currentXP} / {userLevel * 500} XP
{xpGain &&
setXpGain(null)} />}
{/* 2. DYNAMIC SECTIONS GRID */}
{SECTIONS.map((section, idx) => (
{section.items.map((item, i) => (
))}
))}
{/* 3. WIDGETS ROW */}
{/* Priority Tasks */}
Priority Queue
View All
{pendingTasks.length > 0 ? pendingTasks.map(t =>
) : (
All Clear
)}
{/* Active Alerts */}
FTL Network
View Map
{activeFTL.length > 0 ? activeFTL.slice(0, 3).map(m => (
{m.type} ALERT
{m.location}
)) : (
Sector Secure
)}
);
};
export default Dashboard;