Skip to main content
The class management system allows administrators to oversee all virtual English classes, assign learning activities, and track student progress.

Viewing All Classes

The main admin dashboard displays all virtual classes in the system.

Class Data Structure

Each virtual class contains:
id
string
Unique MongoDB ObjectId for the class
googleEventId
string
Google Calendar event ID for synchronization
bookedById
string
User ID of the class host/organizer
accessCode
string
8-character random code for class access
startTime
DateTime
Class start date and time
endTime
DateTime
Class end date and time
classType
enum
Either individual or grupal (group class)
maxParticipants
number
Maximum number of students allowed
currentParticipants
number
Current number of enrolled students
status
enum
Class status: scheduled, pending, completed, or cancelled
activityStatus
enum
Activity assignment status: uploaded or pending
Google Meet link for the virtual class
Schema Reference: prisma/schema.prisma:130-153

Filtering Classes

Administrators can filter classes by status:

Filter Options

  1. Scheduled Classes (?status=scheduled)
    • Shows upcoming and active classes
    • Classes with status “scheduled”
  2. Completed Classes (?status=completed)
    • Historical classes that have finished
    • Useful for analytics and reporting
  3. All Classes (default)
    • Displays every class regardless of status
    • Sorted by start time (descending)

Implementation

Server Action: src/app/(dashboard)/admin/actions.ts:6-20
export const getAllClasses = cache(async () => {
  try {
    const response = db.virtualClass.findMany({
      orderBy: {
        startTime: 'desc'
      }
    })
    return response
  } catch (error) {
    console.error('We could not retrieve the classes at this time', error)
  }
})
The getAllClasses function uses React’s cache() to optimize performance. Results are cached and don’t change with URL parameters.

Creating Activities

Administrators can create AI-powered learning activities for any scheduled class.

Activity Assignment Workflow

  1. Navigate to /admin/actividad/[classId]
  2. Fill out the activity creation form
  3. Submit to generate and assign the activity
  4. Students receive access to the activity after class completion

Activity Form Fields

classId
string
required
Virtual class ID (auto-populated, read-only)
title
string
required
Title of the exam or activity
description
string
required
Detailed description and instructions for the activity
difficulty
enum
required
Difficulty level: easy (inicial), medium (intermedio), or hard (avanzado)
type
enum
required
Activity type:
  • exam - Written examination
  • audio - Listening comprehension
  • video - Video-based activity
  • reading - Reading comprehension
content
string (Markdown)
required
Activity content in Markdown format (unsolved version)
solvedContent
string (Markdown)
required
Answer key/solved version in Markdown format
Form Implementation: src/app/(dashboard)/admin/actividad/[classId]/page.tsx:44-150

Activity Upload Process

When an activity is uploaded:

Step 1: Create Task

const newTask = await db.task.create({ data })
A new Task record is created with the activity content.

Step 2: Update UserActivity

All participants in the class receive the activity:
await db.userActivity.updateMany({
  where: {
    classId: classFound.id
  },
  data: {
    taskId: newTask.id,
    completed: false
  }
})

Step 3: Mark Activity as Uploaded

await db.virtualClass.update({
  where: { id: classFound?.id },
  data: {
    activityStatus: 'uploaded'
  }
});

Step 4: Increment Class Counter

Student total class count is incremented:
await db.user.updateMany({
  where: {
    id: { in: userIds }
  },
  data: {
    totalClasses: { increment: 1 }
  }
})
Full Implementation: src/app/(dashboard)/admin/actividad/[classId]/actions.ts:20-117
Activities can only be assigned once per class. After an activity is uploaded, the status changes from “Pendiente” (Pending) to “Enviada” (Sent) and the button is disabled.

Class Participants

Adding Participants

Users can join classes using an access code. The system handles:
  • Duplicate Prevention: Checks if user is already enrolled
  • Capacity Management: Enforces maxParticipants limit
  • Role Assignment: Distinguishes between host (anfitrion) and participants (participante)
Function: src/services/functions/index.ts:280-335

Participant Tracking

The participantsIds array stores all enrolled user IDs:
participantsIds: {
  push: userId
}
And current count is incremented:
currentParticipants: {
  increment: 1
}

Class Status Management

Status Workflow

  1. pending - Initial state after booking
  2. scheduled - After payment approval and calendar event creation
  3. completed - Class has finished
  4. cancelled - Class was cancelled
Enum Definition: prisma/schema.prisma:35-40

Access Codes

Each class receives a unique 8-character access code:
const randomCode = Math.random().toString(36).substring(2, 10).toUpperCase();
Students use this code to join group classes. Implementation: src/services/functions/index.ts:187

Google Meet Integration

Classes are automatically connected to Google Meet:
  • Meet links are stored in htmlLink field
  • Links are generated when calendar events are created
  • Synchronized with Google Calendar via admin’s refresh token
See Calendar Setup for configuration details.

User Activity Tracking

Monitor student progress through the UserActivity model

Payment Integration

Classes are created after successful payment

Build docs developers (and LLMs) love