);
}
=======================================
Here's the code for both CourseList.js and CourseForm.js components, designed to work with the backend API and token-based authentication you've set up earlier.
📄 /components/CourseList.js
This component fetches and displays all courses. It also supports delete/edit if the user is an admin.
// /components/CourseList.js
import React, { useEffect, useState } from 'react';
import api from '../api';
export default function CourseList({ isAdmin, onEdit }) {
const [courses, setCourses] = useState([]);
const fetchCourses = async () => {
try {
const res = await api.get('/courses');
setCourses(res.data);
} catch (err) {
console.error('Failed to fetch courses', err);
}
};
useEffect(() => {
fetchCourses();
}, []);
const handleDelete = async (id) => {
if (!window.confirm('Are you sure you want to delete this course?')) return;
try {
await api.delete(`/courses/${id}`);
fetchCourses();
} catch (err) {
console.error('Delete failed', err);
}
};
return (
Courses
{courses.map(course => (
{course.title}
{course.description}
{course.lectures.map((lec, i) => (
{lec.title} — {lec.videoUrl}
))}
{isAdmin && (
<>
>
)}
))}
);
}
📄 /components/CourseForm.js
This form is used by the admin to create or update courses, including multiple lectures.
// /components/CourseForm.js
import React, { useState, useEffect } from 'react';
import api from '../api';
export default function CourseForm({ selectedCourse, onSuccess }) {
const [title, setTitle] = useState('');
const [description, setDescription] = useState('');
const [lectures, setLectures] = useState([]);
useEffect(() => {
if (selectedCourse) {
setTitle(selectedCourse.title);
setDescription(selectedCourse.description);
setLectures(selectedCourse.lectures);
} else {
resetForm();
}
}, [selectedCourse]);
const resetForm = () => {
setTitle('');
setDescription('');
setLectures([]);
};
const addLecture = () => {
setLectures([...lectures, { title: '', videoUrl: '' }]);
};
const handleLectureChange = (index, field, value) => {
const updated = [...lectures];
updated[index][field] = value;
setLectures(updated);
};
const handleSubmit = async (e) => {
e.preventDefault();
const payload = { title, description, lectures };
try {
if (selectedCourse) {
await api.put(`/courses/${selectedCourse._id}`, payload);
} else {
await api.post('/courses', payload);
}
resetForm();
onSuccess(); // refresh list
} catch (err) {
console.error('Course save failed', err);
}
};
return (
{selectedCourse ? 'Edit Course' : 'Add New Course'}
);
}
✅ How to Use These Components
In your AdminDashboard.js, you can use both components like this:
import React, { useState } from 'react';
import CourseForm from '../components/CourseForm';
import CourseList from '../components/CourseList';
export default function AdminDashboard() {
const [selectedCourse, setSelectedCourse] = useState(null);
const [refreshKey, setRefreshKey] = useState(0);
const handleEdit = (course) => {
setSelectedCourse(course);
};
const handleSuccess = () => {
setSelectedCourse(null);
setRefreshKey(old => old + 1); // trigger list refresh
};
return (
Admin Dashboard
);
}
==============================
Great! Let's continue by setting up the rest of the React frontend:
✅ 1. StudentDashboard.js
This dashboard is for students to view courses only (no edit/delete options).
// /pages/StudentDashboard.js
import React from 'react';
import CourseList from '../components/CourseList';
export default function StudentDashboard() {
return (
Student Dashboard
);
}
Great! Let's continue by setting up the rest of the React frontend:
✅ 1. StudentDashboard.js
This dashboard is for students to view courses only (no edit/delete options).
// /pages/StudentDashboard.js
import React from 'react';
import CourseList from '../components/CourseList';
export default function StudentDashboard() {
return (
Student Dashboard
);
}
✅ 2. SignupPage.js
Allows users (students by default) to create an account.
// /pages/SignupPage.js
import React, { useState } from 'react';
import api from '../api';
import { useNavigate } from 'react-router-dom';
export default function SignupPage() {
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const navigate = useNavigate();
const signup = async () => {
try {
await api.post('/signup', { username, password });
alert('Signup successful. You can now login.');
navigate('/login');
} catch (err) {
alert('Signup failed');
}
};
return (
);
}
✅ 3. Logout.js (Component or Function)
This function clears the token and redirects the user.
// /utils/logout.js
export default function logout(navigate) {
localStorage.removeItem('token');
navigate('/login');
}
You can call it from any page like this:
import logout from '../utils/logout';
logout(navigate);
✅ 4. App.js with React Router
Set up routing for all pages and protect dashboard routes.
// App.js
import React from 'react';
import { BrowserRouter as Router, Route, Routes, Navigate } from 'react-router-dom';
import LoginPage from './pages/LoginPage';
import SignupPage from './pages/SignupPage';
import AdminDashboard from './pages/AdminDashboard';
import StudentDashboard from './pages/StudentDashboard';
function PrivateRoute({ children, role }) {
const token = localStorage.getItem('token');
const userRole = token ? JSON.parse(atob(token.split('.')[1])).role : null;
if (!token || userRole !== role) return ;
return children;
}
export default function App() {
return (
} />
} />
} />
} />
} />
);
}
✅ 5. Add Logout Button Example (optional)
You can add this to any dashboard:
import { useNavigate } from 'react-router-dom';
import logout from '../utils/logout';
const navigate = useNavigate();
✅ Final File Structure
/src
/components
CourseList.js
CourseForm.js
/pages
AdminDashboard.js
StudentDashboard.js
LoginPage.js
SignupPage.js
/utils
logout.js
api.js
App.js