Skip to main content

Overview

The learning experience is the core of SkillRise’s student platform. The player page (/player/{courseId}) combines a full-featured video player, organized chapter navigation, real-time progress tracking, and integrated quizzes into a seamless learning environment.

Player Page Layout

The player uses a responsive two-column layout: Player page showing video on left and chapter list on right Left Column (Video & Controls)
  • Custom video player with full controls
  • Current lecture information card
  • Mark complete button
  • Course rating widget
Right Column (Navigation)
  • Progress bar with percentage
  • Certificate button (when complete)
  • Collapsible chapter list
  • Quiz buttons per chapter
On mobile, the layout stacks vertically with the video player taking full width.

Video Player Component

SkillRise features a custom-built video player with professional controls:

Player Features

Playback Controls

  • Play/Pause toggle
  • 10-second skip forward/backward
  • Seek bar with progress indicator
  • Keyboard shortcuts (Space, Arrow keys)

Audio Controls

  • Mute/unmute toggle
  • Volume slider (0-100%)
  • Visual volume level indicator
  • Persists across lectures

Speed Control

  • 0.5× to 2× playback speeds
  • 6 preset options
  • Dropdown selector
  • Smooth speed transitions

Display Options

  • Fullscreen mode
  • Quality selector (Auto, 1080p, 720p, 480p, 360p, 240p)
  • Auto-hide controls when playing
  • Responsive aspect ratio

Custom Controls Implementation

The player uses ReactPlayer as the video engine but implements custom controls:
<ReactPlayer
  ref={playerRef}
  url={lectureUrl}
  playing={playing}
  volume={volume}
  muted={muted}
  playbackRate={speed}
  controls={false} // Custom controls only
  width="100%"
  height="100%"
  onProgress={handleProgress}
  onDuration={handleDuration}
/>

Keyboard Shortcuts

Play/Pause ToggleQuick start/stop without mouse interaction
if (e.key === ' ') {
  e.preventDefault()
  togglePlay()
}

Skip Hint Overlay

When using keyboard shortcuts, a visual hint appears:
// User presses → arrow
<div className="skip-hint">
  +10s
</div>
// Fades after 700ms
Video player showing +10s skip hint overlay

Lecture Selection

Chapter Structure Display

Courses are organized into chapters, each containing multiple lectures:
Course
├── Chapter 1: Introduction
│   ├── Lecture 1: Welcome
│   ├── Lecture 2: Setup
│   └── Lecture 3: Overview
├── Chapter 2: Core Concepts
│   ├── Lecture 1: Basics
│   └── Lecture 2: Advanced

Chapter Accordion

The sidebar displays collapsible chapters:
  • Chapter header - Click to expand/collapse
  • Lecture count - Number of lessons in chapter
  • Chevron icon - Rotates when expanded
  • Lecture list - Shows when chapter is open

Lecture Items

Each lecture in the list shows:
1

Completion Icon

  • ✓ Green checkmark if completed
  • ▶ Play icon if not completed
2

Lecture Title

Truncated with ellipsis if too long
3

Duration

Formatted as “Xh Ym” or “Xm”
4

Active State

Currently playing lecture has teal background

Auto-selection Logic

When opening a course, the player intelligently selects a lecture:
// 1. Check localStorage for last played
const saved = localStorage.getItem(`lastPlayed_${courseId}`)
if (saved) {
  setPlayerData(JSON.parse(saved))
  return
}

// 2. Find first uncompleted lecture
for (let chapter of courseContent) {
  for (let lecture of chapter.lectures) {
    if (!completed.includes(lecture.id)) {
      return lecture
    }
  }
}

// 3. Default to first lecture
return courseContent[0].lectures[0]

Progress Tracking

Progress Bar

The top of the sidebar shows overall course progress: Progress card showing 67% completion with progress bar Displays:
  • “Your progress” label - Section header
  • Percentage - Bold, teal number (e.g., “67%”)
  • Progress bar - Visual indicator with smooth animation
  • Lecture count - “12 of 18 lectures completed”
Progress calculation:
const completedCount = progressData.lectureCompleted.length
const totalLectures = courseData.totalLectures
const progressPct = Math.round((completedCount / totalLectures) * 100)

Mark Complete Button

Below the video player, a card shows the current lecture with a completion button: Button States:
<button className="bg-teal-600 hover:bg-teal-700">
  Mark Complete
</button>
Primary teal button, enabled

Progress API Call

Marking a lecture complete triggers:
POST /api/user/update-course-progress
{
  courseId: "...",
  lectureId: "..."
}

Response:
{
  success: true,
  message: "Lecture marked as completed",
  isCourseCompleted: true, // If last lecture
  certificateAvailable: true
}
When the last lecture is completed:
  • Success toast: “Course completed. Certificate ready.”
  • Certificate button appears in sidebar
  • Progress bar animates to 100%

Quiz Integration

Chapter Quiz Unlock

Quiz buttons appear when all lectures in a chapter are marked complete:
if (chapter.lectures.every(lec => 
  progressData.lectureCompleted.includes(lec.id)
)) {
  // Show quiz button
}

Quiz Button Display

Quiz button with results badge showing last score Button variations:
<button className="bg-indigo-600">
  <QuizIcon />
  Take Chapter Quiz
</button>

Quiz Result Badges

After taking a quiz, a colored badge shows the result:

Mastered

76-100%Green badge: ”🏆 Mastered”

On Track

41-75%Yellow badge: ”🎯 On Track”

Needs Review

0-40%Red badge: ”📖 Needs Review”

Rating System

Below the lecture controls, students can rate the course:

Rating Widget

5-star rating widget with interactive stars Features:
  • 5 interactive stars - Click to rate 1-5
  • Hover preview - Stars light up on hover
  • Current rating - Pre-filled if user already rated
  • Instant update - Saves on click

Rating Persistence

const handleRating = async (rating) => {
  POST /api/user/add-rating
  { courseId, rating }
  
  // Updates course average rating
  // Stores in user's rating array
  // Shows success toast
}
Users can change their rating at any time.

Certificate Generation

Certificate Button

When course is 100% complete, a certificate card appears:
{progressPct === 100 && (
  <div className="certificate-card">
    <p className="font-semibold">Certificate</p>
    <p className="text-xs">View your course completion certificate.</p>
    <button onClick={viewCertificate}>
      {loading ? 'Opening...' : 'View Certificate'}
    </button>
  </div>
)}

Certificate Download Flow

1

Request Certificate

GET /api/user/certificate/{courseId}
2

Backend Generation

  • Verifies 100% completion
  • Generates PDF with student name, course title, date
  • Uploads to cloud storage
  • Returns PDF URL
3

Open in New Tab

if (data.pdfUrl) {
  window.open(data.pdfUrl, '_blank', 'noopener,noreferrer')
}
Certificates are generated on-demand and cached. First request may take 2-3 seconds while the PDF is created.

Persistence Features

Last Played Lecture

The player remembers where you left off:
// Save on lecture change
localStorage.setItem(`lastPlayed_${courseId}`, JSON.stringify({
  ...lecture,
  chapter: chapterIndex + 1,
  lecture: lectureIndex + 1,
  chapterIndex
}))

// Restore on page load
const saved = localStorage.getItem(`lastPlayed_${courseId}`)
if (saved) {
  setPlayerData(JSON.parse(saved))
  setOpenSections({ [data.chapterIndex]: true })
}
Benefits:
  • Resume exactly where you stopped
  • Works across browser sessions
  • Chapter auto-expands to show current lecture

Video Playback Position

ReactPlayer maintains playback position during:
  • Speed changes
  • Quality adjustments
  • Fullscreen toggles
  • Volume modifications

Mobile Experience

Responsive Layout

Two columns side-by-side
  • Video player: 60% width
  • Sidebar: 40% width (sticky)

Touch Optimizations

  • Large touch targets - All buttons 44px+ height
  • Swipe gestures - Disabled to prevent conflicts
  • Auto-hide controls - 2.5 second delay
  • Tap to show controls - Single tap reveals interface

Performance Optimizations

Video player only initializes when component mounts. ReactPlayer handles lazy loading of video source.
Progress percentages and completion states are memoized to prevent recalculation on every render.
Progress bar only updates every 100ms during playback to reduce re-renders.
Mark complete button updates UI immediately, API call happens in background.

Accessibility Features

Keyboard navigation for all video controls
ARIA labels on interactive elements
Focus management for modal dialogs
Screen reader announcements for state changes
Sufficient color contrast (WCAG AA compliant)