From 131523d0abadbed7ff0dc91dd1ffcb755d64a9bb Mon Sep 17 00:00:00 2001 From: pedram karimi Date: Fri, 13 Jun 2025 13:56:07 -0400 Subject: [PATCH 1/4] admin page --- middlewareNode/routes/auth.js | 4 +- middlewareNode/routes/users.js | 144 +- react-ystemandchess/src/App.tsx | 36 +- react-ystemandchess/src/AppRoutes.tsx | 105 +- react-ystemandchess/src/Pages/Admin/Admin.tsx | 188 +++ react-ystemandchess/src/Pages/Login/Login.tsx | 124 +- .../Pages/Mentor-Profile/MentorProfile.tsx | 1471 +++++++++++------ .../NewMentorProfile/NewMentorProfile.tsx | 361 ++-- .../NewStudentProfile/NewStudentProfile.tsx | 330 ++-- .../Reset-Password/resetPasswordService.ts | 23 +- .../src/Pages/SignUp/SignUp.tsx | 211 +-- .../src/Pages/Student-Profile/UserProfile.tsx | 484 ++++-- .../src/Pages/Student/Student.tsx | 54 +- .../lesson-overlay/lesson-overlay.test.tsx | 144 +- .../lesson-overlay/lesson-overlay.tsx | 1252 +++++++------- react-ystemandchess/src/globals.ts | 6 +- 16 files changed, 3060 insertions(+), 1877 deletions(-) create mode 100644 react-ystemandchess/src/Pages/Admin/Admin.tsx diff --git a/middlewareNode/routes/auth.js b/middlewareNode/routes/auth.js index c66587e3..18537ea2 100644 --- a/middlewareNode/routes/auth.js +++ b/middlewareNode/routes/auth.js @@ -73,7 +73,7 @@ router.post( function (err, token) { if (err) throw err; res.json({ token }); - }, + } ); return jwt; //Return the encrypted jwt @@ -81,7 +81,7 @@ router.post( console.error(error.message); res.status(500).send("Server error"); } - }, + } ); module.exports = router; diff --git a/middlewareNode/routes/users.js b/middlewareNode/routes/users.js index 91bea764..197163ac 100644 --- a/middlewareNode/routes/users.js +++ b/middlewareNode/routes/users.js @@ -2,6 +2,7 @@ const express = require("express"); const passport = require("passport"); const router = express.Router(); const crypto = require("crypto"); +const jwt = require("jsonwebtoken"); const { check, validationResult } = require("express-validator"); const users = require("../models/users"); const { @@ -9,14 +10,15 @@ const { } = require("../template/changePasswordTemplate"); const { sendMail } = require("../utils/nodemailer"); const { validator } = require("../utils/middleware"); -const { MongoClient } = require('mongodb'); +const { MongoClient } = require("mongodb"); const config = require("config"); let cachedClient = null; // cache db client to prevent repeated connections // get db client async function getDb() { - if (!cachedClient) { // if not cached, connect + if (!cachedClient) { + // if not cached, connect cachedClient = new MongoClient(config.get("mongoURI")); await cachedClient.connect(); } @@ -84,7 +86,6 @@ router.post( //Set the account created date for the new user const currDate = new Date(); - //Switch statement for functionality depending on role if (role === "parent") { let studentsArray = JSON.parse(students); @@ -118,7 +119,7 @@ router.post( timePlayed: 0, }); await newStudent.save(); - }), + }) ); } } @@ -138,7 +139,7 @@ router.post( console.error(error.message); res.status(500).json("Server error"); } - }, + } ); // @route POST /user/children @@ -194,7 +195,7 @@ router.post( console.error(error.message); res.status(500).json("Server error"); } - }, + } ); // @route POST /user/sendMail // @desc sending the mail based on username and email @@ -247,7 +248,7 @@ const updatePassword = async (body) => { const result = await users.findOneAndUpdate( { username: body.username, email: body.email }, { password: body.password }, - { new: true }, + { new: true } ); return result; }; @@ -255,17 +256,19 @@ const updatePassword = async (body) => { // @route GET /user/mentorless/:keyword // @desc for getting the mentorless students whose username matches keyword. router.get("/mentorless", async (req, res) => { - const keyword = req.query.keyword || ''; // get the keyword + const keyword = req.query.keyword || ""; // get the keyword try { const db = await getDb(); const users = db.collection("users"); - const userList = await users.find({ - role: 'student',// get student - username: { $regex: keyword, $options: 'i' }, // case-insensitive match for username - mentorshipUsername: { $ne: "" } - }).toArray();; - res.json(userList.map(user => user.username)); // return a list of the usernames + const userList = await users + .find({ + role: "student", // get student + username: { $regex: keyword, $options: "i" }, // case-insensitive match for username + mentorshipUsername: { $ne: "" }, + }) + .toArray(); + res.json(userList.map((user) => user.username)); // return a list of the usernames } catch (err) { res.status(500).json({ error: err.message }); // error } @@ -276,21 +279,28 @@ router.get("/mentorless", async (req, res) => { // @desc if user is mentor, update its student username to the mentorship= query // @access Public with jwt Authentication router.put( - "/updateMentorship", + "/updateMentorship", async (req, res, next) => { - passport.authenticate("jwt", { session: false }, async (err, user, info) => { - if (!user) { - return res.status(401).json({ message: "Unauthorized" }); + passport.authenticate( + "jwt", + { session: false }, + async (err, user, info) => { + if (!user) { + return res.status(401).json({ message: "Unauthorized" }); + } + req.user = user; + next(); } - req.user = user; - next(); - })(req, res, next) // authenticate jwt - }, + )(req, res, next); // authenticate jwt + }, async (req, res) => { // get the student/mentor username const mentorship = req.query.mentorship; - if (!mentorship) { // mentorship query is required - return res.status(400).json({ message: "Missing mentorship username in query" }); + if (!mentorship) { + // mentorship query is required + return res + .status(400) + .json({ message: "Missing mentorship username in query" }); } try { @@ -305,30 +315,37 @@ router.put( // if mentorship field is not modified if (result.modifiedCount === 0) { - return res.status(404).json({ message: "User not found or already has that mentorshipUsername" }); + return res.status(404).json({ + message: "User not found or already has that mentorshipUsername", + }); } res.json({ message: "Mentorship updated successfully" }); } catch (err) { res.status(500).json({ error: err.message }); // error } - } + } ); // @route GET /user/getMentorship // @desc if user is a student, responds with its mentor's object {username, firstName, lastName} // @desc if user is a mentor, responds with its student's object {username, firstName, lastName} // @access Public with jwt Authentication -router.get("/getMentorship", +router.get( + "/getMentorship", async (req, res, next) => { - passport.authenticate("jwt", { session: false }, async (err, user, info) => { - if (!user) { - return res.status(401).json({ message: "Unauthorized" }); + passport.authenticate( + "jwt", + { session: false }, + async (err, user, info) => { + if (!user) { + return res.status(401).json({ message: "Unauthorized" }); + } + req.user = user; + next(); } - req.user = user; - next(); - })(req, res, next) // authenticate jwt - }, + )(req, res, next); // authenticate jwt + }, async (req, res) => { try { const db = await getDb(); @@ -356,4 +373,63 @@ router.get("/getMentorship", } ); +router.get("/getStudent", async (req, res) => { + const keyword = req.query.keyword || ""; + + try { + const db = await getDb(); + const users = db.collection("users"); + + const userList = await users + .find({ + role: "student", // get student + username: { $regex: keyword, $options: "i" }, // case-insensitive match for username + }) + .toArray(); + + res.json(userList.map((user) => user.username)); // return a list of the usernames + } catch (err) { + res.status(500).json({ error: err.message }); // error + } +}); + +// verify role + +router.post("/verifyRole", async (req, res) => { + const { token } = req.body; + + if (!token) { + return res.status(400).json({ error: "Missing token" }); + } + + const decoded = jwt.verify(token.login, config.get("indexKey")); + + const user = await users + .findOne({ username: decoded.username }) + .select("role"); + + if (!user) { + return res.status(404).json({ error: "User not found" }); + } + console.log(decoded.role, user.role); + if (decoded.role === user.role) { + return res.json({ verified: true }); + } else { + return res.status(403).json({ error: "Role mismatch", verified: false }); + } +}); + +router.get("/getUser", async (req, res) => { + const username = req.query.username || ""; + try { + const user = await users.findOne({ username }).select("-password"); + if (!user) { + return res.status(404).json({ error: "User not found" }); + } + return res.status(200).json(user); + } catch (err) { + return res.status(401).json({ error: err }); + } +}); + module.exports = router; diff --git a/react-ystemandchess/src/App.tsx b/react-ystemandchess/src/App.tsx index 4299327d..f584361e 100644 --- a/react-ystemandchess/src/App.tsx +++ b/react-ystemandchess/src/App.tsx @@ -1,15 +1,15 @@ import "./App.css"; import React, { useEffect } from "react"; import { BrowserRouter as Router } from "react-router-dom"; -import { environment } from './environments/environment'; -import { useCookies } from 'react-cookie'; -import { SetPermissionLevel } from './globals'; +import { environment } from "./environments/environment"; +import { useCookies } from "react-cookie"; +import { SetPermissionLevel } from "./globals"; import NavBar from "./NavBar/NavBar"; import Footer from "./Footer/Footer"; import AppRoutes from "./AppRoutes"; function App() { - const [cookies] = useCookies(['login']); // get login info from cookie + const [cookies] = useCookies(["login"]); // get login info from cookie let username = null; let eventID = null; let startTime = null; @@ -19,18 +19,18 @@ function App() { const uInfo = await SetPermissionLevel(cookies); // get logged-in user info // do nothing if the user is not logged in - if(uInfo.error) return; + if (uInfo.error) return; username = uInfo.username; // else record username // start recording user's time spent browsing the website const response = await fetch( - `${environment.urls.middlewareURL}/timeTracking/start?username=${username}&eventType=website`, + `${environment.urls.middlewareURL}/timeTracking/start?username=${username}&eventType=website`, { - method: 'POST', - headers: { 'Authorization': `Bearer ${cookies.login}` } + method: "POST", + headers: { Authorization: `Bearer ${cookies.login}` }, } ); - if(response.status != 200) console.log(response) // error handling + if (response.status != 200) console.log(response); // error handling // if data is fetched, record for later updates const data = await response.json(); @@ -41,22 +41,22 @@ function App() { // handler called when user exist the website, complete recording time const handleUnload = async () => { try { - const startDate = new Date(startTime) + const startDate = new Date(startTime); const endDate = new Date(); const diffInMs = endDate.getTime() - startDate.getTime(); // time elapsed in milliseconds const diffInSeconds = Math.floor(diffInMs / 1000); // time elapsed in seconds // update the time users spent browsing website const response = await fetch( - `${environment.urls.middlewareURL}/timeTracking/update?username=${username}&eventType=website&eventId=${eventID}&totalTime=${diffInSeconds}`, + `${environment.urls.middlewareURL}/timeTracking/update?username=${username}&eventType=website&eventId=${eventID}&totalTime=${diffInSeconds}`, { - method: 'PUT', - headers: { 'Authorization': `Bearer ${cookies.login}` } + method: "PUT", + headers: { Authorization: `Bearer ${cookies.login}` }, } ); - if(response.status != 200) console.log(response) // error handling + if (response.status != 200) console.log(response); // error handling } catch (err) { - console.log(err) + console.log(err); } }; @@ -64,12 +64,12 @@ function App() { try { startRecording(); // start recording } catch (err) { - console.log(err) + console.log(err); } - window.addEventListener('beforeunload', handleUnload); // end recording when unloading + window.addEventListener("beforeunload", handleUnload); // end recording when unloading return () => { - window.removeEventListener('beforeunload', handleUnload); + window.removeEventListener("beforeunload", handleUnload); }; }, []); diff --git a/react-ystemandchess/src/AppRoutes.tsx b/react-ystemandchess/src/AppRoutes.tsx index af2b4af9..da1f2047 100644 --- a/react-ystemandchess/src/AppRoutes.tsx +++ b/react-ystemandchess/src/AppRoutes.tsx @@ -1,61 +1,63 @@ // Imports for React Components/Pages -import React from 'react'; -import { Route, Router, Routes } from 'react-router-dom'; -import Home from './Pages/Home/Home'; -import Programs from './Pages/Programs/Programs'; -import CSBenefitPage from './Pages/About-Us/Benefit-of-CS/CSBenefitPage'; -import ChessBenefitPage from './Pages/About-Us/Benefit-of-Chess/ChessBenefitPage'; -import MathTutBenefitPage from './Pages/About-Us/Benefit-of-Math-tut/MathTutBenefitPage'; -import MentoringBenefitPage from './Pages/About-Us/Benefit-of-Mentoring/MentoringBenefitPage'; -import Lessons from './Pages/Lessons/Lessons'; -import Login from './Pages/Login/Login'; -import SignUp from './Pages/SignUp/SignUp'; -import Mission from './Pages/About-Us/Mission/Mission'; -import SponsorsPartners from './Pages/About-Us/SponsorsPartners/SponsorsPartners'; -import Board from './Pages/About-Us/Board/Board'; -import Mentor from './Pages/Mentor/Mentor'; -import Financial from './Pages/About-Us/Financial/Financial'; -import StudentInventory from './Pages/Student-Inventory/StudentInventory'; -import ResetPassword from './Pages/Reset-Password/reset-password'; -import SetPassword from './Pages/Set-Password/set-password'; -import Student from './Pages/Student/Student'; +import React from "react"; +import { Route, Router, Routes } from "react-router-dom"; +import Home from "./Pages/Home/Home"; +import Programs from "./Pages/Programs/Programs"; +import CSBenefitPage from "./Pages/About-Us/Benefit-of-CS/CSBenefitPage"; +import ChessBenefitPage from "./Pages/About-Us/Benefit-of-Chess/ChessBenefitPage"; +import MathTutBenefitPage from "./Pages/About-Us/Benefit-of-Math-tut/MathTutBenefitPage"; +import MentoringBenefitPage from "./Pages/About-Us/Benefit-of-Mentoring/MentoringBenefitPage"; +import Lessons from "./Pages/Lessons/Lessons"; +import Login from "./Pages/Login/Login"; +import SignUp from "./Pages/SignUp/SignUp"; +import Mission from "./Pages/About-Us/Mission/Mission"; +import SponsorsPartners from "./Pages/About-Us/SponsorsPartners/SponsorsPartners"; +import Board from "./Pages/About-Us/Board/Board"; +import Mentor from "./Pages/Mentor/Mentor"; +import Financial from "./Pages/About-Us/Financial/Financial"; +import StudentInventory from "./Pages/Student-Inventory/StudentInventory"; +import ResetPassword from "./Pages/Reset-Password/reset-password"; +import SetPassword from "./Pages/Set-Password/set-password"; +import Student from "./Pages/Student/Student"; // import MentorProfile from './Pages/Mentor-Profile/MentorProfile'; -import NewMentorProfile from './Pages/NewMentorProfile/NewMentorProfile'; -import NewStudentProfile from './Pages/NewStudentProfile/NewStudentProfile'; -import AboutUs from './Pages/About-Us/AboutUs/AboutUs'; -import LessonSelection from "./Pages/LessonsSelection/LessonsSelection" +import NewMentorProfile from "./Pages/NewMentorProfile/NewMentorProfile"; +import NewStudentProfile from "./Pages/NewStudentProfile/NewStudentProfile"; +import AboutUs from "./Pages/About-Us/AboutUs/AboutUs"; +import LessonSelection from "./Pages/LessonsSelection/LessonsSelection"; import LessonOverlay from "./Pages/piece-lessons/lesson-overlay/lesson-overlay"; // Variables and Mutable Data -import userPortraitImg from './images/user-portrait-placeholder.svg'; -const userName = 'Nimesh Patel'; +import userPortraitImg from "./images/user-portrait-placeholder.svg"; +import Admin from "./Pages/Admin/Admin"; +const userName = "Nimesh Patel"; const AppRoutes = () => { // All components must be wrapped with the '' tag return ( - } /> - } /> - } /> - } /> + } /> + } /> + } /> + } /> } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> { } /> - } /> - } + } /> + } + /> + } /> - } /> - } /> + } /> } /> diff --git a/react-ystemandchess/src/Pages/Admin/Admin.tsx b/react-ystemandchess/src/Pages/Admin/Admin.tsx new file mode 100644 index 00000000..d671587b --- /dev/null +++ b/react-ystemandchess/src/Pages/Admin/Admin.tsx @@ -0,0 +1,188 @@ +import React, { useEffect, useState } from "react"; +import { useNavigate } from "react-router-dom"; +import { useCookies } from "react-cookie"; +import { environment } from "../../environments/environment"; +const Admin = () => { + const navigate = useNavigate(); + // verify admin status + const [cookies, setCookie] = useCookies(["login"]); + + // search input + const [searchInput, setSearchInput] = useState(); + + const [error, setError] = useState(); + + // students + const [studentNames, setStudentNames] = useState<[string] | undefined>(); + + // can't find the User type in global.d.ts + const [students, setStudents] = useState([]); + // temporary + const [verified, setVerified] = useState(false); + + //. + //. + useEffect(() => { + // server url + let url = `${environment.urls.middlewareURL}/user/verifyRole`; + const verifyAdmin = async () => { + try { + const token = cookies; // Read JWT from cookie + if (!token) throw new Error("No token"); + + const response = await fetch(url, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + token, + claimedRole: "admin", + }), + }); + const data = await response.json(); + if (response.ok) { + setVerified(data.verified); + } else { + throw new Error(data.error || "Role verification failed"); + } + + // User is verified as admin + } catch (err) { + console.error("Access denied:", err.message); + navigate("/"); + } + }; + verifyAdmin(); + }, []); + + // search + const handleStudentSearch = async () => { + if (!verified) { + navigate("/"); + return; + } + setStudentNames(undefined); + setStudents([]); + let url = `${environment.urls.middlewareURL}/user/getStudent?keyword=${searchInput}`; + try { + const response = await fetch(url, { + method: "GET", + headers: { + "Content-Type": "application/json", + }, + }); + + // Throws an error if the response status is failure. + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + const data = await response.json(); + console.log(data, "--->"); + setStudentNames(data); + } catch { + console.error("Search error:", error); + // Sets a general error message for signup failure. + setError("Search failed"); + } + }; + + // get basic info about found students + useEffect(() => { + if (!studentNames) { + return; + } + for (let i = 0; i < studentNames.length; i++) { + let url = `${environment.urls.middlewareURL}/user/getUser?username=${studentNames[i]}`; + try { + const getUser = async () => { + const response = await fetch(url, { + method: "GET", + headers: { + "Content-Type": "application/json", + }, + }); + const data = await response.json(); + setStudents((prevStudent) => [...prevStudent, data]); + }; + getUser(); + } catch (err) { + console.log(err); + } + } + }, [studentNames]); + return ( +
+
{ + e.preventDefault(); + handleStudentSearch(); + }} + > + { + setSearchInput(e.target.value); + }} + placeholder="Type student username to search" + /> + +
+ {/* students searched */} +
+
+
+
+ {students.map((student) => ( +
{ + // to the student's profile + }} + > +
+

+ {student.firstName} {student.lastName}{" "} + + ({student.username}) + +

+ + Role: {student.role} + +
+

+ Email: {student.email} +

+

+ Account Created: {student.accountCreatedAt} +

+

+ Lessons Completed: {student.lessonsCompleted.length} +

+

+ Time Played: {student.timePlayed} mins +

+
+ ))} +
+
+
+
+
+ ); +}; + +export default Admin; diff --git a/react-ystemandchess/src/Pages/Login/Login.tsx b/react-ystemandchess/src/Pages/Login/Login.tsx index fd713488..814bca07 100644 --- a/react-ystemandchess/src/Pages/Login/Login.tsx +++ b/react-ystemandchess/src/Pages/Login/Login.tsx @@ -1,15 +1,15 @@ -import React from 'react'; +import React from "react"; // import { Link } from 'react-router-dom'; -import './Login.scss'; -import { useState } from 'react'; -import { environment } from '../../environments/environment'; -import { useCookies } from 'react-cookie'; +import "./Login.scss"; +import { useState } from "react"; +import { environment } from "../../environments/environment"; +import { useCookies } from "react-cookie"; const Login = () => { - const [username, setUsername] = useState(''); - const [password, setPassword] = useState(''); - const [cookies, setCookie] = useCookies(['login']); - const [loginError, setLoginError] = useState(''); + const [username, setUsername] = useState(""); + const [password, setPassword] = useState(""); + const [cookies, setCookie] = useCookies(["login"]); + const [loginError, setLoginError] = useState(""); const [usernameFlag, setUsernameFlag] = useState(false); const [passwordFlag, setPasswordFlag] = useState(false); @@ -25,16 +25,16 @@ const Login = () => { if (password.length < 8) { setPasswordFlag(false); } else { - console.log('verifying pw') + console.log("verifying pw"); setPasswordFlag(true); } }; const errorMessages = () => { if (passwordFlag === false || usernameFlag === false) { - setLoginError('Invalid username or password'); + setLoginError("Invalid username or password"); } else { - setLoginError(''); + setLoginError(""); } }; @@ -42,10 +42,10 @@ const Login = () => { e.preventDefault(); // errorMessages(); if (password.length < 8 || username.length <= 2) { - setLoginError('Invalid username or password'); + setLoginError("Invalid username or password"); return; } else { - setLoginError(''); + setLoginError(""); } let url = `${environment.urls.middlewareURL}/auth/login?username=${username}&password=${password}`; @@ -63,56 +63,60 @@ const Login = () => { } } }; - xmlHttp.open('POST', theUrl, true); + xmlHttp.open("POST", theUrl, true); xmlHttp.send(null); }; - httpGetAsync(url, (response: any) => { - if (response === 'The username or password is incorrect.') { - setLoginError('The username or password is incorrect.'); - } else { - const expires = new Date(); - expires.setDate(expires.getDate() + 1); - setCookie('login', JSON.parse(response).token, { expires }); + httpGetAsync( + url, + (response: any) => { + if (response === "The username or password is incorrect.") { + setLoginError("The username or password is incorrect."); + } else { + const expires = new Date(); + expires.setDate(expires.getDate() + 1); + setCookie("login", JSON.parse(response).token, { expires }); - let payload = JSON.parse(atob(response.split('.')[1])); - console.log(payload) + let payload = JSON.parse(atob(response.split(".")[1])); + console.log(payload); - switch (payload['role']) { - case 'student': - window.location.pathname = '/student-profile'; - console.log(payload['role']) - break; - case 'parent': - window.location.pathname = '/parent'; - break; - case 'mentor': - window.location.pathname = '/mentor-profile'; - break; - case 'admin': - window.location.pathname = '/admin'; - break; - default: - window.location.pathname = ''; + switch (payload["role"]) { + case "student": + window.location.pathname = "/student-profile"; + console.log(payload["role"]); + break; + case "parent": + window.location.pathname = "/parent"; + break; + case "mentor": + window.location.pathname = "/mentor-profile"; + break; + case "admin": + window.location.pathname = "/admin"; + break; + default: + window.location.pathname = ""; + } } + }, + () => { + setLoginError("The username or password is incorrect."); } - }, () => { - setLoginError('The username or password is incorrect.'); - }); + ); }; return ( <> -

Login

- {loginError &&

{loginError}

} +

Login

+ {loginError &&

{loginError}

} -
-
+ +
{ setUsername(e.target.value); @@ -121,12 +125,12 @@ const Login = () => { required />
-
+
{ setPassword(e.target.value); @@ -135,16 +139,16 @@ const Login = () => { required />
- -
- + diff --git a/react-ystemandchess/src/Pages/Mentor-Profile/MentorProfile.tsx b/react-ystemandchess/src/Pages/Mentor-Profile/MentorProfile.tsx index feda8468..a7b40e34 100644 --- a/react-ystemandchess/src/Pages/Mentor-Profile/MentorProfile.tsx +++ b/react-ystemandchess/src/Pages/Mentor-Profile/MentorProfile.tsx @@ -1,9 +1,9 @@ -import React, { useState, useEffect } from 'react'; -import { useCookies } from 'react-cookie'; -import './MentorProfile.scss'; // Import the SCSS file for styles -import { environment } from '../../environments/environment'; -import ViewSDKClient from '../../services/view-sdk.service'; // Adjust the path as necessary -import { SetPermissionLevel } from '../../globals'; // Adjust the path as necessary +import React, { useState, useEffect } from "react"; +import { useCookies } from "react-cookie"; +import "./MentorProfile.scss"; // Import the SCSS file for styles +import { environment } from "../../environments/environment"; +import ViewSDKClient from "../../services/view-sdk.service"; // Adjust the path as necessary +import { SetPermissionLevel } from "../../globals"; // Adjust the path as necessary type PdfItem = { id: string; @@ -11,541 +11,972 @@ type PdfItem = { FilePath: string; }; -type Record = { +type Record = { sid: string; meetingId: string; meetingStartTime: string; [key: string]: any; // This allows any other fields to be added with any type -} - +}; const MentorProfile = () => { - const [username, setUsername] = useState(''); - const [firstName, setFirstName] = useState(''); - const [lastName, setLastName] = useState(''); - const [accountCreatedAt, setAccountCreatedAt] = useState(''); - const [role, setRole] = useState(''); - const [logged, setLogged] = useState(false); - const [recordingList, setRecordingList] = useState([]); - const [signedURL, setSignedURL] = useState(''); - const [showData, setShowData] = useState(false); - const [categoryList, setCategoryList] = useState([ - { id: '1', name: 'Mantra' }, - { id: '2', name: 'Exercise' }, - { id: '3', name: 'One Personal Development Lesson' }, - { id: '4', name: 'Chess Lesson' }, - { id: '5', name: 'Game' }, - { id: '6', name: 'Puzzles' }, - ]); - const [sharedPdfList, setSharedPdfList] = useState([]); - const [categoryName, setCategoryName] = useState(''); - const [showPdfListView, setShowPdfListView] = useState(false); - const [cookies] = useCookies(['login']); - - useEffect(() => { - ViewSDKClient.ready().then(() => { - ViewSDKClient.previewFile( - '../../../assets/pdf/mentor/Y_STEM_Chess_Training_Lessons.pdf', - 'pdf-div', - { - embedMode: 'SIZED_CONTAINER', - dockPageControls: false, - } - ); - }); - - const fetchUserInfo = async () => { - const uInfo = await SetPermissionLevel(cookies); - setUsername(uInfo.username); - setFirstName(uInfo.firstName); - setLastName(uInfo.lastName); - setAccountCreatedAt(uInfo.accountCreatedAt); - setRole(uInfo.role); - - // Wait for the DOM to be fully updated before accessing elements - setTimeout(() => { - const defaultOpen = document.getElementById('defaultOpen'); - const student3 = document.getElementById('student3'); - const defaultOpen2 = document.getElementById('defaultOpen2'); - const defaultOpenStudent = document.getElementById('defaultOpenStudent'); - - if (defaultOpen) defaultOpen.click(); - if (student3) student3.click(); - if (defaultOpen2) defaultOpen2.click(); - if (defaultOpenStudent) defaultOpenStudent.click(); - }, 0); - - if (!uInfo.error) { - setLogged(true); - } - - if (uInfo.role === 'mentor') { - fetchRecordings(); + const [username, setUsername] = useState(""); + const [firstName, setFirstName] = useState(""); + const [lastName, setLastName] = useState(""); + const [accountCreatedAt, setAccountCreatedAt] = useState(""); + const [role, setRole] = useState(""); + const [logged, setLogged] = useState(false); + const [recordingList, setRecordingList] = useState([]); + const [signedURL, setSignedURL] = useState(""); + const [showData, setShowData] = useState(false); + const [categoryList, setCategoryList] = useState([ + { id: "1", name: "Mantra" }, + { id: "2", name: "Exercise" }, + { id: "3", name: "One Personal Development Lesson" }, + { id: "4", name: "Chess Lesson" }, + { id: "5", name: "Game" }, + { id: "6", name: "Puzzles" }, + ]); + const [sharedPdfList, setSharedPdfList] = useState([]); + const [categoryName, setCategoryName] = useState(""); + const [showPdfListView, setShowPdfListView] = useState(false); + const [cookies] = useCookies(["login"]); + + useEffect(() => { + ViewSDKClient.ready().then(() => { + ViewSDKClient.previewFile( + "../../../assets/pdf/mentor/Y_STEM_Chess_Training_Lessons.pdf", + "pdf-div", + { + embedMode: "SIZED_CONTAINER", + dockPageControls: false, } - }; - - fetchUserInfo(); - }, []); - - const fetchRecordings = () => { - const url = `${environment.urls.middlewareURL}/meetings/usersRecordings`; - fetch(url, { - method: 'GET', - headers: { - 'Authorization': `Bearer ${cookies.login}`, - }, - }) - .then((response) => response.json()) - .then((data) => { - setRecordingList(data); - }); - }; - - const openTab = (evt: React.MouseEvent, tabName: string, className: string) => { - const tabcontent = document.getElementsByClassName(className); - for (let i = 0; i < tabcontent.length; i++) { - const element = tabcontent[i] as HTMLElement; - element.style.display = 'none'; - } - const tablinks = document.getElementsByClassName('tablinks'); - for (let i = 0; i < tablinks.length; i++) { - tablinks[i].className = tablinks[i].className.replace(' active', ''); + ); + }); + + const fetchUserInfo = async () => { + const uInfo = await SetPermissionLevel(cookies); + setUsername(uInfo.username); + setFirstName(uInfo.firstName); + setLastName(uInfo.lastName); + setAccountCreatedAt(uInfo.accountCreatedAt); + setRole(uInfo.role); + + // Wait for the DOM to be fully updated before accessing elements + setTimeout(() => { + const defaultOpen = document.getElementById("defaultOpen"); + const student3 = document.getElementById("student3"); + const defaultOpen2 = document.getElementById("defaultOpen2"); + const defaultOpenStudent = + document.getElementById("defaultOpenStudent"); + + if (defaultOpen) defaultOpen.click(); + if (student3) student3.click(); + if (defaultOpen2) defaultOpen2.click(); + if (defaultOpenStudent) defaultOpenStudent.click(); + }, 0); + + if (!uInfo.error) { + setLogged(true); } - document.getElementById(tabName)!.style.display = 'block'; - evt.currentTarget.className += ' active'; - }; - - const showSharedSlideShowPdfList = (catId: any, catName: React.SetStateAction) => { - setShowPdfListView(true); - setCategoryName(catName); - - let list = []; - switch (catId) { - case '1': - list = [ - { id: '1', FileName: 'Mantra 1', FilePath: 'https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf' }, - // Add more files as necessary - ]; - break; - case '2': - list = [ - { id: '1', FileName: 'Exercise 1', FilePath: 'https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf' }, - // Add more files as necessary - ]; - break; - case '3': - list = [ - { id: '1', FileName: 'One Personal Development Lesson 1', FilePath: 'https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf' }, - // Add more files as necessary - ]; - break; - case '4': - list = [ - { id: '1', FileName: 'Chess Lesson 1', FilePath: 'https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf' }, - // Add more files as necessary - ]; - break; - case '5': - list = [ - { id: '1', FileName: 'Game 1', FilePath: 'https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf' }, - // Add more files as necessary - ]; - break; - case '6': - list = [ - { id: '1', FileName: 'Puzzles 1', FilePath: 'https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf' }, - // Add more files as necessary - ]; - break; - default: - list = [ - { id: '1', FileName: 'Demo 1', FilePath: 'https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf' }, - // Add more files as necessary - ]; - break; + + if (uInfo.role === "mentor") { + fetchRecordings(); } - - setSharedPdfList(list); - }; - - const getPresignURL = (sid: any, meetingId: any) => { - const filename = `${sid}_${meetingId}_0.mp4`; - const url = `${environment.urls.middlewareURL}/meetings/singleRecording?filename=${filename}`; - fetch(url, { - method: 'GET', - headers: { - 'Authorization': `Bearer ${cookies.login}`, - }, - }) - .then((response) => response.json()) - .then((data) => { - setSignedURL(data); - if (signedURL !== '') { - window.open(signedURL); - } - }); }; - return ( -
-
- - -
-
-
- User -

Hello, {firstName} {lastName}!

-
+ fetchUserInfo(); + }, []); + + const fetchRecordings = () => { + const url = `${environment.urls.middlewareURL}/meetings/usersRecordings`; + fetch(url, { + method: "GET", + headers: { + Authorization: `Bearer ${cookies.login}`, + }, + }) + .then((response) => response.json()) + .then((data) => { + setRecordingList(data); + }); + }; + + const openTab = ( + evt: React.MouseEvent, + tabName: string, + className: string + ) => { + const tabcontent = document.getElementsByClassName(className); + for (let i = 0; i < tabcontent.length; i++) { + const element = tabcontent[i] as HTMLElement; + element.style.display = "none"; + } + const tablinks = document.getElementsByClassName("tablinks"); + for (let i = 0; i < tablinks.length; i++) { + tablinks[i].className = tablinks[i].className.replace(" active", ""); + } + document.getElementById(tabName)!.style.display = "block"; + evt.currentTarget.className += " active"; + }; + + const showSharedSlideShowPdfList = ( + catId: any, + catName: React.SetStateAction + ) => { + setShowPdfListView(true); + setCategoryName(catName); + + let list = []; + switch (catId) { + case "1": + list = [ + { + id: "1", + FileName: "Mantra 1", + FilePath: + "https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf", + }, + // Add more files as necessary + ]; + break; + case "2": + list = [ + { + id: "1", + FileName: "Exercise 1", + FilePath: + "https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf", + }, + // Add more files as necessary + ]; + break; + case "3": + list = [ + { + id: "1", + FileName: "One Personal Development Lesson 1", + FilePath: + "https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf", + }, + // Add more files as necessary + ]; + break; + case "4": + list = [ + { + id: "1", + FileName: "Chess Lesson 1", + FilePath: + "https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf", + }, + // Add more files as necessary + ]; + break; + case "5": + list = [ + { + id: "1", + FileName: "Game 1", + FilePath: + "https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf", + }, + // Add more files as necessary + ]; + break; + case "6": + list = [ + { + id: "1", + FileName: "Puzzles 1", + FilePath: + "https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf", + }, + // Add more files as necessary + ]; + break; + default: + list = [ + { + id: "1", + FileName: "Demo 1", + FilePath: + "https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf", + }, + // Add more files as necessary + ]; + break; + } + + setSharedPdfList(list); + }; + + const getPresignURL = (sid: any, meetingId: any) => { + const filename = `${sid}_${meetingId}_0.mp4`; + const url = `${environment.urls.middlewareURL}/meetings/singleRecording?filename=${filename}`; + fetch(url, { + method: "GET", + headers: { + Authorization: `Bearer ${cookies.login}`, + }, + }) + .then((response) => response.json()) + .then((data) => { + setSignedURL(data); + if (signedURL !== "") { + window.open(signedURL); + } + }); + }; + + return ( +
+
+ + +
+
+
+ User +

+ Hello, {firstName} {lastName}! +

+
+
+ +
+
+
+ + +
- -
-
-
- - - -
- -
-
-
-
- Student Graph -
-
-
-
-
Time Spent:
-

  Website: 45 minutes

-

  Lesson: 10 minutes

-

  Puzzle: 5 minutes

-

  Playing: 15 minutes

-

  Mentoring: 15 minutes

-
-
-
- -
- - - - - - - - -
- -
-
-
-
    -
  • -
    23rd July 2022
    7:00 PM
    -
    Solved 2 tactical puzzles
    -
  • -
  • -
    19th July 2022
    3:00 PM
    -
    Practiced 7 positions on Piece Checkmates I
    -
  • -
  • -
    17st July 2022
    7:00 PM
    -
    Signed up to ystemandchess.com
    -
  • -
-
-
+ +
+
+
+
+ Student Graph
- -
-

Mentor Session

-

The project started in 2018 when someone needed something.

- - +
+
+
+
+ Time Spent: +
+

+   Website:{" "} + 45 minutes +

+

+   Lesson:{" "} + 10 minutes +

+

+   Puzzle:{" "} + 5 minutes +

+

+   Playing:{" "} + 15 minutes +

+

+   Mentoring:{" "} + 15 minutes +

- -
-

Professional Development

+
+
+ +
+ + + + + + + + +
+ +
+
+
+
    +
  • +
    + 23rd July 2022 +
    + 7:00 PM +
    +
    + Solved 2 tactical puzzles +
    +
  • +
  • +
    + 19th July 2022 +
    + 3:00 PM +
    +
    + Practiced 7 positions on{" "} + Piece Checkmates I +
    +
  • +
  • +
    + 17st July 2022 +
    + 7:00 PM +
    +
    + Signed up to{" "} + + ystemandchess.com + +
    +
  • +
- -
-

Chess Lession

+
+
+ +
+

Mentor Session

+

The project started in 2018 when someone needed something.

+ + +
+ +
+

Professional Development

+
+ +
+

Chess Lession

+
+ +
+

Games

+
+ +
+

Puzzle

+
+ +
+

Computer

+
+ +
+

Recording

+ {recordingList.map((record: Record, index) => ( +

+ Play Icon +   + + + getPresignURL(record.sid, record.meetingId) + } + > + {record.sid}_{record.meetingId}_0.mp4 + + +   - {record.meetingStartTime} +

+ ))} +
+
+ + {/* Repeat similar structure for Studentname2 and Studentname3 */} +
+
+
+
+ Student Graph
- -
-

Games

+
+
+
+
+ Time Spent: +
+

+   Website:{" "} + 60 minutes +

+

+   Lesson:{" "} + 13 minutes +

+

+   Puzzle:{" "} + 35 minutes +

+

+   Playing:{" "} + 15 minutes +

+

+   Mentoring:{" "} + 5 minutes +

- -
-

Puzzle

+
+
+
+ + + + + + + + +
+ +
+
+
+
    +
  • +
    + 23rd July 2022 +
    + 7:00 PM +
    +
    + Solved 2 tactical puzzles +
    +
  • +
  • +
    + 19th July 2022 +
    + 3:00 PM +
    +
    + Practiced 7 positions on{" "} + Piece Checkmates I +
    +
  • +
  • +
    + 17st July 2022 +
    + 7:00 PM +
    +
    + Signed up to{" "} + + ystemandchess.com + +
    +
  • +
- -
-

Computer

+
+
+ +
+

Mentor Session

+

The project started in 2018 when someone needed something.

+
+ +
+

Professional Development

+
+ +
+

Chess Lession

+
+ +
+

Games

+
+ +
+

Puzzle

+
+ +
+

Computer

+
+ +
+

Recording

+ {recordingList.map((record: Record, index) => ( +

+ Play Icon +   + + + getPresignURL(record.sid, record.meetingId) + } + > + {record.sid}_{record.meetingId}_0.mp4 + + +   - {record.meetingStartTime} +

+ ))} +
+
+ +
+
+
+
+ Student Graph
- -
-

Recording

- {recordingList.map((record: Record, index) => ( -

- Play Icon  - - getPresignURL(record.sid, record.meetingId)}> - {record.sid}_{record.meetingId}_0.mp4 - -   - {record.meetingStartTime} -

- ))} +
+
+
+
+ Time Spent: +
+

+   Website:{" "} + 50 minutes +

+

+   Lesson:{" "} + 25 minutes +

+

+   Puzzle:{" "} + 30 minutes +

+

+   Playing:{" "} + 5 minutes +

+

+   Mentoring:{" "} + 20 minutes +

- - {/* Repeat similar structure for Studentname2 and Studentname3 */} -
-
-
-
- Student Graph -
-
-
-
-
Time Spent:
-

  Website: 60 minutes

-

  Lesson: 13 minutes

-

  Puzzle: 35 minutes

-

  Playing: 15 minutes

-

  Mentoring: 5 minutes

+
+ +
+ + + + + + + + +
+ +
+
+
+
    +
  • +
    + 23rd July 2022 +
    + 7:00 PM +
    +
    + Solved 2 tactical puzzles +
    +
  • +
  • +
    + 19th July 2022 +
    + 3:00 PM +
    +
    + Practiced 7 positions on{" "} + Piece Checkmates I
    -
+ +
  • +
    + 17st July 2022 +
    + 7:00 PM +
    +
    + Signed up to{" "} + + ystemandchess.com + +
    +
  • +
    -
    - - - - - - - - -
    - -
    -
    -
    -
      -
    • -
      23rd July 2022
      7:00 PM
      -
      Solved 2 tactical puzzles
      -
    • -
    • -
      19th July 2022
      3:00 PM
      -
      Practiced 7 positions on Piece Checkmates I
      -
    • -
    • -
      17st July 2022
      7:00 PM
      -
      Signed up to ystemandchess.com
      -
    • -
    -
    -
    -
    - -
    -

    Mentor Session

    -

    The project started in 2018 when someone needed something.

    -
    - -
    -

    Professional Development

    -
    - -
    -

    Chess Lession

    -
    - -
    -

    Games

    -
    - -
    -

    Puzzle

    -
    - -
    -

    Computer

    -
    - -
    -

    Recording

    - {recordingList.map((record: Record, index) => ( -

    - Play Icon  - - getPresignURL(record.sid, record.meetingId)}> - {record.sid}_{record.meetingId}_0.mp4 - -   - {record.meetingStartTime} -

    - ))} -
    -
    - -
    -
    -
    -
    - Student Graph -
    -
    -
    -
    -
    Time Spent:
    -

      Website: 50 minutes

    -

      Lesson: 25 minutes

    -

      Puzzle: 30 minutes

    -

      Playing: 5 minutes

    -

      Mentoring: 20 minutes

    -
    -
    -
    - -
    - - - - - - - - -
    - -
    -
    -
    -
      -
    • -
      23rd July 2022
      7:00 PM
      -
      Solved 2 tactical puzzles
      -
    • -
    • -
      19th July 2022
      3:00 PM
      -
      Practiced 7 positions on Piece Checkmates I
      -
    • -
    • -
      17st July 2022
      7:00 PM
      -
      Signed up to ystemandchess.com
      -
    • -
    -
    -
    -
    - -
    -

    Mentor Session

    -

    The project started in 2018 when someone needed something.

    -
    - -
    -

    Professional Development

    -
    - -
    -

    Chess Lession

    -
    - -
    -

    Games

    -
    - -
    -

    Puzzle

    -
    - -
    -

    Computer

    -
    - -
    -

    Recording

    - {recordingList.map((record: Record, index) => ( -

    - Play Icon  - - getPresignURL(record.sid, record.meetingId)}> - {record.sid}_{record.meetingId}_0.mp4 - -   - {record.meetingStartTime} -

    - ))} -
    -
    -
    - -
    -
    -
    -
    - -
    - {/* */} -
    +
    +
    + +
    +

    Mentor Session

    +

    The project started in 2018 when someone needed something.

    +
    + +
    +

    Professional Development

    +
    + +
    +

    Chess Lession

    +
    + +
    +

    Games

    +
    + +
    +

    Puzzle

    +
    + +
    +

    Computer

    +
    + +
    +

    Recording

    + {recordingList.map((record: Record, index) => ( +

    + Play Icon +   + + + getPresignURL(record.sid, record.meetingId) + } + > + {record.sid}_{record.meetingId}_0.mp4 + + +   - {record.meetingStartTime} +

    + ))} +
    +
    -)}; -export default MentorProfile; \ No newline at end of file + +
    +
    +
    +
    + +
    + {/* */} +
    +
    + ); +}; +export default MentorProfile; diff --git a/react-ystemandchess/src/Pages/NewMentorProfile/NewMentorProfile.tsx b/react-ystemandchess/src/Pages/NewMentorProfile/NewMentorProfile.tsx index 3a5a9baf..0373b51c 100644 --- a/react-ystemandchess/src/Pages/NewMentorProfile/NewMentorProfile.tsx +++ b/react-ystemandchess/src/Pages/NewMentorProfile/NewMentorProfile.tsx @@ -1,9 +1,9 @@ import React, { useState, useEffect, useRef } from "react"; import "./NewMentorProfile.scss"; import Images from "../../images/imageImporter"; -import { SetPermissionLevel } from '../../globals'; -import { useCookies } from 'react-cookie'; -import { environment } from '../../environments/environment'; +import { SetPermissionLevel } from "../../globals"; +import { useCookies } from "react-cookie"; +import { environment } from "../../environments/environment"; import { useNavigate } from "react-router"; interface NewMentorProfileProps { @@ -17,10 +17,11 @@ interface Student { lastName: string; } -const NewMentorProfile: React.FC = ({ userPortraitSrc }) => { - +const NewMentorProfile: React.FC = ({ + userPortraitSrc, +}) => { const [activeTab, setActiveTab] = useState("activity"); - const [cookies] = useCookies(['login']); + const [cookies] = useCookies(["login"]); const navigate = useNavigate(); // mentor info @@ -49,17 +50,18 @@ const NewMentorProfile: React.FC = ({ userPortraitSrc }) const containerRef = useRef(null); // current date for display - const [date, setDate] = useState(() => new Date().toLocaleDateString('en-US', { - month: 'long', - day: 'numeric', - }) -); + const [date, setDate] = useState(() => + new Date().toLocaleDateString("en-US", { + month: "long", + day: "numeric", + }) + ); - useEffect(()=>{ - fetchUserData().catch(err => console.log(err)); // fetch user data when the component mounts + useEffect(() => { + fetchUserData().catch((err) => console.log(err)); // fetch user data when the component mounts setStubStudent("joeyman43"); // set a stub student for testing purposes, setting students should happen outside of this component - fetchStudentData().catch(err => console.log(err)); // fetch student data when the component mounts - }, []) + fetchStudentData().catch((err) => console.log(err)); // fetch student data when the component mounts + }, []); useEffect(() => { const el = containerRef.current; @@ -75,65 +77,73 @@ const NewMentorProfile: React.FC = ({ userPortraitSrc }) return () => el.removeEventListener("scroll", handleScroll); }, [events, loading]); - const fetchUserData = async () => { - const uInfo = await SetPermissionLevel(cookies); // get logged-in user info - if (uInfo.error) { - console.log("Error: user not logged in.") // error if the user is not logged in - navigate("/login"); // redirect to login page - } else { - // record user info - setUsername(uInfo.username); - setFirstName(uInfo.firstName); - setLastName(uInfo.lastName) - } + const uInfo = await SetPermissionLevel(cookies); // get logged-in user info + if (uInfo.error) { + console.log("Error: user not logged in."); // error if the user is not logged in + navigate("/login"); // redirect to login page + } else { + // record user info + setUsername(uInfo.username); + setFirstName(uInfo.firstName); + setLastName(uInfo.lastName); + } - // fetch usage time stats - const responseStats = await fetch( - // fetches student's stats if studentUsername is provided, otherwise fetches mentor's stats - `${environment.urls.middlewareURL}/timeTracking/statistics?username=${studentUsername ? studentUsername : uInfo.username}`, - { - method: 'GET', - headers: { 'Authorization': `Bearer ${cookies.login}` } - } - ); - const dataStats = await responseStats.json(); - // update time usage for different events - setWebTime(dataStats.website); - setLessonTime(dataStats.lesson); - setPlayTime(dataStats.play); - setMentorTime(dataStats.mentor); - setPuzzleTime(dataStats.puzzle); + // fetch usage time stats + const responseStats = await fetch( + // fetches student's stats if studentUsername is provided, otherwise fetches mentor's stats + `${environment.urls.middlewareURL}/timeTracking/statistics?username=${ + studentUsername ? studentUsername : uInfo.username + }`, + { + method: "GET", + headers: { Authorization: `Bearer ${cookies.login}` }, + } + ); + const dataStats = await responseStats.json(); + // update time usage for different events + setWebTime(dataStats.website); + setLessonTime(dataStats.lesson); + setPlayTime(dataStats.play); + setMentorTime(dataStats.mentor); + setPuzzleTime(dataStats.puzzle); - // fetch latest usage history - fetchEvents(studentUsername ? studentUsername : uInfo.username) - } + // fetch latest usage history + fetchEvents(studentUsername ? studentUsername : uInfo.username); + }; const fetchStudentData = async () => { console.log("Fetching student data..."); fetch(`${environment.urls.middlewareURL}/user/getMentorship`, { - method: 'GET', - headers: { 'Authorization': `Bearer ${cookies.login}` } - }).then(data => data.json()) - .then(data => { + method: "GET", + headers: { Authorization: `Bearer ${cookies.login}` }, + }) + .then((data) => data.json()) + .then((data) => { setStudentFirstName(data.firstName); setStudentLastName(data.lastName); setStudentUsername(data.username); - setHasStudent(true) + setHasStudent(true); }); - } + }; const setStubStudent = async (stubStudentUsername) => { console.log("Setting stub student:", stubStudentUsername); - fetch(`${environment.urls.middlewareURL}/user/updateMentorship?mentorship=${stubStudentUsername}`, { - method: 'PUT', - headers: { 'Authorization': `Bearer ${cookies.login}`, - 'Content-Type': 'application/json'} - }).then(data => data.json()) - .then(data => { + fetch( + `${environment.urls.middlewareURL}/user/updateMentorship?mentorship=${stubStudentUsername}`, + { + method: "PUT", + headers: { + Authorization: `Bearer ${cookies.login}`, + "Content-Type": "application/json", + }, + } + ) + .then((data) => data.json()) + .then((data) => { console.log("Set student response:", data); }); - } + }; // fetch latest usage history const fetchEvents = async (username) => { @@ -147,32 +157,32 @@ const NewMentorProfile: React.FC = ({ userPortraitSrc }) try { // fetch latest usage history const responseLatest = await fetch( - `${environment.urls.middlewareURL}/timeTracking/latest?username=${username}&limit=${limit}&skip=${skip}`, + `${environment.urls.middlewareURL}/timeTracking/latest?username=${username}&limit=${limit}&skip=${skip}`, { - method: 'GET', - headers: { 'Authorization': `Bearer ${cookies.login}` } + method: "GET", + headers: { Authorization: `Bearer ${cookies.login}` }, } ); const dataLatest = await responseLatest.json(); - setEvents(prev => [...prev, ...dataLatest]); // append more events to old list - setPage(prev => prev + 1); // update pagination number + setEvents((prev) => [...prev, ...dataLatest]); // append more events to old list + setPage((prev) => prev + 1); // update pagination number setHasMore(dataLatest.length === limit && dataLatest.length > 0); } catch (err) { console.error("Failed to fetch events", err); } finally { setLoading(false); // stop fetching } - } + }; const handleTabClick = (tab: any) => { setActiveTab(tab); }; const handleNavigateEvent = (type: string, name: string) => { - if(type == "lesson") { + if (type == "lesson") { navigate("/lessons", { state: { piece: name } }); } - } + }; const renderTabContent = () => { switch (activeTab) { @@ -188,33 +198,48 @@ const NewMentorProfile: React.FC = ({ userPortraitSrc })
    - {events && events.map((event, index) => { // render list of usage history - const dateObj = new Date(event.startTime); - const dateStr = dateObj.toLocaleDateString('en-US', { // date of each history - year: 'numeric', - month: 'short', - day: 'numeric' - }); - const timeStr = dateObj.toLocaleTimeString('en-US', { // time of each history - hour: 'numeric', - minute: '2-digit' - }); + {events && + events.map((event, index) => { + // render list of usage history + const dateObj = new Date(event.startTime); + const dateStr = dateObj.toLocaleDateString("en-US", { + // date of each history + year: "numeric", + month: "short", + day: "numeric", + }); + const timeStr = dateObj.toLocaleTimeString("en-US", { + // time of each history + hour: "numeric", + minute: "2-digit", + }); - return ( -
    -
    -
    -

    {dateStr} {timeStr}

    -
    -
    -

    - Working on {event.eventType}:{' '} - handleNavigateEvent(event.eventType, event.eventName)}>{event.eventName} -

    -
    -
    - ); - })} + return ( +
    +
    +
    +

    + {dateStr} {timeStr} +

    +
    +
    +

    + Working on {event.eventType}:{" "} + + handleNavigateEvent( + event.eventType, + event.eventName + ) + } + > + {event.eventName} + +

    +
    +
    + ); + })} {loading &&

    Loading more...

    } {!hasMore &&

    No more activity left!

    }
    @@ -222,56 +247,80 @@ const NewMentorProfile: React.FC = ({ userPortraitSrc }) ); case "mentor": return ( -
    +

    Mentor

    This is the content for the Mentor tab.

    ); case "learning": return ( -
    +

    Learning

    This is the content for the Learning tab.

    ); case "chessLessons": return ( -
    +

    Chess Lessons

    This is the content for the Chess Lessons tab.

    ); case "games": return ( -
    +

    Games

    This is the content for the Games tab.

    ); case "puzzles": return ( -
    +

    Puzzles

    This is the content for the Puzzles tab.

    ); case "playComputer": return ( -
    +

    Play with Computer

    This is the content for the Play with Computer tab.

    ); case "recordings": return ( -
    +

    Recordings

    This is the content for the Recordings tab.

    ); case "backpack": return ( -
    +

    Backpack

    This is the content for the Backpack tab.

    @@ -301,64 +350,98 @@ const NewMentorProfile: React.FC = ({ userPortraitSrc }) >
    -

    Hello, {firstName} {lastName}!

    +

    + Hello, {firstName} {lastName}! +

    - { hasStudent ? ( -
    -
    -

    Check in on {studentFirstName} {studentLastName}'s progress!

    -
    -
    -
    - + {hasStudent ? ( +
    +
    +

    + Check in on{" "} + + {studentFirstName} {studentLastName}'s + {" "} + progress!{" "} +

    -
    -

    Time Spent:

    -
      -
    • Website: {webTime} minutes
    • -
    • Playing: {playTime} minutes
    • -
    • Lessons: {lessonTime} minutes
    • -
    • Puzzle: {puzzleTime} minutes
    • -
    • Mentoring: {mentorTime} minutes
    • -
    +
    +
    + +
    +
    +

    Time Spent:

    +
      +
    • + Website: {webTime} minutes +
    • +
    • + Playing: {playTime} minutes +
    • +
    • + Lessons: {lessonTime} minutes +
    • +
    • + Puzzle: {puzzleTime} minutes +
    • +
    • + Mentoring: {mentorTime} minutes +
    • +
    +
    -
    -
    - -
    {renderTabContent()}
    -
    -
    ) : ( -
    -

    No Student Selected

    -

    Please select a student to view their progress.

    -
    +
    + {renderTabContent()} +
    +
    +
    + ) : ( +
    +

    No Student Selected

    +

    Please select a student to view their progress.

    +
    )} ); diff --git a/react-ystemandchess/src/Pages/NewStudentProfile/NewStudentProfile.tsx b/react-ystemandchess/src/Pages/NewStudentProfile/NewStudentProfile.tsx index 66563604..831f4186 100644 --- a/react-ystemandchess/src/Pages/NewStudentProfile/NewStudentProfile.tsx +++ b/react-ystemandchess/src/Pages/NewStudentProfile/NewStudentProfile.tsx @@ -1,16 +1,15 @@ import React, { useState, useEffect, useRef } from "react"; import "./NewStudentProfile.scss"; import Images from "../../images/imageImporter"; -import { SetPermissionLevel } from '../../globals'; -import { useCookies } from 'react-cookie'; -import { environment } from '../../environments/environment'; +import { SetPermissionLevel } from "../../globals"; +import { useCookies } from "react-cookie"; +import { environment } from "../../environments/environment"; import { useNavigate } from "react-router"; import { StatsChart } from "./StatsChart"; const NewStudentProfile = ({ userPortraitSrc }: any) => { - const [activeTab, setActiveTab] = useState("activity"); - const [cookies] = useCookies(['login']); + const [cookies] = useCookies(["login"]); const navigate = useNavigate(); // user info @@ -26,8 +25,15 @@ const NewStudentProfile = ({ userPortraitSrc }: any) => { const [mentorTime, setMentorTime] = useState(0); // data for chart plotting - const [displayMonths, setDisplayMonths] = useState(6); // display data from 6 many months back - const [monthAxis, setMonthAxis] = useState(["Jan", "Feb", "Mar", "Apr", "May", "Jun"]); + const [displayMonths, setDisplayMonths] = useState(6); // display data from 6 many months back + const [monthAxis, setMonthAxis] = useState([ + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + ]); const [dataAxis, setDataAxis] = useState([0, 0, 0, 0, 0, 0]); // time spent on events each month // event tracking for pagination @@ -38,27 +44,29 @@ const NewStudentProfile = ({ userPortraitSrc }: any) => { const containerRef = useRef(null); // current date for display - const [date, setDate] = useState(() => new Date().toLocaleDateString('en-US', { - month: 'long', - day: 'numeric', - })); + const [date, setDate] = useState(() => + new Date().toLocaleDateString("en-US", { + month: "long", + day: "numeric", + }) + ); - useEffect(()=>{ + useEffect(() => { try { fetchUserData(); // asynchronously fetch user data upon mounting } catch (err) { - console.log(err) + console.log(err); } - }, []) + }, []); // loading changes, update listener to update handler closures useEffect(() => { - const el = containerRef.current; // get the activity element + const el = containerRef.current; // get the activity element if (!el) return; const handleScroll = () => { // if scrolling within 50px of displayed height - if (el.scrollTop + el.clientHeight >= el.scrollHeight - 50) { + if (el.scrollTop + el.clientHeight >= el.scrollHeight - 50) { fetchActivity(username); // fetch new acitivty } }; @@ -68,42 +76,42 @@ const NewStudentProfile = ({ userPortraitSrc }: any) => { }, [loading]); const fetchUserData = async () => { - const uInfo = await SetPermissionLevel(cookies); // get logged-in user info - if (uInfo.error) { - navigate("/login") // if user is not logged in, go to login page - } else { - // record user info - setUsername(uInfo.username); - setFirstName(uInfo.firstName); - setLastName(uInfo.lastName) - } + const uInfo = await SetPermissionLevel(cookies); // get logged-in user info + if (uInfo.error) { + navigate("/login"); // if user is not logged in, go to login page + } else { + // record user info + setUsername(uInfo.username); + setFirstName(uInfo.firstName); + setLastName(uInfo.lastName); + } - // fetch usage time stats to disaply in header - fetchUsageTime(uInfo.username) - // fetch data for graph plotting - fetchGraphData(uInfo.username) - // fetch latest usage history to show in Activity tab - fetchActivity(uInfo.username) - } + // fetch usage time stats to disaply in header + fetchUsageTime(uInfo.username); + // fetch data for graph plotting + fetchGraphData(uInfo.username); + // fetch latest usage history to show in Activity tab + fetchActivity(uInfo.username); + }; // fetch usage time stats to display in header const fetchUsageTime = async (username) => { - // fetch from back end - const responseStats = await fetch( - `${environment.urls.middlewareURL}/timeTracking/statistics?username=${username}`, - { - method: 'GET', - headers: { 'Authorization': `Bearer ${cookies.login}` } - } - ); - const dataStats = await responseStats.json(); - // update time usage for different events in header display - setWebTime(dataStats.website); - setLessonTime(dataStats.lesson); - setPlayTime(dataStats.play); - setMentorTime(dataStats.mentor); - setPuzzleTime(dataStats.puzzle); - } + // fetch from back end + const responseStats = await fetch( + `${environment.urls.middlewareURL}/timeTracking/statistics?username=${username}`, + { + method: "GET", + headers: { Authorization: `Bearer ${cookies.login}` }, + } + ); + const dataStats = await responseStats.json(); + // update time usage for different events in header display + setWebTime(dataStats.website); + setLessonTime(dataStats.lesson); + setPlayTime(dataStats.play); + setMentorTime(dataStats.mentor); + setPuzzleTime(dataStats.puzzle); + }; // fetch latest usage history (Activity Tab) const fetchActivity = async (username) => { @@ -116,45 +124,45 @@ const NewStudentProfile = ({ userPortraitSrc }: any) => { try { // fetch another batch of usage history const responseLatest = await fetch( - `${environment.urls.middlewareURL}/timeTracking/latest?username=${username}&limit=${limit}&skip=${skip}`, + `${environment.urls.middlewareURL}/timeTracking/latest?username=${username}&limit=${limit}&skip=${skip}`, { - method: 'GET', - headers: { 'Authorization': `Bearer ${cookies.login}` } + method: "GET", + headers: { Authorization: `Bearer ${cookies.login}` }, } ); const dataLatest = await responseLatest.json(); - setEvents(prev => [...prev, ...dataLatest]); // append more events to old list - setPage(prev => prev + 1); // update pagination number + setEvents((prev) => [...prev, ...dataLatest]); // append more events to old list + setPage((prev) => prev + 1); // update pagination number setHasMore(dataLatest.length === limit && dataLatest.length > 0); // if there are more activities setLoading(false); } catch (err) { console.error("Failed to fetch events", err); } - } + }; // fetch data needed for updating graph plot const fetchGraphData = async (username) => { try { // fetch the time spent on the website in the past few months const response = await fetch( - `${environment.urls.middlewareURL}/timeTracking/graph-data?username=${username}&eventType=website&months=${displayMonths}`, + `${environment.urls.middlewareURL}/timeTracking/graph-data?username=${username}&eventType=website&months=${displayMonths}`, { - method: 'GET', - headers: { 'Authorization': `Bearer ${cookies.login}` } + method: "GET", + headers: { Authorization: `Bearer ${cookies.login}` }, } ); - const data = await response.json(); - const months = data.map(item => item.monthText); // month list for ploting - const times = data.map(item => item.timeSpent); // timeSpent for plotting + const data = await response.json(); + const months = data.map((item) => item.monthText); // month list for ploting + const times = data.map((item) => item.timeSpent); // timeSpent for plotting // update for graph plotting setMonthAxis(months); - setDataAxis(times); + setDataAxis(times); } catch (err) { console.error("Failed to fetch events", err); } - } + }; const handleTabClick = (tab: any) => { setActiveTab(tab); @@ -162,10 +170,11 @@ const NewStudentProfile = ({ userPortraitSrc }: any) => { // navigate to previous activities const handleNavigateEvent = (type: string, name: string) => { - if(type == "lesson") { // if event is a lesson + if (type == "lesson") { + // if event is a lesson navigate("/lessons", { state: { piece: name } }); } - } + }; const renderTabContent = () => { switch (activeTab) { @@ -181,33 +190,48 @@ const NewStudentProfile = ({ userPortraitSrc }: any) => {
    - {events && events.map((event, index) => { // render list of usage history - const dateObj = new Date(event.startTime); - const dateStr = dateObj.toLocaleDateString('en-US', { // date of each history - year: 'numeric', - month: 'short', - day: 'numeric' - }); - const timeStr = dateObj.toLocaleTimeString('en-US', { // time of each history - hour: 'numeric', - minute: '2-digit' - }); + {events && + events.map((event, index) => { + // render list of usage history + const dateObj = new Date(event.startTime); + const dateStr = dateObj.toLocaleDateString("en-US", { + // date of each history + year: "numeric", + month: "short", + day: "numeric", + }); + const timeStr = dateObj.toLocaleTimeString("en-US", { + // time of each history + hour: "numeric", + minute: "2-digit", + }); - return ( -
    -
    -
    -

    {dateStr} {timeStr}

    -
    -
    -

    - Working on {event.eventType}:{' '} - handleNavigateEvent(event.eventType, event.eventName)}>{event.eventName} -

    -
    -
    - ); - })} + return ( +
    +
    +
    +

    + {dateStr} {timeStr} +

    +
    +
    +

    + Working on {event.eventType}:{" "} + + handleNavigateEvent( + event.eventType, + event.eventName + ) + } + > + {event.eventName} + +

    +
    +
    + ); + })} {loading &&

    Loading more...

    } {!hasMore &&

    No more activity left!

    }
    @@ -215,56 +239,80 @@ const NewStudentProfile = ({ userPortraitSrc }: any) => { ); case "mentor": return ( -
    +

    Mentor

    This is the content for the Mentor tab.

    ); case "learning": return ( -
    +

    Learning

    This is the content for the Learning tab.

    ); case "chessLessons": return ( -
    +

    Chess Lessons

    This is the content for the Chess Lessons tab.

    ); case "games": return ( -
    +

    Games

    This is the content for the Games tab.

    ); case "puzzles": return ( -
    +

    Puzzles

    This is the content for the Puzzles tab.

    ); case "playComputer": return ( -
    +

    Play with Computer

    This is the content for the Play with Computer tab.

    ); case "recordings": return ( -
    +

    Recordings

    This is the content for the Recordings tab.

    ); case "backpack": return ( -
    +

    Backpack

    This is the content for the Backpack tab.

    @@ -294,7 +342,9 @@ const NewStudentProfile = ({ userPortraitSrc }: any) => { >
    -

    Hello, {firstName} {lastName}!

    +

    + Hello, {firstName} {lastName}! +

    @@ -302,46 +352,76 @@ const NewStudentProfile = ({ userPortraitSrc }: any) => {
    - +

    Time Spent:

      -
    • Website: {webTime} minutes
    • -
    • Playing: {playTime} minutes
    • -
    • Lessons: {lessonTime} minutes
    • -
    • Puzzle: {puzzleTime} minutes
    • -
    • Mentoring: {mentorTime} minutes
    • +
    • + Website: {webTime} minutes +
    • +
    • + Playing: {playTime} minutes +
    • +
    • + Lessons: {lessonTime} minutes +
    • +
    • + Puzzle: {puzzleTime} minutes +
    • +
    • + Mentoring: {mentorTime} minutes +
    -
    {renderTabContent()}
    +
    + {renderTabContent()} +
    diff --git a/react-ystemandchess/src/Pages/Reset-Password/resetPasswordService.ts b/react-ystemandchess/src/Pages/Reset-Password/resetPasswordService.ts index 62cf2173..1a6a15a4 100644 --- a/react-ystemandchess/src/Pages/Reset-Password/resetPasswordService.ts +++ b/react-ystemandchess/src/Pages/Reset-Password/resetPasswordService.ts @@ -1,8 +1,8 @@ -import { environment } from '../../environments/environment'; -const nodemailer = require('nodemailer'); +import { environment } from "../../environments/environment"; +const nodemailer = require("nodemailer"); const transporter = nodemailer.createTransport({ - service: 'Gmail', // Or any other email service + service: "Gmail", // Or any other email service auth: { user: environment.email!.user, pass: environment.email!.pass, @@ -13,18 +13,21 @@ const sendResetPasswordEmail = (email: any, resetLink: any) => { const mailOptions = { from: environment.email!.user, to: email, - subject: 'Password Reset', + subject: "Password Reset", text: `Click the link to reset your password: ${resetLink}`, }; return new Promise((resolve, reject) => { - transporter.sendMail(mailOptions, (error: any, info: { response: unknown; }) => { - if (error) { - reject(error); - } else { - resolve(info.response); + transporter.sendMail( + mailOptions, + (error: any, info: { response: unknown }) => { + if (error) { + reject(error); + } else { + resolve(info.response); + } } - }); + ); }); }; diff --git a/react-ystemandchess/src/Pages/SignUp/SignUp.tsx b/react-ystemandchess/src/Pages/SignUp/SignUp.tsx index 64a0b6de..1ef19334 100644 --- a/react-ystemandchess/src/Pages/SignUp/SignUp.tsx +++ b/react-ystemandchess/src/Pages/SignUp/SignUp.tsx @@ -1,20 +1,20 @@ -import React, { useState } from 'react'; -import './SignUp.scss'; // Imports the stylesheet for this component. -import { environment } from '../../environments/environment'; // Imports environment variables, likely containing API URLs. +import React, { useState } from "react"; +import "./SignUp.scss"; // Imports the stylesheet for this component. +import { environment } from "../../environments/environment"; // Imports environment variables, likely containing API URLs. // Test comment - This is a manual test comment. -console.log('Environment URL:', environment.urls.middlewareURL); // Logs the middleware URL from the environment. +console.log("Environment URL:", environment.urls.middlewareURL); // Logs the middleware URL from the environment. const Signup = () => { // State to manage the form data for the user. const [formData, setFormData] = useState({ - firstName: '', - lastName: '', - email: '', - username: '', - password: '', - retypedPassword: '', - accountType: 'mentor', // Default account type is set to 'mentor'. + firstName: "", + lastName: "", + email: "", + username: "", + password: "", + retypedPassword: "", + accountType: "mentor", // Default account type is set to 'mentor'. }); // State flags to track the validity of individual input fields. @@ -27,12 +27,12 @@ const Signup = () => { // State to store any validation errors for the form fields. const [errors, setErrors] = useState({ - firstName: '', - lastName: '', - email: '', - username: '', - password: '', - retypePassword: '', + firstName: "", + lastName: "", + email: "", + username: "", + password: "", + retypePassword: "", }); // State to manage the parent account specific UI and data. @@ -51,22 +51,22 @@ const Signup = () => { // Performs specific validation based on the input field that changed. switch (name) { - case 'firstName': + case "firstName": firstNameVerification(value); break; - case 'lastName': + case "lastName": lastNameVerification(value); break; - case 'email': + case "email": emailVerification(value); break; - case 'username': + case "username": usernameVerification(value); break; - case 'password': + case "password": passwordVerification(value); break; - case 'retypedPassword': + case "retypedPassword": retypePasswordVerification(value, formData.password); break; default: @@ -80,7 +80,7 @@ const Signup = () => { setFirstNameFlag(isValid); setErrors((prev) => ({ ...prev, - firstName: isValid ? '' : 'Invalid First Name', + firstName: isValid ? "" : "Invalid First Name", })); return isValid; }; @@ -91,7 +91,7 @@ const Signup = () => { setLastNameFlag(isValid); setErrors((prev) => ({ ...prev, - lastName: isValid ? '' : 'Invalid Last Name', + lastName: isValid ? "" : "Invalid Last Name", })); return isValid; }; @@ -102,7 +102,7 @@ const Signup = () => { setEmailFlag(isValid); setErrors((prev) => ({ ...prev, - email: isValid ? '' : 'Invalid Email', + email: isValid ? "" : "Invalid Email", })); return isValid; }; @@ -113,7 +113,7 @@ const Signup = () => { setUserNameFlag(isValid); setErrors((prev) => ({ ...prev, - username: isValid ? '' : 'Invalid Username', + username: isValid ? "" : "Invalid Username", })); return isValid; }; @@ -124,25 +124,28 @@ const Signup = () => { setPasswordFlag(isValid); setErrors((prev) => ({ ...prev, - password: isValid ? '' : 'Password must be at least 8 characters', + password: isValid ? "" : "Password must be at least 8 characters", })); return isValid; }; // Verifies if the retyped password matches the original password. - const retypePasswordVerification = (retypedPassword: string, password: string) => { + const retypePasswordVerification = ( + retypedPassword: string, + password: string + ) => { const isValid = retypedPassword === password; setRetypeFlag(isValid); setErrors((prev) => ({ ...prev, - retypePassword: isValid ? '' : 'Passwords do not match', + retypePassword: isValid ? "" : "Passwords do not match", })); return isValid; }; // Handles changes to the account type dropdown. const handleAccountTypeChange = (e: any) => { - const isParent = e.target.value === 'parent'; + const isParent = e.target.value === "parent"; setParentAccountFlag(isParent); // Updates the accountType in the form data. setFormData((prev) => ({ @@ -155,12 +158,12 @@ const Signup = () => { const handleAddStudent = () => { const newStudent = { id: Date.now(), - firstName: '', - lastName: '', - username: '', - email: '', - password: '', - retypedPassword: '', + firstName: "", + lastName: "", + username: "", + email: "", + password: "", + retypedPassword: "", errors: {}, }; setStudents((prev: any) => [...prev, newStudent]); @@ -168,7 +171,11 @@ const Signup = () => { }; // Handles changes to input fields within a student's form. - const handleStudentInputChange = (studentId: any, field: string, value: string) => { + const handleStudentInputChange = ( + studentId: any, + field: string, + value: string + ) => { // Updates the specific student's data in the students array. setStudents((prev: any) => prev.map((student: any) => @@ -180,7 +187,9 @@ const Signup = () => { // Removes a student form from the UI. const handleRemoveStudent = (studentId: any) => { // Filters out the student with the given ID. - setStudents((prev: any) => prev.filter((student: any) => student.id !== studentId)); + setStudents((prev: any) => + prev.filter((student: any) => student.id !== studentId) + ); // Hides the student form if no students are present. if (students.length === 1) { setShowStudentForm(false); @@ -189,7 +198,7 @@ const Signup = () => { // Handles the submission of the signup form. const handleSubmit = async () => { - console.log('Submit clicked', formData); + console.log("Submit clicked", formData); // Checks if all main form fields are valid based on their flags. const isValid = @@ -200,7 +209,7 @@ const Signup = () => { passwordFlag && retypeFlag; - console.log('Validation status:', { + console.log("Validation status:", { firstNameFlag, lastNameFlag, emailFlag, @@ -211,11 +220,11 @@ const Signup = () => { // If the main form is not valid, prevents submission. if (!isValid) { - console.log('Form validation failed'); + console.log("Form validation failed"); return; } - let url = ''; + let url = ""; // Constructs the API URL based on whether it's a parent account with students. if (parentAccountFlag && students.length > 0) { // Maps student data into the required format for the API. @@ -240,18 +249,18 @@ const Signup = () => { url = `${environment.urls.middlewareURL}/user/?first=${formData.firstName}&last=${formData.lastName}&email=${formData.email}&password=${formData.password}&username=${formData.username}&role=${formData.accountType}`; } - console.log('Request URL:', url); + console.log("Request URL:", url); try { // Sends a POST request to the signup API. const response = await fetch(url, { - method: 'POST', + method: "POST", headers: { - 'Content-Type': 'application/json', + "Content-Type": "application/json", }, }); - console.log('Response status:', response.status); + console.log("Response status:", response.status); // Throws an error if the response status indicates failure. if (!response.ok) { @@ -260,100 +269,100 @@ const Signup = () => { // Parses the JSON response. const data = await response.json(); - console.log('Response data:', data); + console.log("Response data:", data); // Handles the case where the chosen username is already taken. - if (data === 'This username has been taken. Please choose another.') { + if (data === "This username has been taken. Please choose another.") { setErrors((prev) => ({ ...prev, - username: 'Username already taken', + username: "Username already taken", })); } else { // Redirects to the homepage upon successful signup. - window.location.href = '/'; + window.location.href = "/"; } } catch (error) { - console.error('Signup error:', error); + console.error("Signup error:", error); // Sets a general error message for signup failure. setErrors((prev) => ({ ...prev, - general: 'Signup failed. Please try again.', + general: "Signup failed. Please try again.", })); } }; return ( -
    e.preventDefault()}> + e.preventDefault()}>

    Sign up

    -
    +
    {/* Maps through the errors object and displays any error messages. */} {Object.values(errors).map((error, index) => error ?

    {error}

    : null )}
    -
    +
    -
    +

    Select Account Type

    {/* Conditional rendering of the student section for parent accounts. */} {parentAccountFlag && ( -
    +
    {/* Button to add a new student form if the student form is not currently shown. */} {!showStudentForm && ( handleStudentInputChange( student.id, - 'firstName', + "firstName", e.target.value ) } /> handleStudentInputChange( student.id, - 'lastName', + "lastName", e.target.value ) } /> handleStudentInputChange( student.id, - 'username', + "username", e.target.value ) } /> - handleStudentInputChange(student.id, 'email', e.target.value) + handleStudentInputChange(student.id, "email", e.target.value) } /> handleStudentInputChange( student.id, - 'password', + "password", e.target.value ) } /> handleStudentInputChange( student.id, - 'retypedPassword', + "retypedPassword", e.target.value ) } @@ -445,17 +454,17 @@ const Signup = () => {
    )} -
    - - +
    + +
    {/* Submit button for the signup form. */} - ); }; -export default Signup; \ No newline at end of file +export default Signup; diff --git a/react-ystemandchess/src/Pages/Student-Profile/UserProfile.tsx b/react-ystemandchess/src/Pages/Student-Profile/UserProfile.tsx index a393d7db..38e46c96 100644 --- a/react-ystemandchess/src/Pages/Student-Profile/UserProfile.tsx +++ b/react-ystemandchess/src/Pages/Student-Profile/UserProfile.tsx @@ -1,8 +1,8 @@ -import React, { useEffect, useState } from 'react'; -import { SetPermissionLevel } from '../../globals'; -import { useCookies } from 'react-cookie'; -import { environment } from '../../environments/environment'; -import './UserProfile.scss'; +import React, { useEffect, useState } from "react"; +import { SetPermissionLevel } from "../../globals"; +import { useCookies } from "react-cookie"; +import { environment } from "../../environments/environment"; +import "./UserProfile.scss"; type PdfItem = { id: string; @@ -10,28 +10,26 @@ type PdfItem = { FilePath: string; }; -type Record = { +type Record = { sid: string; meetingId: string; meetingStartTime: string; [key: string]: any; // This allows any other fields to be added with any type -} - - +}; const UserProfile = () => { - const [cookies] = useCookies(['login']); - const [username, setUsername] = useState(''); - const [firstName, setFirstName] = useState(''); - const [lastName, setLastName] = useState(''); - const [accountCreatedAt, setAccountCreatedAt] = useState(''); - const [role, setRole] = useState(''); + const [cookies] = useCookies(["login"]); + const [username, setUsername] = useState(""); + const [firstName, setFirstName] = useState(""); + const [lastName, setLastName] = useState(""); + const [accountCreatedAt, setAccountCreatedAt] = useState(""); + const [role, setRole] = useState(""); const [recordingList, setRecordingList] = useState([]); const [sharedPdfList, setSharedPdfList] = useState([]); - const [categoryName, setCategoryName] = useState(''); + const [categoryName, setCategoryName] = useState(""); const [showPdfListView, setShowPdfListView] = useState(false); - const [signedURL, setSignedURL] = useState(''); - const [playLink, setPlayLink] = useState('play-nolog'); + const [signedURL, setSignedURL] = useState(""); + const [playLink, setPlayLink] = useState("play-nolog"); useEffect(() => { async function fetchUserInfo() { @@ -44,10 +42,11 @@ const UserProfile = () => { // Wait for the DOM to be fully updated before accessing elements setTimeout(() => { - const defaultOpen = document.getElementById('defaultOpen'); - const student3 = document.getElementById('student3'); - const defaultOpen2 = document.getElementById('defaultOpen2'); - const defaultOpenStudent = document.getElementById('defaultOpenStudent'); + const defaultOpen = document.getElementById("defaultOpen"); + const student3 = document.getElementById("student3"); + const defaultOpen2 = document.getElementById("defaultOpen2"); + const defaultOpenStudent = + document.getElementById("defaultOpenStudent"); if (defaultOpen) defaultOpen.click(); if (student3) student3.click(); @@ -55,7 +54,10 @@ const UserProfile = () => { if (defaultOpenStudent) defaultOpenStudent.click(); }, 0); - if (!uInfo.error && (uInfo.role === 'mentor' || uInfo.role === 'student')) { + if ( + !uInfo.error && + (uInfo.role === "mentor" || uInfo.role === "student") + ) { fetchRecordings(); } } @@ -66,9 +68,9 @@ const UserProfile = () => { const fetchRecordings = () => { const url = `${environment.urls.middlewareURL}/meetings/usersRecordings`; fetch(url, { - method: 'GET', + method: "GET", headers: { - 'Authorization': `Bearer ${cookies.login}`, + Authorization: `Bearer ${cookies.login}`, }, }) .then((response) => response.json()) @@ -77,80 +79,196 @@ const UserProfile = () => { }); }; - const openTab = (evt: React.MouseEvent, tabName: string) => { + const openTab = ( + evt: React.MouseEvent, + tabName: string + ) => { var i, tabcontent, tablinks; - tabcontent = document.getElementsByClassName('tabcontent'); + tabcontent = document.getElementsByClassName("tabcontent"); for (i = 0; i < tabcontent.length; i++) { - const element = tabcontent[i] as HTMLElement - element.style.display = 'none'; + const element = tabcontent[i] as HTMLElement; + element.style.display = "none"; } - tablinks = document.getElementsByClassName('tablinks'); + tablinks = document.getElementsByClassName("tablinks"); for (i = 0; i < tablinks.length; i++) { - tablinks[i].className = tablinks[i].className.replace(' active', ''); + tablinks[i].className = tablinks[i].className.replace(" active", ""); } const element = document.getElementById(tabName); if (element) { - element.style.display = 'block'; + element.style.display = "block"; } else { console.error(`Element with id ${tabName} not found`); } - - evt.currentTarget.className += ' active'; + + evt.currentTarget.className += " active"; }; - const showSharedSlideShowPdfList = (catId: string, catName: React.SetStateAction) => { + const showSharedSlideShowPdfList = ( + catId: string, + catName: React.SetStateAction + ) => { setShowPdfListView(true); setCategoryName(catName); let pdfList: PdfItem[] = []; switch (catId) { - case '1': + case "1": pdfList = [ - { id: '1', FileName: 'Mantra 1', FilePath: 'https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf' }, - { id: '2', FileName: 'Mantra 2', FilePath: 'https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf' }, - { id: '3', FileName: 'Mantra 3', FilePath: 'https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf' }, - { id: '4', FileName: 'Mantra 4', FilePath: 'https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf' }, - { id: '5', FileName: 'Mantra 5', FilePath: 'https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf' }, - { id: '6', FileName: 'Mantra 6', FilePath: 'https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf' }, + { + id: "1", + FileName: "Mantra 1", + FilePath: + "https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf", + }, + { + id: "2", + FileName: "Mantra 2", + FilePath: + "https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf", + }, + { + id: "3", + FileName: "Mantra 3", + FilePath: + "https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf", + }, + { + id: "4", + FileName: "Mantra 4", + FilePath: + "https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf", + }, + { + id: "5", + FileName: "Mantra 5", + FilePath: + "https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf", + }, + { + id: "6", + FileName: "Mantra 6", + FilePath: + "https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf", + }, ]; break; - case '2': + case "2": pdfList = [ - { id: '1', FileName: 'Exercise 1', FilePath: 'https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf' }, - { id: '2', FileName: 'Exercise 2', FilePath: 'https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf' }, - { id: '3', FileName: 'Exercise 3', FilePath: 'https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf' }, - { id: '4', FileName: 'Exercise 4', FilePath: 'https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf' }, - { id: '5', FileName: 'Exercise 5', FilePath: 'https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf' }, + { + id: "1", + FileName: "Exercise 1", + FilePath: + "https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf", + }, + { + id: "2", + FileName: "Exercise 2", + FilePath: + "https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf", + }, + { + id: "3", + FileName: "Exercise 3", + FilePath: + "https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf", + }, + { + id: "4", + FileName: "Exercise 4", + FilePath: + "https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf", + }, + { + id: "5", + FileName: "Exercise 5", + FilePath: + "https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf", + }, ]; break; - case '3': + case "3": pdfList = [ - { id: '1', FileName: 'One Personal Development Lesson 1', FilePath: 'https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf' }, - { id: '2', FileName: 'One Personal Development Lesson 2', FilePath: 'https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf' }, - { id: '3', FileName: 'One Personal Development Lesson 3', FilePath: 'https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf' }, - { id: '4', FileName: 'One Personal Development Lesson 4', FilePath: 'https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf' }, + { + id: "1", + FileName: "One Personal Development Lesson 1", + FilePath: + "https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf", + }, + { + id: "2", + FileName: "One Personal Development Lesson 2", + FilePath: + "https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf", + }, + { + id: "3", + FileName: "One Personal Development Lesson 3", + FilePath: + "https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf", + }, + { + id: "4", + FileName: "One Personal Development Lesson 4", + FilePath: + "https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf", + }, ]; break; - case '4': + case "4": pdfList = [ - { id: '1', FileName: 'Chess Lesson 1', FilePath: 'https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf' }, - { id: '2', FileName: 'Chess Lesson 2', FilePath: 'https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf' }, - { id: '3', FileName: 'Chess Lesson 3', FilePath: 'https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf' }, + { + id: "1", + FileName: "Chess Lesson 1", + FilePath: + "https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf", + }, + { + id: "2", + FileName: "Chess Lesson 2", + FilePath: + "https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf", + }, + { + id: "3", + FileName: "Chess Lesson 3", + FilePath: + "https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf", + }, ]; break; - case '5': + case "5": pdfList = [ - { id: '1', FileName: 'Game 1', FilePath: 'https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf' }, - { id: '2', FileName: 'Game 2', FilePath: 'https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf' }, + { + id: "1", + FileName: "Game 1", + FilePath: + "https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf", + }, + { + id: "2", + FileName: "Game 2", + FilePath: + "https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf", + }, ]; break; - case '6': + case "6": pdfList = [ - { id: '1', FileName: 'Puzzles 1', FilePath: 'https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf' }, + { + id: "1", + FileName: "Puzzles 1", + FilePath: + "https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf", + }, ]; break; default: pdfList = [ - { id: '1', FileName: 'demo 1', FilePath: 'https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf' }, + { + id: "1", + FileName: "demo 1", + FilePath: + "https://documentcloud.adobe.com/view-sdk-demo/PDFs/Bodea Brochure.pdf", + }, ]; } setSharedPdfList(pdfList); @@ -161,7 +279,7 @@ const UserProfile = () => { // console.error("AdobeDC is not defined"); // return; // } - + // const adobeDCView = new window.AdobeDC.View({ clientId: "YOUR_CLIENT_ID" }); // adobeDCView.previewFile({ // content: { location: { url: filePath } }, @@ -178,12 +296,12 @@ const UserProfile = () => { try { const response = await fetch(url, { - method: 'GET', + method: "GET", headers: { - 'Authorization': `Bearer ${document.cookie}`, // Adjust the way you retrieve the token + Authorization: `Bearer ${document.cookie}`, // Adjust the way you retrieve the token }, }); - + if (response.ok) { const data = await response.json(); setSignedURL(data); @@ -191,26 +309,33 @@ const UserProfile = () => { window.open(data); } } else { - console.error('Failed to fetch pre-signed URL'); + console.error("Failed to fetch pre-signed URL"); } } catch (error) { - console.error('Error fetching pre-signed URL:', error); + console.error("Error fetching pre-signed URL:", error); } -}; - + }; -return ( + return (
    - - + +
    -

    {firstName} {lastName}

    +

    + {firstName} {lastName} +

    - +
    @@ -218,74 +343,173 @@ return (
    -

    Time Spent :

    -
    +

    + Time Spent : +

    +
    -

      Website: 45 minutes

    +

    + {" "} +   Website:{" "} + 45 minutes +

    -

      Lesson: 10 minutes

    +

    +   Lesson:{" "} + 10 minutes +

    -

      Puzzle: 5 minutes

    +

    +   Puzzle:{" "} + 5 minutes +

    -

      Playing: 15 minutes

    +

    +   Playing:{" "} + 15 minutes +

    -

      Mentoring: 15 minutes

    +

    +   Mentoring:{" "} + 15 minutes +

    - +
    - - - - - - - -
    - +
    • -
      23rd July 2022
      7:00 PM
      +
      + 23rd July 2022 +
      + 7:00 PM +
      Solved 2 tactical puzzles
    • -
      19th July 2022
      3:00 PM
      -
      Practiced 7 positions on Piece Checkmates I
      +
      + 19th July 2022 +
      + 3:00 PM +
      +
      + Practiced 7 positions on{" "} + Piece Checkmates I +
    • -
      17st July 2022
      7:00 PM
      -
      Signed up to ystemandchess.com
      +
      + 17st July 2022 +
      + 7:00 PM +
      +
      + Signed up to{" "} + + ystemandchess.com + +
    - +

    Mentor Session

    - +

    Professional Development

    - +

    Chess Lession

    - +

    Games

    - +

    Puzzles

    - +

    Computer

    - +

    Recording

    {recordingList.map((record: Record, index) => (

    - Play Icon  + Play Icon +   - getPresignURL(record.sid, record.meetingId)}> + getPresignURL(record.sid, record.meetingId)} + > {record.sid}_{record.meetingId}_0.mp4 -   - {record.meetingStartTime} + +   - {record.meetingStartTime}

    ))}
    - -
    + +
    - -
    + +
    {/* */}
    - )}; - - export default UserProfile; \ No newline at end of file + ); +}; + +export default UserProfile; diff --git a/react-ystemandchess/src/Pages/Student/Student.tsx b/react-ystemandchess/src/Pages/Student/Student.tsx index 889540c4..381c80d4 100644 --- a/react-ystemandchess/src/Pages/Student/Student.tsx +++ b/react-ystemandchess/src/Pages/Student/Student.tsx @@ -1,32 +1,32 @@ -import React, {useState} from "react"; +import React, { useState } from "react"; import "./Student.scss"; -import {environment} from "../../environments/environment"; +import { environment } from "../../environments/environment"; const Student = () => { - const chessSrc = environment.urls.chessClientURL; - const [movesAhead, setMovesAhead] = useState(5); + const chessSrc = environment.urls.chessClientURL; + const [movesAhead, setMovesAhead] = useState(5); - return ( -
    -
    -
    -
    - + {/* Learn */} +
    +
    + 📘 +
    +
    +

    Learn

    +

    + We strive to empower underserved and at-risk children through + mentoring and STEM skills-development to enable them to pursue + STEM careers and change their life trajectory. +

    +
    +
    + + {/* Donate */} +
    +
    + 💰 +
    +
    +

    Donate

    +

    + The tax deductible donation will be used to scale our program to + underserved communities and students. Y STEM and Chess Inc. is a + registered tax organization. +

    +
    +
    +
    -
    -
    - ChessGroup -
    - Start now and sign up later! + {/* YouTube + Box Section */} +
    +
    + {/* YouTube */} +
    +
    + +
    +
    + + {/* Box Content */} +
    + ChessGroup +
    + Start now and sign up later! +
    + +
    -
    @@ -166,7 +228,10 @@ const Home = () => { alt={`${book.title} cover`} className="book-image" /> -
    @@ -186,5 +251,3 @@ const Home = () => { }; export default Home; - - diff --git a/react-ystemandchess/src/Pages/LessonsSelection/LessonsSelection.test.tsx b/react-ystemandchess/src/Pages/LessonsSelection/LessonsSelection.test.tsx index 0998fce0..a5616a79 100644 --- a/react-ystemandchess/src/Pages/LessonsSelection/LessonsSelection.test.tsx +++ b/react-ystemandchess/src/Pages/LessonsSelection/LessonsSelection.test.tsx @@ -9,7 +9,7 @@ test("renders lesson selection page", () => { ); - + // Check if the lesson selection title is present const lessonTitle = screen.getByTestId("title"); expect(lessonTitle).toBeInTheDocument(); @@ -25,4 +25,4 @@ test("renders lesson selection page", () => { expect(goButton).toBeInTheDocument(); }); -// MAYBE: Add more tests to check if later lessons are blocked if you haven't completed the previous ones \ No newline at end of file +// MAYBE: Add more tests to check if later lessons are blocked if you haven't completed the previous ones diff --git a/react-ystemandchess/src/index.css b/react-ystemandchess/src/index.css index b26551d9..c3b3d894 100644 --- a/react-ystemandchess/src/index.css +++ b/react-ystemandchess/src/index.css @@ -2,7 +2,7 @@ @tailwind components; @tailwind utilities; -html{ +html { scroll-behavior: smooth; /* overflow-x: hidden; overflow-y: hidden; */ @@ -21,3 +21,20 @@ code { font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace; } + +:root { + --color-bg-main: #dff2c8; + --color-bg-accent: #bfd99e; + --color-bg-lightbox: #e8f0d9; + + --color-deep-green: #2f4f2f; + --color-green: #556b2f; + --color-green-hover: #6b8e23; + + --color-black-solid: #101010; + --color-black-hover: #1e1e1e; + --color-dark-text: #3a3a3a; + + --color-glow-purple-1: #e2cbff; + --color-glow-purple-2: #393bb2; +} From 1e3ecb829b40cef4b970c7f67374857bb65d5477 Mon Sep 17 00:00:00 2001 From: pedram karimi Date: Wed, 18 Jun 2025 01:10:09 -0400 Subject: [PATCH 3/4] admin page - unit test fixes --- react-ystemandchess/jest.setup.js | 7 ------- react-ystemandchess/src/Pages/Admin/Admin.tsx | 2 +- react-ystemandchess/src/Pages/Admin/admin.test.tsx | 5 +---- react-ystemandchess/src/setupTests.ts | 6 +++++- 4 files changed, 7 insertions(+), 13 deletions(-) diff --git a/react-ystemandchess/jest.setup.js b/react-ystemandchess/jest.setup.js index 9c8945d5..7bdb5002 100644 --- a/react-ystemandchess/jest.setup.js +++ b/react-ystemandchess/jest.setup.js @@ -2,10 +2,3 @@ import { TextEncoder, TextDecoder } from "util"; global.TextEncoder = TextEncoder; global.TextDecoder = TextDecoder; - -if (typeof global.TextEncoder === "undefined") { - global.TextEncoder = TextEncoder; -} -if (typeof global.TextDecoder === "undefined") { - global.TextDecoder = TextDecoder; -} diff --git a/react-ystemandchess/src/Pages/Admin/Admin.tsx b/react-ystemandchess/src/Pages/Admin/Admin.tsx index d671587b..7ba570a5 100644 --- a/react-ystemandchess/src/Pages/Admin/Admin.tsx +++ b/react-ystemandchess/src/Pages/Admin/Admin.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useState } from "react"; -import { useNavigate } from "react-router-dom"; +import { useNavigate } from "react-router"; import { useCookies } from "react-cookie"; import { environment } from "../../environments/environment"; const Admin = () => { diff --git a/react-ystemandchess/src/Pages/Admin/admin.test.tsx b/react-ystemandchess/src/Pages/Admin/admin.test.tsx index 6dbe9003..41facd9e 100644 --- a/react-ystemandchess/src/Pages/Admin/admin.test.tsx +++ b/react-ystemandchess/src/Pages/Admin/admin.test.tsx @@ -1,9 +1,6 @@ -import { TextEncoder, TextDecoder } from "util"; -Object.assign(global, { TextEncoder, TextDecoder }); - import React from "react"; import { render, screen, fireEvent, waitFor } from "@testing-library/react"; -import { MemoryRouter } from "react-router-dom"; +import { MemoryRouter } from "react-router"; import { CookiesProvider } from "react-cookie"; import Admin from "./Admin"; diff --git a/react-ystemandchess/src/setupTests.ts b/react-ystemandchess/src/setupTests.ts index adee3c83..ec5534f6 100644 --- a/react-ystemandchess/src/setupTests.ts +++ b/react-ystemandchess/src/setupTests.ts @@ -1,2 +1,6 @@ -import '@testing-library/jest-dom'; +import { TextEncoder, TextDecoder } from "util"; +import "@testing-library/jest-dom"; + +global.TextEncoder = TextEncoder; +global.TextDecoder = TextDecoder; From 9087d33f77021d3784e023eb95a85a46850e8f6c Mon Sep 17 00:00:00 2001 From: Yousif Alrubaye Date: Wed, 14 Jan 2026 23:24:16 -0800 Subject: [PATCH 4/4] Fix Login.tsx syntax error --- .../src/features/auth/login/Login.tsx | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/react-ystemandchess/src/features/auth/login/Login.tsx b/react-ystemandchess/src/features/auth/login/Login.tsx index e8b5654b..1060c33b 100644 --- a/react-ystemandchess/src/features/auth/login/Login.tsx +++ b/react-ystemandchess/src/features/auth/login/Login.tsx @@ -47,6 +47,7 @@ const Login = () => { setUsernameFlag(true); setPasswordFlag(true); setLoginError('Invalid username or password'); + setIsLoading(false); return; } else { setLoginError(""); @@ -80,29 +81,28 @@ const Login = () => { expires.setDate(expires.getDate() + 1); setCookie('login', JSON.parse(response).token, { expires }); - let payload = JSON.parse(atob(response.split(".")[1])); - console.log(payload); + let payload = JSON.parse(atob(response.split(".")[1])); + console.log(payload); - switch (payload["role"]) { - case "student": - window.location.pathname = "/student-profile"; - console.log(payload["role"]); - break; - case "parent": - window.location.pathname = "/parent"; - break; - case "mentor": - window.location.pathname = "/mentor-profile"; - break; - case "admin": - window.location.pathname = "/admin"; - break; - default: - window.location.pathname = ""; - } + switch (payload["role"]) { + case "student": + window.location.pathname = "/student-profile"; + console.log(payload["role"]); + break; + case "parent": + window.location.pathname = "/parent"; + break; + case "mentor": + window.location.pathname = "/mentor-profile"; + break; + case "admin": + window.location.pathname = "/admin"; + break; + default: + window.location.pathname = ""; } - }, - setIsLoading(false); + setIsLoading(false); + } }, () => { setLoginError('The username or password is incorrect.'); setIsLoading(false);