diff --git a/bun.lock b/bun.lock
index 2cbace6..82ebd35 100644
--- a/bun.lock
+++ b/bun.lock
@@ -20,6 +20,7 @@
"next": "^14.2.25",
"react": "19.0.0",
"react-dom": "19.0.0",
+ "react-dropzone": "^14.3.8",
"react-icons": "^5.5.0",
"react-markdown": "^10.1.0",
"sharp": "^0.33.5",
@@ -416,6 +417,8 @@
"async-function": ["async-function@1.0.0", "", {}, "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA=="],
+ "attr-accept": ["attr-accept@2.2.5", "", {}, "sha512-0bDNnY/u6pPwHDMoF0FieU354oBi0a8rD9FcsLwzcGWbc8KS8KPIi7y+s13OlVY+gMWc/9xEMUgNE6Qm8ZllYQ=="],
+
"available-typed-arrays": ["available-typed-arrays@1.0.7", "", { "dependencies": { "possible-typed-array-names": "^1.0.0" } }, "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ=="],
"axe-core": ["axe-core@4.10.3", "", {}, "sha512-Xm7bpRXnDSX2YE2YFfBk2FnF0ep6tmG7xPh8iHee8MIcrgq762Nkce856dYtJYLkuIoYZvGfTs/PbZhideTcEg=="],
@@ -600,6 +603,8 @@
"file-entry-cache": ["file-entry-cache@8.0.0", "", { "dependencies": { "flat-cache": "^4.0.0" } }, "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ=="],
+ "file-selector": ["file-selector@2.1.2", "", { "dependencies": { "tslib": "^2.7.0" } }, "sha512-QgXo+mXTe8ljeqUFaX3QVHc5osSItJ/Km+xpocx0aSqWGMSCf6qYs/VnzZgS864Pjn5iceMRFigeAV7AfTlaig=="],
+
"fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="],
"find-root": ["find-root@1.1.0", "", {}, "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng=="],
@@ -956,6 +961,8 @@
"react-dom": ["react-dom@19.0.0", "", { "dependencies": { "scheduler": "^0.25.0" }, "peerDependencies": { "react": "^19.0.0" } }, "sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ=="],
+ "react-dropzone": ["react-dropzone@14.3.8", "", { "dependencies": { "attr-accept": "^2.2.4", "file-selector": "^2.1.0", "prop-types": "^15.8.1" }, "peerDependencies": { "react": ">= 16.8 || 18.0.0" } }, "sha512-sBgODnq+lcA4P296DY4wacOZz3JFpD99fp+hb//iBO2HHnyeZU3FwWyXJ6salNpqQdsZrgMrotuko/BdJMV8Ug=="],
+
"react-fast-compare": ["react-fast-compare@3.2.2", "", {}, "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ=="],
"react-focus-lock": ["react-focus-lock@2.13.6", "", { "dependencies": { "@babel/runtime": "^7.0.0", "focus-lock": "^1.3.6", "prop-types": "^15.6.2", "react-clientside-effect": "^1.2.7", "use-callback-ref": "^1.3.3", "use-sidecar": "^1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ehylFFWyYtBKXjAO9+3v8d0i+cnc1trGS0vlTGhzFW1vbFXVUTmR8s2tt/ZQG8x5hElg6rhENlLG1H3EZK0Llg=="],
@@ -1204,6 +1211,8 @@
"fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
+ "file-selector/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
+
"micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
"parse-entities/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="],
diff --git a/package.json b/package.json
index 5b5ba2d..1457f83 100644
--- a/package.json
+++ b/package.json
@@ -31,6 +31,7 @@
"next": "^14.2.25",
"react": "19.0.0",
"react-dom": "19.0.0",
+ "react-dropzone": "^14.3.8",
"react-icons": "^5.5.0",
"react-markdown": "^10.1.0",
"sharp": "^0.33.5",
@@ -48,4 +49,4 @@
"trustedDependencies": [
"@biomejs/biome"
]
-}
\ No newline at end of file
+}
diff --git a/src/components/general/ClassroomCard.tsx b/src/components/general/ClassroomCard.tsx
index cb80996..7833759 100644
--- a/src/components/general/ClassroomCard.tsx
+++ b/src/components/general/ClassroomCard.tsx
@@ -48,7 +48,9 @@ export default function ClassroomCard({ item }: Readonly<{ item: IClassroom }>)
- {item.memberCount} estudiantes
+
+ {item.memberCount === 1 ? 'Sin ' : item.memberCount - 1} estudiantes
+
+
+
+ >
+ ))}
+
+
+ )}
+
+ {!isProfessor && isAssignment && (
+
+
+ Enviar Tarea
+
+ {hasSubmitted ? (
+
+ ¡Tu tarea ha sido enviada! El profesor la revisará pronto.
+
+ ) : (
+
+
+
+
+
+
- {resource.type === 'file' ? 'Descargar' : 'Abrir'}
-
-
-
- >
- ))}
-
-
- )}
+ {isDragAccept
+ ? 'Suelta para subir los archivos'
+ : isDragReject
+ ? 'Algunos archivos no son válidos'
+ : isDragActive
+ ? 'Suelta los archivos aquí'
+ : 'Arrastra archivos aquí o haz clic para seleccionar'}
+
+
+ Máximo 5 archivos, 10MB por archivo
+
+
+
+
+ {files.length > 0 && (
+
+
+ Archivos adjuntos:
+
+ {files.map((file, index) => (
+
+
+ {file.name} ({(file.size / 1024 / 1024).toFixed(2)}MB)
+
+ }
+ size='sm'
+ variant='ghost'
+ colorScheme='red'
+ onClick={(e) => {
+ e.stopPropagation();
+ removeFile(index);
+ }}
+ />
+
+ ))}
+
+ )}
+
+ setComment(e.target.value)}
+ bg='brand.dark.800'
+ border='1px solid'
+ borderColor='brand.dark.700'
+ _hover={{ borderColor: 'brand.primary.500' }}
+ _focus={{
+ borderColor: 'brand.primary.500',
+ boxShadow: '0 0 0 1px var(--chakra-colors-brand-primary-500)'
+ }}
+ />
+
+ }
+ isLoading={isSubmitting}
+ loadingText='Enviando...'
+ onClick={handleSubmit}
+ >
+ Enviar Tarea
+
+
+ )}
+
+ )}
+
diff --git a/src/components/screens/ClassScreen.tsx b/src/components/screens/ClassScreen.tsx
index 0ac1836..54cd382 100644
--- a/src/components/screens/ClassScreen.tsx
+++ b/src/components/screens/ClassScreen.tsx
@@ -2,6 +2,7 @@
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 { IUser } from '@/types/IUser';
@@ -27,6 +28,7 @@ import {
useDisclosure,
useToast
} from '@chakra-ui/react';
+import { useAtom } from 'jotai';
import { useRouter } from 'next/navigation';
import { useEffect, useState } from 'react';
import { FiCode, FiFileText, FiPlus, FiUsers } from 'react-icons/fi';
@@ -43,6 +45,7 @@ export default function ClassScreen({ id }: Readonly<{ id: string }>) {
const [isMembersLoading, setIsMembersLoading] = useState(false);
const { isOpen, onOpen, onClose } = useDisclosure();
const toast = useToast();
+ const [auth] = useAtom(authAtom);
useEffect(() => {
const fetchData = async () => {
@@ -56,7 +59,7 @@ export default function ClassScreen({ id }: Readonly<{ id: string }>) {
setClassroom(classroomData);
setClassActivities(activitiesData);
setProfessor(professorData);
- } catch (error) {
+ } catch {
toast({
title: 'Error',
description: 'No se pudo cargar la información de la clase',
@@ -84,7 +87,7 @@ export default function ClassScreen({ id }: Readonly<{ id: string }>) {
try {
const members = await api.classroom.getMembers(id);
setClassMembers(members);
- } catch (error) {
+ } catch {
toast({
title: 'Error',
description: 'No se pudo cargar la lista de estudiantes',
@@ -152,12 +155,16 @@ export default function ClassScreen({ id }: Readonly<{ id: string }>) {
- {classroom.memberCount} estudiantes
-
-
-
- Código: {classroom.code}
+
+ {classroom.memberCount === 1 ? 'Sin ' : classroom.memberCount - 1} estudiantes
+
+ {classroom.owner === auth.user?.id && (
+
+
+ Código: {classroom.code}
+
+ )}
@@ -201,7 +208,7 @@ export default function ClassScreen({ id }: Readonly<{ id: string }>) {
>
- Estudiantes
+ Miembros
@@ -263,6 +270,41 @@ export default function ClassScreen({ id }: Readonly<{ id: string }>) {
+ {professor && (
+ <>
+
+ Profesor
+
+
+
+
+
+ {professor.username}
+
+ Profesor
+
+
+
+
+ >
+ )}
Estudiantes
@@ -279,32 +321,28 @@ export default function ClassScreen({ id }: Readonly<{ id: string }>) {
}}
gap={4}
>
- {classMembers.map((member) => (
-
-
-
- {member.username}
- {member.id === classroom.owner ? (
-
- Profesor
-
- ) : (
+ {classMembers
+ .filter((m) => m.id !== classroom.owner)
+ .map((member) => (
+
+
+
+ {member.username}
Estudiante
- )}
-
-
- ))}
+
+
+ ))}
)}