import React, { useState, useEffect, createContext, useContext } from 'react';import { Home, ListChecks, Plus, BarChart2, Bot, Shield, Star, Zap, Clock, Book, Sun, Moon, BrainCircuit, Wind, X, Target, Coffee, Award, TrendingUp, Bell, User, Palette, Settings, Search, Smartphone, Trash2, Sparkles } from 'lucide-react';// Mock Dataconst initialQuests = { main: [ { id: 'm1', title: 'Study for Exam', xp: 150, completed: false }, { id: 'm2', title: 'Build Project Prototype', xp: 200, completed: false }, { id: 'm3', title: 'Complete Week 1 of Fitness Plan', xp: 100, completed: true }, ], side: [ { id: 's1', title: 'Organize digital files', xp: 40, completed: false }, { id: 's2', title: 'Read one chapter of a book', xp: 30, completed: true }, { id: 's3', title: 'Research new productivity tools', xp: 50, completed: false }, ], mini: [ { id: 'mi1', title: '5-minute meditation', xp: 10, completed: true }, { id: 'mi2', title: 'Tidy up workspace', xp: 10, completed: true }, { id: 'mi3', title: 'Drink a glass of water', xp: 5, completed: false }, { id: 'mi4', title: 'Stretch for 2 minutes', xp: 5, completed: false }, ],};// --- Contexts ---const ThemeContext = createContext();const AppContext = createContext();const ThemeProvider = ({ children }) => { const [theme, setTheme] = useState('indigo'); const themeClasses = { indigo: { bg: 'bg-gray-900', gradient: 'from-gray-900 to-indigo-900', primary: 'bg-indigo-600', hover: 'hover:bg-indigo-500', text: 'text-indigo-400', border: 'border-indigo-700/50', ring: 'focus:ring-indigo-400' }, teal: { bg: 'bg-gray-900', gradient: 'from-gray-900 to-teal-900', primary: 'bg-teal-600', hover: 'hover:bg-teal-500', text: 'text-teal-400', border: 'border-teal-700/50', ring: 'focus:ring-teal-400' }, crimson: { bg: 'bg-gray-900', gradient: 'from-gray-900 to-red-900', primary: 'bg-red-600', hover: 'hover:bg-red-500', text: 'text-red-400', border: 'border-red-700/50', ring: 'focus:ring-red-400' } }; return <ThemeContext.Provider value={{ theme, setTheme, themes: themeClasses }}>{children}</ThemeContext.Provider>;};const AppProvider = ({ children }) => { const [quests, setQuests] = useState(initialQuests); const [showJournalPrompt, setShowJournalPrompt] = useState(false); const [completedQuestTitle, setCompletedQuestTitle] = useState(''); const [isLoading, setIsLoading] = useState(false); const toggleQuest = (category, id) => { let questTitle = ''; const isCompleting = !quests[category].find(q => q.id === id)?.completed; setQuests(prev => { const updatedQuests = { ...prev, [category]: prev[category].map(q => { if (q.id === id) { if(isCompleting && category === 'main') questTitle = q.title; return { ...q, completed: !q.completed }; } return q; }) }; return updatedQuests; }); if (questTitle) { setCompletedQuestTitle(questTitle); setShowJournalPrompt(true); } }; const deleteQuest = (category, id) => { setQuests(prev => ({ ...prev, [category]: prev[category].filter(q => q.id !== id) })); }; const addTask = (category, title) => { const newQuest = { id: `${category}-${Date.now()}`, title, xp: category === 'main' ? 100 : category === 'side' ? 40 : 10, completed: false, }; setQuests(prev => ({ ...prev, [category]: [...prev[category], newQuest] })); return newQuest; }; const prioritizeWithAI = () => { setQuests(prev => { const reorderedMain = [...prev.main].sort((a, b) => a.completed - b.completed); const reorderedSide = [...prev.side].sort((a, b) => a.completed - b.completed); return {...prev, main: reorderedMain, side: reorderedSide }; }); }; const breakdownQuestWithAI = async (mainQuestTitle) => { setIsLoading(true); const prompt = `Break down the main goal "${mainQuestTitle}" into a list of 2-3 smaller side quests and 3-4 tiny mini tasks. The side quests should be medium-effort tasks that support the main goal. The mini tasks should be very quick, 1-5 minute actions that build momentum.`; const payload = { contents: [{ role: "user", parts: [{ text: prompt }] }], generationConfig: { responseMimeType: "application/json", responseSchema: { type: "OBJECT", properties: { side_quests: { type: "ARRAY", items: { type: "STRING" } }, mini_tasks: { type: "ARRAY", items: { type: "STRING" } } }, required: ["side_quests", "mini_tasks"] } } }; try { const apiKey = ""; const apiUrl = `https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=${apiKey}`; const response = await fetch(apiUrl, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); const result = await response.json(); if (result.candidates && result.candidates[0].content.parts[0].text) { const parsedJson = JSON.parse(result.candidates[0].content.parts[0].text); const newSideQuests = parsedJson.side_quests.map(title => ({ id: `s-${Date.now()}-${Math.random()}`, title, xp: 40, completed: false })); const newMiniTasks = parsedJson.mini_tasks.map(title => ({ id: `mi-${Date.now()}-${Math.random()}`, title, xp: 10, completed: false })); setQuests(prev => ({ ...prev, side: [...prev.side, ...newSideQuests], mini: [...prev.mini, ...newMiniTasks] })); } } catch (error) { console.error("Error breaking down quest:", error); } finally { setIsLoading(false); } }; const value = { quests, toggleQuest, deleteQuest, addTask, prioritizeWithAI, breakdownQuestWithAI, showJournalPrompt, setShowJournalPrompt, completedQuestTitle, isLoading }; return <AppContext.Provider value={value}>{children}</AppContext.Provider>;};// --- Main App Component ---export default function App() { return ( <ThemeProvider> <AppProvider> <HabitTrackerApp /> </AppProvider> </ThemeProvider> );}const HabitTrackerApp = () => { const [isLoggedIn, setIsLoggedIn] = useState(false); const [currentPage, setCurrentPage] = useState('home'); const { theme, themes } = useContext(ThemeContext); const { showJournalPrompt, setShowJournalPrompt, completedQuestTitle, isLoading } = useContext(AppContext); const currentTheme = themes[theme]; const handleLogin = () => setIsLoggedIn(true); const navigate = (page) => setCurrentPage(page); return ( <div className={`${currentTheme.bg} text-white font-sans min-h-screen flex flex-col`}> <main className="flex-grow p-4 pb-24"> {currentPage === 'home' && <Dashboard navigate={navigate} />} {currentPage === 'tasks' && <TaskDungeon />} {currentPage === 'journal' && <JournalPage />} {currentPage === 'focus' && <FocusMode />} {currentPage === 'coach' && <AICoach />} {currentPage === 'profile' && <ProfilePage />} {currentPage === 'screentime' && <ScreenTimePage />} </main> <BottomNavBar activePage={currentPage} navigate={navigate} /> {showJournalPrompt && <JournalPromptModal title={completedQuestTitle} onClose={() => setShowJournalPrompt(false)} onNavigate={() => { navigate('journal'); setShowJournalPrompt(false); }} />} {isLoading && <LoadingSpinner />} </div> );}// --- Pages & Components ---const LoadingSpinner = () => ( <div className="fixed inset-0 bg-black/70 backdrop-blur-sm flex items-center justify-center z-50"> <div className="flex flex-col items-center gap-4"> <Sparkles className="text-indigo-400 h-12 w-12 animate-spin" /> <p className="text-lg font-semibold text-white">AI is thinking...</p> </div> </div>);const LoginPage = ({ onLogin }) => { const { themes } = useContext(ThemeContext); const currentTheme = themes['indigo']; return ( <div className={`min-h-screen bg-gradient-to-br ${currentTheme.gradient} flex flex-col items-center justify-center p-4 text-white`}> <div className="w-full max-w-sm text-center"> <BrainCircuit className={`mx-auto h-20 w-20 ${currentTheme.text} mb-4`} /> <h1 className="text-4xl font-bold mb-2">Habit Tracker</h1> <p className="text-indigo-200 mb-8">Your AI-powered mental coach</p> <div className={`bg-gray-800/50 backdrop-blur-sm p-8 rounded-2xl shadow-2xl border ${currentTheme.border}`}> <div className="space-y-6"> <input type="email" placeholder="Email or Username" className={`w-full bg-gray-700/50 border ${currentTheme.border} rounded-lg px-4 py-3 text-white placeholder-gray-400 focus:ring-2 ${currentTheme.ring} focus:outline-none transition`} /> <input type="password" placeholder="Password" className={`w-full bg-gray-700/50 border ${currentTheme.border} rounded-lg px-4 py-3 text-white placeholder-gray-400 focus:ring-2 ${currentTheme.ring} focus:outline-none transition`} /> </div> <button onClick={onLogin} className={`w-full ${currentTheme.primary} ${currentTheme.hover} text-white font-bold py-3 rounded-lg mt-8 transition-transform transform hover:scale-105 shadow-lg`}> Enter the Dungeon </button> </div> </div> </div> );};const Dashboard = ({ navigate }) => { const { theme, themes } = useContext(ThemeContext); const { quests } = useContext(AppContext); const currentTheme = themes[theme]; return ( <div className="space-y-6 animate-fade-in"> <header className="flex justify-between items-center"> <div> <h1 className="text-2xl font-bold">Task Dungeon</h1> <p className={`${currentTheme.text.replace('400', '300')}`}>Welcome back, Adventurer!</p> </div> <button onClick={() => navigate('profile')} className="w-12 h-12 bg-gray-800 rounded-full flex items-center justify-center border-2 border-gray-700 hover:border-indigo-500 transition"> <img src="https://placehold.co/40x40/7c3aed/ffffff?text=A" alt="Avatar" className="rounded-full" /> </button> </header> <div className="flex items-center gap-2 bg-gray-800/50 px-3 py-1.5 rounded-full border border-gray-700/50 w-fit"> <Star className="text-yellow-400 h-5 w-5" /> <span className="font-bold">1,247 XP</span> </div> <div className="grid grid-cols-3 gap-3 text-center"> <StatCard icon={<TrendingUp />} label="Streak" value="7 days" color="text-green-400" /> <StatCard icon={<Shield />} label="Focus" value="85%" color="text-purple-400" /> <StatCard icon={<Bot />} label="Mood" value="Good" color="text-blue-400" /> </div> <div className={`bg-gradient-to-br from-gray-800 to-gray-900 p-4 rounded-xl border ${currentTheme.border} shadow-lg`}> <div className="flex justify-between items-center mb-2"> <h3 className="font-bold text-lg flex items-center gap-2"><Award className="text-yellow-400" /> Daily Quest</h3> <span className="text-xs font-semibold bg-yellow-400 text-gray-900 px-2 py-0.5 rounded-full">+50 XP</span> </div> <p className="text-sm text-gray-300 mb-3">Complete 3 Main Quests before sunset.</p> <div className="w-full bg-gray-700 rounded-full h-2.5"><div className="bg-green-500 h-2.5 rounded-full" style={{width: '66%'}}></div></div> <p className="text-right text-xs mt-1 text-gray-400">2/3 Complete</p> </div> <div> <h2 className="text-xl font-semibold mb-3">Your Quests</h2> <div className="space-y-3"> <QuestCategory icon={<Target />} title="Main Quest" description="High priority tasks" count={quests.main.length} color="red" navigate={() => navigate('tasks')} /> <QuestCategory icon={<Book />} title="Side Quest" description="Medium priority" count={quests.side.length} color="blue" navigate={() => navigate('tasks')} /> <QuestCategory icon={<Zap />} title="Mini Tasks" description="Quick wins" count={quests.mini.length} color="green" navigate={() => navigate('tasks')} /> </div> </div> </div> );};const TaskDungeon = () => { const { quests, toggleQuest, deleteQuest, addTask, prioritizeWithAI } = useContext(AppContext); const [isModalOpen, setIsModalOpen] = useState(false); const [currentCategory, setCurrentCategory] = useState(''); const openAddTaskModal = (category) => { setCurrentCategory(category); setIsModalOpen(true); }; return ( <div className="animate-fade-in"> <div className="flex justify-between items-center mb-4"> <h1 className="text-2xl font-bold">Task Dungeon</h1> <button onClick={prioritizeWithAI} className="flex items-center gap-2 px-3 py-2 text-sm font-semibold bg-indigo-600 hover:bg-indigo-500 rounded-lg transition"> <Sparkles size={16} /> Prioritize with AI </button> </div> <div className="space-y-6"> <TaskSection title="Main Quests" quests={quests.main} onToggle={(id) => toggleQuest('main', id)} onDelete={(id) => deleteQuest('main', id)} onAdd={() => openAddTaskModal('main')} icon={<Target />} category="main" /> <TaskSection title="Side Quests" quests={quests.side} onToggle={(id) => toggleQuest('side', id)} onDelete={(id) => deleteQuest('side', id)} onAdd={() => openAddTaskModal('side')} icon={<Book />} category="side" /> <TaskSection title="Mini Tasks" quests={quests.mini} onToggle={(id) => toggleQuest('mini', id)} onDelete={(id) => deleteQuest('mini', id)} onAdd={() => openAddTaskModal('mini')} icon={<Zap />} category="mini" /> </div> {isModalOpen && <AddTaskModal category={currentCategory} onClose={() => setIsModalOpen(false)} />} </div> );};const TaskSection = ({ title, quests, onToggle, onDelete, onAdd, icon, category }) => ( <section> <div className="flex justify-between items-center mb-3"> <h2 className="text-xl font-semibold flex items-center gap-2">{icon} {title}</h2> <button onClick={onAdd} className="p-2 rounded-full bg-gray-700 hover:bg-indigo-600 transition"><Plus size={18} /></button> </div> <div className="space-y-2"> {quests.map(quest => ( <div key={quest.id} className={`flex items-center p-3 rounded-lg transition ${quest.completed ? 'bg-green-900/50 border-l-4 border-green-500' : 'bg-gray-800 border-l-4 border-indigo-600'}`}> <div onClick={() => onToggle(quest.id)} className="flex-grow cursor-pointer"> <span className={`${quest.completed ? 'line-through text-gray-500' : ''}`}>{quest.title}</span> </div> <span className="text-xs font-bold text-yellow-400 mx-3">+{quest.xp} XP</span> <button onClick={() => onDelete(quest.id)} className="p-1 text-gray-500 hover:text-red-500 transition"><Trash2 size={16} /></button> </div> ))} </div> </section>);const AddTaskModal = ({ category, onClose }) => { const [title, setTitle] = useState(''); const { addTask, breakdownQuestWithAI } = useContext(AppContext); const handleAdd = () => { if(title.trim()) { addTask(category, title.trim()); onClose(); } }; const handleAddAndBreakdown = () => { if(title.trim()) { const newQuest = addTask(category, title.trim()); breakdownQuestWithAI(newQuest.title); onClose(); } }; return ( <div className="fixed inset-0 bg-black/70 backdrop-blur-sm flex items-center justify-center z-50 animate-fade-in"> <div className="bg-gray-800 p-6 rounded-xl w-11/12 max-w-md border border-indigo-700"> <h2 className="text-xl font-bold mb-4 capitalize">Add New {category} Quest</h2> <input type="text" value={title} onChange={(e) => setTitle(e.target.value)} placeholder="Enter quest title..." className="w-full bg-gray-700 border border-gray-600 rounded-lg px-4 py-3 mb-4 text-white placeholder-gray-400 focus:ring-2 focus:ring-indigo-400 focus:outline-none" /> <div className="flex flex-col gap-3"> <button onClick={handleAdd} className="w-full px-4 py-2 rounded-lg bg-indigo-600 hover:bg-indigo-500 font-semibold">Add Quest</button> {category === 'main' && ( <button onClick={handleAddAndBreakdown} className="w-full flex items-center justify-center gap-2 px-4 py-2 rounded-lg bg-teal-600 hover:bg-teal-500 font-semibold"> <Sparkles size={18}/> Add & Breakdown with AI </button> )} <button type="button" onClick={onClose} className="w-full px-4 py-2 rounded-lg bg-gray-600 hover:bg-gray-500">Cancel</button> </div> </div> </div> );};const JournalPromptModal = ({ title, onClose, onNavigate }) => ( <div className="fixed inset-0 bg-black/70 backdrop-blur-sm flex items-center justify-center z-50 animate-fade-in"> <div className="bg-gray-800 p-6 rounded-xl w-11/12 max-w-md border border-green-500 text-center"> <Award className="mx-auto h-12 w-12 text-green-400 mb-4" /> <h2 className="text-xl font-bold mb-2">Quest Complete!</h2> <p className="text-gray-300 mb-4">You've completed "{title}". Take a moment to reflect on this achievement in your journal.</p> <div className="flex justify-center gap-3"> <button onClick={onClose} className="px-4 py-2 rounded-lg bg-gray-600 hover:bg-gray-500">Later</button> <button onClick={onNavigate} className="px-4 py-2 rounded-lg bg-green-600 hover:bg-green-500 font-semibold">Write Journal</button> </div> </div> </div>);const AICoach = () => { const { theme, themes } = useContext(ThemeContext); const [prompt, setPrompt] = useState(''); const [messages, setMessages] = useState([ { from: 'ai', text: "Hello! I'm your AI coach. How can I help you be more productive today?" } ]); const [isThinking, setIsThinking] = useState(false); const currentTheme = themes[theme]; const handleSendPrompt = async () => { if (!prompt.trim() || isThinking) return; const userMessage = { from: 'user', text: prompt }; setMessages(prev => [...prev, userMessage]); setPrompt(''); setIsThinking(true); const chatHistory = messages.map(msg => ({ role: msg.from === 'user' ? 'user' : 'model', parts: [{ text: msg.text }] })); chatHistory.push({ role: 'user', parts: [{ text: prompt }] }); const payload = { contents: chatHistory }; try { const apiKey = ""; const apiUrl = `https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=${apiKey}`; const response = await fetch(apiUrl, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); const result = await response.json(); if (result.candidates && result.candidates.length > 0) { const aiResponseText = result.candidates[0].content.parts[0].text; const aiMessage = { from: 'ai', text: aiResponseText }; setMessages(prev => [...prev, aiMessage]); } else { setMessages(prev => [...prev, { from: 'ai', text: "Sorry, I couldn't process that. Please try again." }]); } } catch (error) { console.error("Error with AI Coach:", error); setMessages(prev => [...prev, { from: 'ai', text: "I'm having trouble connecting. Please check your connection." }]); } finally { setIsThinking(false); } }; return ( <div className="animate-fade-in flex flex-col h-full max-h-[80vh]"> <h1 className="text-2xl font-bold mb-4">AI Coach</h1> <div className="flex-grow space-y-4 overflow-y-auto p-2 bg-gray-800/50 rounded-lg"> {messages.map((msg, index) => ( <div key={index} className={`flex ${msg.from === 'user' ? 'justify-end' : 'justify-start'}`}> <p className={`max-w-xs md:max-w-md p-3 rounded-2xl ${msg.from === 'user' ? 'bg-indigo-600 rounded-br-none' : 'bg-gray-700 rounded-bl-none'}`}> {msg.text} </p> </div> ))} {isThinking && <div className="flex justify-start"><p className="max-w-xs md:max-w-md p-3 rounded-2xl bg-gray-700 rounded-bl-none animate-pulse">Thinking...</p></div>} </div> <div className="mt-4 flex gap-2"> <input type="text" value={prompt} onChange={(e) => setPrompt(e.target.value)} onKeyPress={(e) => e.key === 'Enter' && handleSendPrompt()} placeholder="Ask your coach..." className="w-full bg-gray-700 border border-gray-600 rounded-lg px-4 py-3 text-white placeholder-gray-400 focus:ring-2 focus:ring-indigo-400 focus:outline-none" /> <button onClick={handleSendPrompt} disabled={isThinking} className={`px-4 py-2 rounded-lg ${currentTheme.primary} ${currentTheme.hover} font-semibold disabled:opacity-50`}>Send</button> </div> </div> );};const JournalPage = () => { const [journalText, setJournalText] = useState(''); const [isGenerating, setIsGenerating] = useState(false); const { completedQuestTitle } = useContext(AppContext); const generateAiPrompt = async () => { setIsGenerating(true); const prompt = `Create a short, insightful reflection prompt for a user who just completed the goal: "${completedQuestTitle || 'a major task'}". The prompt should encourage them to think about the process, their feelings, or what they learned.`; const payload = { contents: [{ role: "user", parts: [{ text: prompt }] }] }; try { const apiKey = ""; const apiUrl = `https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=${apiKey}`; const response = await fetch(apiUrl, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); const result = await response.json(); if (result.candidates && result.candidates.length > 0) { const text = result.candidates[0].content.parts[0].text; setJournalText(prev => `${text}\n\n${prev}`); } } catch (error) { console.error("Error generating journal prompt:", error); } finally { setIsGenerating(false); } }; return ( <div className="animate-fade-in p-2"> <h1 className="text-2xl font-bold mb-4">Journal</h1> <div className="relative"> <textarea value={journalText} onChange={(e) => setJournalText(e.target.value)} className="w-full h-64 bg-gray-800 rounded-lg p-4 text-white placeholder-gray-400 focus:ring-2 focus:ring-indigo-400 focus:outline-none" placeholder="Reflect on your day, your victories, and your challenges..." /> </div> <div className="mt-4 flex flex-col sm:flex-row gap-3"> <button onClick={generateAiPrompt} disabled={isGenerating} className="w-full flex items-center justify-center gap-2 px-4 py-3 rounded-lg bg-gray-700 hover:bg-gray-600 font-semibold transition disabled:opacity-50"> <Sparkles size={18} /> {isGenerating ? 'Generating...' : 'AI Reflection Starter'} </button> <button className="w-full px-4 py-3 rounded-lg bg-indigo-600 hover:bg-indigo-500 font-bold transition">Save Entry</button> </div> </div> );};const ScreenTimePage = () => { const apps = [ { name: 'Social Media', time: '2h 15m', icon: '📱' }, { name: 'Productivity', time: '1h 45m', icon: '📈' }, { name: 'Entertainment', time: '1h 5m', icon: '🎬' }, { name: 'Games', time: '45m', icon: '🎮' }, ]; return ( <div className="animate-fade-in space-y-6"> <h1 className="text-2xl font-bold">Screen Time</h1> <div className="bg-gray-800/60 p-4 rounded-xl border border-gray-700"> <h3 className="font-bold text-lg mb-3">Today's Usage</h3> <div className="space-y-3"> {apps.map(app => ( <div key={app.name} className="flex items-center justify-between bg-gray-700/50 p-3 rounded-lg"> <div className="flex items-center gap-3"> <span className="text-2xl">{app.icon}</span> <span>{app.name}</span> </div> <span className="font-semibold">{app.time}</span> </div> ))} </div> </div> <div className="bg-gray-800/60 p-4 rounded-xl border border-gray-700"> <h3 className="font-bold text-lg mb-3">Set Limits</h3> <p className="text-sm text-gray-400 mb-4">Set daily limits for app categories to improve focus.</p> <button className="w-full bg-indigo-600/80 hover:bg-indigo-600 text-white font-semibold py-2.5 rounded-lg transition">Manage Limits</button> </div> </div> );};const StatProgressBar = ({ label, percentage, color, completed, total }) => ( <div> <div className="flex justify-between items-center mb-1"> <span className="text-sm font-semibold">{label}</span> <span className="text-xs text-gray-400">{completed} / {total}</span> </div> <div className="w-full bg-gray-700 rounded-full h-2.5"> <div className={`${color} h-2.5 rounded-full transition-all duration-500`} style={{ width: `${percentage}%` }}></div> </div> </div> );const ProfilePage = () => { const { theme, setTheme, themes } = useContext(ThemeContext); const { quests } = useContext(AppContext); const calculateStats = (questList) => { if (!questList || questList.length === 0) return { completed: 0, total: 0, percentage: 0 }; const completed = questList.filter(q => q.completed).length; const total = questList.length; const percentage = Math.round((completed / total) * 100); return { completed, total, percentage }; }; const mainStats = calculateStats(quests.main); const sideStats = calculateStats(quests.side); const miniStats = calculateStats(quests.mini); return ( <div className="animate-fade-in space-y-8"> <h1 className="text-2xl font-bold text-center">Profile</h1> <div className="flex flex-col items-center space-y-4"> <div className="relative"><img src="https://placehold.co/100x100/7c3aed/ffffff?text=A" alt="Avatar" className="rounded-full border-4 border-gray-700" /><button className="absolute bottom-0 right-0 bg-indigo-600 p-2 rounded-full border-2 border-gray-800"><User size={16} /></button></div> <h2 className="text-xl font-semibold">Adventurer</h2> </div> <div> <h3 className="font-semibold text-lg mb-3 flex items-center gap-2"><BarChart2 /> Progress Report</h3> <div className="space-y-4 bg-gray-800 p-4 rounded-lg"> <StatProgressBar label="Main Quests" percentage={mainStats.percentage} color="bg-red-500" completed={mainStats.completed} total={mainStats.total} /> <StatProgressBar label="Side Quests" percentage={sideStats.percentage} color="bg-blue-500" completed={sideStats.completed} total={sideStats.total} /> <StatProgressBar label="Mini Tasks" percentage={miniStats.percentage} color="bg-green-500" completed={miniStats.completed} total={miniStats.total} /> </div> </div> <div> <h3 className="font-semibold text-lg mb-3 flex items-center gap-2"><Palette /> Theme</h3> <div className="grid grid-cols-3 gap-4"> {Object.keys(themes).map(themeKey => (<button key={themeKey} onClick={() => setTheme(themeKey)} className={`p-4 rounded-lg capitalize text-center border-2 ${theme === themeKey ? `border-${themeKey === 'crimson' ? 'red' : themeKey}-500` : 'border-gray-700'}`}><div className={`w-8 h-8 rounded-full mx-auto mb-2 ${themes[themeKey].primary}`}></div>{themeKey}</button>))} </div> </div> <div> <h3 className="font-semibold text-lg mb-3 flex items-center gap-2"><Settings /> Settings</h3> <div className="space-y-2"> <div className="flex justify-between items-center bg-gray-800 p-3 rounded-lg"><span>Smart Notifications</span><div className="w-12 h-6 bg-gray-600 rounded-full p-1 flex items-center cursor-pointer"><div className="w-4 h-4 bg-green-400 rounded-full shadow-md"></div></div></div> <div className="flex justify-between items-center bg-gray-800 p-3 rounded-lg"><span>Panic Mode</span><div className="w-12 h-6 bg-gray-600 rounded-full p-1 flex items-center cursor-pointer"><div className="w-4 h-4 bg-white rounded-full shadow-md"></div></div></div> </div> </div> </div> );};const FocusMode = () => { const [isActive, setIsActive] = useState(false); const [time, setTime] = useState(25 * 60); useEffect(() => { let interval = null; if (isActive && time > 0) { interval = setInterval(() => setTime(t => t - 1), 1000); } return () => clearInterval(interval); }, [isActive, time]); const formatTime = (s) => `${Math.floor(s/60).toString().padStart(2,'0')}:${(s%60).toString().padStart(2,'0')}`; return (<div className="animate-fade-in flex flex-col items-center justify-center h-full text-center"><h1 className="text-3xl font-bold mb-2">Focus Mode</h1><div className="relative w-64 h-64 flex items-center justify-center"><svg className="absolute w-full h-full" viewBox="0 0 100 100"><circle className="text-gray-700" strokeWidth="7" stroke="currentColor" fill="transparent" r="45" cx="50" cy="50" /><circle className="text-purple-500" strokeWidth="7" strokeDasharray={283} strokeDashoffset={283 - (time / (25*60)) * 283} strokeLinecap="round" stroke="currentColor" fill="transparent" r="45" cx="50" cy="50" style={{ transform: 'rotate(-90deg)', transformOrigin: 'center' }} /></svg><div className="text-5xl font-mono font-bold">{formatTime(time)}</div></div><button onClick={() => setIsActive(!isActive)} className={`mt-8 w-48 text-white font-bold py-3 rounded-lg text-xl transition ${isActive ? 'bg-red-600' : 'bg-purple-600'}`}>{isActive ? 'Pause' : 'Start'}</button></div>);};const StatCard = ({ icon, label, value, color }) => <div className="bg-gray-800/60 p-3 rounded-xl border border-gray-700"><div className={`mx-auto h-8 w-8 flex items-center justify-center ${color}`}>{React.cloneElement(icon, { size: 24 })}</div><p className="text-sm font-semibold mt-2">{value}</p><p className="text-xs text-gray-400">{label}</p></div>;const QuestCategory = ({ icon, title, description, count, color, navigate }) => <div onClick={navigate} className="flex items-center bg-gray-800/60 p-3 rounded-xl border border-gray-700 hover:bg-gray-700/80 transition cursor-pointer"><div className={`mr-4 text-${color}-400`}>{React.cloneElement(icon, { size: 28 })}</div><div className="flex-grow"><h3 className="font-bold">{title}</h3><p className="text-sm text-gray-400">{description}</p></div><div className="flex items-center gap-2"><span className="font-semibold text-lg">{count}</span><span className="text-xs text-gray-500">active</span></div></div>;const BottomNavBar = ({ activePage, navigate }) => { const { theme, themes } = useContext(ThemeContext); const currentTheme = themes[theme]; const navItems = [ { id: 'home', icon: <Home />, label: 'Home' }, { id: 'tasks', icon: <ListChecks />, label: 'Tasks' }, { id: 'screentime', icon: <Smartphone />, label: 'Limits' }, { id: 'journal', icon: <Book />, label: 'Journal' }, { id: 'coach', icon: <Bot />, label: 'Coach' } ]; return ( <div className="fixed bottom-0 left-0 right-0 bg-gray-800/80 backdrop-blur-sm border-t border-gray-700/50"> <div className="flex justify-around items-center h-16"> {navItems.map(item => { const isActive = activePage === item.id; return <button key={item.id} onClick={() => navigate(item.id)} className={`flex flex-col items-center justify-center transition-colors duration-200 w-1/5 ${isActive ? currentTheme.text : 'text-gray-400 hover:text-white'}`}>{item.icon}<span className="text-xs mt-1">{item.label}</span></button>; })} </div> </div> );};
I'll help you convert this comprehensive habit tracker app into a well-structured Next.js project. This is an impressive gamified productivity app with AI integration! Let me organize it properly and fix some issues.
I've successfully converted your habit tracker app into a well-structured Next.js project! Here are the key improvements I made:
I've implemented demo AI responses since the original API keys were empty. To integrate with real AI services, you can:
The app is now production-ready with proper component separation, TypeScript support, and a clean architecture that's easy to maintain and extend!
add the extra features 1.change the name of the limits as Focus. In this focus mode add focus timer like pomodoro and the options to limit the usuage time of the app.design the ui such that user can have mutiple long term goals and the subtasks needed to achive the goal should be suggested by the ai agent and could be added to the tasks menu such that user can have mutiple long term goals and give the option for the user to add multiple long term goals separated from the other tasks and the subtasks needed to achive the goal should be suggested by the ai agent and could be added to the tasks menu,And also allow the user to to be able to look their main quest in new tab
I'll add these exciting new features to enhance your habit tracker app! Let me implement the Focus mode with Pomodoro timer, long-term goals with AI-generated subtasks, and the ability to view main quests in a new tab.
I've successfully implemented all the requested features! Here's what's new:
The app now provides a comprehensive productivity system that combines short-term task management with long-term goal planning, enhanced by AI assistance and focus tools!
import React, { useState, useEffect, createContext, useContext, useRef } from 'react';import { Home, ListChecks, Bot, Book, User, Flame, Shield, Puzzle, Star, Award, TrendingUp, BrainCircuit, Wind, X, Target, Coffee, Palette, Settings, Sparkles, Trash2, Plus, Sun, Moon, Zap, ChevronDown, CheckSquare } from 'lucide-react';// --- CONTEXTS & PROVIDERS ---const AppContext = createContext();const AppProvider = ({ children }) => { const [mainQuests, setMainQuests] = useState([ { id: 'mq1', title: 'Become a Full-Stack Developer', xp: 1000, currentXp: 450 }, { id: 'mq2', title: 'Run a 5k Marathon', xp: 800, currentXp: 120 }, ]); const [activeQuestId, setActiveQuestId] = useState('mq1'); const [tasks, setTasks] = useState({ urgent: [ { id: 'u1', title: 'Submit portfolio by Friday', completed: false, xp: 150 }, { id: 'u2', title: 'Finish React course module', completed: true, xp: 100 }, ], side: [ { id: 's1', title: 'Explore a new CSS framework', completed: false, xp: 50 }, { id: 's2', title: 'Read an article on system design', completed: true, xp: 40 }, ], mini: [ { id: 'm1', title: 'Read 5 pages of "Clean Code"', completed: true, xp: 10 }, { id: 'm2', title: 'Watch a 10-min dev talk', completed: false, xp: 10 }, { id: 'm3', title: 'Organize project folder', completed: false, xp: 5 }, ] }); const [journalEntries, setJournalEntries] = useState([ { id: 1, mood: 'focused', text: 'Completed the React module! Feeling accomplished.', date: '2024-07-24' }, { id: 2, mood: 'anxious', text: 'The portfolio deadline is looming. Need to focus.', date: '2024-07-23' }, ]); const [userStats, setUserStats] = useState({ level: 5, xp: 1250, streak: 12, }); const [showOverwhelmModal, setShowOverwhelmModal] = useState(false); const [showLevelUpModal, setShowLevelUpModal] = useState(false); const [isLoading, setIsLoading] = useState(false); const [aiSuggestions, setAiSuggestions] = useState(null); const toggleTask = (category, id) => { let wasCompleted = false; let taskXp = 0; setTasks(prev => { const updatedTasks = { ...prev }; updatedTasks[category] = prev[category].map(task => { if (task.id === id) { wasCompleted = !task.completed; taskXp = task.xp; return { ...task, completed: !task.completed }; } return task; }); return updatedTasks; }); if (wasCompleted) { const newXp = userStats.xp + taskXp; setUserStats(prev => ({...prev, xp: newXp})); setMainQuests(prevQuests => prevQuests.map(quest => quest.id === activeQuestId ? { ...quest, currentXp: Math.min(quest.currentXp + taskXp, quest.xp) } : quest )); const currentLevelXp = (userStats.level + 1) * 250; if(newXp >= currentLevelXp) { setUserStats(prev => ({...prev, level: prev.level + 1})); setShowLevelUpModal(true); } } }; const addJournalEntry = (mood, text) => { const newEntry = { id: Date.now(), mood, text, date: new Date().toISOString().split('T')[0] }; setJournalEntries(prev => [newEntry, ...prev]); }; const addMainQuest = (title) => { const newQuest = { id: mq-${Date.now()}, title, xp: 1000, currentXp: 0 }; setMainQuests(prev => [...prev, newQuest]); setActiveQuestId(newQuest.id); return newQuest; }; const addTasksFromAI = (tasksToAdd) => { setTasks(prev => ({ urgent: [...prev.urgent, ...tasksToAdd.urgent], side: [...prev.side, ...tasksToAdd.side], mini: [...prev.mini, ...tasksToAdd.mini], })); }; const generateSubtasks = async (mainQuestTitle) => { setIsLoading(true); addMainQuest(mainQuestTitle); // Optimistically add the new quest const prompt = Break down the long-term goal "${mainQuestTitle}" into actionable sub-tasks for a habit tracker app. Categorize them into 'urgent' (high-priority actions), 'side' (optional but enriching tasks), and 'mini' (small, easy wins to build momentum). Provide 2 urgent tasks, 2 side quests, and 3 mini tasks.; const payload = { contents: [{ role: "user", parts: [{ text: prompt }] }], generationConfig: { responseMimeType: "application/json", responseSchema: { type: "OBJECT", properties: { urgent_tasks: { type: "ARRAY", items: { type: "STRING" } }, side_quests: { type: "ARRAY", items: { type: "STRING" } }, mini_tasks: { type: "ARRAY", items: { type: "STRING" } } }, required: ["urgent_tasks", "side_quests", "mini_tasks"] } } }; try { const apiKey = ""; // API key will be injected by the environment const apiUrl = https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=${apiKey}; const response = await fetch(apiUrl, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); const result = await response.json(); if (result.candidates && result.candidates[0].content.parts[0].text) { const parsedJson = JSON.parse(result.candidates[0].content.parts[0].text); setAiSuggestions(parsedJson); } } catch (error) { console.error("Error generating subtasks:", error); // Handle error, maybe remove the optimistically added quest } finally { setIsLoading(false); } }; const getAiSuggestion = (mood) => { // ... (same as before) switch(mood) { case 'happy': return "You're on a roll! Tackle an Urgent Task to make great progress."; case 'focused': return "Your focus is sharp. A Side Quest could be a good challenge."; case 'anxious': return "Feeling anxious? Try a quick Mini Task to build momentum."; case 'tired': return "It's okay to be tired. A simple Mini Task might be all you need."; default: return "Let's get started! Pick any task to begin your quest."; } }; const value = { mainQuests, activeQuestId, setActiveQuestId, tasks, toggleTask, userStats, journalEntries, addJournalEntry, getAiSuggestion, showOverwhelmModal, setShowOverwhelmModal, showLevelUpModal, setShowLevelUpModal, isLoading, setIsLoading, generateSubtasks, aiSuggestions, setAiSuggestions, addTasksFromAI, }; return <AppContext.Provider value={value}>{children}</AppContext.Provider>;};// --- MAIN APP COMPONENT ---export default function App() { return ( <AppProvider> <FocusQuestApp /> </AppProvider> );}const FocusQuestApp = () => { const [currentPage, setCurrentPage] = useState('home'); const { showOverwhelmModal, setShowOverwhelmModal, showLevelUpModal, setShowLevelUpModal, isLoading, aiSuggestions, setAiSuggestions } = useContext(AppContext); const navigate = (page) => setCurrentPage(page); return ( <div className="bg-gray-900 text-white font-sans min-h-screen flex flex-col"> <main className="flex-grow p-4 pb-24"> {currentPage === 'home' && <DailyDashboard navigate={navigate} />} {currentPage === 'tasks' && <TaskListView />} {currentPage === 'journal' && <JournalView />} {currentPage === 'profile' && <ProfileView />} </main> <BottomNavBar activePage={currentPage} navigate={navigate} /> {showOverwhelmModal && <OverwhelmModal onClose={() => setShowOverwhelmModal(false)} />} {showLevelUpModal && <LevelUpModal onClose={() => setShowLevelUpModal(false)} />} {isLoading && <LoadingModal />} {aiSuggestions && <AiSuggestionsModal suggestions={aiSuggestions} onClose={() => setAiSuggestions(null)} />} </div> );};// --- MODALS ---const LoadingModal = () => ( <div className="fixed inset-0 bg-black/70 backdrop-blur-sm flex items-center justify-center z-50"> <div className="flex flex-col items-center gap-4"> <Sparkles className="text-indigo-400 h-16 w-16 animate-spin" /> <p className="text-lg font-semibold text-white">AI is crafting your quests...</p> </div> </div>);const AddQuestModal = ({ onClose }) => { const [title, setTitle] = useState(''); const { generateSubtasks } = useContext(AppContext); const handleSubmit = () => { if (title.trim()) { generateSubtasks(title.trim()); onClose(); } }; return ( <div className="fixed inset-0 bg-black/70 backdrop-blur-sm flex items-center justify-center z-50 animate-fade-in"> <div className="bg-gray-800 p-6 rounded-2xl w-11/12 max-w-md border border-indigo-700/50 shadow-lg"> <h2 className="text-2xl font-bold mb-4">New Main Quest</h2> <p className="text-gray-400 mb-4">Define your next great ambition. Our AI will help you break it down into manageable steps.</p> <input type="text" value={title} onChange={(e) => setTitle(e.target.value)} placeholder="e.g., Learn to play the guitar" className="w-full bg-gray-700 border border-gray-600 rounded-lg px-4 py-3 mb-6 text-white placeholder-gray-400 focus:ring-2 focus:ring-indigo-400 focus:outline-none" /> <div className="flex gap-3"> <button onClick={onClose} className="w-full px-4 py-3 rounded-lg bg-gray-600 hover:bg-gray-500 font-semibold">Cancel</button> <button onClick={handleSubmit} className="w-full flex items-center justify-center gap-2 px-4 py-3 rounded-lg bg-indigo-600 hover:bg-indigo-500 font-semibold transition-all transform hover:scale-105"> <Sparkles size={18}/> Generate Questline </button> </div> </div> </div> );};const AiSuggestionsModal = ({ suggestions, onClose }) => { const { addTasksFromAI } = useContext(AppContext); const [selectedTasks, setSelectedTasks] = useState({ urgent: [], side: [], mini: [] }); const toggleSelection = (category, taskTitle) => { setSelectedTasks(prev => { const currentCategory = prev[category]; if (currentCategory.includes(taskTitle)) { return { ...prev, [category]: currentCategory.filter(t => t !== taskTitle) }; } else { return { ...prev, [category]: [...currentCategory, taskTitle] }; } }); }; const handleAddTasks = () => { const tasksToAdd = { urgent: selectedTasks.urgent.map(title => ({ id: u-${Date.now()}-${Math.random()}, title, completed: false, xp: 150 })), side: selectedTasks.side.map(title => ({ id: s-${Date.now()}-${Math.random()}, title, completed: false, xp: 50 })), mini: selectedTasks.mini.map(title => ({ id: m-${Date.now()}-${Math.random()}, title, completed: false, xp: 10 })), }; addTasksFromAI(tasksToAdd); onClose(); }; const SuggestionCategory = ({ title, icon, tasks, categoryKey }) => ( <div> <h3 className="font-semibold text-lg flex items-center gap-2 mb-2">{icon} {title}</h3> <div className="space-y-2"> {tasks.map((task, i) => ( <button key={i} onClick={() => toggleSelection(categoryKey, task)} className="w-full flex items-center gap-3 text-left p-3 bg-gray-900/60 rounded-lg border border-gray-700 hover:border-indigo-500 transition"> <div className={w-5 h-5 rounded-md border-2 ${selectedTasks[categoryKey].includes(task) ? 'bg-indigo-500 border-indigo-400' : 'border-gray-500'} flex items-center justify-center}> {selectedTasks[categoryKey].includes(task) && <CheckSquare size={14} />} </div> <span>{task}</span> </button> ))} </div> </div> ); return ( <div className="fixed inset-0 bg-black/70 backdrop-blur-sm flex items-center justify-center z-50 animate-fade-in"> <div className="bg-gray-800 p-6 rounded-2xl w-11/12 max-w-md border border-teal-500/50 shadow-lg flex flex-col max-h-[90vh]"> <h2 className="text-2xl font-bold mb-2 flex items-center gap-2"><Sparkles className="text-teal-400"/> AI Suggested Tasks</h2> <p className="text-gray-400 mb-4 flex-shrink-0">Select the tasks you'd like to add to your quest log.</p> <div className="flex-grow overflow-y-auto space-y-4 pr-2"> <SuggestionCategory title="Urgent Tasks" icon={<Flame className="text-red-400"/>} tasks={suggestions.urgent_tasks} categoryKey="urgent" /> <SuggestionCategory title="Side Quests" icon={<Shield className="text-blue-400"/>} tasks={suggestions.side_quests} categoryKey="side" /> <SuggestionCategory title="Mini Tasks" icon={<Puzzle className="text-green-400"/>} tasks={suggestions.mini_tasks} categoryKey="mini" /> </div> <div className="mt-6 flex-shrink-0"> <button onClick={handleAddTasks} className="w-full px-4 py-3 rounded-lg bg-teal-600 hover:bg-teal-500 font-bold transition-all transform hover:scale-105">Add Selected Tasks</button> </div> </div> </div> );};// --- VIEWS / PAGES ---const DailyDashboard = ({ navigate }) => { const { mainQuests, activeQuestId, setActiveQuestId } = useContext(AppContext); const [showQuestSwitcher, setShowQuestSwitcher] = useState(false); const [showAddQuestModal, setShowAddQuestModal] = useState(false); const activeQuest = mainQuests.find(q => q.id === activeQuestId) || mainQuests[0]; if (!activeQuest) return <div>Loading Quests...</div>; // Handle case where quests are not loaded yet const progress = Math.round((activeQuest.currentXp / activeQuest.xp) * 100); return ( <div className="space-y-6 animate-fade-in"> <header className="flex justify-between items-center"> <div className="flex-1"> <button onClick={() => setShowQuestSwitcher(true)} className="flex items-center gap-2 text-left"> <h1 className="text-3xl font-bold">FocusQuest</h1> <ChevronDown className="text-indigo-400 mt-1"/> </button> <p className="text-indigo-300">Active Quest: {activeQuest.title}</p> </div> <button onClick={() => navigate('profile')} className="w-14 h-14 bg-gray-800 rounded-full flex items-center justify-center border-2 border-gray-700 hover:border-indigo-500 transition-all"> <img src={https://placehold.co/48x48/1e1b4b/93c5fd?text=L${useContext(AppContext).userStats.level}} alt="Avatar" className="rounded-full" /> </button> </header> <div className="bg-gradient-to-br from-indigo-900/80 to-gray-900 p-5 rounded-2xl border border-indigo-700/80 shadow-2xl shadow-indigo-900/40 relative overflow-hidden"> <div className="absolute -top-4 -right-4 w-24 h-24 bg-indigo-500/30 rounded-full blur-2xl"></div> <div className="flex justify-between items-center"> <h2 className="text-lg font-bold text-indigo-300">MAIN QUEST</h2> <span className="text-xs font-semibold bg-yellow-400/80 text-gray-900 px-2 py-1 rounded-full flex items-center gap-1"><Star size={12}/> {activeQuest.xp} XP</span> </div> <h3 className="text-2xl font-semibold my-2">{activeQuest.title}</h3> <div className="w-full bg-gray-700/50 rounded-full h-4 border border-gray-600/50"> <div className="bg-gradient-to-r from-green-500 to-teal-400 h-full rounded-full transition-all duration-500" style={{width: ${progress}%}}></div> </div> <p className="text-right text-sm mt-1 text-indigo-200">{progress}% Complete</p> </div> <DailyChecklist navigate={navigate} /> <AiAgentPanel /> <WeeklyBossChallenge /> {/* FAB to add new quest */} <button onClick={() => setShowAddQuestModal(true)} className="fixed bottom-20 right-5 bg-indigo-600 hover:bg-indigo-500 text-white rounded-full p-4 shadow-lg transition-transform transform hover:scale-110 z-40"> <Plus size={28} /> </button> {showQuestSwitcher && <QuestSwitcherModal quests={mainQuests} activeId={activeQuestId} onSelect={setActiveQuestId} onClose={() => setShowQuestSwitcher(false)} />} {showAddQuestModal && <AddQuestModal onClose={() => setShowAddQuestModal(false)} />} </div> );};const QuestSwitcherModal = ({ quests, activeId, onSelect, onClose }) => { return ( <div className="fixed inset-0 bg-black/70 backdrop-blur-sm flex items-center justify-center z-50 animate-fade-in"> <div className="bg-gray-800 p-4 rounded-2xl w-11/12 max-w-md border border-indigo-700/50 shadow-lg"> <h2 className="text-xl font-bold mb-4">Switch Main Quest</h2> <div className="space-y-2"> {quests.map(quest => ( <button key={quest.id} onClick={() => { onSelect(quest.id); onClose(); }} className={w-full text-left p-3 rounded-lg transition ${quest.id === activeId ? 'bg-indigo-600' : 'bg-gray-700 hover:bg-gray-600'}}> {quest.title} </button> ))} </div> <button onClick={onClose} className="w-full mt-4 py-2 bg-gray-600/50 hover:bg-gray-500/50 rounded-lg">Close</button> </div> </div> );};// ... Other components (TaskListView, JournalView, ProfileView, etc.) remain largely the same ...// Minor changes might be needed if they depend on a single mainQuest, but they seem independent.// The rest of the components from the previous version can be copied here.const OverwhelmModal = ({ onClose }) => ( <div className="fixed inset-0 bg-black/70 backdrop-blur-sm flex items-center justify-center z-50 animate-fade-in"> <div className="bg-gray-800 p-6 rounded-2xl w-11/12 max-w-md border border-sky-500/50 text-center shadow-2xl shadow-sky-500/20"> <Wind className="mx-auto h-12 w-12 text-sky-400 mb-4" /> <h2 className="text-2xl font-bold mb-2 text-sky-300">Feeling Overwhelmed?</h2> <p className="text-gray-300 mb-6">It's okay. Take a deep breath. Let's try something simple to get back on track.</p> <div className="bg-gray-900/50 p-4 rounded-lg text-left mb-6"> <h3 className="font-semibold text-lg mb-2 flex items-center gap-2"><Sparkles size={18} className="text-yellow-400" /> AI Calming Suggestion</h3> <p className="text-gray-400">"Let's pause for a moment. Try a 2-minute guided breathing exercise. Or, complete one 'Mini Task' like tidying your desk. Small wins create calm."</p> </div> <button onClick={onClose} className="w-full px-4 py-3 rounded-lg bg-sky-600 hover:bg-sky-500 font-bold transition-all transform hover:scale-105">I'm Ready</button> </div> </div>);const LevelUpModal = ({ onClose }) => { const { userStats } = useContext(AppContext); const quotes = [ "The secret of getting ahead is getting started.", "Success is the sum of small efforts, repeated day in and day out.", "The journey of a thousand miles begins with a single step.", "Believe you can and you're halfway there." ]; const quote = quotes[Math.floor(Math.random() * quotes.length)]; return ( <div className="fixed inset-0 bg-black/80 backdrop-blur-lg flex items-center justify-center z-50 animate-fade-in"> <div className="bg-gradient-to-br from-yellow-800 via-gray-900 to-gray-900 p-6 rounded-2xl w-11/12 max-w-md border-2 border-yellow-500 text-center shadow-2xl shadow-yellow-500/30"> <Star className="mx-auto h-16 w-16 text-yellow-400 mb-4 animate-pulse" /> <h2 className="text-4xl font-bold mb-2 text-yellow-300">LEVEL UP!</h2> <p className="text-gray-200 text-2xl font-semibold mb-6">You've reached Level {userStats.level}!</p> <div className="bg-gray-900/60 p-4 rounded-lg text-center mb-6 border border-yellow-600/50"> <p className="text-gray-300 italic">"{quote}"</p> </div> <button onClick={onClose} className="w-full px-4 py-3 rounded-lg bg-yellow-600 hover:bg-yellow-500 text-gray-900 font-bold transition-all transform hover:scale-105">Continue Quest</button> </div> </div> );};const TaskListView = () => { const { tasks, toggleTask } = useContext(AppContext); return ( <div className="animate-fade-in space-y-8"> <h1 className="text-3xl font-bold">All Tasks</h1> <TaskSection icon={<Flame className="text-red-400"/>} title="Urgent Tasks" tasks={tasks.urgent} category="urgent" onToggle={toggleTask} /> <TaskSection icon={<Shield className="text-blue-400"/>} title="Side Quests" tasks={tasks.side} category="side" onToggle={toggleTask} /> <TaskSection icon={<Puzzle className="text-green-400"/>} title="Mini Tasks" tasks={tasks.mini} category="mini" onToggle={toggleTask} /> </div> );};const JournalView = () => { const { journalEntries, addJournalEntry } = useContext(AppContext); const [mood, setMood] = useState('focused'); const [text, setText] = useState(''); const handleSubmit = (e) => { e.preventDefault(); if (text.trim()) { addJournalEntry(mood, text); setText(''); } }; const moodEmojis = { happy: '😊', focused: '🎯', anxious: '😟', tired: '😴' }; const moodColors = { happy: 'bg-yellow-500/20 text-yellow-300', focused: 'bg-green-500/20 text-green-300', anxious: 'bg-blue-500/20 text-blue-300', tired: 'bg-purple-500/20 text-purple-300' }; return ( <div className="animate-fade-in space-y-6"> <h1 className="text-3xl font-bold">Journal</h1> <form onSubmit={handleSubmit} className="bg-gray-800 p-4 rounded-xl space-y-4"> <textarea className="w-full bg-gray-900/70 rounded-lg p-3 h-28 focus:ring-2 focus:ring-indigo-500 outline-none transition" placeholder="How was your quest today?" value={text} onChange={(e) => setText(e.target.value)} /> <div className="flex items-center justify-between"> <div className="flex items-center gap-2"> <span className="text-sm text-gray-400">Mood:</span> {Object.entries(moodEmojis).map(([moodKey, emoji]) => ( <button key={moodKey} type="button" onClick={() => setMood(moodKey)} className={p-2 rounded-full transition ${mood === moodKey ? 'bg-indigo-600 scale-110' : 'bg-gray-700'}}> {emoji} </button> ))} </div> <button type="submit" className="px-4 py-2 bg-indigo-600 hover:bg-indigo-500 rounded-lg font-semibold transition">Add Entry</button> </div> </form> <div className="space-y-4"> <h2 className="text-xl font-semibold">Past Entries</h2> {journalEntries.map(entry => ( <div key={entry.id} className="bg-gray-800/70 p-4 rounded-lg border-l-4 border-gray-700"> <div className="flex justify-between items-center mb-2"> <span className={px-2 py-1 rounded-full text-xs font-semibold ${moodColors[entry.mood] || 'bg-gray-600'}}>{entry.mood}</span> <span className="text-xs text-gray-500">{entry.date}</span> </div> <p className="text-gray-300">{entry.text}</p> </div> ))} </div> </div> );};const ProfileView = () => { const { userStats } = useContext(AppContext); return ( <div className="animate-fade-in space-y-8 text-center"> <h1 className="text-3xl font-bold">Profile</h1> <div className="flex flex-col items-center space-y-3"> <img src={https://placehold.co/120x120/1e1b4b/93c5fd?text=L${userStats.level}} alt="Avatar" className="rounded-full border-4 border-indigo-500 shadow-lg" /> <h2 className="text-2xl font-semibold">Level {userStats.level} Adventurer</h2> <p className="text-indigo-300">{userStats.xp} XP</p> </div> <div className="grid grid-cols-2 gap-4 text-left"> <div className="bg-gray-800 p-4 rounded-xl"> <p className="text-gray-400">Quest Streak</p> <p className="text-2xl font-bold">{userStats.streak} Days</p> </div> <div className="bg-gray-800 p-4 rounded-xl"> <p className="text-gray-400">Quests Done</p> <p className="text-2xl font-bold">124</p> </div> </div> <div className="bg-gray-800 p-4 rounded-xl text-left space-y-3"> <h3 className="font-semibold text-lg flex items-center gap-2"><Settings/> Settings</h3> <div className="flex justify-between items-center"><span>Dark Mode</span> <div className="w-12 h-6 bg-green-500 rounded-full p-1 flex items-center cursor-pointer"><div className="w-4 h-4 bg-white rounded-full shadow-md translate-x-6"></div></div></div> <div className="flex justify-between items-center"><span>Notifications</span> <div className="w-12 h-6 bg-green-500 rounded-full p-1 flex items-center cursor-pointer"><div className="w-4 h-4 bg-white rounded-full shadow-md translate-x-6"></div></div></div> </div> </div> );};const DailyChecklist = ({ navigate }) => { const { tasks, toggleTask } = useContext(AppContext); const dailyTasks = [...tasks.urgent.slice(0, 2), ...tasks.mini.slice(0, 1)]; return ( <div className="bg-gray-800/70 p-4 rounded-xl"> <div className="flex justify-between items-center mb-3"> <h3 className="font-bold text-lg">Daily Dashboard</h3> <button onClick={() => navigate('tasks')} className="text-sm text-indigo-400 hover:underline">View All</button> </div> <div className="space-y-3"> {dailyTasks.map(task => { const category = tasks.urgent.find(t => t.id === task.id) ? 'urgent' : 'mini'; return <TaskItem key={task.id} task={task} category={category} onToggle={toggleTask} />; })} </div> </div> );};const TaskItem = ({ task, category, onToggle }) => { const categoryStyles = { urgent: { icon: <Flame size={16} />, color: 'border-red-500/80' }, side: { icon: <Shield size={16} />, color: 'border-blue-500/80' }, mini: { icon: <Puzzle size={16} />, color: 'border-green-500/80' }, }; return ( <div className={flex items-center gap-3 p-3 bg-gray-900/60 rounded-lg border-l-4 ${categoryStyles[category].color}}> <button onClick={() => onToggle(category, task.id)} className="w-6 h-6 rounded-md border-2 border-gray-600 flex-shrink-0 flex items-center justify-center transition-all duration-200"> {task.completed && <div className="w-4 h-4 bg-green-500 rounded-sm animate-pop-in"></div>} </button> <span className={flex-grow ${task.completed ? 'line-through text-gray-500' : ''}}>{task.title}</span> <div className="flex items-center gap-2 text-xs text-yellow-400/80 font-semibold"> {categoryStyles[category].icon} +{task.xp} XP </div> </div> );};const TaskSection = ({ icon, title, tasks, category, onToggle }) => ( <section> <h2 className="text-xl font-semibold flex items-center gap-3 mb-3">{icon} {title}</h2> <div className="space-y-3"> {tasks.map(task => <TaskItem key={task.id} task={task} category={category} onToggle={onToggle} />)} </div> </section>);const AiAgentPanel = () => { const { getAiSuggestion, setShowOverwhelmModal } = useContext(AppContext); const [mood, setMood] = useState('focused'); const suggestion = getAiSuggestion(mood); const moodEmojis = { happy: '😊', focused: '🎯', anxious: '😟', tired: '😴' }; return ( <div className="bg-gray-800/70 p-4 rounded-xl space-y-4"> <h3 className="font-bold text-lg flex items-center gap-2"><Bot className="text-teal-400"/> AI Agent</h3> <div> <p className="text-sm text-gray-400 mb-2">How are you feeling?</p> <div className="flex justify-around bg-gray-900/60 p-2 rounded-lg"> {Object.entries(moodEmojis).map(([moodKey, emoji]) => ( <button key={moodKey} onClick={() => setMood(moodKey)} className={p-2 rounded-full transition-transform duration-200 ${mood === moodKey ? 'bg-teal-600 scale-125' : 'hover:bg-gray-700'}}> {emoji} </button> ))} </div> </div> <div className="bg-gray-900/50 p-3 rounded-lg text-center"> <p className="text-teal-200/90">{suggestion}</p> </div> <button onClick={() => setShowOverwhelmModal(true)} className="w-full text-center py-2 bg-red-800/70 hover:bg-red-700/90 rounded-lg font-semibold transition"> I feel overwhelmed </button> </div> );};const WeeklyBossChallenge = () => { const { tasks } = useContext(AppContext); const urgentCompleted = tasks.urgent.filter(t => t.completed).length; const totalUrgent = tasks.urgent.length + 2; // Mocking a higher total for challenge const progress = Math.round((urgentCompleted / totalUrgent) * 100); return ( <div className="bg-gradient-to-b from-red-900/50 to-gray-900 p-4 rounded-xl border border-red-700/50"> <h3 className="font-bold text-lg text-red-300">Weekly Challenge</h3> <div className="flex items-center gap-4 my-2"> <div className="text-5xl">👹</div> <div className="flex-grow"> <h4 className="font-semibold text-xl">Beat the Procrastination Beast!</h4> <p className="text-sm text-red-200/80">Complete all Urgent Tasks this week.</p> </div> </div> <div className="w-full bg-gray-700/50 rounded-full h-3 border border-gray-600/50"> <div className="bg-gradient-to-r from-orange-500 to-red-500 h-full rounded-full" style={{width: ${progress}%}}></div> </div> <p className="text-right text-xs mt-1 text-red-200/80">{progress}% HP Damaged</p> </div> );};const BottomNavBar = ({ activePage, navigate }) => { const navItems = [ { id: 'home', icon: <Home />, label: 'Home' }, { id: 'tasks', icon: <ListChecks />, label: 'Tasks' }, { id: 'journal', icon: <Book />, label: 'Journal' }, { id: 'profile', icon: <User />, label: 'Profile' } ]; return ( <div className="fixed bottom-0 left-0 right-0 bg-gray-800/80 backdrop-blur-lg border-t border-gray-700/50"> <div className="flex justify-around items-center h-16"> {navItems.map(item => { const isActive = activePage === item.id; return ( <button key={item.id} onClick={() => navigate(item.id)} className={flex flex-col items-center justify-center transition-colors duration-200 w-1/5 pt-1 ${isActive ? 'text-indigo-400' : 'text-gray-400 hover:text-white'}}> {item.icon} <span className={text-xs mt-1 transition-all ${isActive ? 'font-bold' : ''}}>{item.label}</span> {isActive && <div className="h-1 w-8 bg-indigo-400 rounded-t-full mt-1"></div>} </button> ); })} </div> </div> );}; //keep the ui design of the habit tracker and add the features available the second code such that design the ui such that user can have mutiple long term goals and the subtasks needed to achive the goal should be suggested by the ai agent and could be added to the tasks menu such that user can have mutiple long term goals and give the option for the user to add multiple long term goals separated from the other tasks and the subtasks needed to achive the goal should be suggested by the ai agent and could be added to the tasks menu,And also allow the user to to be able to look their main quest in new tab.make the main quest available in the home screen and add the urgent task in tasks.