diff --git a/src/api/api.ts b/src/api/api.ts index a02cb9e..562d45a 100644 --- a/src/api/api.ts +++ b/src/api/api.ts @@ -1,6 +1,7 @@ import { API_URL } from '@/constants/constants'; import type { IActivity } from '@/types/IActivity'; import type { IClassroom } from '@/types/IClassroomCard'; +import type { ISubmission } from '@/types/ISubmission'; import type { IUser } from '@/types/IUser'; const getAuthHeaders = (): Record => { @@ -146,6 +147,65 @@ export const api = { return res.json(); }, + getSubmissionUrl: async ( + classroomId: string, + activityId: string, + filename: string, + comment: string + ): Promise<{ url: string }> => { + const res = await fetch( + `${API_URL}/classrooms/${encodeURIComponent(classroomId)}/activities/${encodeURIComponent( + activityId + )}/submissions`, + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + ...getAuthHeaders() + }, + body: JSON.stringify({ filename, comment }) + } + ); + + if (!res.ok) throw new Error('Failed to get submission URL'); + return res.json(); + }, + + getAllSubmissions: async ( + classroomId: string, + activityId: string + ): Promise<(ISubmission & { user: IUser })[]> => { + const res = await fetch( + `${API_URL}/classrooms/${encodeURIComponent(classroomId)}/activities/${encodeURIComponent( + activityId + )}/submissions/all`, + { + headers: { + ...getAuthHeaders() + } + } + ); + + if (!res.ok) throw new Error('Failed to fetch submissions'); + return res.json(); + }, + + getUserSubmission: async (classroomId: string, activityId: string): Promise => { + const res = await fetch( + `${API_URL}/classrooms/${encodeURIComponent(classroomId)}/activities/${encodeURIComponent( + activityId + )}/submissions`, + { + headers: { + ...getAuthHeaders() + } + } + ); + + if (!res.ok) throw new Error('Failed to fetch user submission'); + return res.json(); + }, + create: async ( classroomId: string, data: { diff --git a/src/components/screens/ActivityScreen.tsx b/src/components/screens/ActivityScreen.tsx index b0bf27e..03fbca4 100644 --- a/src/components/screens/ActivityScreen.tsx +++ b/src/components/screens/ActivityScreen.tsx @@ -1,10 +1,14 @@ 'use client'; import { api } from '@/api/api'; +import { CDN_URL } from '@/constants/constants'; import { authAtom } from '@/store/auth'; import type { IActivity } from '@/types/IActivity'; import type { IClassroom } from '@/types/IClassroomCard'; +import type { ISubmission } from '@/types/ISubmission'; +import type { IUser } from '@/types/IUser'; import { + Avatar, Badge, Box, Button, @@ -55,6 +59,9 @@ export default function ActivityScreen({ const [activity, setActivity] = useState(null); const [classroom, setClassroom] = useState(null); const [isLoading, setIsLoading] = useState(true); + const [submissions, setSubmissions] = useState<(ISubmission & { user: IUser })[]>([]); + const [userSubmission, setUserSubmission] = useState(null); + const [isLoadingSubmissions, setIsLoadingSubmissions] = useState(false); const [files, setFiles] = useState([]); const [comment, setComment] = useState(''); const [isSubmitting, setIsSubmitting] = useState(false); @@ -119,6 +126,29 @@ export default function ActivityScreen({ setActivity(activityData); setClassroom(classroomData); + + if (classroomData.owner === auth.user?.id && activityData.type === 'assignment') { + setIsLoadingSubmissions(true); + try { + const submissionsData = await api.activities.getAllSubmissions(classroomId, activityId); + setSubmissions(submissionsData); + } catch (error) { + console.error('Failed to fetch submissions:', error); + } finally { + setIsLoadingSubmissions(false); + } + } else if (activityData.type === 'assignment') { + setIsLoadingSubmissions(true); + try { + const submission = await api.activities.getUserSubmission(classroomId, activityId); + setUserSubmission(submission); + setHasSubmitted(true); + } catch (error) { + console.error('Failed to fetch user submission:', error); + } finally { + setIsLoadingSubmissions(false); + } + } } catch { toast({ title: 'Error', @@ -135,7 +165,7 @@ export default function ActivityScreen({ }; fetchData(); - }, [activityId, classroomId, toast]); + }, [activityId, classroomId, toast, auth.user?.id]); const handleSubmit = async () => { if (files.length === 0) { @@ -151,20 +181,45 @@ export default function ActivityScreen({ } setIsSubmitting(true); + try { + for (const file of files) { + const { url } = await api.activities.getSubmissionUrl(classroomId, activityId, file.name, comment); - await new Promise((resolve) => setTimeout(resolve, 1000)); + const uploadRes = await fetch(url, { + method: 'PUT', + body: file, + headers: { + 'Content-Type': file.type + } + }); - toast({ - title: 'Éxito', - description: 'Tu tarea ha sido enviada correctamente', - status: 'success', - position: 'top-right', - duration: 3000, - isClosable: true - }); + if (!uploadRes.ok) { + throw new Error(`Failed to upload file ${file.name}`); + } + } - setHasSubmitted(true); - setIsSubmitting(false); + toast({ + title: 'Éxito', + description: 'Tu tarea ha sido enviada correctamente', + status: 'success', + position: 'top-right', + duration: 3000, + isClosable: true + }); + + setHasSubmitted(true); + } catch (error) { + toast({ + title: 'Error', + description: error instanceof Error ? error.message : 'Ha ocurrido un error al enviar la tarea', + status: 'error', + position: 'top-right', + duration: 3000, + isClosable: true + }); + } finally { + setIsSubmitting(false); + } }; if (isLoading) { @@ -368,6 +423,92 @@ export default function ActivityScreen({ )} + {isProfessor && isAssignment && ( + + + Entregas de Estudiantes + + {isLoadingSubmissions ? ( + + + + ) : submissions.length > 0 ? ( + + {submissions.map((submission) => ( + + + + + + + {submission.user?.username} + + + Entregado el{' '} + {format( + new Date(submission.submittedAt), + "d 'de' MMMM 'a las' HH:mm", + { locale: es } + )} + + + + + + {submission.comment && ( + + Comentario: {submission.comment} + + )} + {submission.files.map((file, index) => ( + + {file.name} + + + + + ))} + + + ))} + + ) : ( + Aún no hay entregas para esta tarea. + )} + + )} + {!isProfessor && isAssignment && ( Enviar Tarea - {hasSubmitted ? ( - - ¡Tu tarea ha sido enviada! El profesor la revisará pronto. - + {isLoadingSubmissions ? ( + + + + ) : hasSubmitted ? ( + + + ¡Tu tarea ha sido enviada! El profesor la revisará pronto. + + {userSubmission && ( + + {userSubmission.comment && ( + + Comentario: + + )} + {userSubmission.comment && ( + {userSubmission.comment} + )} + + Archivos enviados: + + + {userSubmission.files.map((file, index) => ( + + + {file.name} + + + + + + ))} + + + Enviado el{' '} + {format( + new Date(userSubmission.submittedAt), + "d 'de' MMMM 'a las' HH:mm", + { locale: es } + )} + + + )} + ) : ( ; + submittedAt: string; +}