diff --git a/src/components/LessonModal.tsx b/src/components/LessonModal.tsx new file mode 100644 index 0000000..24955f7 --- /dev/null +++ b/src/components/LessonModal.tsx @@ -0,0 +1,90 @@ +import { useEffect, useState } from "react"; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogDescription, +} from "../components/ui/dialog"; +import { api } from "../utils/api"; +import { useAuthStore } from "../stores/authStore"; + +interface LessonModalProps { + lessonId: string | null; + open: boolean; + onOpenChange: (open: boolean) => void; +} + +export const LessonModal = ({ + lessonId, + open, + onOpenChange, +}: LessonModalProps) => { + const user = useAuthStore((state) => state.user); + const [loading, setLoading] = useState(false); + const [lesson, setLesson] = useState(null); + + useEffect(() => { + if (!open || !lessonId || !user) return; + + const fetchLesson = async () => { + try { + setLoading(true); + + const authStorage = localStorage.getItem("auth-storage"); + if (!authStorage) return; + + const parsed = JSON.parse(authStorage) as { + state?: { token?: string }; + }; + + const token = parsed.state?.token; + if (!token) return; + + const response = await api.fetchLessonById(token, lessonId); + setLesson(response); + } catch (err) { + console.error("Failed to fetch lesson", err); + } finally { + setLoading(false); + } + }; + + fetchLesson(); + }, [open, lessonId, user]); + + return ( + + + {loading && ( +
+ Loading lesson... +
+ )} + + {lesson ? lesson.title : "Lesson details"} + + + {!loading && lesson && ( +
+ {lesson.video_url && ( +
+ )} +
+
+ ); +}; diff --git a/src/components/LessonSkeleton.tsx b/src/components/LessonSkeleton.tsx new file mode 100644 index 0000000..b0cd53d --- /dev/null +++ b/src/components/LessonSkeleton.tsx @@ -0,0 +1,11 @@ +import { Card, CardContent } from "./ui/card"; + +export const LessonSkeleton = () => ( + +
+ +
+
+ + +); diff --git a/src/pages/student/Lessons.tsx b/src/pages/student/Lessons.tsx index 781e743..e570250 100644 --- a/src/pages/student/Lessons.tsx +++ b/src/pages/student/Lessons.tsx @@ -1,4 +1,5 @@ -// import { useAuthStore } from "../../stores/authStore"; +import { useAuthStore } from "../../stores/authStore"; +import { useEffect, useState } from "react"; import { Card, CardHeader, @@ -12,9 +13,52 @@ import { TabsList, TabsTrigger, } from "../../components/ui/tabs"; +import { api } from "../../utils/api"; +import { type Lesson } from "../../types/lesson"; +import { LessonSkeleton } from "../../components/LessonSkeleton"; +import { LessonModal } from "../../components/LessonModal"; export const Lessons = () => { - // const user = useAuthStore((state) => state.user); + const user = useAuthStore((state) => state.user); + const [lessons, setLessons] = useState([]); + const [lessonLoading, setLessonlLoading] = useState(true); + + const [selectedLessonId, setSelectedLessonId] = useState(null); + const [isModalOpen, setIsModalOpen] = useState(false); + + const handleLessonClick = (lessonId: string) => { + setSelectedLessonId(lessonId); + setIsModalOpen(true); + }; + + useEffect(() => { + const fetchAllLessons = async () => { + if (!user) return; + + try { + setLessonlLoading(true); + const authStorage = localStorage.getItem("auth-storage"); + if (!authStorage) return; + + const parsed = JSON.parse(authStorage) as { + state?: { token?: string }; + }; + + const token = parsed.state?.token; + if (!token) return; + + const response = await api.fetchAllLessons(token); + + setLessonlLoading(false); + setLessons(response.data); + } catch (error) { + setLessonlLoading(false); + console.error("Error fetching lessons:", error); + } + }; + + fetchAllLessons(); + }, [user]); return (
@@ -43,61 +87,99 @@ export const Lessons = () => {
- - - Video Thumbnail - - - Video Title - Video Description - - - - - Video Thumbnail - - - Video Title - Video Description - - - - - Video Thumbnail - - - Video Title - Video Description - - + {lessonLoading && ( +
+ {Array.from({ length: 6 }).map((_, i) => ( + + ))} +
+ )} + {!lessonLoading && lessons.length === 0 && ( +
+ No lessons available +
+ )} + + {!lessonLoading && lessons.length > 0 && ( +
+ {lessons.map((lesson) => ( + handleLessonClick(lesson.id)} + className="py-0 pb-5 rounded-4xl overflow-hidden" + > + + {lesson.title} + + + + {lesson.title} + {lesson.topic.name} + + + ))} +
+ )} + { + setIsModalOpen(open); + if (!open) setSelectedLessonId(null); + }} + />
- - - Video Thumbnail - - - Video Title - Video Description - - + {lessonLoading && ( +
+ {Array.from({ length: 6 }).map((_, i) => ( + + ))} +
+ )} + {!lessonLoading && lessons.length === 0 && ( +
+ No lessons available +
+ )} + + {!lessonLoading && lessons.length > 0 && ( +
+ {lessons.map((lesson) => ( + handleLessonClick(lesson.id)} + className="py-0 pb-5 rounded-4xl overflow-hidden" + > + + {lesson.title} + + + + {lesson.title} + {lesson.topic.name} + + + ))} +
+ )} + { + setIsModalOpen(open); + if (!open) setSelectedLessonId(null); + }} + />
diff --git a/src/types/lesson.ts b/src/types/lesson.ts new file mode 100644 index 0000000..b76f60a --- /dev/null +++ b/src/types/lesson.ts @@ -0,0 +1,35 @@ +import type { Topic } from "./sheet"; + +export type Lesson = { + id: string; + title: string; + thumbnail_url: string; + topic: Topic; +}; + +export interface LessonsResponse { + data: Lesson[]; + pagination: { + page: number; + limit: number; + total: number; + total_pages: number; + }; +} + +export interface LessonDetails { + title: string; + topic_id: string; + video_url: string; + content: string; + description: string; + thumbnail_url: string; + resources: any[]; + id: string; + created_by: { + id: string; + name: string; + email: string; + }; + topic: Topic[]; +} diff --git a/src/utils/api.ts b/src/utils/api.ts index ae5270f..83ed390 100644 --- a/src/utils/api.ts +++ b/src/utils/api.ts @@ -1,3 +1,4 @@ +import type { Lesson, LessonsResponse } from "../types/lesson"; import type { SessionAnswerResponse, SessionQuestionsResponse, @@ -183,5 +184,12 @@ class ApiClient { token, ); } + async fetchAllLessons(token: string): Promise { + return this.authenticatedRequest(`/lessons/`, token); + } + + async fetchLessonById(token: string, lessonId: string): Promise { + return this.authenticatedRequest(`/lessons/${lessonId}`, token); + } } export const api = new ApiClient(API_URL);