Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 30 additions & 20 deletions app/[locale]/dashboard/student/courses/[courseId]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CheckCircle, Clock, Dumbbell, FileText } from 'lucide-react'
import { CheckCircle, Clock, Clock10, Dumbbell, FileText } from 'lucide-react'
import Image from 'next/image'
import Link from 'next/link'
import { redirect } from 'next/navigation'
Expand All @@ -17,9 +17,9 @@ const ExerciseCard = ({ title, description, difficulty, type, status, courseId,
<CardHeader>
<CardTitle className="flex items-center justify-between">
<span>{title}</span>
<Badge variant={status === 'Completed' ? 'default' : 'outline'}>
{status === 'Completed' ? <CheckCircle className="mr-1 h-3 w-3" /> : <Clock className="mr-1 h-3 w-3" />}
{status === 'Completed' ? t('dashboard.student.CourseStudentPage.completed') : t('dashboard.student.CourseStudentPage.notStarted')}
<Badge variant={status === 'Completed' ? 'default' : status === 'In Progress' ? 'outline' : 'secondary'}>
{status === 'Completed' ? <CheckCircle className="mr-1 h-3 w-3" /> : status === 'In Progress' ? <Clock className="mr-1 h-3 w-3" /> : <Clock10 className="mr-1 h-3 w-3" />}
{status === 'Completed' ? t('dashboard.student.CourseStudentPage.completed') : status === 'In Progress' ? t('dashboard.student.CourseStudentPage.inProgress') : t('dashboard.student.CourseStudentPage.notStarted')}
</Badge>
</CardTitle>
<CardDescription>{type} - {difficulty}</CardDescription>
Expand All @@ -29,12 +29,15 @@ const ExerciseCard = ({ title, description, difficulty, type, status, courseId,
</CardContent>
<CardFooter>
<Button
variant={status === 'Completed' ? 'secondary' : 'default'}
variant={status === 'Completed' ? 'secondary' : status === 'In Progress' ? 'default' : 'outline'}
asChild
className='w-full'
>
<Link href={`/dashboard/student/courses/${courseId}/exercises/${exerciseId}`}>
<Dumbbell className="mr-2 h-4 w-4" /> {t('dashboard.student.CourseStudentPage.startExercise')}
<Dumbbell className="mr-2 h-4 w-4" />
{
status === 'Completed' ? t('dashboard.student.CourseStudentPage.review') : status === 'In Progress' ? t('dashboard.student.CourseStudentPage.continue') : t('dashboard.student.CourseStudentPage.start')
}
</Link>
</Button>
</CardFooter>
Expand Down Expand Up @@ -211,7 +214,8 @@ export default async function CourseStudentPage({
)
),
exercises(*,
exercise_completions(id)
exercise_completions(id),
exercise_messages(id)
)
`
)
Expand All @@ -220,6 +224,7 @@ export default async function CourseStudentPage({
.eq('lessons.lesson_completions.user_id', userData.data.user.id)
.eq('exams.exam_submissions.student_id', userData.data.user.id)
.eq('exercises.exercise_completions.user_id', userData.data.user.id)
.eq('exercises.exercise_messages.user_id', userData.data.user.id)
.single()

if (courseData.error != null) {
Expand Down Expand Up @@ -294,19 +299,24 @@ export default async function CourseStudentPage({
value="exercises"
>
{courseData.data.exercises
.map((exercise) => (
<ExerciseCard
key={exercise.id}
title={exercise.title}
description={exercise.description}
difficulty={exercise.difficulty_level}
type={exercise.exercise_type}
status={exercise.exercise_completions?.length > 0 ? 'Completed' : 'Not Started'}
courseId={courseData.data.course_id}
exerciseId={exercise.id}
t={t}
/>
))}
.map((exercise) => {
// if exercise has a completion, it is completed, else if it has a message, it is in progress else not started
const status = exercise.exercise_completions?.length > 0 ? 'Completed' : exercise.exercise_messages?.length > 0 ? 'In Progress' : 'Not Started'

return (
<ExerciseCard
key={exercise.id}
title={exercise.title}
description={exercise.description}
difficulty={exercise.difficulty_level}
type={exercise.exercise_type}
status={status}
courseId={courseData.data.course_id}
exerciseId={exercise.id}
t={t}
/>
)
})}
</TabsContent>
<TabsContent
className='grid gap-4 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4'
Expand Down
7 changes: 0 additions & 7 deletions app/api/chat/exercises/student/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,8 @@ export async function POST(req: Request) {
}
},
async onFinish({ responseMessages, text, toolResults }) {
console.log('Response messages:', responseMessages)
console.log(text, 'TEXT')

const lastMessage = body.messages[body.messages.length - 1]

console.log('Tool results:', toolResults)

const save = await supabase.from('exercise_messages').insert([
{
exercise_id: body.exerciseId,
Expand Down Expand Up @@ -79,8 +74,6 @@ export async function POST(req: Request) {
}
)
}

console.log('Save:', save)
}
})

Expand Down
17 changes: 6 additions & 11 deletions app/api/chatbox-ai/route.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,23 @@
import { google } from '@ai-sdk/google'
import { generateText } from 'ai'
import { convertToCoreMessages, Message, streamText } from 'ai'
import { NextRequest, NextResponse } from 'next/server'

interface RequestBody {
message: string;
instructions: string;
messages: Message[];
}

export async function POST(request: NextRequest): Promise<NextResponse> {
export async function POST(request: NextRequest) {
try {
const reqBody: RequestBody = await request.json()
const { message, instructions } = reqBody
const model = google('gemini-1.5-flash')

const result = await generateText({
const result = await streamText({
model,
system: `Act like a teacher. Always provide responses in plain text without using any markdown or special formatting like **, _ or other font styles. Respond naturally and clearly. ${instructions}`,
prompt: message,
messages: convertToCoreMessages(reqBody.messages),
temperature: 0.7,
})

const responseText = result.text

return new NextResponse(responseText)
return result.toDataStreamResponse()
} catch (error) {
console.error('Error al generar la respuesta:', error)
return NextResponse.json(
Expand Down
18 changes: 18 additions & 0 deletions app/locales/en/components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -534,5 +534,23 @@ If you have doubts, try saying: "Could you give me a fake scenario to practice m
vibrantCommunity: 'Join our vibrant learning community',
certificates: 'Certificates',
earnCertificates: 'Earn certificates upon course completion',
},
ChatBox: {
closeChat: 'Close chat',
openChat: 'Open chat',
chatAssistant: 'Chat Assistant',
minimize: 'Minimize',
expand: 'Expand',
greeting: "Hi! I'm your AI assistant. How can I help you today?",
quickAccess: {
productQuestions: 'Product & General questions',
shareFeedback: 'Share feedback',
loggingIn: 'Logging in',
reset2FA: 'Reset 2FA',
abuseReport: 'Abuse report',
contactingSales: 'Contacting Sales & Partnerships',
},
typeMessage: 'Type your message...',
sendMessage: 'Send message',
}
} as const
2 changes: 2 additions & 0 deletions app/locales/en/views.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,8 @@ export default {
startExercise: 'Start Exercise',
exercises: 'Exercises',
exercisesCompleted: 'Exercises Completed',
inProgress: 'In Progress',
continue: 'Continue',
},
LessonPage: {
description: 'View and track your progress through the course lessons.',
Expand Down
18 changes: 18 additions & 0 deletions app/locales/es/components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -531,5 +531,23 @@ Si tienes dudas, intenta diciendo: "Could you give me a fake scenario to practic
vibrantCommunity: 'Únete a nuestra vibrante comunidad de aprendizaje',
certificates: 'Certificados',
earnCertificates: 'Obtén certificados al completar los cursos',
},
ChatBox: {
closeChat: 'Cerrar chat',
openChat: 'Abrir chat',
chatAssistant: 'Asistente de Chat',
minimize: 'Minimizar',
expand: 'Expandir',
greeting: '¡Hola! Soy tu asistente de IA. ¿Cómo puedo ayudarte hoy?',
quickAccess: {
productQuestions: 'Preguntas sobre productos y generales',
shareFeedback: 'Compartir comentarios',
loggingIn: 'Iniciar sesión',
reset2FA: 'Restablecer 2FA',
abuseReport: 'Informe de abuso',
contactingSales: 'Contactar con Ventas y Asociaciones',
},
typeMessage: 'Escribe tu mensaje...',
sendMessage: 'Enviar mensaje',
}
} as const
2 changes: 2 additions & 0 deletions app/locales/es/views.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,8 @@ export default {
viewExercise: 'Ver ejercicio',
exercises: 'Ejercicios',
exercisesCompleted: 'Ejercicios completados',
inProgress: 'En progreso',
continue: 'Continuar',
},
LessonPage: {
description: 'Ver y realizar un seguimiento de tu progreso a través de la lección.',
Expand Down
2 changes: 1 addition & 1 deletion components/ScrollToTopButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ function ScrollToTopButton () {
<Button
variant='outline'
onClick={scrollToTop}
className="fixed bottom-5 right-5 p-3 rounded-md shadow-lg"
className="fixed bottom-5 right-20 p-3 rounded-md shadow-lg"
>
<ArrowBigUpDash size={24} />
</Button>
Expand Down
Loading