+
+
+ );
+}
diff --git a/src/hooks/useMicroLearningCompletions.js b/src/hooks/useMicroLearningCompletions.js
new file mode 100644
index 0000000..2536516
--- /dev/null
+++ b/src/hooks/useMicroLearningCompletions.js
@@ -0,0 +1,53 @@
+import pb from '../lib/pb';
+import { useAuthStore } from '../store/authStore';
+
+export function useMicroLearningCompletions() {
+ const { user } = useAuthStore?.() || { user: pb.authStore.model };
+
+ // Note: user in PB context for team_members usually matches user_id or team_member_id.
+ // We need the team_member record. If the frontend is currently storing it in authStore, we can get it.
+
+ const recordCompletion = async ({ microLearningId, topicId, type, sessionWeek }) => {
+ try {
+ // Find the team_member record for the current user
+ let teamMemberId = user?.id;
+ // If user is just the auth user, we might need to query the team_members collection
+ // but in many setups, the auth user is the team_member or there's a 1-to-1.
+ // Let's ensure we fetch team_member_id properly if needed.
+ const teamMemberRec = await pb.collection('team_members').getFirstListItem(`user_id = "${user.id}"`);
+
+ if (!teamMemberRec) {
+ throw new Error("Team member record not found for user.");
+ }
+
+ const record = await pb.collection('micro_learning_completions').create({
+ team_member_id: teamMemberRec.id,
+ micro_learning_id: microLearningId,
+ topic_id: topicId,
+ type: type,
+ session_week: sessionWeek
+ });
+ return record;
+ } catch (err) {
+ console.error("Error recording completion:", err);
+ return null;
+ }
+ };
+
+ const getSessionCompletions = async (sessionWeek) => {
+ try {
+ const teamMemberRec = await pb.collection('team_members').getFirstListItem(`user_id = "${pb.authStore.model.id}"`);
+ if (!teamMemberRec) return [];
+
+ const records = await pb.collection('micro_learning_completions').getFullList({
+ filter: `team_member_id = "${teamMemberRec.id}" && session_week = ${sessionWeek}`
+ });
+ return records;
+ } catch (err) {
+ console.error("Error fetching session completions:", err);
+ return [];
+ }
+ };
+
+ return { recordCompletion, getSessionCompletions };
+}
diff --git a/src/hooks/useMicroLearnings.js b/src/hooks/useMicroLearnings.js
new file mode 100644
index 0000000..2d2da59
--- /dev/null
+++ b/src/hooks/useMicroLearnings.js
@@ -0,0 +1,17 @@
+import pb from '../lib/pb';
+
+export function useMicroLearnings() {
+ const getMicroLearningsByTopic = async (topicId) => {
+ try {
+ const records = await pb.collection('micro_learnings').getFullList({
+ filter: `topic_id = "${topicId}" && status = 'published'`,
+ });
+ return records;
+ } catch (err) {
+ console.error("Error fetching micro learnings:", err);
+ return [];
+ }
+ };
+
+ return { getMicroLearningsByTopic };
+}
diff --git a/src/pages/Leren.jsx b/src/pages/Leren.jsx
index 18459e2..d895388 100644
--- a/src/pages/Leren.jsx
+++ b/src/pages/Leren.jsx
@@ -1,15 +1,16 @@
import { useState, useEffect } from 'react';
-import { BookOpen, CheckCircle, Loader, ArrowRight, ChevronLeft, MessageSquare, Calendar, TrendingUp } from 'lucide-react';
-import { motion, AnimatePresence } from 'framer-motion';
+import { BookOpen, CheckCircle, ArrowRight, ChevronLeft, Calendar } from 'lucide-react';
+import { motion } from 'framer-motion';
import { Link } from 'react-router-dom';
import Card from '../components/ui/Card';
import Button from '../components/ui/Button';
import Tag from '../components/ui/Tag';
-import LearningContentViewer from '../components/ui/LearningContentViewer';
import { useApp } from '../store/AppContext';
-import { getAssignedTopic, generateLearningContent, getCachedContent } from '../lib/learningService';
+import { getAssignedTopic } from '../lib/learningService';
import { getYearProgress, getCurriculumCycle, getCurriculumWeek, getActiveVersion, getCurrentWeekContent } from '../lib/curriculumService';
import * as db from '../lib/db';
+import MicroLearningSelector from '../components/micro_learning/MicroLearningSelector';
+import { useMicroLearningCompletions } from '../hooks/useMicroLearningCompletions';
const Leren = () => {
const { state } = useApp();
@@ -19,39 +20,30 @@ const Leren = () => {
// View state
const [view, setView] = useState('overview'); // overview, detail
const [activeTopic, setActiveTopic] = useState(null);
- const [content, setContent] = useState(null);
-
- // Loading & Error
- const [isLoading, setIsLoading] = useState(false);
- const [error, setError] = useState(null);
// Weekly status
const [weeklyDone, setWeeklyDone] = useState(false);
const [sessionDone, setSessionDone] = useState(false);
- // Feedback
- const [showFeedbackModal, setShowFeedbackModal] = useState(false);
- const [feedbackText, setFeedbackText] = useState('');
- const [feedbackPrompted, setFeedbackPrompted] = useState(false);
-
// Curriculum state
const [hasCurriculum, setHasCurriculum] = useState(false);
const [yearProgress, setYearProgress] = useState(null);
const [weekContent, setWeekContent] = useState(null);
+ const { getSessionCompletions } = useMicroLearningCompletions();
+
useEffect(() => {
if (state.currentUser) {
const load = async () => {
- const [assigned, topics, done] = await Promise.all([
+ const [assigned, topics] = await Promise.all([
getAssignedTopic(state.currentUser.id, state.weekNumber),
db.getTopics(),
- db.getLearnDone(state.currentUser.id, state.weekNumber),
]);
setAssignedTopic(assigned);
setAllTopics(topics);
- if (done) setWeeklyDone(true);
// Load curriculum data
+ let currentWeekContent = null;
try {
const activeVersion = await getActiveVersion();
setHasCurriculum(!!activeVersion);
@@ -61,76 +53,38 @@ const Leren = () => {
getCurrentWeekContent(state.weekNumber),
]);
setYearProgress(yProgress);
+ currentWeekContent = wc;
setWeekContent(wc);
}
} catch (e) {
console.warn('[Learn] Could not load curriculum data:', e.message);
}
+
+ // Check completions for the current week
+ const completions = await getSessionCompletions(state.weekNumber);
+
+ // Define required topics for the week
+ // We assume assignedTopic is the minimum required if no explicit list in weekContent.
+ // Actually, let's just check if the assignedTopic is completed.
+ const requiredTopicIds = currentWeekContent?.topics || [assigned?.id].filter(Boolean);
+
+ const completedTopicIds = new Set(completions.map(c => c.topic_id));
+ const allRequiredCompleted = requiredTopicIds.length > 0 && requiredTopicIds.every(id => completedTopicIds.has(id));
+
+ setWeeklyDone(allRequiredCompleted);
};
load();
}
- }, [state.currentUser, state.weekNumber]);
+ }, [state.currentUser, state.weekNumber, view]); // Reload when view changes (e.g. going back to overview)
- const handleOpenTopic = async (topic) => {
+ const handleOpenTopic = (topic) => {
setActiveTopic(topic);
setView('detail');
setSessionDone(false);
- setError(null);
- setFeedbackText('');
- setFeedbackPrompted(false);
- const cached = await getCachedContent(topic.id);
- if (cached) {
- setContent(cached);
- } else {
- setContent(null);
- }
};
- const loadContent = async (selectedType = 'article') => {
- if (!activeTopic) return;
- setIsLoading(true);
- setError(null);
- try {
- const generated = await generateLearningContent(activeTopic, false, selectedType);
- setContent(generated);
- } catch (e) {
- setError(e.message);
- } finally {
- setIsLoading(false);
- }
- };
-
- const doComplete = async () => {
+ const handleTopicCompleted = () => {
setSessionDone(true);
- if (!weeklyDone) {
- setWeeklyDone(true);
- await db.setLearnDone(state.currentUser.id, state.weekNumber);
- }
- };
-
- const handleComplete = () => {
- if (!feedbackPrompted) {
- setFeedbackPrompted(true);
- setShowFeedbackModal(true);
- return;
- }
- doComplete();
- };
-
- const handleSubmitFeedback = async () => {
- if (feedbackText.trim()) {
- await db.setSetting(
- `feedback:${state.currentUser.id}:${activeTopic.id}:${state.weekNumber}`,
- feedbackText.trim()
- );
- }
- setShowFeedbackModal(false);
- doComplete();
- };
-
- const handleSkipFeedback = () => {
- setShowFeedbackModal(false);
- doComplete();
};
// ── Detail View ──────────────────────────────────────────
@@ -141,16 +95,14 @@ const Leren = () => {
-
Learning session complete!
+
Topic reviewed!
- You have successfully reviewed "{activeTopic.label}".
- {weeklyDone && ' Your weekly minimum is met.'}
+ You have successfully completed a micro learning for "{activeTopic.label}".