import { useState, useEffect } from 'react'; import { BookOpen, CheckCircle, ArrowRight, ChevronLeft, Calendar, CheckSquare, Sparkles } from 'lucide-react'; import { motion } from 'framer-motion'; import { useNavigate } from 'react-router-dom'; import Card from '../components/ui/Card'; import Button from '../components/ui/Button'; import Tag from '../components/ui/Tag'; import { useApp } from '../store/AppContext'; import { generateWeeklyQuiz } from '../lib/testService'; import { getYearProgress, getCurriculumCycle, getCurriculumWeek, getActiveVersion, getCurrentWeekContent } from '../lib/curriculumService'; import * as db from '../lib/db'; import MicroLearningSelector from '../components/micro_learning/MicroLearningSelector'; import ThemeSessionView from '../components/theme_session/ThemeSessionView'; const Leren = () => { const { state } = useApp(); const navigate = useNavigate(); const [allTopics, setAllTopics] = useState([]); // View state — overview | session | topic const [view, setView] = useState('overview'); const [activeTopic, setActiveTopic] = useState(null); // Per-topic micro-learning post-completion state const [topicDone, setTopicDone] = useState(false); // Curriculum state const [activeVersion, setActiveVersion] = useState(null); const [yearProgress, setYearProgress] = useState(null); const [weekContent, setWeekContent] = useState(null); // Theme session completion flag for the current week const [themeSessionDone, setThemeSessionDone] = useState(false); useEffect(() => { if (state.currentUser) { const load = async () => { const topics = await db.getTopics(); setAllTopics(topics); try { const av = await getActiveVersion(); setActiveVersion(av || null); if (av) { const [yProgress, wc, completion] = await Promise.all([ getYearProgress(state.currentUser.id, state.weekNumber), getCurrentWeekContent(state.weekNumber), db.getThemeSessionCompletion(state.currentUser.id, state.weekNumber), ]); setYearProgress(yProgress); setWeekContent(wc); setThemeSessionDone(!!completion); } } catch (e) { console.warn('[Learn] Could not load curriculum data:', e.message); } }; load(); } }, [state.currentUser, state.weekNumber, view]); const handleOpenSession = () => { setView('session'); }; const handleOpenTopic = (topic) => { setActiveTopic(topic); setView('topic'); setTopicDone(false); }; const handlePracticeTopicId = (topicId) => { const t = allTopics.find(x => x.id === topicId); if (t) handleOpenTopic(t); }; const handleThemeSessionCompleted = async (record) => { if (!state.currentUser || !record) return; try { await db.setThemeSessionCompletion(state.currentUser.id, record.id, state.weekNumber); setThemeSessionDone(true); generateWeeklyQuiz(state.currentUser.id, state.weekNumber).catch(() => {}); } catch (e) { console.warn('[Learn] Failed to record theme session completion:', e.message); } }; const handleTopicCompleted = () => { setTopicDone(true); }; // ── Theme session view ──────────────────────────────────── if (view === 'session' && activeVersion && weekContent) { return (
{themeSessionDone && ( )}
); } // ── Per-topic detail view ──────────────────────────────── if (view === 'topic' && activeTopic) { if (topicDone) { return (

Topic reviewed!

You have successfully completed a micro learning for "{activeTopic.label}".

Ready to put it to the test, or explore another format for this topic?

); } const isWeekly = (weekContent?.topics || []).some(t => t.id === activeTopic.id); return (
{activeTopic.type} {isWeekly && In this week's theme}

{activeTopic.label}

{activeTopic.description}

); } // ── Overview ────────────────────────────────────────────── const hasCurriculum = !!activeVersion; const currentCycle = getCurriculumCycle(state.weekNumber); const currWeek = getCurriculumWeek(state.weekNumber); const weeklyTopicIds = new Set((weekContent?.topics || []).map(t => t.id)); // Library = every learnable topic, grouped by theme. // Topics already part of this week's theme session are shown inline under // that theme but flagged so the learner sees they're already covered. const learnableTopics = allTopics.filter(t => t.type !== 'fact' && t.learning_relevance !== 'exclude'); const libraryByTheme = new Map(); for (const t of learnableTopics) { const themeName = t.theme || 'General'; if (!libraryByTheme.has(themeName)) libraryByTheme.set(themeName, []); libraryByTheme.get(themeName).push(t); } // Sort: current week's theme first, then alphabetical. const currentTheme = weekContent?.theme || null; const sortedThemes = Array.from(libraryByTheme.keys()).sort((a, b) => { if (a === currentTheme) return -1; if (b === currentTheme) return 1; return a.localeCompare(b); }); return (

Learning Station

{hasCurriculum ? `Cycle ${currentCycle} · Week ${currWeek} of 26` : 'Complete at least one theme session per week. Explore more from the library!'}

{/* Progress Cards */} {hasCurriculum && yearProgress && (
{yearProgress.percentage}%
Cycle Progress
{yearProgress.completed}/{yearProgress.total} weeks
{currWeek}
Current Week
{weekContent?.theme || 'General'}
Current Theme
)} {/* Weekly Theme Session */} {hasCurriculum && weekContent && (

This Week's Theme Session {themeSessionDone && }

{themeSessionDone ? 'Completed' : 'Required'} Theme: {weekContent.theme} {weekContent.topics.length} topic{weekContent.topics.length === 1 ? '' : 's'} {weekContent.estimatedDuration && ( ~{weekContent.estimatedDuration} min )}

{weekContent.theme}

A detailed weekly summary covering every topic in this theme: {weekContent.topics.map(t => t.label).join(', ')}.

)} {/* Theme-grouped library */} {sortedThemes.length > 0 && (

Knowledge Library

Every topic in the knowledge base, grouped by theme. Topics in this week's theme also appear inside the theme session above.

{sortedThemes.map((themeName) => { const topics = libraryByTheme.get(themeName) || []; const isCurrent = themeName === currentTheme; return (

{themeName}

{isCurrent && This week} · {topics.length} topic{topics.length === 1 ? '' : 's'}
{topics.map(topic => { const inWeek = weeklyTopicIds.has(topic.id); return ( handleOpenTopic(topic)} >
{topic.type} {inWeek && In this week's session}

{topic.label}

{topic.description}

Practice
); })}
); })}
)}
); }; export default Leren;