import React, { useState } from 'react'; import { FileText, Edit2, X, ChevronLeft, ChevronRight, Calendar, Clock } from 'lucide-react'; function StudyPlanner() { const defaultClasses = [ { id: 1, name: "Digital Forensics in Cybersecurity – D431", credits: 3, priority: true, estimatedWeeks: 2, estimatedDays: 3, completed: false, startDate: "2024-01-15", notes: "", studyNotes: "", completionNotes: "" }, { id: 2, name: "Data Management - Foundations – D426", credits: 3, priority: false, estimatedWeeks: 3, estimatedDays: 0, completed: false, startDate: "2024-02-01", notes: "", studyNotes: "", completionNotes: "" }, { id: 3, name: "Data Management - Applications – D427", credits: 3, priority: false, estimatedWeeks: 0, estimatedDays: 0, completed: false, startDate: "", notes: "", studyNotes: "", completionNotes: "" }, { id: 4, name: "Information Systems Security – C845", credits: 4, priority: false, estimatedWeeks: 0, estimatedDays: 0, completed: false, startDate: "", notes: "", studyNotes: "", completionNotes: "" }, { id: 5, name: "Introduction to Cryptography – D334", credits: 3, priority: true, estimatedWeeks: 0, estimatedDays: 0, completed: false, startDate: "", notes: "", studyNotes: "", completionNotes: "" } ]; const [darkMode, setDarkMode] = useState(false); const [classes, setClasses] = useState(defaultClasses); const [editingClass, setEditingClass] = useState(null); const [editForm, setEditForm] = useState({ name: '', credits: 3, priority: false, startDate: '' }); const [showNotesModal, setShowNotesModal] = useState(false); const [notesModalClass, setNotesModalClass] = useState(null); const [showCompletionModal, setShowCompletionModal] = useState(false); const [completionModalClass, setCompletionModalClass] = useState(null); const [tempNotes, setTempNotes] = useState(""); const [currentCalendarDate, setCurrentCalendarDate] = useState(new Date()); const [globalStartDate, setGlobalStartDate] = useState(new Date().toISOString().split('T')[0]); const [autoSchedule, setAutoSchedule] = useState(true); const [showReflections, setShowReflections] = useState(false); const monthNames = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]; const getClassColor = (classId) => { const colors = ['bg-blue-500', 'bg-emerald-500', 'bg-purple-500', 'bg-rose-500', 'bg-amber-500']; return colors[classId % colors.length]; }; const calculateTimeline = () => { // If auto-schedule is enabled, calculate dates sequentially if (autoSchedule && globalStartDate) { // Parse date properly to avoid timezone issues let currentDate = new Date(globalStartDate + 'T00:00:00'); const scheduledClasses = []; // First, schedule priority classes const priorityClasses = classes.filter(cls => !cls.completed && cls.priority && (cls.estimatedWeeks > 0 || cls.estimatedDays > 0)); const regularClasses = classes.filter(cls => !cls.completed && !cls.priority && (cls.estimatedWeeks > 0 || cls.estimatedDays > 0)); const allToSchedule = [...priorityClasses, ...regularClasses]; allToSchedule.forEach(cls => { const startDate = new Date(currentDate); const totalDays = (cls.estimatedWeeks * 7) + cls.estimatedDays; const endDate = new Date(startDate); endDate.setDate(endDate.getDate() + totalDays - 1); // End date is inclusive scheduledClasses.push({ ...cls, startDate: startDate, endDate: endDate, totalDays, autoScheduled: true }); // Move to next start date (day after this course ends) currentDate = new Date(endDate); currentDate.setDate(currentDate.getDate() + 1); }); return scheduledClasses; } // Original timeline calculation for manual dates return classes .filter(cls => !cls.completed && cls.startDate && (cls.estimatedWeeks > 0 || cls.estimatedDays > 0)) .map(cls => { const start = new Date(cls.startDate + 'T00:00:00'); const totalDays = (cls.estimatedWeeks * 7) + cls.estimatedDays; const end = new Date(start); end.setDate(end.getDate() + totalDays - 1); // End date is inclusive return { ...cls, startDate: start, endDate: end, totalDays }; }) .sort((a, b) => a.startDate - b.startDate); }; const generateCalendar = () => { const timeline = calculateTimeline(); const year = currentCalendarDate.getFullYear(); const month = currentCalendarDate.getMonth(); const firstDay = new Date(year, month, 1); const lastDay = new Date(year, month + 1, 0); const daysInMonth = lastDay.getDate(); const startingDayOfWeek = firstDay.getDay(); const calendar = []; const today = new Date(); today.setHours(0, 0, 0, 0); for (let i = 0; i < startingDayOfWeek; i++) { calendar.push(null); } for (let day = 1; day <= daysInMonth; day++) { const currentDate = new Date(year, month, day); currentDate.setHours(0, 0, 0, 0); const isToday = currentDate.toDateString() === today.toDateString(); const activeClasses = timeline.filter(cls => { const start = new Date(cls.startDate); const end = new Date(cls.endDate); start.setHours(0, 0, 0, 0); end.setHours(0, 0, 0, 0); return currentDate >= start && currentDate <= end; }); calendar.push({ day, isToday, activeClasses }); } return calendar; }; const toggleCompleted = (id) => { const cls = classes.find(c => c.id === id); if (cls && !cls.completed) { setCompletionModalClass(cls); setTempNotes(""); setShowCompletionModal(true); } else { setClasses(prev => prev.map(c => c.id === id ? { ...c, completed: false } : c)); } }; const completeClass = () => { setClasses(prev => prev.map(c => c.id === completionModalClass.id ? { ...c, completed: true, completionNotes: tempNotes, completedDate: new Date().toISOString() } : c )); setShowCompletionModal(false); setTempNotes(""); }; const formatText = (tag) => { const textarea = document.getElementById('reflectionTextarea'); const start = textarea.selectionStart; const end = textarea.selectionEnd; const text = textarea.value; const selectedText = text.substring(start, end); let formattedText = ''; switch(tag) { case 'bold': formattedText = `**${selectedText}**`; break; case 'italic': formattedText = `*${selectedText}*`; break; case 'highlight': formattedText = `==${selectedText}==`; break; case 'underline': formattedText = `__${selectedText}__`; break; } const newText = text.substring(0, start) + formattedText + text.substring(end); setTempNotes(newText); }; const renderFormattedText = (text) => { if (!text) return null; // Simple markdown-like formatting let formatted = text .replace(/\*\*(.*?)\*\*/g, '$1') .replace(/\*(.*?)\*/g, '$1') .replace(/__(.*?)__/g, '$1') .replace(/==(.*?)==/g, '$1'); return
; }; const openNotes = (cls) => { setNotesModalClass(cls); setTempNotes(cls.studyNotes || ""); setShowNotesModal(true); }; const saveNotes = () => { setClasses(prev => prev.map(c => c.id === notesModalClass.id ? { ...c, studyNotes: tempNotes } : c )); setShowNotesModal(false); }; const startEdit = (cls) => { setEditingClass(cls.id); setEditForm({ name: cls.name, credits: cls.credits, priority: cls.priority, startDate: cls.startDate }); }; const saveEdit = () => { setClasses(prev => prev.map(c => c.id === editingClass ? { ...c, ...editForm, credits: parseInt(editForm.credits) } : c )); setEditingClass(null); }; const deleteClass = (id) => { setClasses(prev => prev.filter(c => c.id !== id)); }; const updateTime = (id, field, value) => { setClasses(prev => prev.map(c => c.id === id ? { ...c, [field]: parseInt(value) || 0 } : c )); }; const timeline = calculateTimeline(); const completedCount = classes.filter(c => c.completed).length; const totalCredits = classes.reduce((sum, c) => sum + c.credits, 0); const completedCredits = classes.filter(c => c.completed).reduce((sum, c) => sum + c.credits, 0); const calendarDays = generateCalendar(); return (
{/* Header */}

Academic Study Planner

Track courses and plan your schedule

{/* Stats */}
{/* Progress Ring */}
{Math.round((completedCount / classes.length) * 100)}%
Complete
{/* Course Stats */}
Courses {completedCount} / {classes.length}
Credits {completedCredits} / {totalCredits}
{/* Time Stats */}
Estimated Time Remaining
{(() => { const totalDays = classes.filter(c => !c.completed) .reduce((sum, c) => sum + (c.estimatedWeeks * 7) + c.estimatedDays, 0); const weeks = Math.floor(totalDays / 7); const days = totalDays % 7; return `${weeks}w ${days}d`; })()}
{timeline.length > 0 && (
Target: {timeline[timeline.length - 1]?.endDate.toLocaleDateString()}
)}
{/* Auto-Schedule Settings */}
{autoSchedule && ( <>
setGlobalStartDate(e.target.value)} className={`px-3 py-1 rounded border ${darkMode ? 'bg-slate-700 border-slate-600' : 'bg-white border-gray-300'}`} />
(Priority courses will be scheduled first)
)}
{!autoSchedule && (
Set individual start dates for each course
)}
{autoSchedule && timeline.length > 0 && (
Projected completion: {timeline[timeline.length - 1]?.endDate.toLocaleDateString()}
)}
{/* Calendar */}

Study Calendar

{monthNames[currentCalendarDate.getMonth()]} {currentCalendarDate.getFullYear()}
{['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'].map(day => (
{day}
))} {calendarDays.map((day, i) => (
{day && ( <>
{day.day}
{day.activeClasses.map(cls => (
{cls.name.split(' – ')[0]}
))} )}
))}
{/* Course List */}

Courses

{!showReflections ? (
{classes.map(cls => (
toggleCompleted(cls.id)} className="mt-1" />
{editingClass === cls.id ? (
setEditForm({...editForm, name: e.target.value})} className={`w-full p-1 rounded border ${darkMode ? 'bg-slate-700 border-slate-600' : ''}`} />
setEditForm({...editForm, credits: e.target.value})} className={`w-16 p-1 rounded border ${darkMode ? 'bg-slate-700 border-slate-600' : ''}`} /> {!autoSchedule && ( setEditForm({...editForm, startDate: e.target.value})} className={`p-1 rounded border ${darkMode ? 'bg-slate-700 border-slate-600' : ''}`} /> )}
) : ( <>

{cls.name}

{cls.credits} credits {cls.priority && Priority} {autoSchedule && timeline.find(t => t.id === cls.id) && ( Starts: {timeline.find(t => t.id === cls.id)?.startDate.toLocaleDateString()} )}
updateTime(cls.id, 'estimatedWeeks', e.target.value)} className="w-12 p-1 border rounded" placeholder="0" /> weeks updateTime(cls.id, 'estimatedDays', e.target.value)} className="w-12 p-1 border rounded" placeholder="0" /> days
)}
))}
) : (

Course Reflections Journal

{classes.filter(c => c.completed && c.completionNotes).length === 0 ? (

No reflections yet. Complete a course to add your first reflection!

) : ( classes.filter(c => c.completed && c.completionNotes).map(cls => (

{cls.name}

{cls.completedDate && new Date(cls.completedDate).toLocaleDateString()}
{renderFormattedText(cls.completionNotes)}
Completed {cls.credits} credits
)) )}
)}
{/* Timeline */}

Timeline

{timeline.length === 0 ? (

Add dates and time estimates to see timeline

) : (
{timeline.map(item => (

{item.name}

{item.startDate.toLocaleDateString()} → {item.endDate.toLocaleDateString()}

Duration: {item.estimatedWeeks}w {item.estimatedDays}d

))}
)}
{/* Notes Modal */} {showNotesModal && (

Study Notes - {notesModalClass?.name}