Skip to content
This repository was archived by the owner on Jun 12, 2025. It is now read-only.
Merged

Dev #13

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
13 changes: 13 additions & 0 deletions src/api/api.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { API_URL } from '@/constants/constants';
import type { IActivity } from '@/types/IActivity';
import type { IClassroom } from '@/types/IClassroomCard';
import type { IUser } from '@/types/IUser';

const getAuthHeaders = (): Record<string, string> => {
const token = typeof window !== 'undefined' ? localStorage.getItem('token') : null;
Expand Down Expand Up @@ -31,6 +32,18 @@ export const api = {
return res.json();
},

getMembers: async (id: string): Promise<IUser[]> => {
const res = await fetch(`${API_URL}/classrooms/${encodeURIComponent(id)}/members`, {
headers: {
...getAuthHeaders()
}
});

if (!res.ok) throw new Error('Failed to fetch classroom');
return res.json();
},


create: async (data: {
name: string;
description: string;
Expand Down
1 change: 1 addition & 0 deletions src/components/modals/JoinClassModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export default function JoinClassModal({ isOpen, onClose, onClassroomJoined }: R

setIsLoading(true);
try {
await api.classroom.join(code);
const updatedClassrooms = await api.classroom.getAll();
onClassroomJoined?.(updatedClassrooms);

Expand Down
117 changes: 66 additions & 51 deletions src/components/screens/ClassScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,15 @@ import { useEffect, useState } from 'react';
import { FiCode, FiFileText, FiPlus, FiUsers } from 'react-icons/fi';
import ActivityCard from '../general/ActivityCard';
import CreateActivityModal from '../modals/CreateActivityModal';
import type { IUser } from '@/types/IUser';

export default function ClassScreen({ id }: Readonly<{ id: string }>) {
const [classroom, setClassroom] = useState<IClassroom | null>(null);
const [isLoading, setIsLoading] = useState(true);
const router = useRouter();
const [classActivities, setClassActivities] = useState<IActivity[]>([]);
const [classMembers, setClassMembers] = useState<IUser[]>([]);
const [isMembersLoading, setIsMembersLoading] = useState(false);
const { isOpen, onOpen, onClose } = useDisclosure();
const toast = useToast();

Expand Down Expand Up @@ -72,6 +75,28 @@ export default function ClassScreen({ id }: Readonly<{ id: string }>) {
setClassActivities((prev) => [...prev, activity]);
};

const handleTabChange = async (index: number) => {
// Index 1 is the "Estudiantes" tab
if (index === 1 && classMembers.length === 0) {
setIsMembersLoading(true);
try {
const members = await api.classroom.getMembers(id);
setClassMembers(members);
} catch (error) {
toast({
title: 'Error',
description: 'No se pudo cargar la lista de estudiantes',
status: 'error',
position: 'top-right',
duration: 3000,
isClosable: true
});
} finally {
setIsMembersLoading(false);
}
}
};

if (isLoading) {
return (
<Flex h='100%' align='center' justify='center'>
Expand Down Expand Up @@ -125,7 +150,7 @@ export default function ClassScreen({ id }: Readonly<{ id: string }>) {
<Flex gap={6} color='gray.400'>
<Flex align='center' gap={2}>
<Icon as={FiUsers} />
<Text>24 estudiantes</Text>
<Text>{classMembers.length || '...'} estudiantes</Text>
</Flex>
<Flex align='center' gap={2}>
<Icon as={FiCode} />
Expand All @@ -148,7 +173,7 @@ export default function ClassScreen({ id }: Readonly<{ id: string }>) {

<Box>
<Container maxW='container.xl'>
<Tabs variant='unstyled'>
<Tabs variant='unstyled' onChange={handleTabChange}>
<Box borderBottom='1px solid' borderColor='brand.dark.800'>
<TabList gap={4}>
<Tab
Expand Down Expand Up @@ -243,57 +268,47 @@ export default function ClassScreen({ id }: Readonly<{ id: string }>) {
<Heading size='lg' mb={6}>
Estudiantes
</Heading>
<Grid
templateColumns={{
base: '1fr',
sm: 'repeat(2, 1fr)',
md: 'repeat(3, 1fr)'
}}
gap={4}
>
<Flex
p={4}
{isMembersLoading ? (
<Flex justify='center' py={8}>
<Spinner size='xl' />
</Flex>
) : (
<Grid
templateColumns={{
base: '1fr',
sm: 'repeat(2, 1fr)',
md: 'repeat(3, 1fr)'
}}
gap={4}
align='center'
bg='brand.dark.900'
borderRadius='xl'
border='1px solid'
borderColor='brand.dark.800'
>
<Avatar
size='md'
name='Ángel'
src='https://avatars.githubusercontent.com/u/57068341?v=4'
/>
<Box>
<Text fontWeight='bold'>Ángel</Text>
<Text fontSize='sm' color='brand.primary.400'>
Profesor
</Text>
</Box>
</Flex>

{Array.from({ length: 5 }).map((_, i) => (
<Flex
key={i}
p={4}
gap={4}
align='center'
bg='brand.dark.900'
borderRadius='xl'
border='1px solid'
borderColor='brand.dark.800'
>
<Avatar size='md' name={`Estudiante ${i + 1}`} />
<Box>
<Text fontWeight='bold'>Estudiante {i + 1}</Text>
<Text fontSize='sm' color='gray.400'>
Estudiante
</Text>
</Box>
</Flex>
))}
</Grid>
{classMembers.map((member) => (
<Flex
key={member.id}
p={4}
gap={4}
align='center'
bg='brand.dark.900'
borderRadius='xl'
border='1px solid'
borderColor='brand.dark.800'
>
<Avatar size='md' name={member.username} />
<Box>
<Text fontWeight='bold'>{member.username}</Text>
{member.id === classroom.owner ? (
<Text fontSize='sm' color='brand.primary.400'>
Profesor
</Text>
) : (
<Text fontSize='sm' color='gray.400'>
Estudiante
</Text>
)}
</Box>
</Flex>
))}
</Grid>
)}
</Box>
</VStack>
</TabPanel>
Expand Down
Loading