Skip to content

Commit 51a86d5

Browse files
Merge pull request #57 from guillermoscript/51-implement-course-enrollment
51-implement-course-enrollment
2 parents d250eed + 600821b commit 51a86d5

File tree

18 files changed

+453
-85
lines changed

18 files changed

+453
-85
lines changed

actions/dashboard/courseActions.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,47 @@ export async function deleteCourseAction (data: {
6565
revalidatePath('/dashboard/teacher/courses', 'layout')
6666
return createResponse('success', 'Course deleted successfully', null, null)
6767
}
68+
69+
export async function enrollUserToCourseAction ({
70+
courseId
71+
}: {
72+
courseId: number
73+
}) {
74+
if (!courseId) {
75+
return createResponse('error', 'Something went wrong', null, 'Course id is required')
76+
}
77+
78+
const supabase = createClient()
79+
const userData = await supabase.auth.getUser()
80+
81+
if (userData.error) {
82+
return createResponse('error', 'User not found', null, null)
83+
}
84+
85+
const userSubscription = await supabase
86+
.from('subscriptions')
87+
.select('subscription_id')
88+
.eq('user_id', userData.data.user.id)
89+
.single()
90+
91+
if (userSubscription.error) {
92+
return createResponse('error', 'Error getting user subscription', null, userSubscription.error.message)
93+
}
94+
95+
console.log(userSubscription.data)
96+
97+
const enrollmentData = await supabase.from('enrollments').insert([{
98+
course_id: courseId,
99+
subscription_id: userSubscription.data.subscription_id,
100+
user_id: userData.data.user.id,
101+
enrollment_date: new Date().toISOString()
102+
}])
103+
104+
if (enrollmentData.error) {
105+
console.log(enrollmentData.error)
106+
return createResponse('error', 'Error enrolling user to course', null, enrollmentData.error.message)
107+
}
108+
109+
revalidatePath('/dashboard/student/courses', 'layout')
110+
return createResponse('success', 'User enrolled to course successfully', null, null)
111+
}

app/api/chat/route.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ export async function POST (req: Request) {
55
const { messages } = await req.json()
66

77
const result = await streamText({
8-
model: google('models/gemini-pro'),
8+
model: google('models/gemini-1.5-flash-latest'),
99
messages,
1010
temperature: 0
1111
})

app/api/lessons/chat/student/route.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ export async function POST (req: Request) {
1818
const supabase = createClient()
1919

2020
const result = await streamText({
21-
model: google('models/gemini-pro'),
21+
model: google('models/gemini-1.5-flash-latest'),
2222
onFinish: async (event) => {
2323
const userData = await supabase.auth.getUser()
2424
if (userData.error) {

app/api/lessons/chat/teacher/route.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export async function POST (req: Request) {
1515
} = await req.json()
1616

1717
const result = await streamText({
18-
model: google('models/gemini-pro'),
18+
model: google('models/gemini-1.5-flash-latest'),
1919
messages: convertToCoreMessages(messages),
2020
tools: {
2121
// server-side tool with execute function:

app/dashboard/student/courses/[courseId]/exams/[examId]/review/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export default async function StudentExamCoursePage ({
3030
const userData = await supabase.auth.getUser()
3131

3232
if (userData.error != null) {
33-
return redirect('/auth/login')
33+
throw new Error(userData.error.message)
3434
}
3535

3636
const examData = await supabase
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
2+
import EnrollCard from '@/components/dashboards/student/course/EnrollCard'
3+
import { createClient } from '@/utils/supabase/server'
4+
5+
export default async function CoursesPageLayout ({
6+
children,
7+
params
8+
}: {
9+
children: React.ReactNode
10+
params: {
11+
courseId: string
12+
}
13+
}) {
14+
const supabase = createClient()
15+
const user = await supabase.auth.getUser()
16+
17+
if (user.error != null) {
18+
throw new Error(user.error.message)
19+
}
20+
const isUserEnrolled = await supabase
21+
.from('enrollments')
22+
.select('enrollment_id')
23+
.eq('user_id', user.data.user.id)
24+
.eq('course_id', Number(params.courseId))
25+
26+
const userSubscriptions = await supabase
27+
.from('subscriptions')
28+
.select('subscription_id')
29+
.eq('user_id', user.data.user.id)
30+
31+
if (isUserEnrolled.error != null) {
32+
if (isUserEnrolled.error.code === 'PGRST116') {
33+
if (userSubscriptions.error != null || userSubscriptions.data.length === 0) {
34+
throw new Error(userSubscriptions?.error?.message || 'You are not authorized to view this page.')
35+
}
36+
return (
37+
<EnrollCard courseId={Number(params.courseId)} />
38+
)
39+
}
40+
throw new Error(isUserEnrolled.error.message)
41+
}
42+
43+
if (isUserEnrolled.data.length === 0) {
44+
if (userSubscriptions.error != null || userSubscriptions.data.length === 0) {
45+
throw new Error(userSubscriptions?.error?.message || 'You are not authorized to view this page.')
46+
}
47+
return (
48+
<EnrollCard courseId={Number(params.courseId)} />
49+
)
50+
}
51+
52+
return (
53+
<>
54+
{children}
55+
</>
56+
)
57+
}

app/dashboard/student/courses/[courseId]/lessons/[lessonsId]/page.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ export default async function StudentLessonPage ({
2626
}) {
2727
const supabase = createClient()
2828
const user = await supabase.auth.getUser()
29+
30+
if (user.error != null) {
31+
throw new Error(user.error.message)
32+
}
33+
2934
const lessonData = await supabase
3035
.from('lessons')
3136
.select(`*,
@@ -37,6 +42,7 @@ export default async function StudentLessonPage ({
3742
lessons_ai_task_messages(*)
3843
`)
3944
.eq('id', params.lessonsId)
45+
.eq('lessons_ai_task_messages.user_id', user.data.user.id)
4046
.single()
4147

4248
// TODO - finish the completion of the lesson
@@ -54,10 +60,6 @@ export default async function StudentLessonPage ({
5460

5561
const isLessonAiTaskCompleted = lessonCompletion?.data?.id
5662

57-
console.log(isLessonAiTaskCompleted)
58-
59-
console.log(lessonData.data.lessons_ai_tasks)
60-
6163
return (
6264
<>
6365
<LessonPage

app/dashboard/student/courses/[courseId]/lessons/page.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,17 @@ export default async function StudentCourseLessonsPage ({
1919
}
2020
}) {
2121
const supabase = createClient()
22+
const user = await supabase.auth.getUser()
23+
24+
if (user.error != null) {
25+
throw new Error(user.error.message)
26+
}
2227

2328
const lessons = await supabase
2429
.from('lessons')
2530
.select('*,courses(*),lesson_completions(*)')
2631
.eq('course_id', params.courseId)
32+
.eq('lesson_completions.user_id', user.data.user.id)
2733
.order('sequence')
2834

2935
if (lessons.error != null) {

app/dashboard/student/courses/[courseId]/page.tsx

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,43 @@ export default async function CourseStudentPage ({
2020
params: { courseId: string }
2121
}) {
2222
const supabase = createClient()
23+
const userData = await supabase.auth.getUser()
24+
25+
if (userData.error != null) {
26+
return redirect('/auth/login')
27+
}
2328

2429
const courseData = await supabase
2530
.from('courses')
2631
.select(
2732
`*,
28-
lessons(*),
33+
lessons(*, lesson_completions(*)),
2934
exams(*,
30-
exam_scores(*)
35+
exam_submissions(
36+
submission_id,
37+
student_id,
38+
submission_date,
39+
exam_answers(
40+
answer_id,
41+
question_id,
42+
answer_text,
43+
is_correct,
44+
feedback
45+
),
46+
exam_scores (
47+
score_id,
48+
score
49+
)
50+
)
3151
)
3252
`
3353
)
3454
.eq('course_id', params.courseId)
55+
.eq('status', 'published')
56+
// .eq('lessons.status', 'published')
57+
// .eq('exams.status', 'published')
58+
.eq('lessons.lesson_completions.user_id', userData.data.user.id)
59+
.eq('exams.exam_submissions.student_id', userData.data.user.id)
3560
.single()
3661

3762
if (courseData.error != null) {
@@ -106,7 +131,9 @@ export default async function CourseStudentPage ({
106131
title={lesson.title}
107132
lessonNumber={lesson.sequence}
108133
description={lesson.description}
109-
status={lesson.status}
134+
status={lesson.lesson_completions.length > 0
135+
? 'Completed'
136+
: 'Not Started'}
110137
courseId={
111138
courseData.data.course_id
112139
}
@@ -129,8 +156,16 @@ export default async function CourseStudentPage ({
129156
title={exam.title}
130157
examNumber={exam.sequence}
131158
description={exam.description}
132-
status={exam.status}
133-
grade={100}
159+
status={ exam.exam_submissions.length > 0
160+
? exam.exam_submissions[0].exam_scores
161+
.length > 0
162+
? 'Completed'
163+
: 'In Progress'
164+
: 'Not Started'}
165+
grade={exam.exam_submissions.length > 0
166+
? exam?.exam_submissions[0]
167+
?.exam_scores[0]?.score
168+
: 'N/A'}
134169
courseId={
135170
courseData.data.course_id
136171
}
@@ -232,7 +267,7 @@ const ExamCard = ({
232267
</p>
233268
<div className="mt-2">
234269
<div className="flex items-center justify-between">
235-
<p>Grade: {grade}%</p>
270+
<p>Grade: {grade}</p>
236271
<Link
237272
className={buttonVariants({ variant: 'link' })}
238273
href={`/dashboard/student/courses/${courseId}/exams/${examId}`}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
'use client' // Error components must be Client Components
2+
3+
import { useEffect } from 'react'
4+
5+
import GenericError from '@/components/GenericError'
6+
7+
export default function Error ({
8+
error,
9+
reset
10+
}: {
11+
error: Error & { digest?: string }
12+
reset: () => void
13+
}) {
14+
useEffect(() => {
15+
// Log the error to an error reporting service
16+
console.error(error)
17+
}, [error])
18+
19+
return (
20+
<GenericError
21+
retry={reset}
22+
title="Oh no! An error occurred"
23+
description={error.message}
24+
/>
25+
)
26+
}

0 commit comments

Comments
 (0)