import React, { useState, useEffect, useRef } from 'react'; import { BookOpen, CheckSquare, MessageSquare, Clock, Settings, Zap, Trash2, Plus, Play, Pause, RotateCcw, Save, X, Brain, ChevronRight, GraduationCap, Download, Upload, AlertCircle, Edit3 } from 'lucide-react'; /** * STUDY NEXUS v2.1 - Production Ready Student OS * Fixes: Updated Model ID for compatibility, Added Custom Model setting. */ // --- UTILS & API --- // Default to the preview model which is currently supported in this environment const DEFAULT_MODEL = "gemini-2.5-flash-preview-09-2025"; const callGemini = async (apiKey, modelId, prompt, systemInstruction = "") => { if (!apiKey) throw new Error("API Key is missing. Go to Settings to add it."); // Use the user's custom model or fallback to default const model = modelId || DEFAULT_MODEL; const url = `https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent?key=${apiKey}`; const payload = { contents: [{ role: "user", parts: [{ text: prompt }] }], systemInstruction: { parts: [{ text: systemInstruction }] }, generationConfig: { temperature: 0.7, maxOutputTokens: 1000, } }; try { const response = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); const data = await response.json(); if (!response.ok) { const errorMsg = data.error?.message || "Unknown API Error"; if (errorMsg.includes("not found")) throw new Error(`Model '${model}' not found. Try 'gemini-2.5-flash-preview-09-2025' in Settings.`); if (errorMsg.includes("API key")) throw new Error("Invalid API Key. Please check settings."); throw new Error(errorMsg); } if (!data.candidates || !data.candidates[0]?.content?.parts?.[0]?.text) { throw new Error("AI returned an empty response. Try rephrasing."); } return data.candidates[0].content.parts[0].text; } catch (error) { console.error("Gemini API Error:", error); throw error; } }; // --- HOOKS --- const useLocalStorage = (key, initialValue) => { const [storedValue, setStoredValue] = useState(() => { try { const item = window.localStorage.getItem(key); return item ? JSON.parse(item) : initialValue; } catch (error) { console.error("Storage Error:", error); return initialValue; } }); const setValue = (value) => { try { const valueToStore = value instanceof Function ? value(storedValue) : value; setStoredValue(valueToStore); window.localStorage.setItem(key, JSON.stringify(valueToStore)); } catch (error) { console.error("Storage Save Error:", error); } }; return [storedValue, setValue]; }; // --- COMPONENTS --- const Navigation = ({ activeTab, setActiveTab }) => { const tabs = [ { id: 'dashboard', icon: , label: 'Nexus' }, { id: 'chat', icon: , label: 'AI Guru' }, { id: 'tasks', icon: , label: 'Tasks' }, { id: 'flashcards', icon: , label: 'Cards' }, { id: 'focus', icon: , label: 'Focus' }, { id: 'settings', icon: , label: 'Settings' }, ]; return ( ); }; // 1. DASHBOARD const Dashboard = ({ userName, stats, setActiveTab }) => (

Hello, {userName || 'Student'}

Your academic dashboard is ready. Kya padhna hai aaj?

setActiveTab('tasks')} className="bg-slate-800/50 p-6 rounded-2xl border border-slate-700 hover:border-cyan-500/50 transition-all cursor-pointer group hover:bg-slate-800">
{stats.pendingTasks}

Pending Tasks

setActiveTab('flashcards')} className="bg-slate-800/50 p-6 rounded-2xl border border-slate-700 hover:border-purple-500/50 transition-all cursor-pointer group hover:bg-slate-800">
{stats.decks}

Study Decks

setActiveTab('focus')} className="bg-slate-800/50 p-6 rounded-2xl border border-slate-700 hover:border-emerald-500/50 transition-all cursor-pointer group hover:bg-slate-800">
{stats.minutesFocused}

Mins Focused

setActiveTab('chat')} className="bg-gradient-to-br from-cyan-600/20 to-purple-600/20 p-6 rounded-2xl border border-slate-700 hover:border-cyan-400/50 transition-all cursor-pointer group relative overflow-hidden">

Ask AI Guru

Hinglish Tutor.

); // 2. CHAT COMPONENT (GURU) const AIChat = ({ apiKey, modelId, userName }) => { const [messages, setMessages] = useState([ { role: 'ai', text: `Namaste ${userName || 'Student'}! I am Guru. Study mein kya help chahiye aaj? I can explain any topic in Hinglish or English.` } ]); const [input, setInput] = useState(''); const [loading, setLoading] = useState(false); const messagesEndRef = useRef(null); const scrollToBottom = () => { messagesEndRef.current?.scrollIntoView({ behavior: "smooth" }); }; useEffect(scrollToBottom, [messages]); const handleSend = async () => { if (!input.trim()) return; if (!apiKey) { setMessages(prev => [...prev, { role: 'user', text: input }, { role: 'system', text: "⚠️ Error: No API Key found. Please go to Settings to add it." }]); setInput(''); return; } const userMsg = input; setMessages(prev => [...prev, { role: 'user', text: userMsg }]); setInput(''); setLoading(true); const systemPrompt = `You are "Guru", a smart and friendly student mentor for Indian students. User Name: ${userName || 'Student'} Language Preference: Mix of English and Hindi (Hinglish) unless requested otherwise. Instructions: 1. Explain concepts simply and clearly. 2. Use Hinglish naturally (e.g., "Concept bohot simple hai," "Basically..."). 3. If the user asks for a "Practice Sheet" or "Questions", generate 3-5 practice questions relevant to the topic. 4. If the user previously made a mistake (in conversation context), gently correct them. 5. Be encouraging. Example: "Electron nucleus ke around ghumta hai, jaise planets sun ke around."`; try { const history = messages.slice(-10).map(m => `${m.role === 'user' ? 'Student' : 'Guru'}: ${m.text}`).join('\n'); const fullPrompt = `${history}\nStudent: ${userMsg}\nGuru:`; const response = await callGemini(apiKey, modelId, fullPrompt, systemPrompt); setMessages(prev => [...prev, { role: 'ai', text: response }]); } catch (error) { setMessages(prev => [...prev, { role: 'system', text: `❌ Error: ${error.message}` }]); } finally { setLoading(false); } }; return (
{messages.map((msg, idx) => (
{msg.role === 'ai' &&
GURU
}
{msg.text}
))} {loading && (
Guru is thinking...
)}
setInput(e.target.value)} onKeyDown={(e) => e.key === 'Enter' && handleSend()} placeholder="Ask a doubt..." className="flex-1 bg-slate-900 border border-slate-700 rounded-xl px-4 py-3 text-white focus:outline-none focus:border-cyan-500 transition-colors" />
); }; // 3. TASK BOARD const TaskBoard = ({ tasks, setTasks }) => { const [newTask, setNewTask] = useState(''); const [filter, setFilter] = useState('all'); const addTask = () => { if (!newTask.trim()) return; const task = { id: Date.now(), text: newTask, status: 'todo', createdAt: new Date().toISOString() }; setTasks(prev => [task, ...prev]); setNewTask(''); }; const toggleTask = (id) => { setTasks(prev => prev.map(t => t.id === id ? { ...t, status: t.status === 'todo' ? 'done' : 'todo' } : t)); }; const deleteTask = (id) => { setTasks(prev => prev.filter(t => t.id !== id)); }; const filteredTasks = tasks.filter(t => filter === 'all' ? true : t.status === filter); return (

Assignments

{['all', 'todo', 'done'].map(f => ( ))}
setNewTask(e.target.value)} onKeyDown={(e) => e.key === 'Enter' && addTask()} placeholder="New task..." className="flex-1 bg-slate-800 border border-slate-700 rounded-xl px-4 py-3 text-white focus:outline-none focus:border-cyan-500 transition-colors" />
{filteredTasks.length === 0 ? (

No tasks. Time to relax!

) : ( filteredTasks.map(task => (
{task.text}
)) )}
); }; // 4. FLASHCARDS const Flashcards = ({ apiKey, modelId, decks, setDecks }) => { const [mode, setMode] = useState('list'); const [inputText, setInputText] = useState(''); const [generating, setGenerating] = useState(false); const [activeDeck, setActiveDeck] = useState(null); const [cardIndex, setCardIndex] = useState(0); const [flipped, setFlipped] = useState(false); const [error, setError] = useState(null); const generateCards = async () => { if (!inputText.trim()) return; if (!apiKey) { setError("Please add an API key in Settings first."); return; } setGenerating(true); setError(null); try { const prompt = `Create a list of 5 to 10 flashcards from this text. OUTPUT JSON ONLY. Format: [{"front": "Question", "back": "Answer"}]. Text: "${inputText.substring(0, 4000)}"`; let response = await callGemini(apiKey, modelId, prompt, "You are a JSON generator."); const cleanJson = response.replace(/```json/g, '').replace(/```/g, '').trim(); const cards = JSON.parse(cleanJson); if (!Array.isArray(cards)) throw new Error("AI format error."); const newDeck = { id: Date.now(), title: `Study Set ${new Date().toLocaleDateString()}`, cards: cards, createdAt: new Date().toISOString() }; setDecks(prev => [newDeck, ...prev]); setMode('list'); setInputText(''); } catch (err) { setError(err.message); } finally { setGenerating(false); } }; const deleteDeck = (id, e) => { e.stopPropagation(); if(confirm("Delete this deck?")) setDecks(prev => prev.filter(d => d.id !== id)); }; if (mode === 'create') { return (

New Deck

Paste your notes below. The AI will extract key points into flashcards.