From 954cbf7cdca37526a555293bcff039c2028dc1f2 Mon Sep 17 00:00:00 2001 From: f-hejazi Date: Tue, 28 Oct 2025 01:45:16 +0100 Subject: [PATCH 01/23] feat: add new scenarios for Pawn, Bishop, Knight, Rook, Queen, and King --- .../src/Pages/Lessons/Scenarios.js | 386 +++++++++--------- 1 file changed, 193 insertions(+), 193 deletions(-) diff --git a/react-ystemandchess/src/Pages/Lessons/Scenarios.js b/react-ystemandchess/src/Pages/Lessons/Scenarios.js index 7f3a2418..e24b2ad5 100644 --- a/react-ystemandchess/src/Pages/Lessons/Scenarios.js +++ b/react-ystemandchess/src/Pages/Lessons/Scenarios.js @@ -1,197 +1,197 @@ export const scenariosArray = [ - // { - // name: 'Pawn - It moves forward only', - // subSections: [ - // { - // name: 'Basic', - // fen: '8/8/8/P7/8/5p2/8/8 w k - 0 1', - // info: `Pawns move one square only. - // But when they reach the other side of the board, they become a stronger piece!`, - // }, - // { - // name: 'Capture', - // fen: '8/3p4/2p5/3p4/8/4P3/8/8 w - - 0 1', - // info: `Pawns move forward, - // but capture diagonally!`, - // }, - // { - // name: 'Training 1', - // fen: '8/2p5/1ppp4/8/1pp5/1P6/8/8 w - - 0 1', - // info: 'Capture, then promote!', - // }, - // { - // name: 'Training 2', - // fen: '2p5/3p4/1p2p3/1p1p4/2p5/3P4/8/8 w - - 0 1', - // info: `Capture, then promote!`, - // }, - // { - // name: 'Traning 3', - // fen: '8/8/8/1pp1p3/3p2p1/P1PP3P/8/8 w - - 0 1', - // info: `Use all the pawns! - // No need to promote.`, - // }, - // { - // name: 'Special Move', - // fen: '8/8/3p4/8/8/8/4P3/8 w - - 0 1', - // info: `A pawn on the second rank can move 2 squares at once!`, - // }, - // ], - // }, - // { - // name: 'Bishop - It moves diagonally ', - // subSections: [ - // { - // name: 'The Basic', - // fen: '8/7p/8/8/4p3/8/6B1/8 w - - 0 1', - // info: 'Grab all the black pawns! ', - // }, - // { - // name: 'Training 1', - // fen: '8/8/8/1p6/8/1B1p4/p3p3/1p1p4 w - - 0 1', - // info: `The fewer moves you make, the better!`, - // }, - // { - // name: 'Training 2', - // fen: '8/8/8/8/p1B5/1p1p4/2p1p3/1p6 w - - 0 1', - // info: 'Grab all the black pawns!', - // }, - // { - // name: 'Training 3', - // fen: '8/8/8/3pp3/3pp3/3pp3/8/2B2B2 w - - 0 1', - // info: `One light-squared bishop, one dark-squared bishop. You need both!`, - // }, - // { - // name: 'Training 4', - // fen: '8/6p1/1p5p/8/3B4/4p3/8/p1p5 w - - 0 1', - // info: 'Grab all the black pawns!', - // }, - // { - // name: 'Final', - // fen: '6p1/3Bp2p/5p2/5p2/7p/p1B5/2p5/8 w - - 0 1', - // info: `One light-squared bishop, one dark-squared bishop. You need both!`, - // }, - // ], - // }, - // { - // name: 'Knight - It moves in an L shape ', - // subSections: [ - // { - // name: 'The Basic', - // fen: '8/3p4/8/2p5/4N3/8/8/8 w - - 0 1', - // info: `Knights have a fancy way of jumping around!`, - // }, - // { - // name: 'Training 1', - // fen: '7p/5p2/8/6p1/3p4/2p2p2/4p3/1N6 w - - 0 1', - // info: `Grab all the pawns!`, - // }, - // { - // name: 'Training 2', - // fen: '8/2Np4/1p2p3/3p4/5p2/8/8/8 w - - 0 1', - // info: `Grab all the pawns!`, - // }, - // { - // name: 'Training 3', - // fen: '8/8/8/8/4ppp1/4pNp1/4ppp1/8 w - - 0 1', - // info: `Knights can jump over obstacles!Escape and vanquish the pawns!`, - // }, - // { - // name: 'Training 4', - // fen: '8/8/6p1/8/4pp2/2pN4/4pp2/8 w - - 0 1', - // info: `Grab all the pawns!`, - // }, - // { - // name: 'Final', - // fen: '2p5/2N1p3/2p5/1p1p1p2/1p1p4/4p3/8/8 w - - 0 1', - // info: `Grab all the pawns!`, - // }, - // ], - // }, - // { - // name: 'Rook - It moves in straight lines ', - // subSections: [ - // { - // name: 'The Basic', - // fen: '8/8/4p3/8/8/8/4R3/8 w - - 0 1', - // info: `Click on the rook to bring it to the pawn!`, - // }, - // { - // name: 'Training 1', - // fen: '8/2R5/8/2p2p2/8/8/8/8 w - - 0 1', - // info: `Grab all the pawns!`, - // }, - // { - // name: 'Training 2', - // fen: '8/8/8/8/8/1p2R2p/7p/8 w - - 0 1', - // info: `The fewer moves you make, the better!`, - // }, - // { - // name: 'Training 3', - // fen: '5ppR/6pp/8/8/8/8/8/6p1 w - - 0 1', - // info: `The fewer moves you make, the better!`, - // }, - // { - // name: 'Training 4', - // fen: '8/2R3p1/8/8/p3R2p/6p1/8/8 w - - 0 1', - // info: `Use two rooks to speed things up!`, - // }, - // { - // name: 'Final', - // fen: '8/1p3pp1/8/3p4/6p1/5R2/5p2/R2p4 w - - 0 1', - // info: `Use two rooks to speed things up!`, - // }, - // ], - // }, - // { - // name: 'Queen - Queen = Rook + Bishop ', - // subSections: [ - // { - // name: 'The Basic', - // fen: '8/2p5/8/4p3/8/8/4Q3/8 w - - 0 1', - // info: `Grab all the pawns!`, - // }, - // { - // name: 'Training 1', - // fen: '5p2/8/8/8/3Q4/p6p/5p2/8 w - - 0 1', - // info: `Grab all the pawns!`, - // }, - // { - // name: 'Training 2', - // fen: '5p2/8/3p3p/8/2Q5/p5p1/8/5p2 w - - 0 1', - // info: `Grab all the pawns!`, - // }, - // { - // name: 'Training 3', - // fen: '6p1/6Q1/8/1p5p/8/3p4/p6p/6p1 w - - 0 1', - // info: `Grab all the pawns!`, - // }, - // { - // name: 'Final', - // fen: '6p1/8/p4pp1/8/7p/8/5p2/3pQ2p w - - 0 1', - // info: `Grab all the pawns!`, - // }, - // ], - // }, - // { - // name: 'King - The most important piece ', - // subSections: [ - // { - // name: 'The Basic', - // fen: '8/8/3p4/8/8/8/3K4/8 w - - 0 1', - // info: 'The king is slow. ', - // }, - // { - // name: 'Training', - // fen: '8/8/8/8/8/3p4/2p1p3/4K3 w - - 0 1', - // info: `Grab all the pawns!`, - // }, - // { - // name: 'Final', - // fen: '8/8/8/2ppK3/2p3p1/4pp2/8/8 w - - 0 1', - // info: `Grab all the pawns!`, - // }, - // ], - // }, + { + name: 'Pawn - It moves forward only', + subSections: [ + { + name: 'Basic', + fen: '7k/8/8/P7/8/5p2/8/K7 w - - 0 1', + info: `Pawns move one square only. + But when they reach the other side of the board, they become a stronger piece!`, + }, + { + name: 'Capture', + fen: '8/3p4/2p5/3p4/8/4P3/8/K6k w - - 0 1', + info: `Pawns move forward, + but capture diagonally!`, + }, + { + name: 'Training 1', + fen: '8/2p5/1ppp4/8/1pp5/1P6/8/K6k w - - 0 1', + info: 'Capture, then promote!', + }, + { + name: 'Training 2', + fen: '2p5/3p4/1p2p3/1p1p4/2p5/3P4/8/K6k w - - 0 1', + info: `Capture, then promote!`, + }, + { + name: 'Traning 3', + fen: '8/8/8/1pp1p3/3p2p1/P1PP3P/8/K6k w - - 0 1', + info: `Use all the pawns! + No need to promote.`, + }, + { + name: 'Special Move', + fen: '8/8/3p4/8/8/8/4P3/K6k w - - 0 1', + info: `A pawn on the second rank can move 2 squares at once!`, + }, + ], + }, + { + name: 'Bishop - It moves diagonally', + subSections: [ + { + name: 'The Basic', + fen: '7k/7p/8/8/4p3/8/6B1/K7 w - - 0 1', + info: 'Grab all the black pawns! ', + }, + { + name: 'Training 1', + fen: '7k/8/8/1p6/8/1B1p4/p3p3/Kp1p4 w - - 0 1', + info: `The fewer moves you make, the better!`, + }, + { + name: 'Training 2', + fen: '7k/8/8/8/p1B5/1p1p4/2p1p3/Kp6 w - - 0 1', + info: 'Grab all the black pawns!', + }, + { + name: 'Training 3', + fen: '7k/8/8/3pp3/3pp3/3pp3/8/K2B2B1 w - - 0 1', + info: `One light-squared bishop, one dark-squared bishop. You need both!`, + }, + { + name: 'Training 4', + fen: '7k/6p1/1p5p/8/3B4/4p3/8/K1p1p3 w - - 0 1', + info: 'Grab all the black pawns!', + }, + { + name: 'Final', + fen: '6pk/3Bp2p/5p2/5p2/7p/p1B5/2p5/K7 w - - 0 1', + info: `One light-squared bishop, one dark-squared bishop. You need both!`, + }, + ], + }, + { + name: 'Knight - It moves in an L shape', + subSections: [ + { + name: 'The Basic', + fen: '7k/3p4/8/2p5/4N3/8/8/K7 w - - 0 1', + info: `Knights have a fancy way of jumping around!`, + }, + { + name: 'Training 1', + fen: 'k6p/5p2/8/6p1/3p4/2p2p2/4p3/KN6 w - - 0 1', + info: `Grab all the pawns!`, + }, + { + name: 'Training 2', + fen: '7k/2Np4/1p2p3/3p4/5p2/8/8/K7 w - - 0 1', + info: `Grab all the pawns!`, + }, + { + name: 'Training 3', + fen: '7k/8/8/8/4ppp1/4pNp1/4ppp1/K7 w - - 0 1', + info: `Knights can jump over obstacles! Escape and vanquish the pawns!`, + }, + { + name: 'Training 4', + fen: '7k/8/6p1/8/4pp2/2pN4/4pp2/K7 w - - 0 1', + info: `Grab all the pawns!`, + }, + { + name: 'Final', + fen: 'k1p5/2N1p3/2p5/1p1p1p2/1p1p4/4p3/8/K7 w - - 0 1', + info: `Grab all the pawns!`, + }, + ], + }, + { + name: 'Rook - It moves in straight lines', + subSections: [ + { + name: 'The Basic', + fen: 'k7/8/4p3/8/8/8/4R3/7K w - - 0 1', + info: `Click on the rook to bring it to the pawn!`, + }, + { + name: 'Training 1', + fen: 'k7/2R5/8/2p2p2/8/8/8/7K w - - 0 1', + info: `Grab all the pawns!`, + }, + { + name: 'Training 2', + fen: 'k7/8/8/8/8/1p2R2p/7p/7K w - - 0 1', + info: `The fewer moves you make, the better!`, + }, + { + name: 'Training 3', + fen: 'k4ppR/6pp/8/8/8/8/8/6pK w - - 0 1', + info: `The fewer moves you make, the better!`, + }, + { + name: 'Training 4', + fen: 'k7/2R3p1/8/8/p3R2p/6p1/8/7K w - - 0 1', + info: `Use two rooks to speed things up!`, + }, + { + name: 'Final', + fen: 'k7/1p3pp1/8/3p4/6p1/5R2/5p2/R2p3K w - - 0 1', + info: `Use two rooks to speed things up!`, + }, + ], + }, + { + name: 'Queen - Queen = Rook + Bishop', + subSections: [ + { + name: 'The Basic', + fen: 'k7/2p5/8/4p3/8/8/4Q3/7K w - - 0 1', + info: `Grab all the pawns!`, + }, + { + name: 'Training 1', + fen: 'k4p2/8/8/8/3Q4/p6p/5p2/7K w - - 0 1', + info: `Grab all the pawns!`, + }, + { + name: 'Training 2', + fen: 'k4p2/8/3p3p/8/2Q5/p5p1/8/5p1K w - - 0 1', + info: `Grab all the pawns!`, + }, + { + name: 'Training 3', + fen: 'k5p1/6Q1/8/1p5p/8/3p4/p6p/6pK w - - 0 1', + info: `Grab all the pawns!`, + }, + { + name: 'Final', + fen: 'k5p1/8/p4pp1/8/7p/8/5p2/K2pQ2p w - - 0 1', + info: `Grab all the pawns!`, + }, + ], + }, + { + name: 'King - The most important piece', + subSections: [ + { + name: 'The Basic', + fen: '7k/8/3p4/8/8/8/3K4/8 w - - 0 1', + info: 'The king is slow. ', + }, + { + name: 'Training', + fen: '7k/8/8/8/8/3p4/2p1p3/4K3 w - - 0 1', + info: `Grab all the pawns!`, + }, + { + name: 'Final', + fen: '7k/8/8/2ppK3/2p3p1/4pp2/8/8 w - - 0 1', + info: `Grab all the pawns!`, + }, + ], + }, { name: 'Piece Checkmate 1 Basic checkmates', subSections: [ From 8fce1a8db497e3fe86b1cea5d47c8481d4179f2a Mon Sep 17 00:00:00 2001 From: f-hejazi Date: Mon, 3 Nov 2025 17:24:55 +0100 Subject: [PATCH 02/23] chore: add node-schedule dependency for activity scheduler --- middlewareNode/package-lock.json | 1 + 1 file changed, 1 insertion(+) diff --git a/middlewareNode/package-lock.json b/middlewareNode/package-lock.json index adc30e6b..ffa0f23e 100644 --- a/middlewareNode/package-lock.json +++ b/middlewareNode/package-lock.json @@ -3171,6 +3171,7 @@ "resolved": "https://registry.npmjs.org/node-schedule/-/node-schedule-2.1.1.tgz", "integrity": "sha512-OXdegQq03OmXEjt2hZP33W2YPs/E5BcFQks46+G2gAxs4gHOIVD1u7EqlYLYSKsaIpyKCK9Gbk0ta1/gjRSMRQ==", "dev": true, + "license": "MIT", "dependencies": { "cron-parser": "^4.2.0", "long-timeout": "0.1.1", From e0c0f022a50f2216f5b642e102dc00f3d9261bb4 Mon Sep 17 00:00:00 2001 From: f-hejazi Date: Mon, 3 Nov 2025 23:25:04 +0100 Subject: [PATCH 03/23] feat: add timed instruction popup with dynamic loading bar and fade-out --- .../Lesson-overlay-profile.module.scss | 18 ++++++- .../lesson-overlay/Lesson-overlay.module.scss | 23 ++++++++- .../lesson-overlay/Lesson-overlay.tsx | 48 +++++++++++++++---- 3 files changed, 79 insertions(+), 10 deletions(-) diff --git a/react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/Lesson-overlay-profile.module.scss b/react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/Lesson-overlay-profile.module.scss index 653a6e84..1b88f01c 100644 --- a/react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/Lesson-overlay-profile.module.scss +++ b/react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/Lesson-overlay-profile.module.scss @@ -1,3 +1,19 @@ +.loadingBarContainer { + width: 100%; + height: 6px; + background-color: #e0e0e0; + border-radius: 3px; + overflow: hidden; + margin-top: 1rem; +} + +.loadingBar { + height: 100%; + background-color: var(--green-color); + transition: width 0.1s linear; +} + + .lessonContainer { align-content: center; } @@ -272,7 +288,7 @@ } .popupHeader { - color: rgb(108, 107, 107); + color: black; font-size: 30px; font-weight: bold; margin-bottom: 3px; diff --git a/react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/Lesson-overlay.module.scss b/react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/Lesson-overlay.module.scss index 014365f7..181e2f54 100644 --- a/react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/Lesson-overlay.module.scss +++ b/react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/Lesson-overlay.module.scss @@ -1,3 +1,23 @@ +.loadingBarContainer { + width: 100%; + height: 6px; + background-color: #e0e0e0; + border-radius: 3px; + overflow: hidden; + margin-top: 1rem; +} + +.loadingBar { + height: 100%; + background-color: var(--green-color); + transition: width 0.1s linear; +} + +.fadeOut { + opacity: 0; + transition: opacity 0.5s ease; +} + .lessonContainer { background-image: url("../../../images/chess_background.png"); background-repeat: no-repeat; @@ -247,6 +267,7 @@ justify-content: center; align-items: center; z-index: 9999; + transition: opacity 0.7s ease; } .popupContent { @@ -304,7 +325,7 @@ } .popupHeader { - color: rgb(108, 107, 107); + color: black; font-size: 30px; font-weight: bold; margin-bottom: 3px; diff --git a/react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/Lesson-overlay.tsx b/react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/Lesson-overlay.tsx index f22551e8..6ddd45b8 100644 --- a/react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/Lesson-overlay.tsx +++ b/react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/Lesson-overlay.tsx @@ -59,6 +59,8 @@ const LessonOverlay: React.FC = ({ const turnRef = useRef("white"); const [name, setName] = useState(""); // name of lesson const [info, setInfo] = useState(""); // description of lesson + const [progress, setProgress] = useState(0); // for time tracking progress bar + const [isFading, setIsFading] = useState(false); // for instructions fade-out effect // Information needed for move tracker const [level, setLevel] = useState(20); @@ -107,11 +109,11 @@ const LessonOverlay: React.FC = ({ if (!chessBoardRef.current) return; chessBoardRef.current.undo(); - const engineFEN = chessBoardRef.current.getFen(); - setCurrentFEN(engineFEN); - currentFenRef.current = engineFEN; + const engineFEN = chessBoardRef.current.getFen(); + setCurrentFEN(engineFEN); + currentFenRef.current = engineFEN; - setMoveHistory(prev => prev.slice(0, -1)); + setMoveHistory(prev => prev.slice(0, -1)); } const handleEvaluationComplete = useCallback((data) => { @@ -221,6 +223,30 @@ const LessonOverlay: React.FC = ({ }, [lessonData, socketRef]); + // Handle instruction popup with dynamic loading bar and fade-out + useEffect(() => { + if (!showInstruction) return; + + // Calculate time dynamically based on instruction length + const wordCount = info ? info.split(/\s+/).length : 0; + const totalTime = Math.min(20000, 3000 + wordCount * 300); // cap at 20s max + + let startTime = Date.now(); + + const interval = setInterval(() => { + const elapsed = Date.now() - startTime; + const pct = Math.min((elapsed / totalTime) * 100, 100); + setProgress(pct); + if (pct >= 100) { + clearInterval(interval); + setIsFading(true); // trigger fade-out + setTimeout(() => setShowInstruction(false), 500); // match CSS duration +} + }, 100); + + return () => clearInterval(interval); + }, [showInstruction, info]); + // send lesson to chess client to update UI const sendLessonToChessBoard = () => { @@ -479,7 +505,7 @@ const LessonOverlay: React.FC = ({ cy="60" r="54" fill="none" - stroke="#a3d0ff" + stroke="#7fcc26" strokeWidth="6" > @@ -492,11 +518,17 @@ const LessonOverlay: React.FC = ({ {/* have users read instructions first */} {showInstruction && ( -
+
-

Read this instruction:

+

Lesson Instructions

{info}

- + {/* Loading bar at the bottom */} +
+
+
)} From b6694ab41dded20f1198685558b0f9ffc7dd8eb3 Mon Sep 17 00:00:00 2001 From: f-hejazi Date: Thu, 6 Nov 2025 00:06:00 +0100 Subject: [PATCH 04/23] fix(ui): improve responsiveness, spacing, and error handling in lesson/scenario selection --- .../LessonsSelection/LessonsSelection.jsx | 120 +++--- .../LessonsSelection/LessonsStyle.module.scss | 350 ++++++++++-------- 2 files changed, 267 insertions(+), 203 deletions(-) diff --git a/react-ystemandchess/src/Pages/LessonsSelection/LessonsSelection.jsx b/react-ystemandchess/src/Pages/LessonsSelection/LessonsSelection.jsx index 7de17f6c..9133faab 100644 --- a/react-ystemandchess/src/Pages/LessonsSelection/LessonsSelection.jsx +++ b/react-ystemandchess/src/Pages/LessonsSelection/LessonsSelection.jsx @@ -1,7 +1,7 @@ import profileStyles from "./ProfileStyle.module.scss"; import pageStyles from "./LessonsStyle.module.scss"; import { useNavigate } from "react-router"; -import React, { useState, useEffect, useCallback, useMemo } from 'react'; +import { useState, useEffect, useRef, useCallback, useMemo } from 'react'; import { environment } from "../../environments/environment"; import { getAllScenarios } from "../Lessons/Scenarios"; import { useCookies } from "react-cookie"; @@ -21,11 +21,11 @@ export default function LessonSelection({ onGo, styleType = "page" }) { // what const [selectedLesson, setSelectedLesson] = useState(null); const [isLessonsLoading, setLoadingLessons] = useState(false); const [unlockedLessonCount, setUnlockedLessonCount] = useState(0); // Renamed for clarity - - const [error, setError] = useState(null); // Combine error states - const [scenarios, setScenarios] = useState([]); const [lessons, setLessons] = useState([]); + const scenarioRef = useRef(null); + const lessonRef = useRef(null); + const [error, setError] = useState(""); // Effect to fetch the list of scenarios when the component mounts. useEffect(() => { @@ -60,7 +60,7 @@ export default function LessonSelection({ onGo, styleType = "page" }) { // what // Handles the submission (click on the "Go!" button) to navigate to the selected lesson. const handleSubmit = async () => { if (!selectedLesson || !selectedScenario) { - setError("Select a scenario & lesson."); + setError("Please select a scenario and a lesson."); return; } @@ -129,6 +129,29 @@ export default function LessonSelection({ onGo, styleType = "page" }) { // what fetchLessonsForScenario(); }, [selectedScenario, cookies.login, scenarios]); + useEffect(() => { + const handleClickOutside = (event) => { + if ( + scenarioRef.current && + !scenarioRef.current.contains(event.target) + ) { + setShowScenarios(false); + } + + if ( + lessonRef.current && + !lessonRef.current.contains(event.target) + ) { + setShowLessons(false); + } + }; + + document.addEventListener("click", handleClickOutside); + return () => { + document.removeEventListener("click", handleClickOutside); + }; + }, []); + const renderedScenarios = useMemo(() => { return scenarios.map((scenarioItem) => ( @@ -154,53 +177,66 @@ export default function LessonSelection({ onGo, styleType = "page" }) { // what return (
- {/* Conditional rendering of the error message popup. */} - {error && ( -
-
-
{error}
- -
-
- )}
Lesson Selection
{/* Dropdown-like selector for choosing a scenario. */} -
setShowScenarios(!showScenarios)}> -
- {selectedScenario || "Select a scenario."} -
-
- {showScenarios ? "▼" : "▲"} +
+
setShowScenarios(!showScenarios)}> +
+ {selectedScenario || "Select a scenario"} +
+
+ {showScenarios ? "▼" : "▲"} +
-
- {/* Conditional rendering of the scenarios list. */} - {showScenarios && ( -
- {renderedScenarios} -
- )} + {/* Conditional rendering of the scenarios list. */} + {showScenarios && ( +
+ {renderedScenarios} +
+ )} +
{/* Dropdown-like selector for choosing a lesson within the selected scenario. */} -
setShowLessons(!showLessons)}> -
- {selectedLesson || "Select a lesson."} -
-
- {showLessons ? "▼" : "▲"} +
+
{ + if (!selectedScenario) { + setError("Please select a scenario first."); + setTimeout(() => setError(""), 2500); // auto-clear after 2.5s + return; + } + setShowLessons(!showLessons); + }}> +
+ {selectedLesson || "Select a lesson"} +
+
+ {showLessons ? "▼" : "▲"} +
+ + {/* Conditional rendering of the lessons list for the selected scenario. */} + {showLessons && ( +
+ {isLessonsLoading ? ( +
Loading...
+ ) : (renderedLessons) + } +
+ )}
- {/* Conditional rendering of the lessons list for the selected scenario. */} - {showLessons && ( -
- {isLessonsLoading ? ( -
Loading...
- ) : (renderedLessons) - } -
- )} + +
+ {error && ( +
+ {error} +
+ )} +
+ {/* Button to submit the selection and navigate to the lesson. */} - +
+ + +
+
{ + if (navigateFunc) navigateFunc(); + else navigate("/lessons-selection"); + }}>Switch Lesson +
@@ -387,9 +387,9 @@ const LessonOverlay: React.FC = ({ ) }
- {styleType != 'profile' && ()} + {styleType !== 'profile' && ()}
-
+
div { - max-width: 100% !important; - box-sizing: border-box; + height: auto; + display: flex; + justify-content: center; + align-items: center; } /* Tablet/Large Mobile Responsive */ @media screen and (max-width: 1024px) { - .chessboard-container { - max-width: 50vw; - width: 50vw !important; - max-height: 50vw !important; - height: auto !important; - padding: 0; - margin: 0 auto; - } - .board-b72b1 { - max-width: 100% !important; - width: 100% !important; box-sizing: border-box !important; border-width: 1px !important; } @@ -114,24 +97,12 @@ } @media screen and (max-width: 768px) { - .chessboard-container { - max-width: 55vw; - width: 55vw !important; - max-height: 55vw !important; - } - .notation-322f9 { font-size: 9px; } } @media screen and (max-width: 480px) { - .chessboard-container { - max-width: 60vw; - width: 60vw !important; - max-height: 60vw !important; - } - .notation-322f9 { font-size: 8px; } diff --git a/react-ystemandchess/src/components/ChessBoard/ChessBoard.tsx b/react-ystemandchess/src/components/ChessBoard/ChessBoard.tsx index 038c81f4..088dda9e 100644 --- a/react-ystemandchess/src/components/ChessBoard/ChessBoard.tsx +++ b/react-ystemandchess/src/components/ChessBoard/ChessBoard.tsx @@ -30,36 +30,26 @@ export interface ChessBoardRef { const ChessBoard = forwardRef( ({ lessonMoves = [], onMove, onPromote, onReset, fen: controlledFEN, onLessonComplete }, ref) => { const gameRef = useRef(new Chess()); - const canvasRef = useRef(null); const [fen, setFen] = useState(gameRef.current.fen()); const [highlightSquares, setHighlightSquares] = useState([]); const [lessonIndex, setLessonIndex] = useState(0); const [isShaking, setIsShaking] = useState(false); const [orientation, setOrientationState] = useState<"white" | "black">("white"); - const [boardWidth, setBoardWidth] = useState(600); - - // Calculate board width based on viewport - const calcWidth = () => { - if (typeof window !== 'undefined') { - const width = window.innerWidth; - // Use smaller widths to ensure entire 8x8 board fits with all rows visible - if (width <= 480) return Math.floor(width * 0.60); // 60% for small phones - if (width <= 768) return Math.floor(width * 0.55); // 55% for tablets - if (width <= 1024) return Math.floor(width * 0.50); // 50% for medium tablets - return 600; - } - return 600; - }; + const [boardWidth, setBoardWidth] = useState(0); + const boardRef = useRef(null); - // Update board width on mount and window resize + // Update width based on parent size useEffect(() => { - const updateWidth = () => { - setBoardWidth(calcWidth()); + const handleResize = () => { + if (boardRef.current) { + const containerWidth = boardRef.current.offsetWidth; + setBoardWidth(containerWidth); + } }; - - updateWidth(); // Set initial width - window.addEventListener('resize', updateWidth); - return () => window.removeEventListener('resize', updateWidth); + + handleResize(); // initial + window.addEventListener("resize", handleResize); + return () => window.removeEventListener("resize", handleResize); }, []); // Sync controlled FEN to engine whenever it changes @@ -67,10 +57,10 @@ const ChessBoard = forwardRef( if (!controlledFEN) return; if (controlledFEN !== gameRef.current.fen()) { try { - gameRef.current.load(controlledFEN); - } catch (err) { - console.warn("Invalid FEN passed to ChessBoard:", controlledFEN, err); - } + gameRef.current.load(controlledFEN); + } catch (err) { + console.warn("Invalid FEN passed to ChessBoard:", controlledFEN, err); + } setFen(gameRef.current.fen()); setHighlightSquares([]); } @@ -161,7 +151,7 @@ const ChessBoard = forwardRef( }; return ( -
+
( return acc; }, {} as Record)} /> -
); } From 6b7a92293ce11bc5644495341d374eacaea99835 Mon Sep 17 00:00:00 2001 From: Lahari Gandrapu Date: Sat, 15 Nov 2025 03:30:17 -0500 Subject: [PATCH 06/23] modularized the codebase --- README.md | 46 +- chessClient/{ => archive}/both.html | 0 chessClient/{ => archive}/parent.html | 0 chessClient/{ => archive}/rapid_render.json | 0 chessClient/{ => docs}/CHANGELOG.md | 0 chessClient/{ => docs}/LICENSE.md | 0 .../{ => docs}/README_MOBILE_RESPONSIVE.md | 0 chessServer/package.json | 4 +- chessServer/{ => src/archive}/index old 2.js | 0 chessServer/{ => src/archive}/index old.js | 0 chessServer/{ => src}/index.js | 0 .../{ => src}/managers/EventHandlers.js | 0 chessServer/{ => src}/managers/GameManager.js | 0 .../tests}/GameManager.test.js | 0 .../{__tests__ => src/tests}/index.test.js | 0 chessServer/{ => src/tests}/server.test.js | 0 .../docker-compose.yml | 0 .../mission-image.png | Bin middleware/{ => src/config}/php.ini | 0 middleware/{ => src/endpoints}/awsGen.php | 0 middleware/{ => src/endpoints}/delete.php | 0 middleware/{ => src/endpoints}/endMeeting.php | 0 middleware/{ => src/endpoints}/endSearch.php | 0 middleware/{ => src/endpoints}/genLink.php | 0 .../endpoints}/getCompletedLesson.php | 0 middleware/{ => src/endpoints}/getInfo.php | 0 middleware/{ => src/endpoints}/getLesson.php | 0 .../{ => src/endpoints}/getRecordings.php | 0 .../endpoints}/getTotalPieceLesson.php | 0 middleware/{ => src/endpoints}/index.php | 0 .../{ => src/endpoints}/isInMeeting.php | 0 middleware/{ => src/endpoints}/newGame.php | 0 middleware/{ => src/endpoints}/pairUp.php | 0 middleware/{ => src/endpoints}/record.php | 0 .../{ => src/endpoints}/studentInfo.php | 0 .../endpoints}/updateLessonCompletion.php | 0 middleware/{ => src/endpoints}/verify.php | 0 .../{ => src/endpoints}/verifyNoEcho.php | 0 middleware/{ => src}/testQueries.txt | 0 middlewareNode/package.json | 4 +- middlewareNode/{ => src}/badges/catalog.js | 0 middlewareNode/{ => src}/badges/service.js | 0 .../config/custom-environment-variables.json | 32 + middlewareNode/{ => src}/config/db.js | 0 middlewareNode/{ => src}/config/passport.js | 0 .../{ => src}/controllers/meetings.js | 0 middlewareNode/{ => src}/models/UserBadges.js | 0 middlewareNode/{ => src}/models/activities.js | 0 middlewareNode/{ => src}/models/categorys.js | 0 middlewareNode/{ => src}/models/guest.js | 0 middlewareNode/{ => src}/models/meetings.js | 0 middlewareNode/{ => src}/models/moves.js | 0 middlewareNode/{ => src}/models/puzzles.js | 0 .../{ => src}/models/timeTracking.js | 0 .../{ => src}/models/undoPermission.js | 0 middlewareNode/{ => src}/models/users.js | 0 middlewareNode/{ => src}/models/waiting.js | 0 middlewareNode/{ => src}/routes/activities.js | 0 middlewareNode/{ => src}/routes/auth.js | 0 middlewareNode/{ => src}/routes/badges.js | 0 middlewareNode/{ => src}/routes/categorys.js | 0 middlewareNode/{ => src}/routes/lessons.js | 0 middlewareNode/{ => src}/routes/meetings.js | 0 middlewareNode/{ => src}/routes/puzzles.js | 0 middlewareNode/{ => src}/routes/streak.js | 0 .../{ => src}/routes/timeTracking.js | 0 middlewareNode/{ => src}/routes/users.js | 0 .../scheduler/activitiesScheduler.js | 0 middlewareNode/{ => src}/server.js | 0 .../template/changePasswordTemplate.js | 0 middlewareNode/{ => src}/utils/activities.js | 0 middlewareNode/{ => src}/utils/middleware.js | 0 middlewareNode/{ => src}/utils/nodemailer.js | 0 middlewareNode/{ => src}/utils/recordings.js | 0 react-ystemandchess/README.md | 100 ++- react-ystemandchess/src/App.tsx | 6 +- react-ystemandchess/src/AppRoutes.tsx | 50 +- .../images/ActivitiesAssets/bottom_vine.svg | 0 .../images/ActivitiesAssets/growth_box.svg | 0 .../images/ActivitiesAssets/hanging_vine.svg | 0 .../images/ActivitiesAssets/middle_vine.svg | 0 .../ActivitiesAssets/short_bottom_vine.svg | 0 .../images/ActivitiesAssets/stemmy.svg | 0 .../images/ActivitiesAssets/top_vine.svg | 0 .../images/ActivitiesAssets/topic_bag.svg | 0 .../ActivitiesAssets/vine_background.png | Bin .../images/ActivitiesAssets/water_meter.svg | 0 .../src/{ => assets}/images/LogoLineBreak.png | Bin .../images/StreakProgressAssets/Calendar.png | Bin .../images/StreakProgressAssets/polygon.svg | 0 .../images/StreakProgressAssets/polygon_2.svg | 0 .../images/StreakProgressAssets/stemette.svg | 0 .../images/StreakProgressAssets/stemmy.svg | 0 .../streak_progress_clock.png | Bin .../streak_progress_clock.svg | 0 .../StudentInventoryIcons/activity-icon.svg | 0 .../StudentInventoryIcons/backpack-icon.svg | 0 .../chess-lessons-icon.svg | 0 .../StudentInventoryIcons/games-icon.svg | 0 .../StudentInventoryIcons/learning-icon.svg | 0 .../StudentInventoryIcons/mentor-icon.svg | 0 .../play-computer-icon.svg | 0 .../StudentInventoryIcons/puzzles-icon.svg | 0 .../StudentInventoryIcons/recordings-icon.svg | 0 .../src/{ => assets}/images/Trees-Group.png | Bin .../src/{ => assets}/images/aboutUs/02.png | Bin .../src/{ => assets}/images/aboutUs/09.png | Bin .../src/{ => assets}/images/aboutUs/40.png | Bin .../{ => assets}/images/aboutUs/about-us.png | Bin .../images/aboutUs/divide_icon.png | Bin .../{ => assets}/images/aboutUs/student.png | Bin .../{ => assets}/images/book-howtostart.png | Bin .../images/book-thezerodollar.png | Bin .../src/{ => assets}/images/buy-now.png | Bin .../src/{ => assets}/images/camera.svg | 0 .../images/chess-piece-pattern.png | Bin .../images/chess-piece-pattern.svg | 0 .../src/{ => assets}/images/chessGroup.png | Bin .../images}/chess_background.png | Bin .../src/{ => assets}/images/difference.png | Bin .../src/{ => assets}/images/donate.png | Bin .../src/{ => assets}/images/facebookIcon.svg | 0 .../src/{ => assets}/images/founder-story.png | Bin .../src/{ => assets}/images/free-lunch.png | Bin .../src/{ => assets}/images/full_logo.png | Bin .../src/{ => assets}/images/gem-regular.svg | 0 .../src/{ => assets}/images/googleIcon.svg | 0 .../src/{ => assets}/images/heart-regular.svg | 0 .../images/icons}/icon_back.svg | 0 .../images/icons}/icon_back_inactive.svg | 0 .../images/icons}/icon_next.svg | 0 .../images/icons}/icon_next_inactive.svg | 0 .../images/icons}/icon_redo.svg | 0 .../src/{ => assets}/images/imageImporter.tsx | 2 +- .../src/{ => assets}/images/instagramIcon.svg | 0 .../src/{ => assets}/images/kidsCoding.png | Bin .../src/{ => assets}/images/large_info.png | Bin .../images/line-graph-placeholder.png | Bin .../images/mathArticle/Footer.png | Bin .../images/mathArticle/Group 67.png | Bin .../images/mathArticle/Junechamp 2.png | Bin .../images/mathArticle}/Rectangle 313.png | Bin .../images/mathArticle/Signup.png | Bin .../images/mathArticle/computer.png | Bin .../{ => assets}/images/mathArticle/logo.png | Bin .../src/{ => assets}/images/mission-image.png | Bin .../{ => assets}/images/partners/Rotary.png | Bin .../images/partners/boiseDistrict.png | Bin .../images/partners/boiseRescue.png | Bin .../images/partners/boysAndGirls.png | Bin .../{ => assets}/images/partners/possible.png | Bin .../src/{ => assets}/images/premium.png | Bin .../src/{ => assets}/images/sponsors/PH.svg | 0 .../images/sponsors/idahoCentral.png | Bin .../{ => assets}/images/sponsors/kount.png | Bin .../{ => assets}/images/sponsors/ventive.png | Bin .../student/Leaderboard_User_avatar_1.png | Bin .../student/Leaderboard_User_avatar_2.png | Bin .../student/Leaderboard_User_avatar_3.png | Bin .../images/student/Leaderboard_rank_1.svg | 0 .../images/student/Leaderboard_rank_2.svg | 0 .../images/student/Leaderboard_rank_3.svg | 0 .../images/student/STEMy_Mascot.png | Bin .../images/student/activities_button.svg | 0 .../images/student/activity_tab.png | Bin .../images/student/badges_button.svg | 0 .../{ => assets}/images/student/bg-image.png | Bin .../{ => assets}/images/student/chess_tab.png | Bin .../images/student/chess_tab1.png | Bin .../{ => assets}/images/student/games_tab.png | Bin .../images/student/games_tab1.png | Bin .../images/student/inventory_tab.png | Bin .../images/student/leaderboard_button.svg | 0 .../student/leaderboard_sidebar_icon.svg | 0 .../{ => assets}/images/student/math_tab.png | Bin .../{ => assets}/images/student/mento_tab.png | Bin .../images/student/mento_tab1.png | Bin .../{ => assets}/images/student/play_tab.png | Bin .../{ => assets}/images/student/play_tab1.png | Bin .../images/student/prodev_tab.png | Bin .../images/student/prodev_tab1.png | Bin .../images/student/profilePic 2.png | Bin .../images/student/profilePic.png | Bin .../images/student/profile_button.svg | 0 .../src/{ => assets}/images/student/pupil.svg | 0 .../images/student/puzzles_tab.png | Bin .../images/student/puzzles_tab1.png | Bin .../images/student/recordings_tab.png | Bin .../images/student/recordings_tab1.png | Bin .../{ => assets}/images/student/sponsor_1.png | Bin .../{ => assets}/images/student/sponsor_2.png | Bin .../{ => assets}/images/student/sponsor_3.png | Bin .../{ => assets}/images/student/sponsor_4.png | Bin .../{ => assets}/images/student/sponsor_5.png | Bin .../{ => assets}/images/student/sponsor_6.png | Bin .../{ => assets}/images/student/sponsor_7.png | Bin .../{ => assets}/images/student/sponsor_8.png | Bin .../images/student/streak_button.svg | 0 .../{ => assets}/images/student/sunrise.png | Bin .../src/{ => assets}/images/teaching.png | Bin .../src/{ => assets}/images/twitterIcon.svg | 0 .../images/user-portrait-placeholder.svg | 0 .../src/{ => assets}/images/volunteer.png | Bin .../src/components/ChessBoard/ChessBoard.tsx | 2 +- .../{Footer => components/footer}/Footer.css | 0 .../{Footer => components/footer}/Footer.tsx | 26 +- .../{NavBar => components/navbar}/NavBar.scss | 0 .../{NavBar => components/navbar}/NavBar.tsx | 4 +- .../src/components/ui/tailwindcss-buttons.tsx | 2 +- .../src/{ => core}/services/badgesApi.ts | 0 .../src/{ => core}/services/themesService.ts | 0 .../{ => core}/services/view-sdk.service.ts | 0 .../src/{ => core}/types/chessboardjsx.d.ts | 0 .../src/{ => core}/types/declarations.d.ts | 0 .../src/{ => core}/types/global.d.ts | 0 .../src/{ => core}/utils/activityNames.ts | 0 .../src/{lib/utils.ts => core/utils/cn.ts} | 0 .../about-us/aboutus}/AboutUs.scss | 2 +- .../about-us/aboutus}/AboutUs.test.tsx | 0 .../about-us/aboutus}/AboutUs.tsx | 12 +- .../benefit-of-chess}/ChessBenefitPage.scss | 0 .../benefit-of-chess}/ChessBenefitPage.tsx | 2 +- .../benefit-of-cs}/CSBenefitPage.scss | 0 .../about-us/benefit-of-cs}/CSBenefitPage.tsx | 4 +- .../MathTutBenefitPage.scss | 0 .../MathTutBenefitPage.tsx | 4 +- .../MentoringBenefitPage.scss | 0 .../MentoringBenefitPage.tsx | 4 +- .../about-us/board}/Board.scss | 0 .../about-us/board}/Board.tsx | 2 +- .../about-us/financial}/Financial.scss | 0 .../about-us/financial}/Financial.tsx | 2 +- .../about-us/mission}/Mission.scss | 0 .../about-us/mission}/Mission.tsx | 8 +- .../online-expansion}/OnlineExpansion.tsx | 0 .../sponsors-partners}/SponsorsPartners.scss | 0 .../sponsors-partners}/SponsorsPartners.tsx | 20 +- .../Login => features/auth/login}/Login.scss | 0 .../auth/login}/Login.test.tsx | 0 .../Login => features/auth/login}/Login.tsx | 2 +- .../auth/login}/loginController.ts | 0 .../auth/login}/loginRouter.ts | 0 .../auth/login}/loginService.ts | 0 .../reset-password.component.scss | 0 .../Reset-Password/reset-password.test.tsx | 0 .../Reset-Password/reset-password.tsx | 0 .../Reset-Password/resetPasswordController.ts | 0 .../Reset-Password/resetPasswordRouter.ts | 0 .../Reset-Password/resetPasswordService.ts | 2 +- .../Set-Password/set-password.component.scss | 0 .../Set-Password/set-password.test.ts | 0 .../Set-Password/set-password.test.tsx | 0 .../Set-Password/set-password.tsx | 0 .../Set-Password/setPasswordController.ts | 0 .../Set-Password/setPasswordRouter.ts | 0 .../Set-Password/setPasswordService.ts | 0 .../auth/signup}/SignUp.scss | 0 .../auth/signup}/SignUp.test.tsx | 0 .../auth/signup}/SignUp.tsx | 2 +- .../auth/signup}/signupController.ts | 0 .../auth/signup}/signupRouter.ts | 0 .../auth/signup}/signupService.ts | 0 .../{Pages/Home => features/home}/Home.css | 0 .../Home => features/home}/Home.test.tsx | 0 .../{Pages/Home => features/home}/Home.tsx | 2 +- .../src/features/home/Home/Home.tsx | 275 ++++++ .../lessons-main}/Lessons-profile.module.scss | 0 .../lessons/lessons-main}/Lessons.module.scss | 0 .../lessons/lessons-main}/Lessons.test.tsx | 0 .../lessons/lessons-main}/Lessons.tsx | 0 .../lessons/lessons-main}/Placeholder.jsx | 0 .../lessons/lessons-main}/PromotionPopup.tsx | 0 .../lessons/lessons-main}/Rectangle 313.png | Bin .../lessons/lessons-main}/Scenarios.js | 0 .../lessons-main}/chess_background.png | Bin .../lessons/lessons-main}/icon_back.svg | 0 .../lessons-main}/icon_back_inactive.svg | 0 .../lessons/lessons-main}/icon_next.svg | 0 .../lessons-main}/icon_next_inactive.svg | 0 .../lessons/lessons-main}/icon_redo.svg | 0 .../lessons/lessons-main}/register_button.png | Bin .../LessonTemplate/LessonTemplate.jsx | 0 .../lessons-selection}/LessonsSelection.jsx | 4 +- .../LessonsSelection.test.tsx | 0 .../LessonsStyle.module.scss | 0 .../ProfileStyle.module.scss | 0 .../ScenarioTemplate/ScenarioTemplate.jsx | 0 .../Lesson-overlay-profile.module.scss | 0 .../lesson-overlay/Lesson-overlay.module.scss | 2 +- .../lesson-overlay/Lesson-overlay.test.tsx | 0 .../lesson-overlay/Lesson-overlay.tsx | 14 +- .../piece-lessons/lesson-overlay/answers.js | 0 .../hooks/useChessGameLogic.test.ts | 0 .../lesson-overlay/hooks/useChessGameLogic.ts | 0 .../hooks/useLessonManager.test.ts | 0 .../lesson-overlay/hooks/useLessonManager.ts | 2 +- .../hooks/useSocketChessEngine.test.ts | 0 .../hooks/useSocketChessEngine.ts | 2 +- .../hooks/useTimeTracking.test.ts | 8 +- .../lesson-overlay/hooks/useTimeTracking.ts | 4 +- .../move-tracker/MoveTracker.tsx | 0 .../piece-lessons/play-lesson/PlayLesson.tsx | 0 .../play-lesson/lesson-content copy.scss | 0 .../play-lesson/lesson-content.scss | 0 .../mentor/mentor-page}/Mentor.scss | 0 .../mentor/mentor-page}/Mentor.test.tsx | 0 .../mentor/mentor-page}/Mentor.tsx | 10 +- .../mentor-profile}/NewMentorProfile.scss | 0 .../mentor-profile}/NewMentorProfile.test.tsx | 4 +- .../mentor-profile}/NewMentorProfile.tsx | 16 +- .../NewMentorProfile/NewMentorProfile.tsx | 436 ++++++++++ .../programs}/Programs.scss | 0 .../programs}/Programs.test.tsx | 0 .../programs}/Programs.tsx | 2 +- .../puzzles-page}/Puzzles-profile.module.scss | 0 .../puzzles/puzzles-page}/Puzzles.module.scss | 2 +- .../puzzles/puzzles-page}/Puzzles.test.tsx | 0 .../puzzles/puzzles-page}/Puzzles.tsx | 6 +- .../Student-Inventory/StudentInventory.tsx | 820 ++++++++++++++++++ .../student-inventory}/StudentInventory.scss | 2 +- .../student-inventory}/StudentInventory.tsx | 8 +- .../student/student-page}/Student.scss | 0 .../student/student-page}/Student.tsx | 2 +- .../Modals/ActivitiesModal.scss | 2 +- .../Modals/ActivitiesModal.tsx | 22 +- .../student-profile}/Modals/BadgesModal.scss | 0 .../student-profile}/Modals/BadgesModal.tsx | 2 +- .../Modals/LeaderboardModal.scss | 0 .../Modals/LeaderboardModal.tsx | 8 +- .../student-profile}/Modals/StreakModal.scss | 0 .../student-profile}/Modals/StreakModal.tsx | 12 +- .../student-profile}/NewStudentProfile.scss | 2 +- .../NewStudentProfile.test.tsx | 2 +- .../student-profile}/NewStudentProfile.tsx | 42 +- .../NewStudentProfile/Modals/BadgesModal.tsx | 89 ++ .../student/student-profile}/StatsChart.tsx | 0 react-ystemandchess/src/globals.ts | 2 +- stockfishServer/package.json | 4 +- .../{ => src/archive}/index_new.js | 0 .../{ => src}/bin/stockfish_11_linux | Bin .../{ => src}/bin/stockfish_11_mac | Bin .../{ => src}/bin/stockfish_11_win.exe | Bin stockfishServer/{ => src}/index.js | 0 .../{ => src/managers}/StockfishManager.js | 0 stockfishServer/{ => src/managers}/socket.js | 0 .../tests}/StockfishManager.test.js | 0 .../{__tests__ => src/tests}/index.test.js | 0 347 files changed, 1967 insertions(+), 185 deletions(-) rename chessClient/{ => archive}/both.html (100%) rename chessClient/{ => archive}/parent.html (100%) rename chessClient/{ => archive}/rapid_render.json (100%) rename chessClient/{ => docs}/CHANGELOG.md (100%) rename chessClient/{ => docs}/LICENSE.md (100%) rename chessClient/{ => docs}/README_MOBILE_RESPONSIVE.md (100%) rename chessServer/{ => src/archive}/index old 2.js (100%) rename chessServer/{ => src/archive}/index old.js (100%) rename chessServer/{ => src}/index.js (100%) rename chessServer/{ => src}/managers/EventHandlers.js (100%) rename chessServer/{ => src}/managers/GameManager.js (100%) rename chessServer/{__tests__ => src/tests}/GameManager.test.js (100%) rename chessServer/{__tests__ => src/tests}/index.test.js (100%) rename chessServer/{ => src/tests}/server.test.js (100%) rename docker-compose.yml => config/docker-compose.yml (100%) rename mission-image.png => documentation/mission-image.png (100%) rename middleware/{ => src/config}/php.ini (100%) rename middleware/{ => src/endpoints}/awsGen.php (100%) rename middleware/{ => src/endpoints}/delete.php (100%) rename middleware/{ => src/endpoints}/endMeeting.php (100%) rename middleware/{ => src/endpoints}/endSearch.php (100%) rename middleware/{ => src/endpoints}/genLink.php (100%) rename middleware/{ => src/endpoints}/getCompletedLesson.php (100%) rename middleware/{ => src/endpoints}/getInfo.php (100%) rename middleware/{ => src/endpoints}/getLesson.php (100%) rename middleware/{ => src/endpoints}/getRecordings.php (100%) rename middleware/{ => src/endpoints}/getTotalPieceLesson.php (100%) rename middleware/{ => src/endpoints}/index.php (100%) rename middleware/{ => src/endpoints}/isInMeeting.php (100%) rename middleware/{ => src/endpoints}/newGame.php (100%) rename middleware/{ => src/endpoints}/pairUp.php (100%) rename middleware/{ => src/endpoints}/record.php (100%) rename middleware/{ => src/endpoints}/studentInfo.php (100%) rename middleware/{ => src/endpoints}/updateLessonCompletion.php (100%) rename middleware/{ => src/endpoints}/verify.php (100%) rename middleware/{ => src/endpoints}/verifyNoEcho.php (100%) rename middleware/{ => src}/testQueries.txt (100%) rename middlewareNode/{ => src}/badges/catalog.js (100%) rename middlewareNode/{ => src}/badges/service.js (100%) create mode 100644 middlewareNode/src/config/custom-environment-variables.json rename middlewareNode/{ => src}/config/db.js (100%) rename middlewareNode/{ => src}/config/passport.js (100%) rename middlewareNode/{ => src}/controllers/meetings.js (100%) rename middlewareNode/{ => src}/models/UserBadges.js (100%) rename middlewareNode/{ => src}/models/activities.js (100%) rename middlewareNode/{ => src}/models/categorys.js (100%) rename middlewareNode/{ => src}/models/guest.js (100%) rename middlewareNode/{ => src}/models/meetings.js (100%) rename middlewareNode/{ => src}/models/moves.js (100%) rename middlewareNode/{ => src}/models/puzzles.js (100%) rename middlewareNode/{ => src}/models/timeTracking.js (100%) rename middlewareNode/{ => src}/models/undoPermission.js (100%) rename middlewareNode/{ => src}/models/users.js (100%) rename middlewareNode/{ => src}/models/waiting.js (100%) rename middlewareNode/{ => src}/routes/activities.js (100%) rename middlewareNode/{ => src}/routes/auth.js (100%) rename middlewareNode/{ => src}/routes/badges.js (100%) rename middlewareNode/{ => src}/routes/categorys.js (100%) rename middlewareNode/{ => src}/routes/lessons.js (100%) rename middlewareNode/{ => src}/routes/meetings.js (100%) rename middlewareNode/{ => src}/routes/puzzles.js (100%) rename middlewareNode/{ => src}/routes/streak.js (100%) rename middlewareNode/{ => src}/routes/timeTracking.js (100%) rename middlewareNode/{ => src}/routes/users.js (100%) rename middlewareNode/{ => src}/scheduler/activitiesScheduler.js (100%) rename middlewareNode/{ => src}/server.js (100%) rename middlewareNode/{ => src}/template/changePasswordTemplate.js (100%) rename middlewareNode/{ => src}/utils/activities.js (100%) rename middlewareNode/{ => src}/utils/middleware.js (100%) rename middlewareNode/{ => src}/utils/nodemailer.js (100%) rename middlewareNode/{ => src}/utils/recordings.js (100%) rename react-ystemandchess/src/{ => assets}/images/ActivitiesAssets/bottom_vine.svg (100%) rename react-ystemandchess/src/{ => assets}/images/ActivitiesAssets/growth_box.svg (100%) rename react-ystemandchess/src/{ => assets}/images/ActivitiesAssets/hanging_vine.svg (100%) rename react-ystemandchess/src/{ => assets}/images/ActivitiesAssets/middle_vine.svg (100%) rename react-ystemandchess/src/{ => assets}/images/ActivitiesAssets/short_bottom_vine.svg (100%) rename react-ystemandchess/src/{ => assets}/images/ActivitiesAssets/stemmy.svg (100%) rename react-ystemandchess/src/{ => assets}/images/ActivitiesAssets/top_vine.svg (100%) rename react-ystemandchess/src/{ => assets}/images/ActivitiesAssets/topic_bag.svg (100%) rename react-ystemandchess/src/{ => assets}/images/ActivitiesAssets/vine_background.png (100%) rename react-ystemandchess/src/{ => assets}/images/ActivitiesAssets/water_meter.svg (100%) rename react-ystemandchess/src/{ => assets}/images/LogoLineBreak.png (100%) rename react-ystemandchess/src/{ => assets}/images/StreakProgressAssets/Calendar.png (100%) rename react-ystemandchess/src/{ => assets}/images/StreakProgressAssets/polygon.svg (100%) rename react-ystemandchess/src/{ => assets}/images/StreakProgressAssets/polygon_2.svg (100%) rename react-ystemandchess/src/{ => assets}/images/StreakProgressAssets/stemette.svg (100%) rename react-ystemandchess/src/{ => assets}/images/StreakProgressAssets/stemmy.svg (100%) rename react-ystemandchess/src/{ => assets}/images/StreakProgressAssets/streak_progress_clock.png (100%) rename react-ystemandchess/src/{ => assets}/images/StreakProgressAssets/streak_progress_clock.svg (100%) rename react-ystemandchess/src/{ => assets}/images/StudentInventoryIcons/activity-icon.svg (100%) rename react-ystemandchess/src/{ => assets}/images/StudentInventoryIcons/backpack-icon.svg (100%) rename react-ystemandchess/src/{ => assets}/images/StudentInventoryIcons/chess-lessons-icon.svg (100%) rename react-ystemandchess/src/{ => assets}/images/StudentInventoryIcons/games-icon.svg (100%) rename react-ystemandchess/src/{ => assets}/images/StudentInventoryIcons/learning-icon.svg (100%) rename react-ystemandchess/src/{ => assets}/images/StudentInventoryIcons/mentor-icon.svg (100%) rename react-ystemandchess/src/{ => assets}/images/StudentInventoryIcons/play-computer-icon.svg (100%) rename react-ystemandchess/src/{ => assets}/images/StudentInventoryIcons/puzzles-icon.svg (100%) rename react-ystemandchess/src/{ => assets}/images/StudentInventoryIcons/recordings-icon.svg (100%) rename react-ystemandchess/src/{ => assets}/images/Trees-Group.png (100%) rename react-ystemandchess/src/{ => assets}/images/aboutUs/02.png (100%) rename react-ystemandchess/src/{ => assets}/images/aboutUs/09.png (100%) rename react-ystemandchess/src/{ => assets}/images/aboutUs/40.png (100%) rename react-ystemandchess/src/{ => assets}/images/aboutUs/about-us.png (100%) rename react-ystemandchess/src/{ => assets}/images/aboutUs/divide_icon.png (100%) rename react-ystemandchess/src/{ => assets}/images/aboutUs/student.png (100%) rename react-ystemandchess/src/{ => assets}/images/book-howtostart.png (100%) rename react-ystemandchess/src/{ => assets}/images/book-thezerodollar.png (100%) rename react-ystemandchess/src/{ => assets}/images/buy-now.png (100%) rename react-ystemandchess/src/{ => assets}/images/camera.svg (100%) rename react-ystemandchess/src/{ => assets}/images/chess-piece-pattern.png (100%) rename react-ystemandchess/src/{ => assets}/images/chess-piece-pattern.svg (100%) rename react-ystemandchess/src/{ => assets}/images/chessGroup.png (100%) rename react-ystemandchess/src/{Pages/Lessons => assets/images}/chess_background.png (100%) rename react-ystemandchess/src/{ => assets}/images/difference.png (100%) rename react-ystemandchess/src/{ => assets}/images/donate.png (100%) rename react-ystemandchess/src/{ => assets}/images/facebookIcon.svg (100%) rename react-ystemandchess/src/{ => assets}/images/founder-story.png (100%) rename react-ystemandchess/src/{ => assets}/images/free-lunch.png (100%) rename react-ystemandchess/src/{ => assets}/images/full_logo.png (100%) rename react-ystemandchess/src/{ => assets}/images/gem-regular.svg (100%) rename react-ystemandchess/src/{ => assets}/images/googleIcon.svg (100%) rename react-ystemandchess/src/{ => assets}/images/heart-regular.svg (100%) rename react-ystemandchess/src/{Pages/Lessons => assets/images/icons}/icon_back.svg (100%) rename react-ystemandchess/src/{Pages/Lessons => assets/images/icons}/icon_back_inactive.svg (100%) rename react-ystemandchess/src/{Pages/Lessons => assets/images/icons}/icon_next.svg (100%) rename react-ystemandchess/src/{Pages/Lessons => assets/images/icons}/icon_next_inactive.svg (100%) rename react-ystemandchess/src/{Pages/Lessons => assets/images/icons}/icon_redo.svg (100%) rename react-ystemandchess/src/{ => assets}/images/imageImporter.tsx (99%) rename react-ystemandchess/src/{ => assets}/images/instagramIcon.svg (100%) rename react-ystemandchess/src/{ => assets}/images/kidsCoding.png (100%) rename react-ystemandchess/src/{ => assets}/images/large_info.png (100%) rename react-ystemandchess/src/{ => assets}/images/line-graph-placeholder.png (100%) rename react-ystemandchess/src/{ => assets}/images/mathArticle/Footer.png (100%) rename react-ystemandchess/src/{ => assets}/images/mathArticle/Group 67.png (100%) rename react-ystemandchess/src/{ => assets}/images/mathArticle/Junechamp 2.png (100%) rename react-ystemandchess/src/{Pages/Lessons => assets/images/mathArticle}/Rectangle 313.png (100%) rename react-ystemandchess/src/{ => assets}/images/mathArticle/Signup.png (100%) rename react-ystemandchess/src/{ => assets}/images/mathArticle/computer.png (100%) rename react-ystemandchess/src/{ => assets}/images/mathArticle/logo.png (100%) rename react-ystemandchess/src/{ => assets}/images/mission-image.png (100%) rename react-ystemandchess/src/{ => assets}/images/partners/Rotary.png (100%) rename react-ystemandchess/src/{ => assets}/images/partners/boiseDistrict.png (100%) rename react-ystemandchess/src/{ => assets}/images/partners/boiseRescue.png (100%) rename react-ystemandchess/src/{ => assets}/images/partners/boysAndGirls.png (100%) rename react-ystemandchess/src/{ => assets}/images/partners/possible.png (100%) rename react-ystemandchess/src/{ => assets}/images/premium.png (100%) rename react-ystemandchess/src/{ => assets}/images/sponsors/PH.svg (100%) rename react-ystemandchess/src/{ => assets}/images/sponsors/idahoCentral.png (100%) rename react-ystemandchess/src/{ => assets}/images/sponsors/kount.png (100%) rename react-ystemandchess/src/{ => assets}/images/sponsors/ventive.png (100%) rename react-ystemandchess/src/{ => assets}/images/student/Leaderboard_User_avatar_1.png (100%) rename react-ystemandchess/src/{ => assets}/images/student/Leaderboard_User_avatar_2.png (100%) rename react-ystemandchess/src/{ => assets}/images/student/Leaderboard_User_avatar_3.png (100%) rename react-ystemandchess/src/{ => assets}/images/student/Leaderboard_rank_1.svg (100%) rename react-ystemandchess/src/{ => assets}/images/student/Leaderboard_rank_2.svg (100%) rename react-ystemandchess/src/{ => assets}/images/student/Leaderboard_rank_3.svg (100%) rename react-ystemandchess/src/{ => assets}/images/student/STEMy_Mascot.png (100%) rename react-ystemandchess/src/{ => assets}/images/student/activities_button.svg (100%) rename react-ystemandchess/src/{ => assets}/images/student/activity_tab.png (100%) rename react-ystemandchess/src/{ => assets}/images/student/badges_button.svg (100%) rename react-ystemandchess/src/{ => assets}/images/student/bg-image.png (100%) rename react-ystemandchess/src/{ => assets}/images/student/chess_tab.png (100%) rename react-ystemandchess/src/{ => assets}/images/student/chess_tab1.png (100%) rename react-ystemandchess/src/{ => assets}/images/student/games_tab.png (100%) rename react-ystemandchess/src/{ => assets}/images/student/games_tab1.png (100%) rename react-ystemandchess/src/{ => assets}/images/student/inventory_tab.png (100%) rename react-ystemandchess/src/{ => assets}/images/student/leaderboard_button.svg (100%) rename react-ystemandchess/src/{ => assets}/images/student/leaderboard_sidebar_icon.svg (100%) rename react-ystemandchess/src/{ => assets}/images/student/math_tab.png (100%) rename react-ystemandchess/src/{ => assets}/images/student/mento_tab.png (100%) rename react-ystemandchess/src/{ => assets}/images/student/mento_tab1.png (100%) rename react-ystemandchess/src/{ => assets}/images/student/play_tab.png (100%) rename react-ystemandchess/src/{ => assets}/images/student/play_tab1.png (100%) rename react-ystemandchess/src/{ => assets}/images/student/prodev_tab.png (100%) rename react-ystemandchess/src/{ => assets}/images/student/prodev_tab1.png (100%) rename react-ystemandchess/src/{ => assets}/images/student/profilePic 2.png (100%) rename react-ystemandchess/src/{ => assets}/images/student/profilePic.png (100%) rename react-ystemandchess/src/{ => assets}/images/student/profile_button.svg (100%) rename react-ystemandchess/src/{ => assets}/images/student/pupil.svg (100%) rename react-ystemandchess/src/{ => assets}/images/student/puzzles_tab.png (100%) rename react-ystemandchess/src/{ => assets}/images/student/puzzles_tab1.png (100%) rename react-ystemandchess/src/{ => assets}/images/student/recordings_tab.png (100%) rename react-ystemandchess/src/{ => assets}/images/student/recordings_tab1.png (100%) rename react-ystemandchess/src/{ => assets}/images/student/sponsor_1.png (100%) rename react-ystemandchess/src/{ => assets}/images/student/sponsor_2.png (100%) rename react-ystemandchess/src/{ => assets}/images/student/sponsor_3.png (100%) rename react-ystemandchess/src/{ => assets}/images/student/sponsor_4.png (100%) rename react-ystemandchess/src/{ => assets}/images/student/sponsor_5.png (100%) rename react-ystemandchess/src/{ => assets}/images/student/sponsor_6.png (100%) rename react-ystemandchess/src/{ => assets}/images/student/sponsor_7.png (100%) rename react-ystemandchess/src/{ => assets}/images/student/sponsor_8.png (100%) rename react-ystemandchess/src/{ => assets}/images/student/streak_button.svg (100%) rename react-ystemandchess/src/{ => assets}/images/student/sunrise.png (100%) rename react-ystemandchess/src/{ => assets}/images/teaching.png (100%) rename react-ystemandchess/src/{ => assets}/images/twitterIcon.svg (100%) rename react-ystemandchess/src/{ => assets}/images/user-portrait-placeholder.svg (100%) rename react-ystemandchess/src/{ => assets}/images/volunteer.png (100%) rename react-ystemandchess/src/{Footer => components/footer}/Footer.css (100%) rename react-ystemandchess/src/{Footer => components/footer}/Footer.tsx (78%) rename react-ystemandchess/src/{NavBar => components/navbar}/NavBar.scss (100%) rename react-ystemandchess/src/{NavBar => components/navbar}/NavBar.tsx (99%) rename react-ystemandchess/src/{ => core}/services/badgesApi.ts (100%) rename react-ystemandchess/src/{ => core}/services/themesService.ts (100%) rename react-ystemandchess/src/{ => core}/services/view-sdk.service.ts (100%) rename react-ystemandchess/src/{ => core}/types/chessboardjsx.d.ts (100%) rename react-ystemandchess/src/{ => core}/types/declarations.d.ts (100%) rename react-ystemandchess/src/{ => core}/types/global.d.ts (100%) rename react-ystemandchess/src/{ => core}/utils/activityNames.ts (100%) rename react-ystemandchess/src/{lib/utils.ts => core/utils/cn.ts} (100%) rename react-ystemandchess/src/{Pages/About-Us/AboutUs => features/about-us/aboutus}/AboutUs.scss (94%) rename react-ystemandchess/src/{Pages/About-Us/AboutUs => features/about-us/aboutus}/AboutUs.test.tsx (100%) rename react-ystemandchess/src/{Pages/About-Us/AboutUs => features/about-us/aboutus}/AboutUs.tsx (83%) rename react-ystemandchess/src/{Pages/About-Us/Benefit-of-Chess => features/about-us/benefit-of-chess}/ChessBenefitPage.scss (100%) rename react-ystemandchess/src/{Pages/About-Us/Benefit-of-Chess => features/about-us/benefit-of-chess}/ChessBenefitPage.tsx (99%) rename react-ystemandchess/src/{Pages/About-Us/Benefit-of-CS => features/about-us/benefit-of-cs}/CSBenefitPage.scss (100%) rename react-ystemandchess/src/{Pages/About-Us/Benefit-of-CS => features/about-us/benefit-of-cs}/CSBenefitPage.tsx (97%) rename react-ystemandchess/src/{Pages/About-Us/Benefit-of-Math-tut => features/about-us/benefit-of-math-tut}/MathTutBenefitPage.scss (100%) rename react-ystemandchess/src/{Pages/About-Us/Benefit-of-Math-tut => features/about-us/benefit-of-math-tut}/MathTutBenefitPage.tsx (97%) rename react-ystemandchess/src/{Pages/About-Us/Benefit-of-Mentoring => features/about-us/benefit-of-mentoring}/MentoringBenefitPage.scss (100%) rename react-ystemandchess/src/{Pages/About-Us/Benefit-of-Mentoring => features/about-us/benefit-of-mentoring}/MentoringBenefitPage.tsx (97%) rename react-ystemandchess/src/{Pages/About-Us/Board => features/about-us/board}/Board.scss (100%) rename react-ystemandchess/src/{Pages/About-Us/Board => features/about-us/board}/Board.tsx (96%) rename react-ystemandchess/src/{Pages/About-Us/Financial => features/about-us/financial}/Financial.scss (100%) rename react-ystemandchess/src/{Pages/About-Us/Financial => features/about-us/financial}/Financial.tsx (96%) rename react-ystemandchess/src/{Pages/About-Us/Mission => features/about-us/mission}/Mission.scss (100%) rename react-ystemandchess/src/{Pages/About-Us/Mission => features/about-us/mission}/Mission.tsx (92%) rename react-ystemandchess/src/{Pages/About-Us/Online-Expansion => features/about-us/online-expansion}/OnlineExpansion.tsx (100%) rename react-ystemandchess/src/{Pages/About-Us/SponsorsPartners => features/about-us/sponsors-partners}/SponsorsPartners.scss (100%) rename react-ystemandchess/src/{Pages/About-Us/SponsorsPartners => features/about-us/sponsors-partners}/SponsorsPartners.tsx (70%) rename react-ystemandchess/src/{Pages/Login => features/auth/login}/Login.scss (100%) rename react-ystemandchess/src/{Pages/Login => features/auth/login}/Login.test.tsx (100%) rename react-ystemandchess/src/{Pages/Login => features/auth/login}/Login.tsx (98%) rename react-ystemandchess/src/{Pages/Login => features/auth/login}/loginController.ts (100%) rename react-ystemandchess/src/{Pages/Login => features/auth/login}/loginRouter.ts (100%) rename react-ystemandchess/src/{Pages/Login => features/auth/login}/loginService.ts (100%) rename react-ystemandchess/src/{Pages => features/auth/reset-password}/Reset-Password/reset-password.component.scss (100%) rename react-ystemandchess/src/{Pages => features/auth/reset-password}/Reset-Password/reset-password.test.tsx (100%) rename react-ystemandchess/src/{Pages => features/auth/reset-password}/Reset-Password/reset-password.tsx (100%) rename react-ystemandchess/src/{Pages => features/auth/reset-password}/Reset-Password/resetPasswordController.ts (100%) rename react-ystemandchess/src/{Pages => features/auth/reset-password}/Reset-Password/resetPasswordRouter.ts (100%) rename react-ystemandchess/src/{Pages => features/auth/reset-password}/Reset-Password/resetPasswordService.ts (94%) rename react-ystemandchess/src/{Pages => features/auth/set-password}/Set-Password/set-password.component.scss (100%) rename react-ystemandchess/src/{Pages => features/auth/set-password}/Set-Password/set-password.test.ts (100%) rename react-ystemandchess/src/{Pages => features/auth/set-password}/Set-Password/set-password.test.tsx (100%) rename react-ystemandchess/src/{Pages => features/auth/set-password}/Set-Password/set-password.tsx (100%) rename react-ystemandchess/src/{Pages => features/auth/set-password}/Set-Password/setPasswordController.ts (100%) rename react-ystemandchess/src/{Pages => features/auth/set-password}/Set-Password/setPasswordRouter.ts (100%) rename react-ystemandchess/src/{Pages => features/auth/set-password}/Set-Password/setPasswordService.ts (100%) rename react-ystemandchess/src/{Pages/SignUp => features/auth/signup}/SignUp.scss (100%) rename react-ystemandchess/src/{Pages/SignUp => features/auth/signup}/SignUp.test.tsx (100%) rename react-ystemandchess/src/{Pages/SignUp => features/auth/signup}/SignUp.tsx (99%) rename react-ystemandchess/src/{Pages/SignUp => features/auth/signup}/signupController.ts (100%) rename react-ystemandchess/src/{Pages/SignUp => features/auth/signup}/signupRouter.ts (100%) rename react-ystemandchess/src/{Pages/SignUp => features/auth/signup}/signupService.ts (100%) rename react-ystemandchess/src/{Pages/Home => features/home}/Home.css (100%) rename react-ystemandchess/src/{Pages/Home => features/home}/Home.test.tsx (100%) rename react-ystemandchess/src/{Pages/Home => features/home}/Home.tsx (99%) create mode 100644 react-ystemandchess/src/features/home/Home/Home.tsx rename react-ystemandchess/src/{Pages/Lessons => features/lessons/lessons-main}/Lessons-profile.module.scss (100%) rename react-ystemandchess/src/{Pages/Lessons => features/lessons/lessons-main}/Lessons.module.scss (100%) rename react-ystemandchess/src/{Pages/Lessons => features/lessons/lessons-main}/Lessons.test.tsx (100%) rename react-ystemandchess/src/{Pages/Lessons => features/lessons/lessons-main}/Lessons.tsx (100%) rename react-ystemandchess/src/{Pages/Lessons => features/lessons/lessons-main}/Placeholder.jsx (100%) rename react-ystemandchess/src/{Pages/Lessons => features/lessons/lessons-main}/PromotionPopup.tsx (100%) rename react-ystemandchess/src/{images/mathArticle => features/lessons/lessons-main}/Rectangle 313.png (100%) rename react-ystemandchess/src/{Pages/Lessons => features/lessons/lessons-main}/Scenarios.js (100%) rename react-ystemandchess/src/{images => features/lessons/lessons-main}/chess_background.png (100%) rename react-ystemandchess/src/{images/icons => features/lessons/lessons-main}/icon_back.svg (100%) rename react-ystemandchess/src/{images/icons => features/lessons/lessons-main}/icon_back_inactive.svg (100%) rename react-ystemandchess/src/{images/icons => features/lessons/lessons-main}/icon_next.svg (100%) rename react-ystemandchess/src/{images/icons => features/lessons/lessons-main}/icon_next_inactive.svg (100%) rename react-ystemandchess/src/{images/icons => features/lessons/lessons-main}/icon_redo.svg (100%) rename react-ystemandchess/src/{Pages/Lessons => features/lessons/lessons-main}/register_button.png (100%) rename react-ystemandchess/src/{Pages/LessonsSelection => features/lessons/lessons-selection}/LessonTemplate/LessonTemplate.jsx (100%) rename react-ystemandchess/src/{Pages/LessonsSelection => features/lessons/lessons-selection}/LessonsSelection.jsx (98%) rename react-ystemandchess/src/{Pages/LessonsSelection => features/lessons/lessons-selection}/LessonsSelection.test.tsx (100%) rename react-ystemandchess/src/{Pages/LessonsSelection => features/lessons/lessons-selection}/LessonsStyle.module.scss (100%) rename react-ystemandchess/src/{Pages/LessonsSelection => features/lessons/lessons-selection}/ProfileStyle.module.scss (100%) rename react-ystemandchess/src/{Pages/LessonsSelection => features/lessons/lessons-selection}/ScenarioTemplate/ScenarioTemplate.jsx (100%) rename react-ystemandchess/src/{Pages => features/lessons}/piece-lessons/lesson-overlay/Lesson-overlay-profile.module.scss (100%) rename react-ystemandchess/src/{Pages => features/lessons}/piece-lessons/lesson-overlay/Lesson-overlay.module.scss (99%) rename react-ystemandchess/src/{Pages => features/lessons}/piece-lessons/lesson-overlay/Lesson-overlay.test.tsx (100%) rename react-ystemandchess/src/{Pages => features/lessons}/piece-lessons/lesson-overlay/Lesson-overlay.tsx (96%) rename react-ystemandchess/src/{Pages => features/lessons}/piece-lessons/lesson-overlay/answers.js (100%) rename react-ystemandchess/src/{Pages => features/lessons}/piece-lessons/lesson-overlay/hooks/useChessGameLogic.test.ts (100%) rename react-ystemandchess/src/{Pages => features/lessons}/piece-lessons/lesson-overlay/hooks/useChessGameLogic.ts (100%) rename react-ystemandchess/src/{Pages => features/lessons}/piece-lessons/lesson-overlay/hooks/useLessonManager.test.ts (100%) rename react-ystemandchess/src/{Pages => features/lessons}/piece-lessons/lesson-overlay/hooks/useLessonManager.ts (98%) rename react-ystemandchess/src/{Pages => features/lessons}/piece-lessons/lesson-overlay/hooks/useSocketChessEngine.test.ts (100%) rename react-ystemandchess/src/{Pages => features/lessons}/piece-lessons/lesson-overlay/hooks/useSocketChessEngine.ts (91%) rename react-ystemandchess/src/{Pages => features/lessons}/piece-lessons/lesson-overlay/hooks/useTimeTracking.test.ts (92%) rename react-ystemandchess/src/{Pages => features/lessons}/piece-lessons/lesson-overlay/hooks/useTimeTracking.ts (92%) rename react-ystemandchess/src/{Pages => features/lessons}/piece-lessons/move-tracker/MoveTracker.tsx (100%) rename react-ystemandchess/src/{Pages => features/lessons}/piece-lessons/play-lesson/PlayLesson.tsx (100%) rename react-ystemandchess/src/{Pages => features/lessons}/piece-lessons/play-lesson/lesson-content copy.scss (100%) rename react-ystemandchess/src/{Pages => features/lessons}/piece-lessons/play-lesson/lesson-content.scss (100%) rename react-ystemandchess/src/{Pages/Mentor => features/mentor/mentor-page}/Mentor.scss (100%) rename react-ystemandchess/src/{Pages/Mentor => features/mentor/mentor-page}/Mentor.test.tsx (100%) rename react-ystemandchess/src/{Pages/Mentor => features/mentor/mentor-page}/Mentor.tsx (79%) rename react-ystemandchess/src/{Pages/NewMentorProfile => features/mentor/mentor-profile}/NewMentorProfile.scss (100%) rename react-ystemandchess/src/{Pages/NewMentorProfile => features/mentor/mentor-profile}/NewMentorProfile.test.tsx (98%) rename react-ystemandchess/src/{Pages/NewMentorProfile => features/mentor/mentor-profile}/NewMentorProfile.tsx (96%) create mode 100644 react-ystemandchess/src/features/mentor/mentor-profile/NewMentorProfile/NewMentorProfile.tsx rename react-ystemandchess/src/{Pages/Programs => features/programs}/Programs.scss (100%) rename react-ystemandchess/src/{Pages/Programs => features/programs}/Programs.test.tsx (100%) rename react-ystemandchess/src/{Pages/Programs => features/programs}/Programs.tsx (98%) rename react-ystemandchess/src/{Pages/Puzzles => features/puzzles/puzzles-page}/Puzzles-profile.module.scss (100%) rename react-ystemandchess/src/{Pages/Puzzles => features/puzzles/puzzles-page}/Puzzles.module.scss (94%) rename react-ystemandchess/src/{Pages/Puzzles => features/puzzles/puzzles-page}/Puzzles.test.tsx (100%) rename react-ystemandchess/src/{Pages/Puzzles => features/puzzles/puzzles-page}/Puzzles.tsx (99%) create mode 100644 react-ystemandchess/src/features/student/student-inventory/Student-Inventory/StudentInventory.tsx rename react-ystemandchess/src/{Pages/Student-Inventory => features/student/student-inventory}/StudentInventory.scss (99%) rename react-ystemandchess/src/{Pages/Student-Inventory => features/student/student-inventory}/StudentInventory.tsx (99%) rename react-ystemandchess/src/{Pages/Student => features/student/student-page}/Student.scss (100%) rename react-ystemandchess/src/{Pages/Student => features/student/student-page}/Student.tsx (92%) rename react-ystemandchess/src/{Pages/NewStudentProfile => features/student/student-profile}/Modals/ActivitiesModal.scss (98%) rename react-ystemandchess/src/{Pages/NewStudentProfile => features/student/student-profile}/Modals/ActivitiesModal.tsx (80%) rename react-ystemandchess/src/{Pages/NewStudentProfile => features/student/student-profile}/Modals/BadgesModal.scss (100%) rename react-ystemandchess/src/{Pages/NewStudentProfile => features/student/student-profile}/Modals/BadgesModal.tsx (96%) rename react-ystemandchess/src/{Pages/NewStudentProfile => features/student/student-profile}/Modals/LeaderboardModal.scss (100%) rename react-ystemandchess/src/{Pages/NewStudentProfile => features/student/student-profile}/Modals/LeaderboardModal.tsx (94%) rename react-ystemandchess/src/{Pages/NewStudentProfile => features/student/student-profile}/Modals/StreakModal.scss (100%) rename react-ystemandchess/src/{Pages/NewStudentProfile => features/student/student-profile}/Modals/StreakModal.tsx (81%) rename react-ystemandchess/src/{Pages/NewStudentProfile => features/student/student-profile}/NewStudentProfile.scss (99%) rename react-ystemandchess/src/{Pages/NewStudentProfile => features/student/student-profile}/NewStudentProfile.test.tsx (98%) rename react-ystemandchess/src/{Pages/NewStudentProfile => features/student/student-profile}/NewStudentProfile.tsx (91%) create mode 100644 react-ystemandchess/src/features/student/student-profile/NewStudentProfile/Modals/BadgesModal.tsx rename react-ystemandchess/src/{Pages/NewStudentProfile => features/student/student-profile}/StatsChart.tsx (100%) rename stockfishServer/{ => src/archive}/index_new.js (100%) rename stockfishServer/{ => src}/bin/stockfish_11_linux (100%) rename stockfishServer/{ => src}/bin/stockfish_11_mac (100%) rename stockfishServer/{ => src}/bin/stockfish_11_win.exe (100%) rename stockfishServer/{ => src}/index.js (100%) rename stockfishServer/{ => src/managers}/StockfishManager.js (100%) rename stockfishServer/{ => src/managers}/socket.js (100%) rename stockfishServer/{__tests__ => src/tests}/StockfishManager.test.js (100%) rename stockfishServer/{__tests__ => src/tests}/index.test.js (100%) diff --git a/README.md b/README.md index 5885bc6d..0bbabced 100644 --- a/README.md +++ b/README.md @@ -128,15 +128,16 @@ Each service runs independently and requires its own terminal window. Start the Handles user authentication, database operations, and coordinates other services. - ```bash cd middlewareNode npm install # Install backend dependencies -npm start # Start the API server +npm start # Start the API server (runs from src/server.js) ``` The server typically runs on port 8000. You should see "MongoDB Connected..." when it starts successfully. +> **Note**: After modularization, the entry point is now `src/server.js` + **If you intend to test the mentor and student login pages, you may use the following usernames and passwords respectively:** mentor 123123123 @@ -166,11 +167,13 @@ Manages chess game logic, validates moves, and handles real-time gameplay: ```bash cd chessServer npm install -npm start +npm start # Starts from src/index.js ``` Defaults to port 3000 (or the next available port if taken). +> **Note**: After modularization, the entry point is now `src/index.js` + --- #### Chess Engine Server @@ -180,11 +183,13 @@ Integrates Stockfish for AI opponents and move analysis: ```bash cd stockfishServer npm install -npm start +npm start # Starts from src/index.js ``` This service usually runs on port 8080. +> **Note**: After modularization, the entry point is now `src/index.js` + --- #### Chess Client (Testing Interface) @@ -198,8 +203,9 @@ Run the http server on port 80 using: `npx http-server -p 80` to ensure that the You can use the **Live Server extension in VS Code** to open the HTML files for local testing of the chess board: * **Board only:** Right-click `index.html` → "Open with Live Server" -* **Board with controls:** Right-click `parent.html` → "Open with Live Server" -* **Mentor/Student interaction:** Right-click `both.html` → "Open with Live Server" +* **Archived files:** `archive/parent.html` and `archive/both.html` contain legacy testing interfaces + +> **Note**: Old HTML test files have been moved to `archive/` directory after modularization --- @@ -231,4 +237,30 @@ git checkout -b my-branch-name --- -You’re all set! Happy coding and thank you for contributing to educational equity! 🎯♟️ \ No newline at end of file +## Project Structure + +This project has been recently modularized for better organization and maintainability. Key structural changes: + +- **All Node.js services** now have their code in a `src/` directory +- **React app** uses a feature-based architecture with: + - `components/` - Reusable UI components + - `features/` - Feature modules (auth, lessons, student, mentor, etc.) + - `core/` - Core infrastructure (services, types, utils) + - `assets/` - Static assets and images +- **Configuration files** are organized in the `config/` directory +- **Kubernetes deployments** are in the `yaml/` directory + +--- + +## Docker Deployment + +To run all services using Docker: + +```bash +cd config +docker-compose up +``` + +--- + +You're all set! Happy coding and thank you for contributing to educational equity! 🎯♟️ \ No newline at end of file diff --git a/chessClient/both.html b/chessClient/archive/both.html similarity index 100% rename from chessClient/both.html rename to chessClient/archive/both.html diff --git a/chessClient/parent.html b/chessClient/archive/parent.html similarity index 100% rename from chessClient/parent.html rename to chessClient/archive/parent.html diff --git a/chessClient/rapid_render.json b/chessClient/archive/rapid_render.json similarity index 100% rename from chessClient/rapid_render.json rename to chessClient/archive/rapid_render.json diff --git a/chessClient/CHANGELOG.md b/chessClient/docs/CHANGELOG.md similarity index 100% rename from chessClient/CHANGELOG.md rename to chessClient/docs/CHANGELOG.md diff --git a/chessClient/LICENSE.md b/chessClient/docs/LICENSE.md similarity index 100% rename from chessClient/LICENSE.md rename to chessClient/docs/LICENSE.md diff --git a/chessClient/README_MOBILE_RESPONSIVE.md b/chessClient/docs/README_MOBILE_RESPONSIVE.md similarity index 100% rename from chessClient/README_MOBILE_RESPONSIVE.md rename to chessClient/docs/README_MOBILE_RESPONSIVE.md diff --git a/chessServer/package.json b/chessServer/package.json index 05f6e79c..86ebbe29 100644 --- a/chessServer/package.json +++ b/chessServer/package.json @@ -2,9 +2,9 @@ "name": "chess-server", "version": "1.0.0", "description": "", - "main": "index.js", + "main": "src/index.js", "scripts": { - "start": "nodemon index.js", + "start": "nodemon src/index.js", "test": "jest --detectOpenHandles --forceExit" }, "keywords": [], diff --git a/chessServer/index old 2.js b/chessServer/src/archive/index old 2.js similarity index 100% rename from chessServer/index old 2.js rename to chessServer/src/archive/index old 2.js diff --git a/chessServer/index old.js b/chessServer/src/archive/index old.js similarity index 100% rename from chessServer/index old.js rename to chessServer/src/archive/index old.js diff --git a/chessServer/index.js b/chessServer/src/index.js similarity index 100% rename from chessServer/index.js rename to chessServer/src/index.js diff --git a/chessServer/managers/EventHandlers.js b/chessServer/src/managers/EventHandlers.js similarity index 100% rename from chessServer/managers/EventHandlers.js rename to chessServer/src/managers/EventHandlers.js diff --git a/chessServer/managers/GameManager.js b/chessServer/src/managers/GameManager.js similarity index 100% rename from chessServer/managers/GameManager.js rename to chessServer/src/managers/GameManager.js diff --git a/chessServer/__tests__/GameManager.test.js b/chessServer/src/tests/GameManager.test.js similarity index 100% rename from chessServer/__tests__/GameManager.test.js rename to chessServer/src/tests/GameManager.test.js diff --git a/chessServer/__tests__/index.test.js b/chessServer/src/tests/index.test.js similarity index 100% rename from chessServer/__tests__/index.test.js rename to chessServer/src/tests/index.test.js diff --git a/chessServer/server.test.js b/chessServer/src/tests/server.test.js similarity index 100% rename from chessServer/server.test.js rename to chessServer/src/tests/server.test.js diff --git a/docker-compose.yml b/config/docker-compose.yml similarity index 100% rename from docker-compose.yml rename to config/docker-compose.yml diff --git a/mission-image.png b/documentation/mission-image.png similarity index 100% rename from mission-image.png rename to documentation/mission-image.png diff --git a/middleware/php.ini b/middleware/src/config/php.ini similarity index 100% rename from middleware/php.ini rename to middleware/src/config/php.ini diff --git a/middleware/awsGen.php b/middleware/src/endpoints/awsGen.php similarity index 100% rename from middleware/awsGen.php rename to middleware/src/endpoints/awsGen.php diff --git a/middleware/delete.php b/middleware/src/endpoints/delete.php similarity index 100% rename from middleware/delete.php rename to middleware/src/endpoints/delete.php diff --git a/middleware/endMeeting.php b/middleware/src/endpoints/endMeeting.php similarity index 100% rename from middleware/endMeeting.php rename to middleware/src/endpoints/endMeeting.php diff --git a/middleware/endSearch.php b/middleware/src/endpoints/endSearch.php similarity index 100% rename from middleware/endSearch.php rename to middleware/src/endpoints/endSearch.php diff --git a/middleware/genLink.php b/middleware/src/endpoints/genLink.php similarity index 100% rename from middleware/genLink.php rename to middleware/src/endpoints/genLink.php diff --git a/middleware/getCompletedLesson.php b/middleware/src/endpoints/getCompletedLesson.php similarity index 100% rename from middleware/getCompletedLesson.php rename to middleware/src/endpoints/getCompletedLesson.php diff --git a/middleware/getInfo.php b/middleware/src/endpoints/getInfo.php similarity index 100% rename from middleware/getInfo.php rename to middleware/src/endpoints/getInfo.php diff --git a/middleware/getLesson.php b/middleware/src/endpoints/getLesson.php similarity index 100% rename from middleware/getLesson.php rename to middleware/src/endpoints/getLesson.php diff --git a/middleware/getRecordings.php b/middleware/src/endpoints/getRecordings.php similarity index 100% rename from middleware/getRecordings.php rename to middleware/src/endpoints/getRecordings.php diff --git a/middleware/getTotalPieceLesson.php b/middleware/src/endpoints/getTotalPieceLesson.php similarity index 100% rename from middleware/getTotalPieceLesson.php rename to middleware/src/endpoints/getTotalPieceLesson.php diff --git a/middleware/index.php b/middleware/src/endpoints/index.php similarity index 100% rename from middleware/index.php rename to middleware/src/endpoints/index.php diff --git a/middleware/isInMeeting.php b/middleware/src/endpoints/isInMeeting.php similarity index 100% rename from middleware/isInMeeting.php rename to middleware/src/endpoints/isInMeeting.php diff --git a/middleware/newGame.php b/middleware/src/endpoints/newGame.php similarity index 100% rename from middleware/newGame.php rename to middleware/src/endpoints/newGame.php diff --git a/middleware/pairUp.php b/middleware/src/endpoints/pairUp.php similarity index 100% rename from middleware/pairUp.php rename to middleware/src/endpoints/pairUp.php diff --git a/middleware/record.php b/middleware/src/endpoints/record.php similarity index 100% rename from middleware/record.php rename to middleware/src/endpoints/record.php diff --git a/middleware/studentInfo.php b/middleware/src/endpoints/studentInfo.php similarity index 100% rename from middleware/studentInfo.php rename to middleware/src/endpoints/studentInfo.php diff --git a/middleware/updateLessonCompletion.php b/middleware/src/endpoints/updateLessonCompletion.php similarity index 100% rename from middleware/updateLessonCompletion.php rename to middleware/src/endpoints/updateLessonCompletion.php diff --git a/middleware/verify.php b/middleware/src/endpoints/verify.php similarity index 100% rename from middleware/verify.php rename to middleware/src/endpoints/verify.php diff --git a/middleware/verifyNoEcho.php b/middleware/src/endpoints/verifyNoEcho.php similarity index 100% rename from middleware/verifyNoEcho.php rename to middleware/src/endpoints/verifyNoEcho.php diff --git a/middleware/testQueries.txt b/middleware/src/testQueries.txt similarity index 100% rename from middleware/testQueries.txt rename to middleware/src/testQueries.txt diff --git a/middlewareNode/package.json b/middlewareNode/package.json index c05159ee..236c407e 100644 --- a/middlewareNode/package.json +++ b/middlewareNode/package.json @@ -2,7 +2,7 @@ "name": "middleware", "version": "1.0.0", "description": "API for Y STEM And Chess Inc", - "main": "server.js", + "main": "src/server.js", "dependencies": { "aws-sdk": "^2.889.0", "axios": "^0.21.1", @@ -22,7 +22,7 @@ "uuid": "^8.3.2" }, "scripts": { - "start": "nodemon server.js" + "start": "nodemon src/server.js" }, "author": "", "license": "ISC", diff --git a/middlewareNode/badges/catalog.js b/middlewareNode/src/badges/catalog.js similarity index 100% rename from middlewareNode/badges/catalog.js rename to middlewareNode/src/badges/catalog.js diff --git a/middlewareNode/badges/service.js b/middlewareNode/src/badges/service.js similarity index 100% rename from middlewareNode/badges/service.js rename to middlewareNode/src/badges/service.js diff --git a/middlewareNode/src/config/custom-environment-variables.json b/middlewareNode/src/config/custom-environment-variables.json new file mode 100644 index 00000000..9589aa2f --- /dev/null +++ b/middlewareNode/src/config/custom-environment-variables.json @@ -0,0 +1,32 @@ +{ + "mongoURI": "MONGO_URI", + "jwtSecret": "JWT_SECRET", + "indexKey": "INDEX_KEY", + + "corsOptions": { "origin": "CORS_ORIGIN" }, + + "email": { + "user": "EMAIL_USER", + "pass": "EMAIL_PASS" + }, + + "user": "EMAIL_USER", + "senderEmail": "SENDER_EMAIL", + + "clientId": "GOOGLE_CLIENT_ID", + "clientSecret": "GOOGLE_CLIENT_SECRET", + "redirectUri": "GOOGLE_REDIRECT_URI", + "refreshToken": "GOOGLE_REFRESH_TOKEN", + + "basepath": "BASEPATH", + + "awsAccessKey": "AWS_ACCESS_KEY_ID", + "awsSecretKey": "AWS_SECRET_ACCESS_KEY", + + "appID": "AGORA_APP_ID", + "uid": "AGORA_UID", + "customerId": "AGORA_CUSTOMER_ID", + "customerCertificate": "AGORA_CUSTOMER_CERT", + + "server": { "port": "PORT" } +} diff --git a/middlewareNode/config/db.js b/middlewareNode/src/config/db.js similarity index 100% rename from middlewareNode/config/db.js rename to middlewareNode/src/config/db.js diff --git a/middlewareNode/config/passport.js b/middlewareNode/src/config/passport.js similarity index 100% rename from middlewareNode/config/passport.js rename to middlewareNode/src/config/passport.js diff --git a/middlewareNode/controllers/meetings.js b/middlewareNode/src/controllers/meetings.js similarity index 100% rename from middlewareNode/controllers/meetings.js rename to middlewareNode/src/controllers/meetings.js diff --git a/middlewareNode/models/UserBadges.js b/middlewareNode/src/models/UserBadges.js similarity index 100% rename from middlewareNode/models/UserBadges.js rename to middlewareNode/src/models/UserBadges.js diff --git a/middlewareNode/models/activities.js b/middlewareNode/src/models/activities.js similarity index 100% rename from middlewareNode/models/activities.js rename to middlewareNode/src/models/activities.js diff --git a/middlewareNode/models/categorys.js b/middlewareNode/src/models/categorys.js similarity index 100% rename from middlewareNode/models/categorys.js rename to middlewareNode/src/models/categorys.js diff --git a/middlewareNode/models/guest.js b/middlewareNode/src/models/guest.js similarity index 100% rename from middlewareNode/models/guest.js rename to middlewareNode/src/models/guest.js diff --git a/middlewareNode/models/meetings.js b/middlewareNode/src/models/meetings.js similarity index 100% rename from middlewareNode/models/meetings.js rename to middlewareNode/src/models/meetings.js diff --git a/middlewareNode/models/moves.js b/middlewareNode/src/models/moves.js similarity index 100% rename from middlewareNode/models/moves.js rename to middlewareNode/src/models/moves.js diff --git a/middlewareNode/models/puzzles.js b/middlewareNode/src/models/puzzles.js similarity index 100% rename from middlewareNode/models/puzzles.js rename to middlewareNode/src/models/puzzles.js diff --git a/middlewareNode/models/timeTracking.js b/middlewareNode/src/models/timeTracking.js similarity index 100% rename from middlewareNode/models/timeTracking.js rename to middlewareNode/src/models/timeTracking.js diff --git a/middlewareNode/models/undoPermission.js b/middlewareNode/src/models/undoPermission.js similarity index 100% rename from middlewareNode/models/undoPermission.js rename to middlewareNode/src/models/undoPermission.js diff --git a/middlewareNode/models/users.js b/middlewareNode/src/models/users.js similarity index 100% rename from middlewareNode/models/users.js rename to middlewareNode/src/models/users.js diff --git a/middlewareNode/models/waiting.js b/middlewareNode/src/models/waiting.js similarity index 100% rename from middlewareNode/models/waiting.js rename to middlewareNode/src/models/waiting.js diff --git a/middlewareNode/routes/activities.js b/middlewareNode/src/routes/activities.js similarity index 100% rename from middlewareNode/routes/activities.js rename to middlewareNode/src/routes/activities.js diff --git a/middlewareNode/routes/auth.js b/middlewareNode/src/routes/auth.js similarity index 100% rename from middlewareNode/routes/auth.js rename to middlewareNode/src/routes/auth.js diff --git a/middlewareNode/routes/badges.js b/middlewareNode/src/routes/badges.js similarity index 100% rename from middlewareNode/routes/badges.js rename to middlewareNode/src/routes/badges.js diff --git a/middlewareNode/routes/categorys.js b/middlewareNode/src/routes/categorys.js similarity index 100% rename from middlewareNode/routes/categorys.js rename to middlewareNode/src/routes/categorys.js diff --git a/middlewareNode/routes/lessons.js b/middlewareNode/src/routes/lessons.js similarity index 100% rename from middlewareNode/routes/lessons.js rename to middlewareNode/src/routes/lessons.js diff --git a/middlewareNode/routes/meetings.js b/middlewareNode/src/routes/meetings.js similarity index 100% rename from middlewareNode/routes/meetings.js rename to middlewareNode/src/routes/meetings.js diff --git a/middlewareNode/routes/puzzles.js b/middlewareNode/src/routes/puzzles.js similarity index 100% rename from middlewareNode/routes/puzzles.js rename to middlewareNode/src/routes/puzzles.js diff --git a/middlewareNode/routes/streak.js b/middlewareNode/src/routes/streak.js similarity index 100% rename from middlewareNode/routes/streak.js rename to middlewareNode/src/routes/streak.js diff --git a/middlewareNode/routes/timeTracking.js b/middlewareNode/src/routes/timeTracking.js similarity index 100% rename from middlewareNode/routes/timeTracking.js rename to middlewareNode/src/routes/timeTracking.js diff --git a/middlewareNode/routes/users.js b/middlewareNode/src/routes/users.js similarity index 100% rename from middlewareNode/routes/users.js rename to middlewareNode/src/routes/users.js diff --git a/middlewareNode/scheduler/activitiesScheduler.js b/middlewareNode/src/scheduler/activitiesScheduler.js similarity index 100% rename from middlewareNode/scheduler/activitiesScheduler.js rename to middlewareNode/src/scheduler/activitiesScheduler.js diff --git a/middlewareNode/server.js b/middlewareNode/src/server.js similarity index 100% rename from middlewareNode/server.js rename to middlewareNode/src/server.js diff --git a/middlewareNode/template/changePasswordTemplate.js b/middlewareNode/src/template/changePasswordTemplate.js similarity index 100% rename from middlewareNode/template/changePasswordTemplate.js rename to middlewareNode/src/template/changePasswordTemplate.js diff --git a/middlewareNode/utils/activities.js b/middlewareNode/src/utils/activities.js similarity index 100% rename from middlewareNode/utils/activities.js rename to middlewareNode/src/utils/activities.js diff --git a/middlewareNode/utils/middleware.js b/middlewareNode/src/utils/middleware.js similarity index 100% rename from middlewareNode/utils/middleware.js rename to middlewareNode/src/utils/middleware.js diff --git a/middlewareNode/utils/nodemailer.js b/middlewareNode/src/utils/nodemailer.js similarity index 100% rename from middlewareNode/utils/nodemailer.js rename to middlewareNode/src/utils/nodemailer.js diff --git a/middlewareNode/utils/recordings.js b/middlewareNode/src/utils/recordings.js similarity index 100% rename from middlewareNode/utils/recordings.js rename to middlewareNode/src/utils/recordings.js diff --git a/react-ystemandchess/README.md b/react-ystemandchess/README.md index 58beeacc..6007de33 100644 --- a/react-ystemandchess/README.md +++ b/react-ystemandchess/README.md @@ -1,7 +1,41 @@ -# Getting Started with Create React App +# Y STEM and Chess React Application + +This is the main frontend application for the Y STEM and Chess educational platform. It provides an interactive interface for students and mentors to engage with chess lessons, puzzles, and educational content. This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). +## Project Structure + +After recent modularization, the project follows a feature-based architecture: + +``` +src/ +├── components/ # Reusable UI components +│ ├── navbar/ # Navigation bar component +│ ├── footer/ # Footer component +│ ├── chessboard/ # Chess board component +│ └── ui/ # Generic UI components +├── features/ # Feature-based modules +│ ├── about-us/ # About Us pages +│ ├── auth/ # Authentication (login, signup, password) +│ ├── home/ # Landing page +│ ├── lessons/ # Chess lessons +│ ├── mentor/ # Mentor features +│ ├── programs/ # Programs information +│ ├── puzzles/ # Chess puzzles +│ └── student/ # Student features +├── core/ # Core infrastructure +│ ├── environments/ # Environment configuration +│ ├── services/ # API services +│ ├── types/ # TypeScript type definitions +│ └── utils/ # Utility functions +├── assets/ # Static assets +│ └── images/ # Image files +├── App.tsx # Main application component +├── AppRoutes.tsx # Route definitions +└── index.tsx # Application entry point +``` + ## Available Scripts In the project directory, you can run: @@ -68,3 +102,67 @@ This section has moved here: [https://facebook.github.io/create-react-app/docs/d ### `npm run build` fails to minify This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify) + +## Development Guidelines + +### Adding New Features + +When adding new features to the application: + +1. **Create a new feature directory** under `src/features/` with appropriate naming +2. **Use the existing structure** as a template (components, hooks, services) +3. **Update routes** in `src/AppRoutes.tsx` if adding new pages +4. **Follow the established patterns** for imports and file organization + +### Component Organization + +- **Reusable components** → Place in `src/components/` +- **Feature-specific components** → Place within the relevant feature directory +- **Shared utilities** → Place in `src/core/utils/` +- **API services** → Place in `src/core/services/` + +### Import Path Recommendations + +Consider using path aliases in `tsconfig.json` for cleaner imports: + +```json +{ + "compilerOptions": { + "paths": { + "@components/*": ["src/components/*"], + "@features/*": ["src/features/*"], + "@core/*": ["src/core/*"], + "@assets/*": ["src/assets/*"] + } + } +} +``` + +## Technology Stack + +- **React** 18.3 +- **TypeScript** 4.9 +- **React Router** 7 +- **Tailwind CSS** 3 +- **Socket.IO Client** 4 +- **Axios** for API calls +- **Chess.js** for chess logic +- **Framer Motion** for animations + +## Backend Services + +This frontend connects to several backend services: + +- **Middleware Node** - Main API backend (port 8000) +- **Chess Server** - Real-time game server (port 3000) +- **Stockfish Server** - Chess AI engine (port 8080) + +Make sure these services are running for full functionality. + +## Contributing + +1. Follow the established directory structure +2. Write TypeScript with proper typing +3. Include tests for new components +4. Update documentation as needed +5. Follow existing code style and conventions diff --git a/react-ystemandchess/src/App.tsx b/react-ystemandchess/src/App.tsx index 240e44e8..f0be45f5 100644 --- a/react-ystemandchess/src/App.tsx +++ b/react-ystemandchess/src/App.tsx @@ -9,11 +9,11 @@ import "./App.css"; import React, { useEffect } from "react"; import { BrowserRouter as Router } from "react-router-dom"; -import { environment } from "./environments/environment"; +import { environment } from "./core/environments/environment"; import { useCookies } from "react-cookie"; import { SetPermissionLevel } from "./globals"; -import NavBar from "./NavBar/NavBar"; -import Footer from "./Footer/Footer"; +import NavBar from "./components/navbar/NavBar"; +import Footer from "./components/footer/Footer"; import AppRoutes from "./AppRoutes"; /** diff --git a/react-ystemandchess/src/AppRoutes.tsx b/react-ystemandchess/src/AppRoutes.tsx index 6c8b6feb..b566c568 100644 --- a/react-ystemandchess/src/AppRoutes.tsx +++ b/react-ystemandchess/src/AppRoutes.tsx @@ -18,41 +18,41 @@ import { Route, Router, Routes } from "react-router-dom"; // Page component imports - organized by category // Home and main pages -import Home from "./Pages/Home/Home"; -import Programs from "./Pages/Programs/Programs"; +import Home from "./features/home/Home"; +import Programs from "./features/programs/Programs"; // About Us section pages -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 Mission from "./Pages/About-Us/Mission/Mission"; -import SponsorsPartners from "./Pages/About-Us/SponsorsPartners/SponsorsPartners"; -import Board from "./Pages/About-Us/Board/Board"; -import Financial from "./Pages/About-Us/Financial/Financial"; -import AboutUs from "./Pages/About-Us/AboutUs/AboutUs"; +import CSBenefitPage from "./features/about-us/benefit-of-cs/CSBenefitPage"; +import ChessBenefitPage from "./features/about-us/benefit-of-chess/ChessBenefitPage"; +import MathTutBenefitPage from "./features/about-us/benefit-of-math-tut/MathTutBenefitPage"; +import MentoringBenefitPage from "./features/about-us/benefit-of-mentoring/MentoringBenefitPage"; +import Mission from "./features/about-us/mission/Mission"; +import SponsorsPartners from "./features/about-us/sponsors-partners/SponsorsPartners"; +import Board from "./features/about-us/board/Board"; +import Financial from "./features/about-us/financial/Financial"; +import AboutUs from "./features/about-us/aboutus/AboutUs"; // Educational content pages -import Lessons from "./Pages/Lessons/Lessons"; -import Puzzles from './Pages/Puzzles/Puzzles'; -import LessonSelection from "./Pages/LessonsSelection/LessonsSelection"; -import LessonOverlay from "./Pages/piece-lessons/lesson-overlay/Lesson-overlay"; +import Lessons from "./features/lessons/lessons-main/Lessons"; +import Puzzles from './features/puzzles/puzzles-page/Puzzles'; +import LessonSelection from "./features/lessons/lessons-selection/LessonsSelection"; +import LessonOverlay from "./features/lessons/piece-lessons/lesson-overlay/Lesson-overlay"; // Authentication and user management pages -import Login from "./Pages/Login/Login"; -import SignUp from "./Pages/SignUp/SignUp"; -import ResetPassword from "./Pages/Reset-Password/reset-password"; -import SetPassword from "./Pages/Set-Password/set-password"; +import Login from "./features/auth/login/Login"; +import SignUp from "./features/auth/signup/SignUp"; +import ResetPassword from "./features/auth/reset-password/Reset-Password/reset-password"; +import SetPassword from "./features/auth/set-password/Set-Password/set-password"; // User profile and dashboard pages -import Student from "./Pages/Student/Student"; -import Mentor from "./Pages/Mentor/Mentor"; -import StudentInventory from "./Pages/Student-Inventory/StudentInventory"; -import NewMentorProfile from "./Pages/NewMentorProfile/NewMentorProfile"; -import NewStudentProfile from "./Pages/NewStudentProfile/NewStudentProfile"; +import Student from "./features/student/student-page/Student"; +import Mentor from "./features/mentor/mentor-page/Mentor"; +import StudentInventory from "./features/student/student-inventory/StudentInventory"; +import NewMentorProfile from "./features/mentor/mentor-profile/NewMentorProfile"; +import NewStudentProfile from "./features/student/student-profile/NewStudentProfile"; // Static assets and default data -import userPortraitImg from "./images/user-portrait-placeholder.svg"; +import userPortraitImg from "./assets/images/user-portrait-placeholder.svg"; /** * Default username for components that require user data diff --git a/react-ystemandchess/src/images/ActivitiesAssets/bottom_vine.svg b/react-ystemandchess/src/assets/images/ActivitiesAssets/bottom_vine.svg similarity index 100% rename from react-ystemandchess/src/images/ActivitiesAssets/bottom_vine.svg rename to react-ystemandchess/src/assets/images/ActivitiesAssets/bottom_vine.svg diff --git a/react-ystemandchess/src/images/ActivitiesAssets/growth_box.svg b/react-ystemandchess/src/assets/images/ActivitiesAssets/growth_box.svg similarity index 100% rename from react-ystemandchess/src/images/ActivitiesAssets/growth_box.svg rename to react-ystemandchess/src/assets/images/ActivitiesAssets/growth_box.svg diff --git a/react-ystemandchess/src/images/ActivitiesAssets/hanging_vine.svg b/react-ystemandchess/src/assets/images/ActivitiesAssets/hanging_vine.svg similarity index 100% rename from react-ystemandchess/src/images/ActivitiesAssets/hanging_vine.svg rename to react-ystemandchess/src/assets/images/ActivitiesAssets/hanging_vine.svg diff --git a/react-ystemandchess/src/images/ActivitiesAssets/middle_vine.svg b/react-ystemandchess/src/assets/images/ActivitiesAssets/middle_vine.svg similarity index 100% rename from react-ystemandchess/src/images/ActivitiesAssets/middle_vine.svg rename to react-ystemandchess/src/assets/images/ActivitiesAssets/middle_vine.svg diff --git a/react-ystemandchess/src/images/ActivitiesAssets/short_bottom_vine.svg b/react-ystemandchess/src/assets/images/ActivitiesAssets/short_bottom_vine.svg similarity index 100% rename from react-ystemandchess/src/images/ActivitiesAssets/short_bottom_vine.svg rename to react-ystemandchess/src/assets/images/ActivitiesAssets/short_bottom_vine.svg diff --git a/react-ystemandchess/src/images/ActivitiesAssets/stemmy.svg b/react-ystemandchess/src/assets/images/ActivitiesAssets/stemmy.svg similarity index 100% rename from react-ystemandchess/src/images/ActivitiesAssets/stemmy.svg rename to react-ystemandchess/src/assets/images/ActivitiesAssets/stemmy.svg diff --git a/react-ystemandchess/src/images/ActivitiesAssets/top_vine.svg b/react-ystemandchess/src/assets/images/ActivitiesAssets/top_vine.svg similarity index 100% rename from react-ystemandchess/src/images/ActivitiesAssets/top_vine.svg rename to react-ystemandchess/src/assets/images/ActivitiesAssets/top_vine.svg diff --git a/react-ystemandchess/src/images/ActivitiesAssets/topic_bag.svg b/react-ystemandchess/src/assets/images/ActivitiesAssets/topic_bag.svg similarity index 100% rename from react-ystemandchess/src/images/ActivitiesAssets/topic_bag.svg rename to react-ystemandchess/src/assets/images/ActivitiesAssets/topic_bag.svg diff --git a/react-ystemandchess/src/images/ActivitiesAssets/vine_background.png b/react-ystemandchess/src/assets/images/ActivitiesAssets/vine_background.png similarity index 100% rename from react-ystemandchess/src/images/ActivitiesAssets/vine_background.png rename to react-ystemandchess/src/assets/images/ActivitiesAssets/vine_background.png diff --git a/react-ystemandchess/src/images/ActivitiesAssets/water_meter.svg b/react-ystemandchess/src/assets/images/ActivitiesAssets/water_meter.svg similarity index 100% rename from react-ystemandchess/src/images/ActivitiesAssets/water_meter.svg rename to react-ystemandchess/src/assets/images/ActivitiesAssets/water_meter.svg diff --git a/react-ystemandchess/src/images/LogoLineBreak.png b/react-ystemandchess/src/assets/images/LogoLineBreak.png similarity index 100% rename from react-ystemandchess/src/images/LogoLineBreak.png rename to react-ystemandchess/src/assets/images/LogoLineBreak.png diff --git a/react-ystemandchess/src/images/StreakProgressAssets/Calendar.png b/react-ystemandchess/src/assets/images/StreakProgressAssets/Calendar.png similarity index 100% rename from react-ystemandchess/src/images/StreakProgressAssets/Calendar.png rename to react-ystemandchess/src/assets/images/StreakProgressAssets/Calendar.png diff --git a/react-ystemandchess/src/images/StreakProgressAssets/polygon.svg b/react-ystemandchess/src/assets/images/StreakProgressAssets/polygon.svg similarity index 100% rename from react-ystemandchess/src/images/StreakProgressAssets/polygon.svg rename to react-ystemandchess/src/assets/images/StreakProgressAssets/polygon.svg diff --git a/react-ystemandchess/src/images/StreakProgressAssets/polygon_2.svg b/react-ystemandchess/src/assets/images/StreakProgressAssets/polygon_2.svg similarity index 100% rename from react-ystemandchess/src/images/StreakProgressAssets/polygon_2.svg rename to react-ystemandchess/src/assets/images/StreakProgressAssets/polygon_2.svg diff --git a/react-ystemandchess/src/images/StreakProgressAssets/stemette.svg b/react-ystemandchess/src/assets/images/StreakProgressAssets/stemette.svg similarity index 100% rename from react-ystemandchess/src/images/StreakProgressAssets/stemette.svg rename to react-ystemandchess/src/assets/images/StreakProgressAssets/stemette.svg diff --git a/react-ystemandchess/src/images/StreakProgressAssets/stemmy.svg b/react-ystemandchess/src/assets/images/StreakProgressAssets/stemmy.svg similarity index 100% rename from react-ystemandchess/src/images/StreakProgressAssets/stemmy.svg rename to react-ystemandchess/src/assets/images/StreakProgressAssets/stemmy.svg diff --git a/react-ystemandchess/src/images/StreakProgressAssets/streak_progress_clock.png b/react-ystemandchess/src/assets/images/StreakProgressAssets/streak_progress_clock.png similarity index 100% rename from react-ystemandchess/src/images/StreakProgressAssets/streak_progress_clock.png rename to react-ystemandchess/src/assets/images/StreakProgressAssets/streak_progress_clock.png diff --git a/react-ystemandchess/src/images/StreakProgressAssets/streak_progress_clock.svg b/react-ystemandchess/src/assets/images/StreakProgressAssets/streak_progress_clock.svg similarity index 100% rename from react-ystemandchess/src/images/StreakProgressAssets/streak_progress_clock.svg rename to react-ystemandchess/src/assets/images/StreakProgressAssets/streak_progress_clock.svg diff --git a/react-ystemandchess/src/images/StudentInventoryIcons/activity-icon.svg b/react-ystemandchess/src/assets/images/StudentInventoryIcons/activity-icon.svg similarity index 100% rename from react-ystemandchess/src/images/StudentInventoryIcons/activity-icon.svg rename to react-ystemandchess/src/assets/images/StudentInventoryIcons/activity-icon.svg diff --git a/react-ystemandchess/src/images/StudentInventoryIcons/backpack-icon.svg b/react-ystemandchess/src/assets/images/StudentInventoryIcons/backpack-icon.svg similarity index 100% rename from react-ystemandchess/src/images/StudentInventoryIcons/backpack-icon.svg rename to react-ystemandchess/src/assets/images/StudentInventoryIcons/backpack-icon.svg diff --git a/react-ystemandchess/src/images/StudentInventoryIcons/chess-lessons-icon.svg b/react-ystemandchess/src/assets/images/StudentInventoryIcons/chess-lessons-icon.svg similarity index 100% rename from react-ystemandchess/src/images/StudentInventoryIcons/chess-lessons-icon.svg rename to react-ystemandchess/src/assets/images/StudentInventoryIcons/chess-lessons-icon.svg diff --git a/react-ystemandchess/src/images/StudentInventoryIcons/games-icon.svg b/react-ystemandchess/src/assets/images/StudentInventoryIcons/games-icon.svg similarity index 100% rename from react-ystemandchess/src/images/StudentInventoryIcons/games-icon.svg rename to react-ystemandchess/src/assets/images/StudentInventoryIcons/games-icon.svg diff --git a/react-ystemandchess/src/images/StudentInventoryIcons/learning-icon.svg b/react-ystemandchess/src/assets/images/StudentInventoryIcons/learning-icon.svg similarity index 100% rename from react-ystemandchess/src/images/StudentInventoryIcons/learning-icon.svg rename to react-ystemandchess/src/assets/images/StudentInventoryIcons/learning-icon.svg diff --git a/react-ystemandchess/src/images/StudentInventoryIcons/mentor-icon.svg b/react-ystemandchess/src/assets/images/StudentInventoryIcons/mentor-icon.svg similarity index 100% rename from react-ystemandchess/src/images/StudentInventoryIcons/mentor-icon.svg rename to react-ystemandchess/src/assets/images/StudentInventoryIcons/mentor-icon.svg diff --git a/react-ystemandchess/src/images/StudentInventoryIcons/play-computer-icon.svg b/react-ystemandchess/src/assets/images/StudentInventoryIcons/play-computer-icon.svg similarity index 100% rename from react-ystemandchess/src/images/StudentInventoryIcons/play-computer-icon.svg rename to react-ystemandchess/src/assets/images/StudentInventoryIcons/play-computer-icon.svg diff --git a/react-ystemandchess/src/images/StudentInventoryIcons/puzzles-icon.svg b/react-ystemandchess/src/assets/images/StudentInventoryIcons/puzzles-icon.svg similarity index 100% rename from react-ystemandchess/src/images/StudentInventoryIcons/puzzles-icon.svg rename to react-ystemandchess/src/assets/images/StudentInventoryIcons/puzzles-icon.svg diff --git a/react-ystemandchess/src/images/StudentInventoryIcons/recordings-icon.svg b/react-ystemandchess/src/assets/images/StudentInventoryIcons/recordings-icon.svg similarity index 100% rename from react-ystemandchess/src/images/StudentInventoryIcons/recordings-icon.svg rename to react-ystemandchess/src/assets/images/StudentInventoryIcons/recordings-icon.svg diff --git a/react-ystemandchess/src/images/Trees-Group.png b/react-ystemandchess/src/assets/images/Trees-Group.png similarity index 100% rename from react-ystemandchess/src/images/Trees-Group.png rename to react-ystemandchess/src/assets/images/Trees-Group.png diff --git a/react-ystemandchess/src/images/aboutUs/02.png b/react-ystemandchess/src/assets/images/aboutUs/02.png similarity index 100% rename from react-ystemandchess/src/images/aboutUs/02.png rename to react-ystemandchess/src/assets/images/aboutUs/02.png diff --git a/react-ystemandchess/src/images/aboutUs/09.png b/react-ystemandchess/src/assets/images/aboutUs/09.png similarity index 100% rename from react-ystemandchess/src/images/aboutUs/09.png rename to react-ystemandchess/src/assets/images/aboutUs/09.png diff --git a/react-ystemandchess/src/images/aboutUs/40.png b/react-ystemandchess/src/assets/images/aboutUs/40.png similarity index 100% rename from react-ystemandchess/src/images/aboutUs/40.png rename to react-ystemandchess/src/assets/images/aboutUs/40.png diff --git a/react-ystemandchess/src/images/aboutUs/about-us.png b/react-ystemandchess/src/assets/images/aboutUs/about-us.png similarity index 100% rename from react-ystemandchess/src/images/aboutUs/about-us.png rename to react-ystemandchess/src/assets/images/aboutUs/about-us.png diff --git a/react-ystemandchess/src/images/aboutUs/divide_icon.png b/react-ystemandchess/src/assets/images/aboutUs/divide_icon.png similarity index 100% rename from react-ystemandchess/src/images/aboutUs/divide_icon.png rename to react-ystemandchess/src/assets/images/aboutUs/divide_icon.png diff --git a/react-ystemandchess/src/images/aboutUs/student.png b/react-ystemandchess/src/assets/images/aboutUs/student.png similarity index 100% rename from react-ystemandchess/src/images/aboutUs/student.png rename to react-ystemandchess/src/assets/images/aboutUs/student.png diff --git a/react-ystemandchess/src/images/book-howtostart.png b/react-ystemandchess/src/assets/images/book-howtostart.png similarity index 100% rename from react-ystemandchess/src/images/book-howtostart.png rename to react-ystemandchess/src/assets/images/book-howtostart.png diff --git a/react-ystemandchess/src/images/book-thezerodollar.png b/react-ystemandchess/src/assets/images/book-thezerodollar.png similarity index 100% rename from react-ystemandchess/src/images/book-thezerodollar.png rename to react-ystemandchess/src/assets/images/book-thezerodollar.png diff --git a/react-ystemandchess/src/images/buy-now.png b/react-ystemandchess/src/assets/images/buy-now.png similarity index 100% rename from react-ystemandchess/src/images/buy-now.png rename to react-ystemandchess/src/assets/images/buy-now.png diff --git a/react-ystemandchess/src/images/camera.svg b/react-ystemandchess/src/assets/images/camera.svg similarity index 100% rename from react-ystemandchess/src/images/camera.svg rename to react-ystemandchess/src/assets/images/camera.svg diff --git a/react-ystemandchess/src/images/chess-piece-pattern.png b/react-ystemandchess/src/assets/images/chess-piece-pattern.png similarity index 100% rename from react-ystemandchess/src/images/chess-piece-pattern.png rename to react-ystemandchess/src/assets/images/chess-piece-pattern.png diff --git a/react-ystemandchess/src/images/chess-piece-pattern.svg b/react-ystemandchess/src/assets/images/chess-piece-pattern.svg similarity index 100% rename from react-ystemandchess/src/images/chess-piece-pattern.svg rename to react-ystemandchess/src/assets/images/chess-piece-pattern.svg diff --git a/react-ystemandchess/src/images/chessGroup.png b/react-ystemandchess/src/assets/images/chessGroup.png similarity index 100% rename from react-ystemandchess/src/images/chessGroup.png rename to react-ystemandchess/src/assets/images/chessGroup.png diff --git a/react-ystemandchess/src/Pages/Lessons/chess_background.png b/react-ystemandchess/src/assets/images/chess_background.png similarity index 100% rename from react-ystemandchess/src/Pages/Lessons/chess_background.png rename to react-ystemandchess/src/assets/images/chess_background.png diff --git a/react-ystemandchess/src/images/difference.png b/react-ystemandchess/src/assets/images/difference.png similarity index 100% rename from react-ystemandchess/src/images/difference.png rename to react-ystemandchess/src/assets/images/difference.png diff --git a/react-ystemandchess/src/images/donate.png b/react-ystemandchess/src/assets/images/donate.png similarity index 100% rename from react-ystemandchess/src/images/donate.png rename to react-ystemandchess/src/assets/images/donate.png diff --git a/react-ystemandchess/src/images/facebookIcon.svg b/react-ystemandchess/src/assets/images/facebookIcon.svg similarity index 100% rename from react-ystemandchess/src/images/facebookIcon.svg rename to react-ystemandchess/src/assets/images/facebookIcon.svg diff --git a/react-ystemandchess/src/images/founder-story.png b/react-ystemandchess/src/assets/images/founder-story.png similarity index 100% rename from react-ystemandchess/src/images/founder-story.png rename to react-ystemandchess/src/assets/images/founder-story.png diff --git a/react-ystemandchess/src/images/free-lunch.png b/react-ystemandchess/src/assets/images/free-lunch.png similarity index 100% rename from react-ystemandchess/src/images/free-lunch.png rename to react-ystemandchess/src/assets/images/free-lunch.png diff --git a/react-ystemandchess/src/images/full_logo.png b/react-ystemandchess/src/assets/images/full_logo.png similarity index 100% rename from react-ystemandchess/src/images/full_logo.png rename to react-ystemandchess/src/assets/images/full_logo.png diff --git a/react-ystemandchess/src/images/gem-regular.svg b/react-ystemandchess/src/assets/images/gem-regular.svg similarity index 100% rename from react-ystemandchess/src/images/gem-regular.svg rename to react-ystemandchess/src/assets/images/gem-regular.svg diff --git a/react-ystemandchess/src/images/googleIcon.svg b/react-ystemandchess/src/assets/images/googleIcon.svg similarity index 100% rename from react-ystemandchess/src/images/googleIcon.svg rename to react-ystemandchess/src/assets/images/googleIcon.svg diff --git a/react-ystemandchess/src/images/heart-regular.svg b/react-ystemandchess/src/assets/images/heart-regular.svg similarity index 100% rename from react-ystemandchess/src/images/heart-regular.svg rename to react-ystemandchess/src/assets/images/heart-regular.svg diff --git a/react-ystemandchess/src/Pages/Lessons/icon_back.svg b/react-ystemandchess/src/assets/images/icons/icon_back.svg similarity index 100% rename from react-ystemandchess/src/Pages/Lessons/icon_back.svg rename to react-ystemandchess/src/assets/images/icons/icon_back.svg diff --git a/react-ystemandchess/src/Pages/Lessons/icon_back_inactive.svg b/react-ystemandchess/src/assets/images/icons/icon_back_inactive.svg similarity index 100% rename from react-ystemandchess/src/Pages/Lessons/icon_back_inactive.svg rename to react-ystemandchess/src/assets/images/icons/icon_back_inactive.svg diff --git a/react-ystemandchess/src/Pages/Lessons/icon_next.svg b/react-ystemandchess/src/assets/images/icons/icon_next.svg similarity index 100% rename from react-ystemandchess/src/Pages/Lessons/icon_next.svg rename to react-ystemandchess/src/assets/images/icons/icon_next.svg diff --git a/react-ystemandchess/src/Pages/Lessons/icon_next_inactive.svg b/react-ystemandchess/src/assets/images/icons/icon_next_inactive.svg similarity index 100% rename from react-ystemandchess/src/Pages/Lessons/icon_next_inactive.svg rename to react-ystemandchess/src/assets/images/icons/icon_next_inactive.svg diff --git a/react-ystemandchess/src/Pages/Lessons/icon_redo.svg b/react-ystemandchess/src/assets/images/icons/icon_redo.svg similarity index 100% rename from react-ystemandchess/src/Pages/Lessons/icon_redo.svg rename to react-ystemandchess/src/assets/images/icons/icon_redo.svg diff --git a/react-ystemandchess/src/images/imageImporter.tsx b/react-ystemandchess/src/assets/images/imageImporter.tsx similarity index 99% rename from react-ystemandchess/src/images/imageImporter.tsx rename to react-ystemandchess/src/assets/images/imageImporter.tsx index 907ce4d2..114accfb 100644 --- a/react-ystemandchess/src/images/imageImporter.tsx +++ b/react-ystemandchess/src/assets/images/imageImporter.tsx @@ -82,7 +82,7 @@ type ImageKey = * * Usage: * ```typescript - * import images from './images/imageImporter'; + * import images from "./assets/images/imageImporter'; * * // Type-safe image access * const logoSrc = images.LogoLineBr; diff --git a/react-ystemandchess/src/images/instagramIcon.svg b/react-ystemandchess/src/assets/images/instagramIcon.svg similarity index 100% rename from react-ystemandchess/src/images/instagramIcon.svg rename to react-ystemandchess/src/assets/images/instagramIcon.svg diff --git a/react-ystemandchess/src/images/kidsCoding.png b/react-ystemandchess/src/assets/images/kidsCoding.png similarity index 100% rename from react-ystemandchess/src/images/kidsCoding.png rename to react-ystemandchess/src/assets/images/kidsCoding.png diff --git a/react-ystemandchess/src/images/large_info.png b/react-ystemandchess/src/assets/images/large_info.png similarity index 100% rename from react-ystemandchess/src/images/large_info.png rename to react-ystemandchess/src/assets/images/large_info.png diff --git a/react-ystemandchess/src/images/line-graph-placeholder.png b/react-ystemandchess/src/assets/images/line-graph-placeholder.png similarity index 100% rename from react-ystemandchess/src/images/line-graph-placeholder.png rename to react-ystemandchess/src/assets/images/line-graph-placeholder.png diff --git a/react-ystemandchess/src/images/mathArticle/Footer.png b/react-ystemandchess/src/assets/images/mathArticle/Footer.png similarity index 100% rename from react-ystemandchess/src/images/mathArticle/Footer.png rename to react-ystemandchess/src/assets/images/mathArticle/Footer.png diff --git a/react-ystemandchess/src/images/mathArticle/Group 67.png b/react-ystemandchess/src/assets/images/mathArticle/Group 67.png similarity index 100% rename from react-ystemandchess/src/images/mathArticle/Group 67.png rename to react-ystemandchess/src/assets/images/mathArticle/Group 67.png diff --git a/react-ystemandchess/src/images/mathArticle/Junechamp 2.png b/react-ystemandchess/src/assets/images/mathArticle/Junechamp 2.png similarity index 100% rename from react-ystemandchess/src/images/mathArticle/Junechamp 2.png rename to react-ystemandchess/src/assets/images/mathArticle/Junechamp 2.png diff --git a/react-ystemandchess/src/Pages/Lessons/Rectangle 313.png b/react-ystemandchess/src/assets/images/mathArticle/Rectangle 313.png similarity index 100% rename from react-ystemandchess/src/Pages/Lessons/Rectangle 313.png rename to react-ystemandchess/src/assets/images/mathArticle/Rectangle 313.png diff --git a/react-ystemandchess/src/images/mathArticle/Signup.png b/react-ystemandchess/src/assets/images/mathArticle/Signup.png similarity index 100% rename from react-ystemandchess/src/images/mathArticle/Signup.png rename to react-ystemandchess/src/assets/images/mathArticle/Signup.png diff --git a/react-ystemandchess/src/images/mathArticle/computer.png b/react-ystemandchess/src/assets/images/mathArticle/computer.png similarity index 100% rename from react-ystemandchess/src/images/mathArticle/computer.png rename to react-ystemandchess/src/assets/images/mathArticle/computer.png diff --git a/react-ystemandchess/src/images/mathArticle/logo.png b/react-ystemandchess/src/assets/images/mathArticle/logo.png similarity index 100% rename from react-ystemandchess/src/images/mathArticle/logo.png rename to react-ystemandchess/src/assets/images/mathArticle/logo.png diff --git a/react-ystemandchess/src/images/mission-image.png b/react-ystemandchess/src/assets/images/mission-image.png similarity index 100% rename from react-ystemandchess/src/images/mission-image.png rename to react-ystemandchess/src/assets/images/mission-image.png diff --git a/react-ystemandchess/src/images/partners/Rotary.png b/react-ystemandchess/src/assets/images/partners/Rotary.png similarity index 100% rename from react-ystemandchess/src/images/partners/Rotary.png rename to react-ystemandchess/src/assets/images/partners/Rotary.png diff --git a/react-ystemandchess/src/images/partners/boiseDistrict.png b/react-ystemandchess/src/assets/images/partners/boiseDistrict.png similarity index 100% rename from react-ystemandchess/src/images/partners/boiseDistrict.png rename to react-ystemandchess/src/assets/images/partners/boiseDistrict.png diff --git a/react-ystemandchess/src/images/partners/boiseRescue.png b/react-ystemandchess/src/assets/images/partners/boiseRescue.png similarity index 100% rename from react-ystemandchess/src/images/partners/boiseRescue.png rename to react-ystemandchess/src/assets/images/partners/boiseRescue.png diff --git a/react-ystemandchess/src/images/partners/boysAndGirls.png b/react-ystemandchess/src/assets/images/partners/boysAndGirls.png similarity index 100% rename from react-ystemandchess/src/images/partners/boysAndGirls.png rename to react-ystemandchess/src/assets/images/partners/boysAndGirls.png diff --git a/react-ystemandchess/src/images/partners/possible.png b/react-ystemandchess/src/assets/images/partners/possible.png similarity index 100% rename from react-ystemandchess/src/images/partners/possible.png rename to react-ystemandchess/src/assets/images/partners/possible.png diff --git a/react-ystemandchess/src/images/premium.png b/react-ystemandchess/src/assets/images/premium.png similarity index 100% rename from react-ystemandchess/src/images/premium.png rename to react-ystemandchess/src/assets/images/premium.png diff --git a/react-ystemandchess/src/images/sponsors/PH.svg b/react-ystemandchess/src/assets/images/sponsors/PH.svg similarity index 100% rename from react-ystemandchess/src/images/sponsors/PH.svg rename to react-ystemandchess/src/assets/images/sponsors/PH.svg diff --git a/react-ystemandchess/src/images/sponsors/idahoCentral.png b/react-ystemandchess/src/assets/images/sponsors/idahoCentral.png similarity index 100% rename from react-ystemandchess/src/images/sponsors/idahoCentral.png rename to react-ystemandchess/src/assets/images/sponsors/idahoCentral.png diff --git a/react-ystemandchess/src/images/sponsors/kount.png b/react-ystemandchess/src/assets/images/sponsors/kount.png similarity index 100% rename from react-ystemandchess/src/images/sponsors/kount.png rename to react-ystemandchess/src/assets/images/sponsors/kount.png diff --git a/react-ystemandchess/src/images/sponsors/ventive.png b/react-ystemandchess/src/assets/images/sponsors/ventive.png similarity index 100% rename from react-ystemandchess/src/images/sponsors/ventive.png rename to react-ystemandchess/src/assets/images/sponsors/ventive.png diff --git a/react-ystemandchess/src/images/student/Leaderboard_User_avatar_1.png b/react-ystemandchess/src/assets/images/student/Leaderboard_User_avatar_1.png similarity index 100% rename from react-ystemandchess/src/images/student/Leaderboard_User_avatar_1.png rename to react-ystemandchess/src/assets/images/student/Leaderboard_User_avatar_1.png diff --git a/react-ystemandchess/src/images/student/Leaderboard_User_avatar_2.png b/react-ystemandchess/src/assets/images/student/Leaderboard_User_avatar_2.png similarity index 100% rename from react-ystemandchess/src/images/student/Leaderboard_User_avatar_2.png rename to react-ystemandchess/src/assets/images/student/Leaderboard_User_avatar_2.png diff --git a/react-ystemandchess/src/images/student/Leaderboard_User_avatar_3.png b/react-ystemandchess/src/assets/images/student/Leaderboard_User_avatar_3.png similarity index 100% rename from react-ystemandchess/src/images/student/Leaderboard_User_avatar_3.png rename to react-ystemandchess/src/assets/images/student/Leaderboard_User_avatar_3.png diff --git a/react-ystemandchess/src/images/student/Leaderboard_rank_1.svg b/react-ystemandchess/src/assets/images/student/Leaderboard_rank_1.svg similarity index 100% rename from react-ystemandchess/src/images/student/Leaderboard_rank_1.svg rename to react-ystemandchess/src/assets/images/student/Leaderboard_rank_1.svg diff --git a/react-ystemandchess/src/images/student/Leaderboard_rank_2.svg b/react-ystemandchess/src/assets/images/student/Leaderboard_rank_2.svg similarity index 100% rename from react-ystemandchess/src/images/student/Leaderboard_rank_2.svg rename to react-ystemandchess/src/assets/images/student/Leaderboard_rank_2.svg diff --git a/react-ystemandchess/src/images/student/Leaderboard_rank_3.svg b/react-ystemandchess/src/assets/images/student/Leaderboard_rank_3.svg similarity index 100% rename from react-ystemandchess/src/images/student/Leaderboard_rank_3.svg rename to react-ystemandchess/src/assets/images/student/Leaderboard_rank_3.svg diff --git a/react-ystemandchess/src/images/student/STEMy_Mascot.png b/react-ystemandchess/src/assets/images/student/STEMy_Mascot.png similarity index 100% rename from react-ystemandchess/src/images/student/STEMy_Mascot.png rename to react-ystemandchess/src/assets/images/student/STEMy_Mascot.png diff --git a/react-ystemandchess/src/images/student/activities_button.svg b/react-ystemandchess/src/assets/images/student/activities_button.svg similarity index 100% rename from react-ystemandchess/src/images/student/activities_button.svg rename to react-ystemandchess/src/assets/images/student/activities_button.svg diff --git a/react-ystemandchess/src/images/student/activity_tab.png b/react-ystemandchess/src/assets/images/student/activity_tab.png similarity index 100% rename from react-ystemandchess/src/images/student/activity_tab.png rename to react-ystemandchess/src/assets/images/student/activity_tab.png diff --git a/react-ystemandchess/src/images/student/badges_button.svg b/react-ystemandchess/src/assets/images/student/badges_button.svg similarity index 100% rename from react-ystemandchess/src/images/student/badges_button.svg rename to react-ystemandchess/src/assets/images/student/badges_button.svg diff --git a/react-ystemandchess/src/images/student/bg-image.png b/react-ystemandchess/src/assets/images/student/bg-image.png similarity index 100% rename from react-ystemandchess/src/images/student/bg-image.png rename to react-ystemandchess/src/assets/images/student/bg-image.png diff --git a/react-ystemandchess/src/images/student/chess_tab.png b/react-ystemandchess/src/assets/images/student/chess_tab.png similarity index 100% rename from react-ystemandchess/src/images/student/chess_tab.png rename to react-ystemandchess/src/assets/images/student/chess_tab.png diff --git a/react-ystemandchess/src/images/student/chess_tab1.png b/react-ystemandchess/src/assets/images/student/chess_tab1.png similarity index 100% rename from react-ystemandchess/src/images/student/chess_tab1.png rename to react-ystemandchess/src/assets/images/student/chess_tab1.png diff --git a/react-ystemandchess/src/images/student/games_tab.png b/react-ystemandchess/src/assets/images/student/games_tab.png similarity index 100% rename from react-ystemandchess/src/images/student/games_tab.png rename to react-ystemandchess/src/assets/images/student/games_tab.png diff --git a/react-ystemandchess/src/images/student/games_tab1.png b/react-ystemandchess/src/assets/images/student/games_tab1.png similarity index 100% rename from react-ystemandchess/src/images/student/games_tab1.png rename to react-ystemandchess/src/assets/images/student/games_tab1.png diff --git a/react-ystemandchess/src/images/student/inventory_tab.png b/react-ystemandchess/src/assets/images/student/inventory_tab.png similarity index 100% rename from react-ystemandchess/src/images/student/inventory_tab.png rename to react-ystemandchess/src/assets/images/student/inventory_tab.png diff --git a/react-ystemandchess/src/images/student/leaderboard_button.svg b/react-ystemandchess/src/assets/images/student/leaderboard_button.svg similarity index 100% rename from react-ystemandchess/src/images/student/leaderboard_button.svg rename to react-ystemandchess/src/assets/images/student/leaderboard_button.svg diff --git a/react-ystemandchess/src/images/student/leaderboard_sidebar_icon.svg b/react-ystemandchess/src/assets/images/student/leaderboard_sidebar_icon.svg similarity index 100% rename from react-ystemandchess/src/images/student/leaderboard_sidebar_icon.svg rename to react-ystemandchess/src/assets/images/student/leaderboard_sidebar_icon.svg diff --git a/react-ystemandchess/src/images/student/math_tab.png b/react-ystemandchess/src/assets/images/student/math_tab.png similarity index 100% rename from react-ystemandchess/src/images/student/math_tab.png rename to react-ystemandchess/src/assets/images/student/math_tab.png diff --git a/react-ystemandchess/src/images/student/mento_tab.png b/react-ystemandchess/src/assets/images/student/mento_tab.png similarity index 100% rename from react-ystemandchess/src/images/student/mento_tab.png rename to react-ystemandchess/src/assets/images/student/mento_tab.png diff --git a/react-ystemandchess/src/images/student/mento_tab1.png b/react-ystemandchess/src/assets/images/student/mento_tab1.png similarity index 100% rename from react-ystemandchess/src/images/student/mento_tab1.png rename to react-ystemandchess/src/assets/images/student/mento_tab1.png diff --git a/react-ystemandchess/src/images/student/play_tab.png b/react-ystemandchess/src/assets/images/student/play_tab.png similarity index 100% rename from react-ystemandchess/src/images/student/play_tab.png rename to react-ystemandchess/src/assets/images/student/play_tab.png diff --git a/react-ystemandchess/src/images/student/play_tab1.png b/react-ystemandchess/src/assets/images/student/play_tab1.png similarity index 100% rename from react-ystemandchess/src/images/student/play_tab1.png rename to react-ystemandchess/src/assets/images/student/play_tab1.png diff --git a/react-ystemandchess/src/images/student/prodev_tab.png b/react-ystemandchess/src/assets/images/student/prodev_tab.png similarity index 100% rename from react-ystemandchess/src/images/student/prodev_tab.png rename to react-ystemandchess/src/assets/images/student/prodev_tab.png diff --git a/react-ystemandchess/src/images/student/prodev_tab1.png b/react-ystemandchess/src/assets/images/student/prodev_tab1.png similarity index 100% rename from react-ystemandchess/src/images/student/prodev_tab1.png rename to react-ystemandchess/src/assets/images/student/prodev_tab1.png diff --git a/react-ystemandchess/src/images/student/profilePic 2.png b/react-ystemandchess/src/assets/images/student/profilePic 2.png similarity index 100% rename from react-ystemandchess/src/images/student/profilePic 2.png rename to react-ystemandchess/src/assets/images/student/profilePic 2.png diff --git a/react-ystemandchess/src/images/student/profilePic.png b/react-ystemandchess/src/assets/images/student/profilePic.png similarity index 100% rename from react-ystemandchess/src/images/student/profilePic.png rename to react-ystemandchess/src/assets/images/student/profilePic.png diff --git a/react-ystemandchess/src/images/student/profile_button.svg b/react-ystemandchess/src/assets/images/student/profile_button.svg similarity index 100% rename from react-ystemandchess/src/images/student/profile_button.svg rename to react-ystemandchess/src/assets/images/student/profile_button.svg diff --git a/react-ystemandchess/src/images/student/pupil.svg b/react-ystemandchess/src/assets/images/student/pupil.svg similarity index 100% rename from react-ystemandchess/src/images/student/pupil.svg rename to react-ystemandchess/src/assets/images/student/pupil.svg diff --git a/react-ystemandchess/src/images/student/puzzles_tab.png b/react-ystemandchess/src/assets/images/student/puzzles_tab.png similarity index 100% rename from react-ystemandchess/src/images/student/puzzles_tab.png rename to react-ystemandchess/src/assets/images/student/puzzles_tab.png diff --git a/react-ystemandchess/src/images/student/puzzles_tab1.png b/react-ystemandchess/src/assets/images/student/puzzles_tab1.png similarity index 100% rename from react-ystemandchess/src/images/student/puzzles_tab1.png rename to react-ystemandchess/src/assets/images/student/puzzles_tab1.png diff --git a/react-ystemandchess/src/images/student/recordings_tab.png b/react-ystemandchess/src/assets/images/student/recordings_tab.png similarity index 100% rename from react-ystemandchess/src/images/student/recordings_tab.png rename to react-ystemandchess/src/assets/images/student/recordings_tab.png diff --git a/react-ystemandchess/src/images/student/recordings_tab1.png b/react-ystemandchess/src/assets/images/student/recordings_tab1.png similarity index 100% rename from react-ystemandchess/src/images/student/recordings_tab1.png rename to react-ystemandchess/src/assets/images/student/recordings_tab1.png diff --git a/react-ystemandchess/src/images/student/sponsor_1.png b/react-ystemandchess/src/assets/images/student/sponsor_1.png similarity index 100% rename from react-ystemandchess/src/images/student/sponsor_1.png rename to react-ystemandchess/src/assets/images/student/sponsor_1.png diff --git a/react-ystemandchess/src/images/student/sponsor_2.png b/react-ystemandchess/src/assets/images/student/sponsor_2.png similarity index 100% rename from react-ystemandchess/src/images/student/sponsor_2.png rename to react-ystemandchess/src/assets/images/student/sponsor_2.png diff --git a/react-ystemandchess/src/images/student/sponsor_3.png b/react-ystemandchess/src/assets/images/student/sponsor_3.png similarity index 100% rename from react-ystemandchess/src/images/student/sponsor_3.png rename to react-ystemandchess/src/assets/images/student/sponsor_3.png diff --git a/react-ystemandchess/src/images/student/sponsor_4.png b/react-ystemandchess/src/assets/images/student/sponsor_4.png similarity index 100% rename from react-ystemandchess/src/images/student/sponsor_4.png rename to react-ystemandchess/src/assets/images/student/sponsor_4.png diff --git a/react-ystemandchess/src/images/student/sponsor_5.png b/react-ystemandchess/src/assets/images/student/sponsor_5.png similarity index 100% rename from react-ystemandchess/src/images/student/sponsor_5.png rename to react-ystemandchess/src/assets/images/student/sponsor_5.png diff --git a/react-ystemandchess/src/images/student/sponsor_6.png b/react-ystemandchess/src/assets/images/student/sponsor_6.png similarity index 100% rename from react-ystemandchess/src/images/student/sponsor_6.png rename to react-ystemandchess/src/assets/images/student/sponsor_6.png diff --git a/react-ystemandchess/src/images/student/sponsor_7.png b/react-ystemandchess/src/assets/images/student/sponsor_7.png similarity index 100% rename from react-ystemandchess/src/images/student/sponsor_7.png rename to react-ystemandchess/src/assets/images/student/sponsor_7.png diff --git a/react-ystemandchess/src/images/student/sponsor_8.png b/react-ystemandchess/src/assets/images/student/sponsor_8.png similarity index 100% rename from react-ystemandchess/src/images/student/sponsor_8.png rename to react-ystemandchess/src/assets/images/student/sponsor_8.png diff --git a/react-ystemandchess/src/images/student/streak_button.svg b/react-ystemandchess/src/assets/images/student/streak_button.svg similarity index 100% rename from react-ystemandchess/src/images/student/streak_button.svg rename to react-ystemandchess/src/assets/images/student/streak_button.svg diff --git a/react-ystemandchess/src/images/student/sunrise.png b/react-ystemandchess/src/assets/images/student/sunrise.png similarity index 100% rename from react-ystemandchess/src/images/student/sunrise.png rename to react-ystemandchess/src/assets/images/student/sunrise.png diff --git a/react-ystemandchess/src/images/teaching.png b/react-ystemandchess/src/assets/images/teaching.png similarity index 100% rename from react-ystemandchess/src/images/teaching.png rename to react-ystemandchess/src/assets/images/teaching.png diff --git a/react-ystemandchess/src/images/twitterIcon.svg b/react-ystemandchess/src/assets/images/twitterIcon.svg similarity index 100% rename from react-ystemandchess/src/images/twitterIcon.svg rename to react-ystemandchess/src/assets/images/twitterIcon.svg diff --git a/react-ystemandchess/src/images/user-portrait-placeholder.svg b/react-ystemandchess/src/assets/images/user-portrait-placeholder.svg similarity index 100% rename from react-ystemandchess/src/images/user-portrait-placeholder.svg rename to react-ystemandchess/src/assets/images/user-portrait-placeholder.svg diff --git a/react-ystemandchess/src/images/volunteer.png b/react-ystemandchess/src/assets/images/volunteer.png similarity index 100% rename from react-ystemandchess/src/images/volunteer.png rename to react-ystemandchess/src/assets/images/volunteer.png diff --git a/react-ystemandchess/src/components/ChessBoard/ChessBoard.tsx b/react-ystemandchess/src/components/ChessBoard/ChessBoard.tsx index 038c81f4..2c7b1e98 100644 --- a/react-ystemandchess/src/components/ChessBoard/ChessBoard.tsx +++ b/react-ystemandchess/src/components/ChessBoard/ChessBoard.tsx @@ -1,7 +1,7 @@ import React, { useState, useRef, useImperativeHandle, useEffect, forwardRef } from "react"; import Chessboard from "chessboardjsx"; import { Chess, Square } from "chess.js"; -import "./ChessBoard.css"; +import "./chessboard.css"; interface Move { from: string; diff --git a/react-ystemandchess/src/Footer/Footer.css b/react-ystemandchess/src/components/footer/Footer.css similarity index 100% rename from react-ystemandchess/src/Footer/Footer.css rename to react-ystemandchess/src/components/footer/Footer.css diff --git a/react-ystemandchess/src/Footer/Footer.tsx b/react-ystemandchess/src/components/footer/Footer.tsx similarity index 78% rename from react-ystemandchess/src/Footer/Footer.tsx rename to react-ystemandchess/src/components/footer/Footer.tsx index 6fb2bef7..7dee8d3d 100644 --- a/react-ystemandchess/src/Footer/Footer.tsx +++ b/react-ystemandchess/src/components/footer/Footer.tsx @@ -13,19 +13,19 @@ import React from "react"; import "./Footer.css"; -import TwitterIcon from "../images/twitterIcon.svg"; -import InstagramIcon from "../images/instagramIcon.svg"; -import FacebookIcon from "../images/facebookIcon.svg"; -import GoogleIcon from "../images/googleIcon.svg"; -import Ventive from "../images/sponsors/ventive.png"; -import Kount from "../images/sponsors/kount.png"; -import IdahoCentral from "../images/sponsors/idahoCentral.png"; -import PH from "../images/sponsors/PH.svg"; -import BoiseDistrict from "../images/partners/boiseDistrict.png"; -import BoiseRescue from "../images/partners/boiseRescue.png"; -import BoysAndGirls from "../images/partners/boysAndGirls.png"; -import Possible from "../images/partners/possible.png"; -import Rotary from "../images/partners/Rotary.png"; +import TwitterIcon from "../../assets/images/twitterIcon.svg"; +import InstagramIcon from "../../assets/images/instagramIcon.svg"; +import FacebookIcon from "../../assets/images/facebookIcon.svg"; +import GoogleIcon from "../../assets/images/googleIcon.svg"; +import Ventive from "../../assets/images/sponsors/ventive.png"; +import Kount from "../../assets/images/sponsors/kount.png"; +import IdahoCentral from "../../assets/images/sponsors/idahoCentral.png"; +import PH from "../../assets/images/sponsors/PH.svg"; +import BoiseDistrict from "../../assets/images/partners/boiseDistrict.png"; +import BoiseRescue from "../../assets/images/partners/boiseRescue.png"; +import BoysAndGirls from "../../assets/images/partners/boysAndGirls.png"; +import Possible from "../../assets/images/partners/possible.png"; +import Rotary from "../../assets/images/partners/Rotary.png"; /** * Footer component - displays contact info, social links, sponsors, and partners diff --git a/react-ystemandchess/src/NavBar/NavBar.scss b/react-ystemandchess/src/components/navbar/NavBar.scss similarity index 100% rename from react-ystemandchess/src/NavBar/NavBar.scss rename to react-ystemandchess/src/components/navbar/NavBar.scss diff --git a/react-ystemandchess/src/NavBar/NavBar.tsx b/react-ystemandchess/src/components/navbar/NavBar.tsx similarity index 99% rename from react-ystemandchess/src/NavBar/NavBar.tsx rename to react-ystemandchess/src/components/navbar/NavBar.tsx index 3d3ffb05..5fcefce8 100644 --- a/react-ystemandchess/src/NavBar/NavBar.tsx +++ b/react-ystemandchess/src/components/navbar/NavBar.tsx @@ -17,11 +17,11 @@ import React, { useState, useEffect, useRef } from "react"; import { motion } from "framer-motion"; import { Link } from "react-router-dom"; -import FullLogo from "../images/full_logo.png"; +import FullLogo from "../../assets/images/full_logo.png"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faCaretDown, faCaretUp } from "@fortawesome/free-solid-svg-icons"; import "./NavBar.scss"; -import { SetPermissionLevel } from "../globals"; +import { SetPermissionLevel } from "../../globals"; import { useCookies } from "react-cookie"; /** diff --git a/react-ystemandchess/src/components/ui/tailwindcss-buttons.tsx b/react-ystemandchess/src/components/ui/tailwindcss-buttons.tsx index 69e6082a..19036eeb 100644 --- a/react-ystemandchess/src/components/ui/tailwindcss-buttons.tsx +++ b/react-ystemandchess/src/components/ui/tailwindcss-buttons.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { cn } from "../../lib/utils"; +import { cn } from "../../core/utils/cn"; import { IconClipboard } from "@tabler/icons-react"; export const ButtonsCard = ({ diff --git a/react-ystemandchess/src/services/badgesApi.ts b/react-ystemandchess/src/core/services/badgesApi.ts similarity index 100% rename from react-ystemandchess/src/services/badgesApi.ts rename to react-ystemandchess/src/core/services/badgesApi.ts diff --git a/react-ystemandchess/src/services/themesService.ts b/react-ystemandchess/src/core/services/themesService.ts similarity index 100% rename from react-ystemandchess/src/services/themesService.ts rename to react-ystemandchess/src/core/services/themesService.ts diff --git a/react-ystemandchess/src/services/view-sdk.service.ts b/react-ystemandchess/src/core/services/view-sdk.service.ts similarity index 100% rename from react-ystemandchess/src/services/view-sdk.service.ts rename to react-ystemandchess/src/core/services/view-sdk.service.ts diff --git a/react-ystemandchess/src/types/chessboardjsx.d.ts b/react-ystemandchess/src/core/types/chessboardjsx.d.ts similarity index 100% rename from react-ystemandchess/src/types/chessboardjsx.d.ts rename to react-ystemandchess/src/core/types/chessboardjsx.d.ts diff --git a/react-ystemandchess/src/types/declarations.d.ts b/react-ystemandchess/src/core/types/declarations.d.ts similarity index 100% rename from react-ystemandchess/src/types/declarations.d.ts rename to react-ystemandchess/src/core/types/declarations.d.ts diff --git a/react-ystemandchess/src/types/global.d.ts b/react-ystemandchess/src/core/types/global.d.ts similarity index 100% rename from react-ystemandchess/src/types/global.d.ts rename to react-ystemandchess/src/core/types/global.d.ts diff --git a/react-ystemandchess/src/utils/activityNames.ts b/react-ystemandchess/src/core/utils/activityNames.ts similarity index 100% rename from react-ystemandchess/src/utils/activityNames.ts rename to react-ystemandchess/src/core/utils/activityNames.ts diff --git a/react-ystemandchess/src/lib/utils.ts b/react-ystemandchess/src/core/utils/cn.ts similarity index 100% rename from react-ystemandchess/src/lib/utils.ts rename to react-ystemandchess/src/core/utils/cn.ts diff --git a/react-ystemandchess/src/Pages/About-Us/AboutUs/AboutUs.scss b/react-ystemandchess/src/features/about-us/aboutus/AboutUs.scss similarity index 94% rename from react-ystemandchess/src/Pages/About-Us/AboutUs/AboutUs.scss rename to react-ystemandchess/src/features/about-us/aboutus/AboutUs.scss index daa90693..fb99e6a3 100644 --- a/react-ystemandchess/src/Pages/About-Us/AboutUs/AboutUs.scss +++ b/react-ystemandchess/src/features/about-us/aboutus/AboutUs.scss @@ -104,7 +104,7 @@ gap: 10px; &::before { - content: url('../../../images/aboutUs/divide_icon.png'); /* Replace with the actual path to the icon */ + content: url('../../../assets/images/aboutUs/divide_icon.png'); /* Replace with the actual path to the icon */ display: inline-block; margin-right: 8px; } diff --git a/react-ystemandchess/src/Pages/About-Us/AboutUs/AboutUs.test.tsx b/react-ystemandchess/src/features/about-us/aboutus/AboutUs.test.tsx similarity index 100% rename from react-ystemandchess/src/Pages/About-Us/AboutUs/AboutUs.test.tsx rename to react-ystemandchess/src/features/about-us/aboutus/AboutUs.test.tsx diff --git a/react-ystemandchess/src/Pages/About-Us/AboutUs/AboutUs.tsx b/react-ystemandchess/src/features/about-us/aboutus/AboutUs.tsx similarity index 83% rename from react-ystemandchess/src/Pages/About-Us/AboutUs/AboutUs.tsx rename to react-ystemandchess/src/features/about-us/aboutus/AboutUs.tsx index d6ccf65a..b946a760 100644 --- a/react-ystemandchess/src/Pages/About-Us/AboutUs/AboutUs.tsx +++ b/react-ystemandchess/src/features/about-us/aboutus/AboutUs.tsx @@ -1,11 +1,11 @@ import React from 'react'; import './AboutUs.scss'; -import aboutUsImage from '../../../images/aboutUs/about-us.png'; // Replace with actual image path -import dividerIcon from '../../../images/aboutUs/divide_icon.png'; // Replace with actual icon path -import statusIcon1 from '../../../images/aboutUs/02.png'; // Replace with actual icon path -import statusIcon2 from '../../../images/aboutUs/09.png'; // Replace with actual icon path -import statusIcon3 from '../../../images/aboutUs/40.png'; // Replace with actual icon path -import studentsImage from '../../../images/aboutUs/student.png'; // Replace with actual image path +import aboutUsImage from "../../../assets/images/aboutUs/about-us.png"; // Replace with actual image path +import dividerIcon from "../../../assets/images/aboutUs/divide_icon.png"; // Replace with actual icon path +import statusIcon1 from "../../../assets/images/aboutUs/02.png"; // Replace with actual icon path +import statusIcon2 from "../../../assets/images/aboutUs/09.png"; // Replace with actual icon path +import statusIcon3 from "../../../assets/images/aboutUs/40.png"; // Replace with actual icon path +import studentsImage from "../../../assets/images/aboutUs/student.png"; // Replace with actual image path const AboutUs = () => { return ( diff --git a/react-ystemandchess/src/Pages/About-Us/Benefit-of-Chess/ChessBenefitPage.scss b/react-ystemandchess/src/features/about-us/benefit-of-chess/ChessBenefitPage.scss similarity index 100% rename from react-ystemandchess/src/Pages/About-Us/Benefit-of-Chess/ChessBenefitPage.scss rename to react-ystemandchess/src/features/about-us/benefit-of-chess/ChessBenefitPage.scss diff --git a/react-ystemandchess/src/Pages/About-Us/Benefit-of-Chess/ChessBenefitPage.tsx b/react-ystemandchess/src/features/about-us/benefit-of-chess/ChessBenefitPage.tsx similarity index 99% rename from react-ystemandchess/src/Pages/About-Us/Benefit-of-Chess/ChessBenefitPage.tsx rename to react-ystemandchess/src/features/about-us/benefit-of-chess/ChessBenefitPage.tsx index ca0853e5..b7d1c4bc 100644 --- a/react-ystemandchess/src/Pages/About-Us/Benefit-of-Chess/ChessBenefitPage.tsx +++ b/react-ystemandchess/src/features/about-us/benefit-of-chess/ChessBenefitPage.tsx @@ -1,6 +1,6 @@ import React from "react"; import "./ChessBenefitPage.scss"; -import Images from "../../../images/imageImporter"; +import Images from "../../../assets/images/imageImporter"; const ChessBenefitPage = () => { return ( diff --git a/react-ystemandchess/src/Pages/About-Us/Benefit-of-CS/CSBenefitPage.scss b/react-ystemandchess/src/features/about-us/benefit-of-cs/CSBenefitPage.scss similarity index 100% rename from react-ystemandchess/src/Pages/About-Us/Benefit-of-CS/CSBenefitPage.scss rename to react-ystemandchess/src/features/about-us/benefit-of-cs/CSBenefitPage.scss diff --git a/react-ystemandchess/src/Pages/About-Us/Benefit-of-CS/CSBenefitPage.tsx b/react-ystemandchess/src/features/about-us/benefit-of-cs/CSBenefitPage.tsx similarity index 97% rename from react-ystemandchess/src/Pages/About-Us/Benefit-of-CS/CSBenefitPage.tsx rename to react-ystemandchess/src/features/about-us/benefit-of-cs/CSBenefitPage.tsx index cc02fbba..7e5d49cb 100644 --- a/react-ystemandchess/src/Pages/About-Us/Benefit-of-CS/CSBenefitPage.tsx +++ b/react-ystemandchess/src/features/about-us/benefit-of-cs/CSBenefitPage.tsx @@ -1,7 +1,7 @@ import React from "react"; import "./CSBenefitPage.scss"; -import ImageOne from "../../../images/mathArticle/computer.png"; -import ImageTwo from "../../../images/mathArticle/Junechamp 2.png"; +import ImageOne from "../../../assets/images/mathArticle/computer.png"; +import ImageTwo from "../../../assets/images/mathArticle/Junechamp 2.png"; const CSBenefitPage = () => { return ( diff --git a/react-ystemandchess/src/Pages/About-Us/Benefit-of-Math-tut/MathTutBenefitPage.scss b/react-ystemandchess/src/features/about-us/benefit-of-math-tut/MathTutBenefitPage.scss similarity index 100% rename from react-ystemandchess/src/Pages/About-Us/Benefit-of-Math-tut/MathTutBenefitPage.scss rename to react-ystemandchess/src/features/about-us/benefit-of-math-tut/MathTutBenefitPage.scss diff --git a/react-ystemandchess/src/Pages/About-Us/Benefit-of-Math-tut/MathTutBenefitPage.tsx b/react-ystemandchess/src/features/about-us/benefit-of-math-tut/MathTutBenefitPage.tsx similarity index 97% rename from react-ystemandchess/src/Pages/About-Us/Benefit-of-Math-tut/MathTutBenefitPage.tsx rename to react-ystemandchess/src/features/about-us/benefit-of-math-tut/MathTutBenefitPage.tsx index 27a6cd34..7d09093b 100644 --- a/react-ystemandchess/src/Pages/About-Us/Benefit-of-Math-tut/MathTutBenefitPage.tsx +++ b/react-ystemandchess/src/features/about-us/benefit-of-math-tut/MathTutBenefitPage.tsx @@ -1,7 +1,7 @@ import React from "react"; import "./MathTutBenefitPage.scss"; -import ImageOne from "../../../images/mathArticle/computer.png"; -import ImageTwo from "../../../images/mathArticle/Junechamp 2.png"; +import ImageOne from "../../../assets/images/mathArticle/computer.png"; +import ImageTwo from "../../../assets/images/mathArticle/Junechamp 2.png"; const MathTutBenefitPage = () => { return ( diff --git a/react-ystemandchess/src/Pages/About-Us/Benefit-of-Mentoring/MentoringBenefitPage.scss b/react-ystemandchess/src/features/about-us/benefit-of-mentoring/MentoringBenefitPage.scss similarity index 100% rename from react-ystemandchess/src/Pages/About-Us/Benefit-of-Mentoring/MentoringBenefitPage.scss rename to react-ystemandchess/src/features/about-us/benefit-of-mentoring/MentoringBenefitPage.scss diff --git a/react-ystemandchess/src/Pages/About-Us/Benefit-of-Mentoring/MentoringBenefitPage.tsx b/react-ystemandchess/src/features/about-us/benefit-of-mentoring/MentoringBenefitPage.tsx similarity index 97% rename from react-ystemandchess/src/Pages/About-Us/Benefit-of-Mentoring/MentoringBenefitPage.tsx rename to react-ystemandchess/src/features/about-us/benefit-of-mentoring/MentoringBenefitPage.tsx index 43ac9785..b19cc073 100644 --- a/react-ystemandchess/src/Pages/About-Us/Benefit-of-Mentoring/MentoringBenefitPage.tsx +++ b/react-ystemandchess/src/features/about-us/benefit-of-mentoring/MentoringBenefitPage.tsx @@ -1,7 +1,7 @@ import React from "react"; import "./MentoringBenefitPage.scss"; -import ImageOne from "../../../images/mathArticle/computer.png"; -import ImageTwo from "../../../images/mathArticle/Junechamp 2.png"; +import ImageOne from "../../../assets/images/mathArticle/computer.png"; +import ImageTwo from "../../../assets/images/mathArticle/Junechamp 2.png"; const MathTutBenefitPage = () => { return ( diff --git a/react-ystemandchess/src/Pages/About-Us/Board/Board.scss b/react-ystemandchess/src/features/about-us/board/Board.scss similarity index 100% rename from react-ystemandchess/src/Pages/About-Us/Board/Board.scss rename to react-ystemandchess/src/features/about-us/board/Board.scss diff --git a/react-ystemandchess/src/Pages/About-Us/Board/Board.tsx b/react-ystemandchess/src/features/about-us/board/Board.tsx similarity index 96% rename from react-ystemandchess/src/Pages/About-Us/Board/Board.tsx rename to react-ystemandchess/src/features/about-us/board/Board.tsx index 98670bd0..e6685ac3 100644 --- a/react-ystemandchess/src/Pages/About-Us/Board/Board.tsx +++ b/react-ystemandchess/src/features/about-us/board/Board.tsx @@ -1,6 +1,6 @@ import React from "react"; import "./Board.scss"; -import LogoLineBr from "../../../images/LogoLineBreak.png"; +import LogoLineBr from "../../../assets/images/LogoLineBreak.png"; const Board = () => { return ( diff --git a/react-ystemandchess/src/Pages/About-Us/Financial/Financial.scss b/react-ystemandchess/src/features/about-us/financial/Financial.scss similarity index 100% rename from react-ystemandchess/src/Pages/About-Us/Financial/Financial.scss rename to react-ystemandchess/src/features/about-us/financial/Financial.scss diff --git a/react-ystemandchess/src/Pages/About-Us/Financial/Financial.tsx b/react-ystemandchess/src/features/about-us/financial/Financial.tsx similarity index 96% rename from react-ystemandchess/src/Pages/About-Us/Financial/Financial.tsx rename to react-ystemandchess/src/features/about-us/financial/Financial.tsx index dad2b8aa..0519dae1 100644 --- a/react-ystemandchess/src/Pages/About-Us/Financial/Financial.tsx +++ b/react-ystemandchess/src/features/about-us/financial/Financial.tsx @@ -1,6 +1,6 @@ import React from "react"; import "./Financial.scss"; -import LogoLineBr from "../../../images/LogoLineBreak.png"; +import LogoLineBr from "../../../assets/images/LogoLineBreak.png"; const Financial = () => { return ( diff --git a/react-ystemandchess/src/Pages/About-Us/Mission/Mission.scss b/react-ystemandchess/src/features/about-us/mission/Mission.scss similarity index 100% rename from react-ystemandchess/src/Pages/About-Us/Mission/Mission.scss rename to react-ystemandchess/src/features/about-us/mission/Mission.scss diff --git a/react-ystemandchess/src/Pages/About-Us/Mission/Mission.tsx b/react-ystemandchess/src/features/about-us/mission/Mission.tsx similarity index 92% rename from react-ystemandchess/src/Pages/About-Us/Mission/Mission.tsx rename to react-ystemandchess/src/features/about-us/mission/Mission.tsx index 51591b44..6d186f9d 100644 --- a/react-ystemandchess/src/Pages/About-Us/Mission/Mission.tsx +++ b/react-ystemandchess/src/features/about-us/mission/Mission.tsx @@ -1,9 +1,9 @@ import React from "react"; import "./Mission.scss"; -import ImageOne from "../../../images/mission-image.png"; -import LogoLineBreak from "../../../images/LogoLineBreak.png"; -import FounderStory from "../../../images/founder-story.png"; -import Images from "../../../images/imageImporter"; +import ImageOne from "../../../assets/images/mission-image.png"; +import LogoLineBreak from "../../../assets/images/LogoLineBreak.png"; +import FounderStory from "../../../assets/images/founder-story.png"; +import Images from "../../../assets/images/imageImporter"; const Mission = () => { return ( diff --git a/react-ystemandchess/src/Pages/About-Us/Online-Expansion/OnlineExpansion.tsx b/react-ystemandchess/src/features/about-us/online-expansion/OnlineExpansion.tsx similarity index 100% rename from react-ystemandchess/src/Pages/About-Us/Online-Expansion/OnlineExpansion.tsx rename to react-ystemandchess/src/features/about-us/online-expansion/OnlineExpansion.tsx diff --git a/react-ystemandchess/src/Pages/About-Us/SponsorsPartners/SponsorsPartners.scss b/react-ystemandchess/src/features/about-us/sponsors-partners/SponsorsPartners.scss similarity index 100% rename from react-ystemandchess/src/Pages/About-Us/SponsorsPartners/SponsorsPartners.scss rename to react-ystemandchess/src/features/about-us/sponsors-partners/SponsorsPartners.scss diff --git a/react-ystemandchess/src/Pages/About-Us/SponsorsPartners/SponsorsPartners.tsx b/react-ystemandchess/src/features/about-us/sponsors-partners/SponsorsPartners.tsx similarity index 70% rename from react-ystemandchess/src/Pages/About-Us/SponsorsPartners/SponsorsPartners.tsx rename to react-ystemandchess/src/features/about-us/sponsors-partners/SponsorsPartners.tsx index 7e98db16..fcf8c0df 100644 --- a/react-ystemandchess/src/Pages/About-Us/SponsorsPartners/SponsorsPartners.tsx +++ b/react-ystemandchess/src/features/about-us/sponsors-partners/SponsorsPartners.tsx @@ -1,15 +1,15 @@ import React from "react"; import "./SponsorsPartners.scss"; -import LogoLineBreak from "../../../images/LogoLineBreak.png"; -import ventive from "../../../images/sponsors/ventive.png"; -import kount from "../../../images/sponsors/kount.png"; -import idahoCentral from "../../../images/sponsors/idahoCentral.png"; -import PH from "../../../images/sponsors/PH.svg"; -import boiseRescue from "../../../images/partners/boiseRescue.png"; -import boiseDistrict from "../../../images/partners/boiseDistrict.png"; -import boysAndGirls from "../../../images/partners/boysAndGirls.png"; -import possible from "../../../images/partners/possible.png"; -import rotary from "../../../images/partners/Rotary.png"; +import LogoLineBreak from "../../../assets/images/LogoLineBreak.png"; +import ventive from "../../../assets/images/sponsors/ventive.png"; +import kount from "../../../assets/images/sponsors/kount.png"; +import idahoCentral from "../../../assets/images/sponsors/idahoCentral.png"; +import PH from "../../../assets/images/sponsors/PH.svg"; +import boiseRescue from "../../../assets/images/partners/boiseRescue.png"; +import boiseDistrict from "../../../assets/images/partners/boiseDistrict.png"; +import boysAndGirls from "../../../assets/images/partners/boysAndGirls.png"; +import possible from "../../../assets/images/partners/possible.png"; +import rotary from "../../../assets/images/partners/Rotary.png"; const SponsorsPartners = () => { diff --git a/react-ystemandchess/src/Pages/Login/Login.scss b/react-ystemandchess/src/features/auth/login/Login.scss similarity index 100% rename from react-ystemandchess/src/Pages/Login/Login.scss rename to react-ystemandchess/src/features/auth/login/Login.scss diff --git a/react-ystemandchess/src/Pages/Login/Login.test.tsx b/react-ystemandchess/src/features/auth/login/Login.test.tsx similarity index 100% rename from react-ystemandchess/src/Pages/Login/Login.test.tsx rename to react-ystemandchess/src/features/auth/login/Login.test.tsx diff --git a/react-ystemandchess/src/Pages/Login/Login.tsx b/react-ystemandchess/src/features/auth/login/Login.tsx similarity index 98% rename from react-ystemandchess/src/Pages/Login/Login.tsx rename to react-ystemandchess/src/features/auth/login/Login.tsx index 78148fff..c15cea1c 100644 --- a/react-ystemandchess/src/Pages/Login/Login.tsx +++ b/react-ystemandchess/src/features/auth/login/Login.tsx @@ -2,7 +2,7 @@ import React from 'react'; // import { Link } from 'react-router-dom'; import './Login.scss'; import { useState } from 'react'; -import { environment } from '../../environments/environment'; +import { environment } from "../../../core/environments/environment"; import { useCookies } from 'react-cookie'; const Login = () => { diff --git a/react-ystemandchess/src/Pages/Login/loginController.ts b/react-ystemandchess/src/features/auth/login/loginController.ts similarity index 100% rename from react-ystemandchess/src/Pages/Login/loginController.ts rename to react-ystemandchess/src/features/auth/login/loginController.ts diff --git a/react-ystemandchess/src/Pages/Login/loginRouter.ts b/react-ystemandchess/src/features/auth/login/loginRouter.ts similarity index 100% rename from react-ystemandchess/src/Pages/Login/loginRouter.ts rename to react-ystemandchess/src/features/auth/login/loginRouter.ts diff --git a/react-ystemandchess/src/Pages/Login/loginService.ts b/react-ystemandchess/src/features/auth/login/loginService.ts similarity index 100% rename from react-ystemandchess/src/Pages/Login/loginService.ts rename to react-ystemandchess/src/features/auth/login/loginService.ts diff --git a/react-ystemandchess/src/Pages/Reset-Password/reset-password.component.scss b/react-ystemandchess/src/features/auth/reset-password/Reset-Password/reset-password.component.scss similarity index 100% rename from react-ystemandchess/src/Pages/Reset-Password/reset-password.component.scss rename to react-ystemandchess/src/features/auth/reset-password/Reset-Password/reset-password.component.scss diff --git a/react-ystemandchess/src/Pages/Reset-Password/reset-password.test.tsx b/react-ystemandchess/src/features/auth/reset-password/Reset-Password/reset-password.test.tsx similarity index 100% rename from react-ystemandchess/src/Pages/Reset-Password/reset-password.test.tsx rename to react-ystemandchess/src/features/auth/reset-password/Reset-Password/reset-password.test.tsx diff --git a/react-ystemandchess/src/Pages/Reset-Password/reset-password.tsx b/react-ystemandchess/src/features/auth/reset-password/Reset-Password/reset-password.tsx similarity index 100% rename from react-ystemandchess/src/Pages/Reset-Password/reset-password.tsx rename to react-ystemandchess/src/features/auth/reset-password/Reset-Password/reset-password.tsx diff --git a/react-ystemandchess/src/Pages/Reset-Password/resetPasswordController.ts b/react-ystemandchess/src/features/auth/reset-password/Reset-Password/resetPasswordController.ts similarity index 100% rename from react-ystemandchess/src/Pages/Reset-Password/resetPasswordController.ts rename to react-ystemandchess/src/features/auth/reset-password/Reset-Password/resetPasswordController.ts diff --git a/react-ystemandchess/src/Pages/Reset-Password/resetPasswordRouter.ts b/react-ystemandchess/src/features/auth/reset-password/Reset-Password/resetPasswordRouter.ts similarity index 100% rename from react-ystemandchess/src/Pages/Reset-Password/resetPasswordRouter.ts rename to react-ystemandchess/src/features/auth/reset-password/Reset-Password/resetPasswordRouter.ts diff --git a/react-ystemandchess/src/Pages/Reset-Password/resetPasswordService.ts b/react-ystemandchess/src/features/auth/reset-password/Reset-Password/resetPasswordService.ts similarity index 94% rename from react-ystemandchess/src/Pages/Reset-Password/resetPasswordService.ts rename to react-ystemandchess/src/features/auth/reset-password/Reset-Password/resetPasswordService.ts index c7697932..97798183 100644 --- a/react-ystemandchess/src/Pages/Reset-Password/resetPasswordService.ts +++ b/react-ystemandchess/src/features/auth/reset-password/Reset-Password/resetPasswordService.ts @@ -5,7 +5,7 @@ * Uses Nodemailer with Gmail to deliver reset links. */ -import { environment } from '../../environments/environment'; +import { environment } from "../../../../core/environments/environment"; const nodemailer = require('nodemailer'); // Configure email transporter with Gmail credentials diff --git a/react-ystemandchess/src/Pages/Set-Password/set-password.component.scss b/react-ystemandchess/src/features/auth/set-password/Set-Password/set-password.component.scss similarity index 100% rename from react-ystemandchess/src/Pages/Set-Password/set-password.component.scss rename to react-ystemandchess/src/features/auth/set-password/Set-Password/set-password.component.scss diff --git a/react-ystemandchess/src/Pages/Set-Password/set-password.test.ts b/react-ystemandchess/src/features/auth/set-password/Set-Password/set-password.test.ts similarity index 100% rename from react-ystemandchess/src/Pages/Set-Password/set-password.test.ts rename to react-ystemandchess/src/features/auth/set-password/Set-Password/set-password.test.ts diff --git a/react-ystemandchess/src/Pages/Set-Password/set-password.test.tsx b/react-ystemandchess/src/features/auth/set-password/Set-Password/set-password.test.tsx similarity index 100% rename from react-ystemandchess/src/Pages/Set-Password/set-password.test.tsx rename to react-ystemandchess/src/features/auth/set-password/Set-Password/set-password.test.tsx diff --git a/react-ystemandchess/src/Pages/Set-Password/set-password.tsx b/react-ystemandchess/src/features/auth/set-password/Set-Password/set-password.tsx similarity index 100% rename from react-ystemandchess/src/Pages/Set-Password/set-password.tsx rename to react-ystemandchess/src/features/auth/set-password/Set-Password/set-password.tsx diff --git a/react-ystemandchess/src/Pages/Set-Password/setPasswordController.ts b/react-ystemandchess/src/features/auth/set-password/Set-Password/setPasswordController.ts similarity index 100% rename from react-ystemandchess/src/Pages/Set-Password/setPasswordController.ts rename to react-ystemandchess/src/features/auth/set-password/Set-Password/setPasswordController.ts diff --git a/react-ystemandchess/src/Pages/Set-Password/setPasswordRouter.ts b/react-ystemandchess/src/features/auth/set-password/Set-Password/setPasswordRouter.ts similarity index 100% rename from react-ystemandchess/src/Pages/Set-Password/setPasswordRouter.ts rename to react-ystemandchess/src/features/auth/set-password/Set-Password/setPasswordRouter.ts diff --git a/react-ystemandchess/src/Pages/Set-Password/setPasswordService.ts b/react-ystemandchess/src/features/auth/set-password/Set-Password/setPasswordService.ts similarity index 100% rename from react-ystemandchess/src/Pages/Set-Password/setPasswordService.ts rename to react-ystemandchess/src/features/auth/set-password/Set-Password/setPasswordService.ts diff --git a/react-ystemandchess/src/Pages/SignUp/SignUp.scss b/react-ystemandchess/src/features/auth/signup/SignUp.scss similarity index 100% rename from react-ystemandchess/src/Pages/SignUp/SignUp.scss rename to react-ystemandchess/src/features/auth/signup/SignUp.scss diff --git a/react-ystemandchess/src/Pages/SignUp/SignUp.test.tsx b/react-ystemandchess/src/features/auth/signup/SignUp.test.tsx similarity index 100% rename from react-ystemandchess/src/Pages/SignUp/SignUp.test.tsx rename to react-ystemandchess/src/features/auth/signup/SignUp.test.tsx diff --git a/react-ystemandchess/src/Pages/SignUp/SignUp.tsx b/react-ystemandchess/src/features/auth/signup/SignUp.tsx similarity index 99% rename from react-ystemandchess/src/Pages/SignUp/SignUp.tsx rename to react-ystemandchess/src/features/auth/signup/SignUp.tsx index 1070f963..c191aebe 100644 --- a/react-ystemandchess/src/Pages/SignUp/SignUp.tsx +++ b/react-ystemandchess/src/features/auth/signup/SignUp.tsx @@ -1,7 +1,7 @@ import React, { useState } from 'react'; // import { Cookie } from 'react-router'; // 'react-router' does not export 'Cookie'. This line should probably be removed or corrected. import './SignUp.scss'; // Imports the stylesheet for this component. -import { environment } from '../../environments/environment'; // Imports environment variables, likely containing API URLs. +import { environment } from "../../../core/environments/environment"; // Imports environment variables, likely containing API URLs. // import StudentProfile from '../StudentProfile/Student-Profile'; // Only import if actively used in this component // Define the interface for the props of the StudentTemplate component diff --git a/react-ystemandchess/src/Pages/SignUp/signupController.ts b/react-ystemandchess/src/features/auth/signup/signupController.ts similarity index 100% rename from react-ystemandchess/src/Pages/SignUp/signupController.ts rename to react-ystemandchess/src/features/auth/signup/signupController.ts diff --git a/react-ystemandchess/src/Pages/SignUp/signupRouter.ts b/react-ystemandchess/src/features/auth/signup/signupRouter.ts similarity index 100% rename from react-ystemandchess/src/Pages/SignUp/signupRouter.ts rename to react-ystemandchess/src/features/auth/signup/signupRouter.ts diff --git a/react-ystemandchess/src/Pages/SignUp/signupService.ts b/react-ystemandchess/src/features/auth/signup/signupService.ts similarity index 100% rename from react-ystemandchess/src/Pages/SignUp/signupService.ts rename to react-ystemandchess/src/features/auth/signup/signupService.ts diff --git a/react-ystemandchess/src/Pages/Home/Home.css b/react-ystemandchess/src/features/home/Home.css similarity index 100% rename from react-ystemandchess/src/Pages/Home/Home.css rename to react-ystemandchess/src/features/home/Home.css diff --git a/react-ystemandchess/src/Pages/Home/Home.test.tsx b/react-ystemandchess/src/features/home/Home.test.tsx similarity index 100% rename from react-ystemandchess/src/Pages/Home/Home.test.tsx rename to react-ystemandchess/src/features/home/Home.test.tsx diff --git a/react-ystemandchess/src/Pages/Home/Home.tsx b/react-ystemandchess/src/features/home/Home.tsx similarity index 99% rename from react-ystemandchess/src/Pages/Home/Home.tsx rename to react-ystemandchess/src/features/home/Home.tsx index c1e55e7b..d59d6b97 100644 --- a/react-ystemandchess/src/Pages/Home/Home.tsx +++ b/react-ystemandchess/src/features/home/Home.tsx @@ -15,7 +15,7 @@ import React from "react"; import "./Home.css"; -import Images from "../../images/imageImporter"; +import Images from "../../assets/images/imageImporter"; import { ButtonsCard } from "../../components/ui/tailwindcss-buttons"; import { useNavigate } from "react-router"; diff --git a/react-ystemandchess/src/features/home/Home/Home.tsx b/react-ystemandchess/src/features/home/Home/Home.tsx new file mode 100644 index 00000000..eb0e1a3e --- /dev/null +++ b/react-ystemandchess/src/features/home/Home/Home.tsx @@ -0,0 +1,275 @@ +/** + * Home Page Component + * + * This is the main landing page component for the Y STEM and Chess application. + * It serves as the entry point for visitors and provides an overview of the + * organization's mission, featured content, and calls-to-action. + * + * Features: + * - Hero section with organization branding + * - Featured books and publications + * - Donation and purchase functionality + * - Navigation to other sections of the site + * - Responsive design for all device types + */ + +import React from "react"; +import "./Home.css"; +import Images from "../../../assets/images/imageImporter"; +import { ButtonsCard } from "../../../components/ui/tailwindcss-buttons"; +import { useNavigate } from "react-router"; + +/** + * Static data for featured books displayed on the home page + * + * This array contains information about the organization's published books, + * including cover images, titles, subtitles, and descriptions. The data + * is used to render book cards with purchase functionality. + * + * Each book object contains: + * - image: Reference to the book cover image + * - title: Main book title + * - subtitle: Descriptive subtitle + * - description: Detailed book description for marketing + */ +const books = [ + { + image: Images.Book1, + title: "How to Start a Tech-Based Nonprofit", + subtitle: + "Bridging the Opportunity Gap: Building a STEM Nonprofit to Change the Trajectory of Underserved Children's Lives", + description: + "How to start tech-based Nonprofit details the steps of Devin Nakano as he builds Y STEM and Chess (YSC) Inc. The first in its series covers the first 4 years of YSC. Each chapter brings unique perspective of an entrepreneur building a nonprofit that uses technology to fulfill the Company Mission.", + }, + { + image: Images.Book2, + title: "The Zero Dollar Workforce", + subtitle: "Hire a Team, Run Your Company, and Don't Spend Any Money", + description: + "It's easier to hire and manage 40 people than just 2... Someone can also hire and run this same team of 40 people completely for FREE... The above sounds like total nonsense. Like someone is crazy. Like it's some kind of miracle. But a lot of creations in our world don't make any sense until they're fully produced and studied...", + }, +]; + +/** + * Main Home page component + * + * This component renders the landing page with featured content, donation + * options, and book purchases. It serves as the main entry point for + * visitors to learn about the organization and take action. + * + * @returns JSX element representing the complete home page + */ +const Home = () => { + // Hook for programmatic navigation between pages + const navigate = useNavigate(); + + /** + * Handles donation button click events + * + * This function redirects users to the external donation platform + * (DonorBox) where they can make contributions to support the + * organization's mission and programs. + * + * Uses window.location.href for external navigation to ensure + * proper handling of the third-party donation platform. + */ + const handleDonateButton = () => { + window.location.href = + "https://donorbox.org/y-stem-and-chess-inc-learning-platform"; + }; + + /** + * Handles book purchase button click events + * + * This function opens the appropriate Amazon product page in a new tab + * based on the book title provided. It supports multiple books and + * can be easily extended for additional publications. + * + * @param title - The title of the book to purchase (optional) + * + * Supported books: + * - "How to Start a Tech-Based Nonprofit" + * - "The Zero Dollar Workforce" + */ + const handleBuyNow = (title = "") => { + // Handle purchase for "How to Start a Tech-Based Nonprofit" + if (title === "How to Start a Tech-Based Nonprofit") { + window.open( + "https://www.amazon.com/How-Start-Tech-based-Nonprofit-Opportunity/dp/B0C4MML5WG", + "_blank" // Open in new tab to preserve user's current session + ); + } + + // Handle purchase for "The Zero Dollar Workforce" + if (title === "The Zero Dollar Workforce") { + window.open( + "https://www.amazon.com/Zero-Dollar-Workforce-Company-Spend/dp/B09NGVLQSS", + "_blank" // Open in new tab to preserve user's current session + ); + } + }; + return ( +
+
+
+

+ Helping your child develop
+ critical thinking skills! +

+ +

+ We are a nonprofit organization empowering

children to find + their own success in STEM through

Chess, Math and Computer + Science. +

+ + {/* */} + + +
+
+ Group of Y STEM mascots playing chess +
+
+ + + +

Everyone is included. Everyone is welcome.

+ +
+
+ Heart icon +

Free

+

+ For students who qualify for

free and reduced lunch. +

+ Our lessons are free. +

+ +
+
+ Gem icon +

Premium

+

+ For students who don't qualify

for free and reduced lunch.{" "} +

+ $25 / Week

First lesson is FREE.

Cancel anytime. +

+ +
+
+ +
+ Y STEM mission statement emphasising Play, Learn and Donate +
+ +
+ +
+ +
+
+ Chess peices lined up next to eachother +
Start now and sign up later!
+ +
+
+ + Y STEM styled line break + +
+

Books by Devin Nakano

+ {books.map((book, index) => ( +
+
+ {`${book.title} + +
+
+

{book.title}

+

{book.subtitle}

+

{book.description}

+
+
+ ))} +
+

All proceeds will be donated to the organization

+
+
+
+ ); +}; + +export default Home; diff --git a/react-ystemandchess/src/Pages/Lessons/Lessons-profile.module.scss b/react-ystemandchess/src/features/lessons/lessons-main/Lessons-profile.module.scss similarity index 100% rename from react-ystemandchess/src/Pages/Lessons/Lessons-profile.module.scss rename to react-ystemandchess/src/features/lessons/lessons-main/Lessons-profile.module.scss diff --git a/react-ystemandchess/src/Pages/Lessons/Lessons.module.scss b/react-ystemandchess/src/features/lessons/lessons-main/Lessons.module.scss similarity index 100% rename from react-ystemandchess/src/Pages/Lessons/Lessons.module.scss rename to react-ystemandchess/src/features/lessons/lessons-main/Lessons.module.scss diff --git a/react-ystemandchess/src/Pages/Lessons/Lessons.test.tsx b/react-ystemandchess/src/features/lessons/lessons-main/Lessons.test.tsx similarity index 100% rename from react-ystemandchess/src/Pages/Lessons/Lessons.test.tsx rename to react-ystemandchess/src/features/lessons/lessons-main/Lessons.test.tsx diff --git a/react-ystemandchess/src/Pages/Lessons/Lessons.tsx b/react-ystemandchess/src/features/lessons/lessons-main/Lessons.tsx similarity index 100% rename from react-ystemandchess/src/Pages/Lessons/Lessons.tsx rename to react-ystemandchess/src/features/lessons/lessons-main/Lessons.tsx diff --git a/react-ystemandchess/src/Pages/Lessons/Placeholder.jsx b/react-ystemandchess/src/features/lessons/lessons-main/Placeholder.jsx similarity index 100% rename from react-ystemandchess/src/Pages/Lessons/Placeholder.jsx rename to react-ystemandchess/src/features/lessons/lessons-main/Placeholder.jsx diff --git a/react-ystemandchess/src/Pages/Lessons/PromotionPopup.tsx b/react-ystemandchess/src/features/lessons/lessons-main/PromotionPopup.tsx similarity index 100% rename from react-ystemandchess/src/Pages/Lessons/PromotionPopup.tsx rename to react-ystemandchess/src/features/lessons/lessons-main/PromotionPopup.tsx diff --git a/react-ystemandchess/src/images/mathArticle/Rectangle 313.png b/react-ystemandchess/src/features/lessons/lessons-main/Rectangle 313.png similarity index 100% rename from react-ystemandchess/src/images/mathArticle/Rectangle 313.png rename to react-ystemandchess/src/features/lessons/lessons-main/Rectangle 313.png diff --git a/react-ystemandchess/src/Pages/Lessons/Scenarios.js b/react-ystemandchess/src/features/lessons/lessons-main/Scenarios.js similarity index 100% rename from react-ystemandchess/src/Pages/Lessons/Scenarios.js rename to react-ystemandchess/src/features/lessons/lessons-main/Scenarios.js diff --git a/react-ystemandchess/src/images/chess_background.png b/react-ystemandchess/src/features/lessons/lessons-main/chess_background.png similarity index 100% rename from react-ystemandchess/src/images/chess_background.png rename to react-ystemandchess/src/features/lessons/lessons-main/chess_background.png diff --git a/react-ystemandchess/src/images/icons/icon_back.svg b/react-ystemandchess/src/features/lessons/lessons-main/icon_back.svg similarity index 100% rename from react-ystemandchess/src/images/icons/icon_back.svg rename to react-ystemandchess/src/features/lessons/lessons-main/icon_back.svg diff --git a/react-ystemandchess/src/images/icons/icon_back_inactive.svg b/react-ystemandchess/src/features/lessons/lessons-main/icon_back_inactive.svg similarity index 100% rename from react-ystemandchess/src/images/icons/icon_back_inactive.svg rename to react-ystemandchess/src/features/lessons/lessons-main/icon_back_inactive.svg diff --git a/react-ystemandchess/src/images/icons/icon_next.svg b/react-ystemandchess/src/features/lessons/lessons-main/icon_next.svg similarity index 100% rename from react-ystemandchess/src/images/icons/icon_next.svg rename to react-ystemandchess/src/features/lessons/lessons-main/icon_next.svg diff --git a/react-ystemandchess/src/images/icons/icon_next_inactive.svg b/react-ystemandchess/src/features/lessons/lessons-main/icon_next_inactive.svg similarity index 100% rename from react-ystemandchess/src/images/icons/icon_next_inactive.svg rename to react-ystemandchess/src/features/lessons/lessons-main/icon_next_inactive.svg diff --git a/react-ystemandchess/src/images/icons/icon_redo.svg b/react-ystemandchess/src/features/lessons/lessons-main/icon_redo.svg similarity index 100% rename from react-ystemandchess/src/images/icons/icon_redo.svg rename to react-ystemandchess/src/features/lessons/lessons-main/icon_redo.svg diff --git a/react-ystemandchess/src/Pages/Lessons/register_button.png b/react-ystemandchess/src/features/lessons/lessons-main/register_button.png similarity index 100% rename from react-ystemandchess/src/Pages/Lessons/register_button.png rename to react-ystemandchess/src/features/lessons/lessons-main/register_button.png diff --git a/react-ystemandchess/src/Pages/LessonsSelection/LessonTemplate/LessonTemplate.jsx b/react-ystemandchess/src/features/lessons/lessons-selection/LessonTemplate/LessonTemplate.jsx similarity index 100% rename from react-ystemandchess/src/Pages/LessonsSelection/LessonTemplate/LessonTemplate.jsx rename to react-ystemandchess/src/features/lessons/lessons-selection/LessonTemplate/LessonTemplate.jsx diff --git a/react-ystemandchess/src/Pages/LessonsSelection/LessonsSelection.jsx b/react-ystemandchess/src/features/lessons/lessons-selection/LessonsSelection.jsx similarity index 98% rename from react-ystemandchess/src/Pages/LessonsSelection/LessonsSelection.jsx rename to react-ystemandchess/src/features/lessons/lessons-selection/LessonsSelection.jsx index 7de17f6c..38ec6b98 100644 --- a/react-ystemandchess/src/Pages/LessonsSelection/LessonsSelection.jsx +++ b/react-ystemandchess/src/features/lessons/lessons-selection/LessonsSelection.jsx @@ -2,8 +2,8 @@ import profileStyles from "./ProfileStyle.module.scss"; import pageStyles from "./LessonsStyle.module.scss"; import { useNavigate } from "react-router"; import React, { useState, useEffect, useCallback, useMemo } from 'react'; -import { environment } from "../../environments/environment"; -import { getAllScenarios } from "../Lessons/Scenarios"; +import { environment } from "../../../core/environments/environment"; +import { getAllScenarios } from "../lessons-main/Scenarios"; import { useCookies } from "react-cookie"; import ScenarioTemplate from "./ScenarioTemplate/ScenarioTemplate.jsx"; // Importing the ScenarioTemplate component import LessonTemplate from "./LessonTemplate/LessonTemplate.jsx"; // Importing the LessonTemplate component diff --git a/react-ystemandchess/src/Pages/LessonsSelection/LessonsSelection.test.tsx b/react-ystemandchess/src/features/lessons/lessons-selection/LessonsSelection.test.tsx similarity index 100% rename from react-ystemandchess/src/Pages/LessonsSelection/LessonsSelection.test.tsx rename to react-ystemandchess/src/features/lessons/lessons-selection/LessonsSelection.test.tsx diff --git a/react-ystemandchess/src/Pages/LessonsSelection/LessonsStyle.module.scss b/react-ystemandchess/src/features/lessons/lessons-selection/LessonsStyle.module.scss similarity index 100% rename from react-ystemandchess/src/Pages/LessonsSelection/LessonsStyle.module.scss rename to react-ystemandchess/src/features/lessons/lessons-selection/LessonsStyle.module.scss diff --git a/react-ystemandchess/src/Pages/LessonsSelection/ProfileStyle.module.scss b/react-ystemandchess/src/features/lessons/lessons-selection/ProfileStyle.module.scss similarity index 100% rename from react-ystemandchess/src/Pages/LessonsSelection/ProfileStyle.module.scss rename to react-ystemandchess/src/features/lessons/lessons-selection/ProfileStyle.module.scss diff --git a/react-ystemandchess/src/Pages/LessonsSelection/ScenarioTemplate/ScenarioTemplate.jsx b/react-ystemandchess/src/features/lessons/lessons-selection/ScenarioTemplate/ScenarioTemplate.jsx similarity index 100% rename from react-ystemandchess/src/Pages/LessonsSelection/ScenarioTemplate/ScenarioTemplate.jsx rename to react-ystemandchess/src/features/lessons/lessons-selection/ScenarioTemplate/ScenarioTemplate.jsx diff --git a/react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/Lesson-overlay-profile.module.scss b/react-ystemandchess/src/features/lessons/piece-lessons/lesson-overlay/Lesson-overlay-profile.module.scss similarity index 100% rename from react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/Lesson-overlay-profile.module.scss rename to react-ystemandchess/src/features/lessons/piece-lessons/lesson-overlay/Lesson-overlay-profile.module.scss diff --git a/react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/Lesson-overlay.module.scss b/react-ystemandchess/src/features/lessons/piece-lessons/lesson-overlay/Lesson-overlay.module.scss similarity index 99% rename from react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/Lesson-overlay.module.scss rename to react-ystemandchess/src/features/lessons/piece-lessons/lesson-overlay/Lesson-overlay.module.scss index 014365f7..1018c5e8 100644 --- a/react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/Lesson-overlay.module.scss +++ b/react-ystemandchess/src/features/lessons/piece-lessons/lesson-overlay/Lesson-overlay.module.scss @@ -1,5 +1,5 @@ .lessonContainer { - background-image: url("../../../images/chess_background.png"); + background-image: url("../../../../assets/images/chess_background.png"); background-repeat: no-repeat; background-size: cover; align-content: center; diff --git a/react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/Lesson-overlay.test.tsx b/react-ystemandchess/src/features/lessons/piece-lessons/lesson-overlay/Lesson-overlay.test.tsx similarity index 100% rename from react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/Lesson-overlay.test.tsx rename to react-ystemandchess/src/features/lessons/piece-lessons/lesson-overlay/Lesson-overlay.test.tsx diff --git a/react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/Lesson-overlay.tsx b/react-ystemandchess/src/features/lessons/piece-lessons/lesson-overlay/Lesson-overlay.tsx similarity index 96% rename from react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/Lesson-overlay.tsx rename to react-ystemandchess/src/features/lessons/piece-lessons/lesson-overlay/Lesson-overlay.tsx index f22551e8..228ea3b6 100644 --- a/react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/Lesson-overlay.tsx +++ b/react-ystemandchess/src/features/lessons/piece-lessons/lesson-overlay/Lesson-overlay.tsx @@ -4,15 +4,15 @@ import pageStyles from './Lesson-overlay.module.scss'; import profileStyles from './Lesson-overlay-profile.module.scss'; // @ts-ignore import MoveTracker from '../move-tracker/MoveTracker'; -import ChessBoard from '../../../components/ChessBoard/ChessBoard'; -import { ReactComponent as RedoIcon } from '../../../images/icons/icon_redo.svg'; -import { ReactComponent as BackIcon } from '../../../images/icons/icon_back.svg'; -import { ReactComponent as BackIconInactive } from '../../../images/icons/icon_back_inactive.svg'; -import { ReactComponent as NextIcon } from '../../../images/icons/icon_next.svg'; -import { ReactComponent as NextIconInactive } from '../../../images/icons/icon_next_inactive.svg'; +import ChessBoard from '../../../../components/chessboard/ChessBoard'; +import { ReactComponent as RedoIcon } from "../../../../assets/images/icons/icon_redo.svg"; +import { ReactComponent as BackIcon } from "../../../../assets/images/icons/icon_back.svg"; +import { ReactComponent as BackIconInactive } from "../../../../assets/images/icons/icon_back_inactive.svg"; +import { ReactComponent as NextIcon } from "../../../../assets/images/icons/icon_next.svg"; +import { ReactComponent as NextIconInactive } from "../../../../assets/images/icons/icon_next_inactive.svg"; import { useNavigate, useLocation } from 'react-router'; -import PromotionPopup from '../../Lessons/PromotionPopup'; +import PromotionPopup from '../../lessons-main/PromotionPopup'; // Custom Hooks import { useChessGameLogic } from './hooks/useChessGameLogic'; diff --git a/react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/answers.js b/react-ystemandchess/src/features/lessons/piece-lessons/lesson-overlay/answers.js similarity index 100% rename from react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/answers.js rename to react-ystemandchess/src/features/lessons/piece-lessons/lesson-overlay/answers.js diff --git a/react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/hooks/useChessGameLogic.test.ts b/react-ystemandchess/src/features/lessons/piece-lessons/lesson-overlay/hooks/useChessGameLogic.test.ts similarity index 100% rename from react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/hooks/useChessGameLogic.test.ts rename to react-ystemandchess/src/features/lessons/piece-lessons/lesson-overlay/hooks/useChessGameLogic.test.ts diff --git a/react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/hooks/useChessGameLogic.ts b/react-ystemandchess/src/features/lessons/piece-lessons/lesson-overlay/hooks/useChessGameLogic.ts similarity index 100% rename from react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/hooks/useChessGameLogic.ts rename to react-ystemandchess/src/features/lessons/piece-lessons/lesson-overlay/hooks/useChessGameLogic.ts diff --git a/react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/hooks/useLessonManager.test.ts b/react-ystemandchess/src/features/lessons/piece-lessons/lesson-overlay/hooks/useLessonManager.test.ts similarity index 100% rename from react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/hooks/useLessonManager.test.ts rename to react-ystemandchess/src/features/lessons/piece-lessons/lesson-overlay/hooks/useLessonManager.test.ts diff --git a/react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/hooks/useLessonManager.ts b/react-ystemandchess/src/features/lessons/piece-lessons/lesson-overlay/hooks/useLessonManager.ts similarity index 98% rename from react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/hooks/useLessonManager.ts rename to react-ystemandchess/src/features/lessons/piece-lessons/lesson-overlay/hooks/useLessonManager.ts index 72c59c6f..4a45d808 100644 --- a/react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/hooks/useLessonManager.ts +++ b/react-ystemandchess/src/features/lessons/piece-lessons/lesson-overlay/hooks/useLessonManager.ts @@ -1,5 +1,5 @@ import { useState, useCallback } from "react"; -import { environment } from "../../../../environments/environment"; +import { environment } from "../../../../../core/environments/environment"; export function useLessonManager(piece: string, cookies: any, initialLessonNum?: number) { const [lessonNum, setLessonNum] = useState(initialLessonNum ?? 0); diff --git a/react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/hooks/useSocketChessEngine.test.ts b/react-ystemandchess/src/features/lessons/piece-lessons/lesson-overlay/hooks/useSocketChessEngine.test.ts similarity index 100% rename from react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/hooks/useSocketChessEngine.test.ts rename to react-ystemandchess/src/features/lessons/piece-lessons/lesson-overlay/hooks/useSocketChessEngine.test.ts diff --git a/react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/hooks/useSocketChessEngine.ts b/react-ystemandchess/src/features/lessons/piece-lessons/lesson-overlay/hooks/useSocketChessEngine.ts similarity index 91% rename from react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/hooks/useSocketChessEngine.ts rename to react-ystemandchess/src/features/lessons/piece-lessons/lesson-overlay/hooks/useSocketChessEngine.ts index 3e37be23..a5f26124 100644 --- a/react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/hooks/useSocketChessEngine.ts +++ b/react-ystemandchess/src/features/lessons/piece-lessons/lesson-overlay/hooks/useSocketChessEngine.ts @@ -1,4 +1,4 @@ -import { environment } from "../../../../environments/environment"; +import { environment } from "../../../../../core/environments/environment"; import { useEffect, useRef } from "react"; import io from "socket.io-client"; diff --git a/react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/hooks/useTimeTracking.test.ts b/react-ystemandchess/src/features/lessons/piece-lessons/lesson-overlay/hooks/useTimeTracking.test.ts similarity index 92% rename from react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/hooks/useTimeTracking.test.ts rename to react-ystemandchess/src/features/lessons/piece-lessons/lesson-overlay/hooks/useTimeTracking.test.ts index d5410c98..48e1a73b 100644 --- a/react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/hooks/useTimeTracking.test.ts +++ b/react-ystemandchess/src/features/lessons/piece-lessons/lesson-overlay/hooks/useTimeTracking.test.ts @@ -1,15 +1,15 @@ import { renderHook, act } from "@testing-library/react"; import { useTimeTracking } from "./useTimeTracking"; -import { SetPermissionLevel } from "../../../../globals"; -import { environment } from "../../../../environments/environment"; +import { SetPermissionLevel } from "../../../../../globals"; +import { environment } from "../../../../../core/environments/environment"; // mock SetPermissionLevel -jest.mock("../../../../globals", () => ({ +jest.mock("../../../../../globals", () => ({ SetPermissionLevel: jest.fn(), })); // mock environment URL -jest.mock("../../../../environments/environment", () => ({ +jest.mock("../../../../../core/environments/environment", () => ({ environment: { urls: { middlewareURL: "http://mockurl.com" } }, })); diff --git a/react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/hooks/useTimeTracking.ts b/react-ystemandchess/src/features/lessons/piece-lessons/lesson-overlay/hooks/useTimeTracking.ts similarity index 92% rename from react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/hooks/useTimeTracking.ts rename to react-ystemandchess/src/features/lessons/piece-lessons/lesson-overlay/hooks/useTimeTracking.ts index ff4965d2..8762ec05 100644 --- a/react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/hooks/useTimeTracking.ts +++ b/react-ystemandchess/src/features/lessons/piece-lessons/lesson-overlay/hooks/useTimeTracking.ts @@ -1,6 +1,6 @@ import { useEffect, useRef, useState } from "react"; -import { environment } from "../../../../environments/environment"; -import { SetPermissionLevel } from "../../../../globals"; +import { environment } from "../../../../../core/environments/environment"; +import { SetPermissionLevel } from "../../../../../globals"; export function useTimeTracking(piece: string, cookies: any) { const [username, setUsername] = useState(null); diff --git a/react-ystemandchess/src/Pages/piece-lessons/move-tracker/MoveTracker.tsx b/react-ystemandchess/src/features/lessons/piece-lessons/move-tracker/MoveTracker.tsx similarity index 100% rename from react-ystemandchess/src/Pages/piece-lessons/move-tracker/MoveTracker.tsx rename to react-ystemandchess/src/features/lessons/piece-lessons/move-tracker/MoveTracker.tsx diff --git a/react-ystemandchess/src/Pages/piece-lessons/play-lesson/PlayLesson.tsx b/react-ystemandchess/src/features/lessons/piece-lessons/play-lesson/PlayLesson.tsx similarity index 100% rename from react-ystemandchess/src/Pages/piece-lessons/play-lesson/PlayLesson.tsx rename to react-ystemandchess/src/features/lessons/piece-lessons/play-lesson/PlayLesson.tsx diff --git a/react-ystemandchess/src/Pages/piece-lessons/play-lesson/lesson-content copy.scss b/react-ystemandchess/src/features/lessons/piece-lessons/play-lesson/lesson-content copy.scss similarity index 100% rename from react-ystemandchess/src/Pages/piece-lessons/play-lesson/lesson-content copy.scss rename to react-ystemandchess/src/features/lessons/piece-lessons/play-lesson/lesson-content copy.scss diff --git a/react-ystemandchess/src/Pages/piece-lessons/play-lesson/lesson-content.scss b/react-ystemandchess/src/features/lessons/piece-lessons/play-lesson/lesson-content.scss similarity index 100% rename from react-ystemandchess/src/Pages/piece-lessons/play-lesson/lesson-content.scss rename to react-ystemandchess/src/features/lessons/piece-lessons/play-lesson/lesson-content.scss diff --git a/react-ystemandchess/src/Pages/Mentor/Mentor.scss b/react-ystemandchess/src/features/mentor/mentor-page/Mentor.scss similarity index 100% rename from react-ystemandchess/src/Pages/Mentor/Mentor.scss rename to react-ystemandchess/src/features/mentor/mentor-page/Mentor.scss diff --git a/react-ystemandchess/src/Pages/Mentor/Mentor.test.tsx b/react-ystemandchess/src/features/mentor/mentor-page/Mentor.test.tsx similarity index 100% rename from react-ystemandchess/src/Pages/Mentor/Mentor.test.tsx rename to react-ystemandchess/src/features/mentor/mentor-page/Mentor.test.tsx diff --git a/react-ystemandchess/src/Pages/Mentor/Mentor.tsx b/react-ystemandchess/src/features/mentor/mentor-page/Mentor.tsx similarity index 79% rename from react-ystemandchess/src/Pages/Mentor/Mentor.tsx rename to react-ystemandchess/src/features/mentor/mentor-page/Mentor.tsx index 5db7a3f6..22e7d17c 100644 --- a/react-ystemandchess/src/Pages/Mentor/Mentor.tsx +++ b/react-ystemandchess/src/features/mentor/mentor-page/Mentor.tsx @@ -1,10 +1,10 @@ import React from "react"; import "./Mentor.scss"; -import LogoLineBr from "../../images/LogoLineBreak.png"; -import cabbageImg from "../../images/mission-image.png"; -import volunteerImg from "../../images/volunteer.png"; -import teacher from "../../images/teaching.png"; -import makeADifference from "../../images/difference.png"; +import LogoLineBr from "../../../assets/images/LogoLineBreak.png"; +import cabbageImg from "../../../assets/images/mission-image.png"; +import volunteerImg from "../../../assets/images/volunteer.png"; +import teacher from "../../../assets/images/teaching.png"; +import makeADifference from "../../../assets/images/difference.png"; const Mentor = () => { return ( diff --git a/react-ystemandchess/src/Pages/NewMentorProfile/NewMentorProfile.scss b/react-ystemandchess/src/features/mentor/mentor-profile/NewMentorProfile.scss similarity index 100% rename from react-ystemandchess/src/Pages/NewMentorProfile/NewMentorProfile.scss rename to react-ystemandchess/src/features/mentor/mentor-profile/NewMentorProfile.scss diff --git a/react-ystemandchess/src/Pages/NewMentorProfile/NewMentorProfile.test.tsx b/react-ystemandchess/src/features/mentor/mentor-profile/NewMentorProfile.test.tsx similarity index 98% rename from react-ystemandchess/src/Pages/NewMentorProfile/NewMentorProfile.test.tsx rename to react-ystemandchess/src/features/mentor/mentor-profile/NewMentorProfile.test.tsx index f257666b..e83ca584 100644 --- a/react-ystemandchess/src/Pages/NewMentorProfile/NewMentorProfile.test.tsx +++ b/react-ystemandchess/src/features/mentor/mentor-profile/NewMentorProfile.test.tsx @@ -1,12 +1,12 @@ import React from 'react'; import { render, screen, act } from '@testing-library/react'; import { MemoryRouter } from 'react-router'; -import { SetPermissionLevel } from '../../globals'; +import { SetPermissionLevel } from '../../../globals'; import NewMentorProfile from './NewMentorProfile'; // ------------- MOCKS ------------- // mock being logged in -jest.mock('../../globals', () => ({ +jest.mock('../../../globals', () => ({ __esModule: true, SetPermissionLevel: jest.fn(), })); diff --git a/react-ystemandchess/src/Pages/NewMentorProfile/NewMentorProfile.tsx b/react-ystemandchess/src/features/mentor/mentor-profile/NewMentorProfile.tsx similarity index 96% rename from react-ystemandchess/src/Pages/NewMentorProfile/NewMentorProfile.tsx rename to react-ystemandchess/src/features/mentor/mentor-profile/NewMentorProfile.tsx index f4ca1c10..220bb75e 100644 --- a/react-ystemandchess/src/Pages/NewMentorProfile/NewMentorProfile.tsx +++ b/react-ystemandchess/src/features/mentor/mentor-profile/NewMentorProfile.tsx @@ -1,15 +1,15 @@ import React, { useState, useEffect, useRef, useMemo } from "react"; import "./NewMentorProfile.scss"; -import Images from "../../images/imageImporter"; -import { SetPermissionLevel } from '../../globals'; +import Images from "../../../assets/images/imageImporter"; +import { SetPermissionLevel } from '../../../globals'; import { useCookies } from 'react-cookie'; -import { environment } from '../../environments/environment'; +import { environment } from "../../../core/environments/environment"; import { useNavigate } from "react-router"; -import StatsChart from "../NewStudentProfile/StatsChart"; -import Lessons from "../Lessons/Lessons"; -import LessonSelection from "../LessonsSelection/LessonsSelection"; -import LessonOverlay from "../piece-lessons/lesson-overlay/Lesson-overlay"; -import Puzzles from "../Puzzles/Puzzles"; +import StatsChart from "../../student/student-profile/StatsChart"; +import Lessons from "../../lessons/lessons-main/Lessons"; +import LessonSelection from "../../lessons/lessons-selection/LessonsSelection"; +import LessonOverlay from "../../lessons/piece-lessons/lesson-overlay/Lesson-overlay"; +import Puzzles from "../../puzzles/puzzles-page/Puzzles"; interface NewMentorProfileProps { userPortraitSrc: string; diff --git a/react-ystemandchess/src/features/mentor/mentor-profile/NewMentorProfile/NewMentorProfile.tsx b/react-ystemandchess/src/features/mentor/mentor-profile/NewMentorProfile/NewMentorProfile.tsx new file mode 100644 index 00000000..29147100 --- /dev/null +++ b/react-ystemandchess/src/features/mentor/mentor-profile/NewMentorProfile/NewMentorProfile.tsx @@ -0,0 +1,436 @@ +import React, { useState, useEffect, useRef, useMemo } from "react"; +import "./NewMentorProfile.scss"; +import Images from "../../../../assets/images/imageImporter"; +import { SetPermissionLevel } from '../../../../globals'; +import { useCookies } from 'react-cookie'; +import { environment } from "../../../../core/environments/environment"; +import { useNavigate } from "react-router"; +import StatsChart from "../../../student/student-profile/StatsChart"; +import Lessons from "../../../lessons/lessons-main/Lessons"; +import LessonSelection from "../../../lessons/lessons-selection/LessonsSelection"; +import LessonOverlay from "../../../lessons/piece-lessons/lesson-overlay/Lesson-overlay"; +import Puzzles from "../../../puzzles/puzzles-page/Puzzles"; + +interface NewMentorProfileProps { + userPortraitSrc: string; + student?: Student; // optional student prop +} + +interface Student { + username: string; + firstName: string; + lastName: string; +} + +const NewMentorProfile: React.FC = ({ userPortraitSrc }) => { + + const [activeTab, setActiveTab] = useState("activity"); + const [cookies] = useCookies(['login']); + const navigate = useNavigate(); + + // mentor info + const [username, setUsername] = useState(""); + const [firstName, setFirstName] = useState(" "); + const [lastName, setLastName] = useState(" "); + const [hasStudent, setHasStudent] = useState(false); // if the mentor has a student + + // student usage stats in different modules + const [webTime, setWebTime] = useState(0); + const [playTime, setPlayTime] = useState(0); + const [lessonTime, setLessonTime] = useState(0); + const [puzzleTime, setPuzzleTime] = useState(0); + const [mentorTime, setMentorTime] = useState(0); + + // data for chart plotting + const [displayMonths, setDisplayMonths] = useState(6); // display data from 6 many months back + const [displayEvents, setDisplayEvents] = useState(["website", "play", "lesson", "puzzle", "mentor"]) + const [monthAxis, setMonthAxis] = useState(["Jan", "Feb", "Mar", "Apr", "May"]); // display the time as X-axis + const [dataAxis, setDataAxis] = useState<{[key: string]: number[]}>({website: [0, 0, 0, 0, 0],}); // time spent on events each month + + // student info + const [studentFirstName, setStudentFirstName] = useState(""); + const [studentLastName, setStudentLastName] = useState(""); + const [studentUsername, setStudentUsername] = useState(""); + + // event tracking for pagination + const [events, setEvents] = useState([]); + const [page, setPage] = useState(0); // page number + const [loading, setLoading] = useState(false); // if loading for more events + const [hasMore, setHasMore] = useState(true); + const containerRef = useRef(null); + + // current date for display + const [date, setDate] = useState(() => new Date().toLocaleDateString('en-US', { + month: 'long', + day: 'numeric', + }) + ); + + // states for lessons tab + const [lessonSelected, setLessonSelected] = useState(false); // whether user has navigated into a lesson + const [piece, setPiece] = useState(""); // lesson name for props + const [lessonNum, setLessonNum] = useState(0); // lesson number for props + + // Runs once upon first render + useEffect(()=>{ + fetchStudentData().catch(err => console.log(err)); // fetch student data when the component mounts + fetchUserData().catch(err => console.log(err)); // fetch user data when the component mounts + }, []) + + // Loads student data only after hasStudent has been updated + useEffect(() => { + if (hasStudent && studentUsername) { + // fetch student usage time stats to disaply in header + fetchUsageTime(studentUsername) + // fetch student data for graph plotting + fetchGraphData(studentUsername) + // fetch latest usage history to show in Activity tab + fetchActivity(studentUsername) + } + }, [hasStudent, studentUsername]) + + useEffect(() => { + const el = containerRef.current; + if (!el) return; + + const handleScroll = () => { + if (el.scrollTop + el.clientHeight >= el.scrollHeight - 50) { + fetchActivity(studentUsername); + } + }; + + el.addEventListener("scroll", handleScroll); + return () => el.removeEventListener("scroll", handleScroll); + }, [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) + } + } + + // 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); + } + + const fetchStudentData = async () => { + fetch(`${environment.urls.middlewareURL}/user/getMentorship`, { + method: 'GET', + headers: { 'Authorization': `Bearer ${cookies.login}` } + }).then(data => data.json()) + .then(data => { + if (data) { + setStudentFirstName(data.firstName); + setStudentLastName(data.lastName); + setStudentUsername(data.username); + 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 => { + console.log("Set student response:", data); + }); + } + +// fetch latest usage history (Activity Tab) + const fetchActivity = async (username) => { + if (loading || !hasMore) return; // return if already fetching or no more activity left + + setLoading(true); + const limit = 6; // fetch at most 6 activities at a time + const skip = page * limit; // skip over previously fetched data + + try { + // fetch another batch of usage history + const responseLatest = await fetch( + `${environment.urls.middlewareURL}/timeTracking/latest?username=${username}&limit=${limit}&skip=${skip}`, + { + 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 + 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}&events=${displayEvents.join(",")}&months=${displayMonths}`, + { + method: 'GET', + headers: { 'Authorization': `Bearer ${cookies.login}` } + } + ); + const data = await response.json(); + + const newDataAxis = {} as {[key: string]: number[]}; + for(let i = 0; i < displayEvents.length; i++) + { + // get time spent for each event for plotting + let event = displayEvents[i]; + let value = data[event]; + let months = value.map(item => item.monthText); // month list for ploting + let times = value.map(item => item.timeSpent); // timeSpent for plotting + + setMonthAxis(months); + newDataAxis[event] = times; + } + + // update for graph plotting + setDataAxis(newDataAxis); + } catch (err) { + console.error("Failed to fetch events", err); + } + } + + const handleTabClick = (tab: any) => { + setActiveTab(tab); + }; + + const handleNavigateEvent = (type: string, name: string) => { + if(type == "lesson") { + navigate("/lessons", { state: { piece: name } }); + } + } + + const renderTabContent = () => { + switch (activeTab) { + case "activity": + return ( +
+
+

Activity

+

{date}

+
+
+
+ {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} +

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

Loading more...

} + {!hasMore &&

No more activity left!

} +
+
+ ); + case "mentor": + return ( +
+

Mentor

+

This is the content for the Mentor tab.

+
+ ); + case "learning": + return ( +
+ +
+ ); + case "chessLessons": + return ( +
+ {lessonSelected ? ( + { + setLessonSelected(false); + }} styleType="profile"/> + ) : ( + { + setLessonSelected(true); + setPiece(selectedScenario); + setLessonNum(lessonNum); + }}/> + )} +
+ ); + case "games": + return ( +
+

Games

+

This is the content for the Games tab.

+
+ ); + case "puzzles": + return ( +
+ +
+ ); + 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.

+
+ ); + default: + return ( +
+

Select a tab to view its content.

+
+ ); + } + }; + + const tabContent = useMemo(() => renderTabContent(), [activeTab, events, loading, hasMore]); + + return ( +
+
+
+ user portrait + user portrait camera icon +
+
+

Hello, {firstName} {lastName}!

+
+
+ + { 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
  • +
+
+
+
+ + +
{tabContent}
+
+
) : ( +
+

No Student Selected

+

Please select a student to view their progress.

+
+ )} +
+ ); +}; + +export default NewMentorProfile; diff --git a/react-ystemandchess/src/Pages/Programs/Programs.scss b/react-ystemandchess/src/features/programs/Programs.scss similarity index 100% rename from react-ystemandchess/src/Pages/Programs/Programs.scss rename to react-ystemandchess/src/features/programs/Programs.scss diff --git a/react-ystemandchess/src/Pages/Programs/Programs.test.tsx b/react-ystemandchess/src/features/programs/Programs.test.tsx similarity index 100% rename from react-ystemandchess/src/Pages/Programs/Programs.test.tsx rename to react-ystemandchess/src/features/programs/Programs.test.tsx diff --git a/react-ystemandchess/src/Pages/Programs/Programs.tsx b/react-ystemandchess/src/features/programs/Programs.tsx similarity index 98% rename from react-ystemandchess/src/Pages/Programs/Programs.tsx rename to react-ystemandchess/src/features/programs/Programs.tsx index 301d74c1..09958cdf 100644 --- a/react-ystemandchess/src/Pages/Programs/Programs.tsx +++ b/react-ystemandchess/src/features/programs/Programs.tsx @@ -1,5 +1,5 @@ import React from "react"; -import kidsCoding from "../../images/kidsCoding.png"; +import kidsCoding from "../../assets/images/kidsCoding.png"; import "./Programs.scss"; const Programs = () => { return ( diff --git a/react-ystemandchess/src/Pages/Puzzles/Puzzles-profile.module.scss b/react-ystemandchess/src/features/puzzles/puzzles-page/Puzzles-profile.module.scss similarity index 100% rename from react-ystemandchess/src/Pages/Puzzles/Puzzles-profile.module.scss rename to react-ystemandchess/src/features/puzzles/puzzles-page/Puzzles-profile.module.scss diff --git a/react-ystemandchess/src/Pages/Puzzles/Puzzles.module.scss b/react-ystemandchess/src/features/puzzles/puzzles-page/Puzzles.module.scss similarity index 94% rename from react-ystemandchess/src/Pages/Puzzles/Puzzles.module.scss rename to react-ystemandchess/src/features/puzzles/puzzles-page/Puzzles.module.scss index bffbb49b..be5e522c 100644 --- a/react-ystemandchess/src/Pages/Puzzles/Puzzles.module.scss +++ b/react-ystemandchess/src/features/puzzles/puzzles-page/Puzzles.module.scss @@ -1,6 +1,6 @@ body { background-color: #e5f3d2; - background-image: url("../../images/chess-piece-pattern.png"); + background-image: url("../../../assets/images/chess-piece-pattern.png"); } .mainElements { diff --git a/react-ystemandchess/src/Pages/Puzzles/Puzzles.test.tsx b/react-ystemandchess/src/features/puzzles/puzzles-page/Puzzles.test.tsx similarity index 100% rename from react-ystemandchess/src/Pages/Puzzles/Puzzles.test.tsx rename to react-ystemandchess/src/features/puzzles/puzzles-page/Puzzles.test.tsx diff --git a/react-ystemandchess/src/Pages/Puzzles/Puzzles.tsx b/react-ystemandchess/src/features/puzzles/puzzles-page/Puzzles.tsx similarity index 99% rename from react-ystemandchess/src/Pages/Puzzles/Puzzles.tsx rename to react-ystemandchess/src/features/puzzles/puzzles-page/Puzzles.tsx index 80974fe8..d926cbc4 100644 --- a/react-ystemandchess/src/Pages/Puzzles/Puzzles.tsx +++ b/react-ystemandchess/src/features/puzzles/puzzles-page/Puzzles.tsx @@ -2,11 +2,11 @@ import React, { useRef, useState, useEffect } from "react"; import pageStyles from "./Puzzles.module.scss"; import profileStyles from "./Puzzles-profile.module.scss"; import { Chess } from "chess.js"; -import { themesName, themesDescription } from '../../services/themesService'; +import { themesName, themesDescription } from "../../../core/services/themesService"; import Swal from 'sweetalert2'; -import { environment } from "../../environments/environment"; +import { environment } from "../../../core/environments/environment"; import { v4 as uuidv4 } from "uuid"; -import { SetPermissionLevel } from "../../globals"; +import { SetPermissionLevel } from "../../../globals"; import { useCookies } from 'react-cookie'; const chessClientURL = environment.urls.chessClientURL; diff --git a/react-ystemandchess/src/features/student/student-inventory/Student-Inventory/StudentInventory.tsx b/react-ystemandchess/src/features/student/student-inventory/Student-Inventory/StudentInventory.tsx new file mode 100644 index 00000000..8651e0b8 --- /dev/null +++ b/react-ystemandchess/src/features/student/student-inventory/Student-Inventory/StudentInventory.tsx @@ -0,0 +1,820 @@ +import React, { useState, useEffect } from "react"; +import "./StudentInventory.scss"; +import Images from "../../../../assets/images/imageImporter"; +import { createChessBoard, isInBounds, getPawnMoves, getRookMoves, getKnightMoves, getBishopMoves, getKingMoves, getQueenMoves } from '../../../lessons/lessons-main/Lessons' +import LessonSelection from "../../../lessons/lessons-selection/LessonsSelection"; +import Lessons from '../../../lessons/lessons-main/Lessons'; + +type Board = (string | null)[][]; +type Piece = { + color: string; + type: string; // e.g., 'Pawn', 'Rook', etc. +}; + + +const StudentInventory = ({ userPortraitSrc, userName }: any) => { + // bring chessboard + const [board, setBoard] = useState(initializeBoard()); // Initialize the board with chess pieces + const [highlightedSquares, setHighlightedSquares] = useState([]); + const [draggingPiece, setDraggingPiece] = useState(null); // Track which piece is being dragged + + // Description for each Scenarios + const [scenarioDescription, setScenarioDescription] = useState(""); + const [scenarioDescription_2, setScenarioDescription_2] = useState(""); + const [pieceDescription, setpieceDescription] = useState(""); + + // State for showing scenario buttons for pieces + const [showScenarios, setShowScenarios] = useState({ + pawn: false, + rook: false, + bishop: false, + knight: false, + queen: false, + king: false, + }); + + const [showPopup, setShowPopup] = useState(false); // Popup state + const [trainingStarted, setTrainingStarted] = useState(false); // Training state + + // Initialize the chessboard + function initializeBoard(): any { + return [ + [null, null, null, null, null, null, null, null], // Empty row + [null, null, null, null, null, null, null, null], // Empty row + [null, null, null, null, null, null, null, null], // Empty row + [null, null, null, null, null, null, null, null], // Empty row + [null, null, null, null, null, null, null, null], // Empty row + [null, null, null, null, null, null, null, null], // Empty row + [null, null, null, null, null, null, null, null], // Empty row + [null, null, null, null, null, null, null, null], // Empty row + ]; + } + + // Popup + // Function to check if all black pieces are removed + const checkBlackPieces = () => { + const blackPieces = board.flat().filter((piece: string[]) => piece && piece[0] === 'b'); // Filter out black pieces + if (blackPieces.length === 0 && trainingStarted === true) { + setShowPopup(true); // Show the popup + } + }; + + // Reset the chessboard when the popup confirm button is clicked + const handlePopupConfirm = () => { + if (trainingStarted === true) { + setShowPopup(false); + setBoard(initializeBoard()); // Reset the chessboard + setTrainingStarted(false); // Reset training state + setScenarioDescription(""); + setScenarioDescription_2(""); + setpieceDescription(""); + } + }; + + // Check for black pieces every time the board state changes + useEffect(() => { + checkBlackPieces(); + }, [board]); + + // Update the setupScenario function to handle both Pawn and Rook + const setupScenario = (piece: any, scenario: any) => { + const updatedBoard = initializeBoard(); // Reset board + + // setup the board by scenario + switch (piece) { + case 'pawn': + setpieceDescription("Pawn - It moves forward only") + setScenarioDescription("Try this!"); + switch (scenario) { + case 'basic': + updatedBoard[4][0] = 'wP'; // a5 + updatedBoard[5][5] = 'bP'; // f3 + setScenarioDescription_2("Pawns move one square only. But when they reach the other side of the board, they become a stronger piece!"); + setTrainingStarted(true); // Mark training as started + break; + case 'capture': + updatedBoard[5][4] = 'wP'; // e3 + updatedBoard[3][3] = 'bP'; // d5 + updatedBoard[2][2] = 'bP'; // c6 + updatedBoard[1][3] = 'bP'; // d7 + setScenarioDescription_2("A pawn on the second rank can move 2 squares at once!"); + setTrainingStarted(true); // Mark training as started + break; + case 'training_1': + updatedBoard[5][1] = 'wP'; // b3 + updatedBoard[1][2] = 'bP'; // c7 + updatedBoard[2][1] = 'bP'; // b6 + updatedBoard[2][2] = 'bP'; // c6 + updatedBoard[2][3] = 'bP'; // d6 + updatedBoard[4][1] = 'bP'; // b4 + updatedBoard[4][2] = 'bP'; // c4 + setScenarioDescription_2("Capture black pawns and promote!"); + setTrainingStarted(true); // Mark training as started + break; + case 'training_2': + updatedBoard[5][3] = 'wP'; // d3 + updatedBoard[0][2] = 'bP'; // c8 + updatedBoard[1][3] = 'bP'; // d7 + updatedBoard[2][1] = 'bP'; // b6 + updatedBoard[2][4] = 'bP'; // e6 + updatedBoard[3][1] = 'bP'; // b5 + updatedBoard[3][3] = 'bP'; // d5 + updatedBoard[4][2] = 'bP'; // c4 + setScenarioDescription_2("Capture black pawns and promote!"); + setTrainingStarted(true); // Mark training as started + break; + case 'training_3': + updatedBoard[5][0] = 'wP'; // a3 + updatedBoard[5][2] = 'wP'; // c3 + updatedBoard[5][3] = 'wP'; // d3 + updatedBoard[5][7] = 'wP'; // h3 + updatedBoard[3][1] = 'bP'; // b5 + updatedBoard[3][2] = 'bP'; // c5 + updatedBoard[3][4] = 'bP'; // e5 + updatedBoard[4][3] = 'bP'; // d4 + updatedBoard[4][6] = 'bP'; // g4 + setScenarioDescription_2("No need to promote. Capture all black pawns."); + setTrainingStarted(true); // Mark training as started + break; + case 'special_move': + updatedBoard[6][4] = 'wP'; // e2 + updatedBoard[2][3] = 'bP'; // d6 + setScenarioDescription_2("A pawn on the second rank can move two squares forward."); + setTrainingStarted(true); // Mark training as started + break; + default: + break; + } + break; + case 'rook': + setpieceDescription("Rook - It moves in straight lines") + setScenarioDescription("Try this!"); + switch (scenario) { + case 'basic': + updatedBoard[6][4] = 'wR'; // e2 + updatedBoard[2][4] = 'bP'; // e6 + setScenarioDescription_2("Click on the rook to bring it to the pawn!"); + setTrainingStarted(true); + break; + case 'training_1': + updatedBoard[1][2] = 'wR'; // c7 + updatedBoard[3][2] = 'bP'; // c5 + updatedBoard[3][5] = 'bP'; // f5 + setScenarioDescription_2("Grab all the pawns!"); + setTrainingStarted(true); + break; + case 'training_2': + updatedBoard[5][4] = 'wR'; // e3 + updatedBoard[5][1] = 'bP'; // b3 + updatedBoard[6][7] = 'bP'; // h2 + updatedBoard[5][7] = 'bP'; // h3 + setScenarioDescription_2("The fewer moves you make, the better!"); + setTrainingStarted(true); + break; + case 'training_3': + updatedBoard[0][7] = 'wR'; // h8 + updatedBoard[0][5] = 'bP'; // f8 + updatedBoard[7][6] = 'bP'; // g1 + updatedBoard[1][6] = 'bP'; // g7 + updatedBoard[0][6] = 'bP'; // g8 + updatedBoard[1][7] = 'bP'; // h7 + setScenarioDescription_2("The fewer moves you make, the better!"); + setTrainingStarted(true); + break; + case 'training_4': + updatedBoard[1][2] = 'wR'; // c7 + updatedBoard[4][4] = 'wR'; // e4 + updatedBoard[4][0] = 'bP'; // a4 + updatedBoard[5][6] = 'bP'; // g3 + updatedBoard[1][6] = 'bP'; // g7 + updatedBoard[4][7] = 'bP'; // h4 + setScenarioDescription_2("Use two rooks to speed things up!"); + setTrainingStarted(true); + break; + case 'final': + updatedBoard[7][0] = 'wR'; // a1 + updatedBoard[5][5] = 'wR'; // f3 + updatedBoard[1][1] = 'bP'; // b7 + updatedBoard[7][3] = 'bP'; // d1 + updatedBoard[3][3] = 'bP'; // d5 + updatedBoard[6][5] = 'bP'; // f2 + updatedBoard[1][5] = 'bP'; // f7 + updatedBoard[3][6] = 'bP'; // g4 + updatedBoard[1][6] = 'bP'; // g7 + setScenarioDescription_2("Use two rooks to speed things up!"); + setTrainingStarted(true); + break; + + default: + break; + } + break; + case "bishop": + setpieceDescription("Bishop - It moves diagonally"); + setScenarioDescription("Try this!"); + switch (scenario) { + case 'basic': + updatedBoard[6][6] = 'wB'; // g2 + updatedBoard[1][7] = 'bP'; // h7 + updatedBoard[4][4] = 'bP'; // e4 + setScenarioDescription_2("Grab all the black pawns!"); + setTrainingStarted(true); + break; + case 'training_1': + updatedBoard[5][1] = 'wB'; // b3 + updatedBoard[6][0] = 'bP'; // a2 + updatedBoard[7][1] = 'bP'; // b1 + updatedBoard[3][1] = 'bP'; // b5 + updatedBoard[7][3] = 'bP'; // d1 + updatedBoard[5][3] = 'bP'; // d3 + updatedBoard[6][4] = 'bP'; // e2 + setScenarioDescription_2("The fewer moves you make, the better!"); + setTrainingStarted(true); + break; + case 'training_2': + updatedBoard[4][2] = 'wB'; // c4 + updatedBoard[4][0] = 'bP'; // a4 + updatedBoard[7][1] = 'bP'; // b1 + updatedBoard[5][1] = 'bP'; // b3 + updatedBoard[6][2] = 'bP'; // c2 + updatedBoard[5][3] = 'bP'; // d3 + updatedBoard[4][4] = 'bP'; // e2 + setScenarioDescription_2("Grab all the black pawns!"); + setTrainingStarted(true); + break; + case 'training_3': + updatedBoard[7][2] = 'wB'; // c1 + updatedBoard[7][5] = 'wB'; // f1 + updatedBoard[5][3] = 'bP'; // d3 + updatedBoard[5][4] = 'bP'; // e3 + updatedBoard[4][3] = 'bP'; // d4 + updatedBoard[4][4] = 'bP'; // e4 + updatedBoard[3][3] = 'bP'; // d5 + updatedBoard[3][4] = 'bP'; // e5 + setScenarioDescription_2("One light-squared bishop, one dark-squared bishop. You need both!"); + setTrainingStarted(true); + break; + case 'training_4': + updatedBoard[4][3] = 'wB'; // d4 + updatedBoard[7][0] = 'bP'; // a1 + updatedBoard[2][1] = 'bP'; // b6 + updatedBoard[7][2] = 'bP'; // c1 + updatedBoard[5][4] = 'bP'; // e3 + updatedBoard[1][6] = 'bP'; // g7 + updatedBoard[2][7] = 'bP'; // h6 + setScenarioDescription_2("Grab all the black pawns!"); + setTrainingStarted(true); + break; + case 'final': + updatedBoard[5][2] = 'wB'; // c3 + updatedBoard[1][3] = 'wB'; // d7 + updatedBoard[5][0] = 'bP'; // a3 + updatedBoard[6][2] = 'bP'; // c2 + updatedBoard[1][4] = 'bP'; // e7 + updatedBoard[3][5] = 'bP'; // f5 + updatedBoard[2][5] = 'bP'; // f6 + updatedBoard[0][6] = 'bP'; // g8 + updatedBoard[4][7] = 'bP'; // h4 + updatedBoard[1][7] = 'bP'; // h7 + setScenarioDescription_2("One light-squared bishop, one dark-squared bishop. You need both!"); + setTrainingStarted(true); + break; + default: + break; + } + break; + + case 'knight': + setpieceDescription("Knight - It moves in an 'L' shape"); + setScenarioDescription("Try this!"); + switch (scenario) { + case 'basic': + updatedBoard[4][4] = 'wN'; // e4 + updatedBoard[3][2] = 'bP'; // c5 + updatedBoard[1][3] = 'bP'; // d7 + setScenarioDescription_2("Knights have a fancy way of jumping around!"); + setTrainingStarted(true); + break; + + case 'training_1': + updatedBoard[7][1] = 'wN'; // b1 + updatedBoard[5][2] = 'bP'; // c3 + updatedBoard[4][3] = 'bP'; // d4 + updatedBoard[6][4] = 'bP'; // e2 + updatedBoard[5][5] = 'bP'; // f3 + updatedBoard[3][6] = 'bP'; // g5 + updatedBoard[1][5] = 'bP'; // f7 + updatedBoard[0][7] = 'bP'; // h8 + setScenarioDescription_2("Grab all the pawns!"); + setTrainingStarted(true); + break; + + case 'training_2': + updatedBoard[1][2] = 'wN'; // c7 + updatedBoard[2][1] = 'bP'; // b6 + updatedBoard[3][3] = 'bP'; // d5 + updatedBoard[1][3] = 'bP'; // d7 + updatedBoard[2][4] = 'bP'; // e6 + updatedBoard[4][5] = 'bP'; // f4 + setScenarioDescription_2("Grab all the pawns!"); + setTrainingStarted(true); + break; + + case 'training_3': + updatedBoard[5][5] = 'wN'; // f3 + updatedBoard[6][4] = 'bP'; // e2 + updatedBoard[5][4] = 'bP'; // e3 + updatedBoard[4][4] = 'bP'; // e4 + updatedBoard[6][5] = 'bP'; // f2 + updatedBoard[4][5] = 'bP'; // f4 + updatedBoard[6][6] = 'bP'; // g2 + updatedBoard[5][6] = 'bP'; // g3 + updatedBoard[4][6] = 'bP'; // g4 + setScenarioDescription_2("Knights can jump over obstacles! Escape and vanquish the pawns!"); + setTrainingStarted(true); + break; + + case 'training_4': + updatedBoard[5][3] = 'wN'; // d3 + updatedBoard[5][2] = 'bP'; // c3 + updatedBoard[6][4] = 'bP'; // e2 + updatedBoard[4][4] = 'bP'; // e4 + updatedBoard[6][5] = 'bP'; // f2 + updatedBoard[4][5] = 'bP'; // f4 + updatedBoard[2][6] = 'bP'; // g6 + setScenarioDescription_2("Grab all the pawns!"); + setTrainingStarted(true); + break; + + case 'final': + updatedBoard[1][2] = 'wN'; // c7 + updatedBoard[4][1] = 'bP'; // b4 + updatedBoard[3][1] = 'bP'; // b5 + updatedBoard[2][2] = 'bP'; // c6 + updatedBoard[0][2] = 'bP'; // c8 + updatedBoard[4][3] = 'bP'; // d4 + updatedBoard[3][3] = 'bP'; // d5 + updatedBoard[5][4] = 'bP'; // e3 + updatedBoard[1][4] = 'bP'; // e7 + updatedBoard[3][5] = 'bP'; // f5 + setScenarioDescription_2("Grab all the pawns!"); + setTrainingStarted(true); + break; + + } + break; + + case 'queen': + setpieceDescription("Queen - Queen = rook + bishop"); + setScenarioDescription("Try this!"); + switch (scenario) { + case 'basic': + updatedBoard[6][4] = 'wQ'; // e2 + updatedBoard[1][2] = 'bP'; // c7 + updatedBoard[3][4] = 'bP'; // e5 + setScenarioDescription_2("Grab all the pawns!"); + setTrainingStarted(true); + break; + case 'training_1': + updatedBoard[4][3] = 'wQ'; // d4 + updatedBoard[5][0] = 'bP'; // a3 + updatedBoard[6][5] = 'bP'; // f2 + updatedBoard[0][5] = 'bP'; // f8 + updatedBoard[5][7] = 'bP'; // h3 + setScenarioDescription_2("Grab all the pawns!"); + setTrainingStarted(true); + break; + case 'training_2': + updatedBoard[4][2] = 'wQ'; // c4 + updatedBoard[5][0] = 'bP'; // a3 + updatedBoard[2][3] = 'bP'; // d6 + updatedBoard[7][5] = 'bP'; // f1 + updatedBoard[0][5] = 'bP'; // f8 + updatedBoard[5][6] = 'bP'; // g3 + updatedBoard[2][7] = 'bP'; // h6 + setScenarioDescription_2("Grab all the pawns!"); + setTrainingStarted(true); + break; + case 'training_3': + updatedBoard[1][6] = 'wQ'; // g7 + updatedBoard[6][0] = 'bP'; // a2 + updatedBoard[3][1] = 'bP'; // b5 + updatedBoard[5][3] = 'bP'; // d3 + updatedBoard[7][6] = 'bP'; // g1 + updatedBoard[0][6] = 'bP'; // g8 + updatedBoard[6][7] = 'bP'; // h2 + updatedBoard[3][7] = 'bP'; // h5 + setScenarioDescription_2("Grab all the pawns!"); + setTrainingStarted(true); + break; + case 'final': + updatedBoard[7][4] = 'wQ'; // e1 + updatedBoard[2][0] = 'bP'; // a6 + updatedBoard[7][3] = 'bP'; // d1 + updatedBoard[6][5] = 'bP'; // f2 + updatedBoard[2][5] = 'bP'; // f6 + updatedBoard[2][6] = 'bP'; // g6 + updatedBoard[0][6] = 'bP'; // g8 + updatedBoard[7][7] = 'bP'; // h1 + updatedBoard[4][7] = 'bP'; // h4 + setScenarioDescription_2("Grab all the pawns!"); + setTrainingStarted(true); + break; + + default: + break; + } + break; + + case 'king': + setpieceDescription("King - The most important piece"); + setScenarioDescription("Try this!"); + switch (scenario) { + case 'basic': + updatedBoard[6][3] = 'wK'; // d2 + updatedBoard[2][3] = 'bP'; // d6 + setScenarioDescription_2("The king is slow."); + setTrainingStarted(true); + break; + case 'training': + updatedBoard[7][4] = 'wK'; // e1 + updatedBoard[6][2] = 'bP'; // c2 + updatedBoard[5][3] = 'bP'; // d3 + updatedBoard[6][4] = 'bP'; // e2 + setScenarioDescription_2("Grab all the pawns!"); + setTrainingStarted(true); + break; + case 'final': + updatedBoard[3][4] = 'wK'; // e5 + updatedBoard[4][2] = 'bP'; // c4 + updatedBoard[3][2] = 'bP'; // c5 + updatedBoard[3][3] = 'bP'; // d5 + updatedBoard[5][4] = 'bP'; // e3 + updatedBoard[5][5] = 'bP'; // f3 + updatedBoard[4][6] = 'bP'; // g4 + setScenarioDescription_2("Grab all the pawns!"); + setTrainingStarted(true); + break; + + default: + break; + } + break; + + case 'basic_checkmate_1': + setpieceDescription("piece checkmate 1 Basic checkmates"); + setScenarioDescription("Try this!"); + + switch (scenario) { + case 'queen_and_rook_mate': + updatedBoard[7][0] = 'wQ'; // a1 + updatedBoard[5][4] = 'wK'; // e3 + updatedBoard[7][7] = 'wR'; // h1 + updatedBoard[2][3] = 'bK'; // d6 + setScenarioDescription("Use your queen and rook to restrict the king and deliver checkmate. Mate in 3 if played perfectly."); + setTrainingStarted(true); + break; + + case 'two_rook_mate': + updatedBoard[7][0] = 'wR'; // a1 + updatedBoard[7][7] = 'wR'; // h1 + updatedBoard[5][4] = 'wK'; // e3 + updatedBoard[2][3] = 'bK'; // d6 + setScenarioDescription("Use your rooks to restrict the king and deliver checkmate. Mate in 4 if played perfectly."); + setTrainingStarted(true); + break; + + case 'queen_and_bishop_mate': + updatedBoard[5][2] = 'wQ'; // c3 + updatedBoard[5][3] = 'wB'; // d3 + updatedBoard[5][4] = 'wK'; // e3 + updatedBoard[2][3] = 'bK'; // d6 + setScenarioDescription("Use your queen and bishop to restrict the king and deliver checkmate. Mate in 5 if played perfectly."); + setTrainingStarted(true); + break; + + case 'queen_and_knight_mate': + updatedBoard[5][2] = 'wQ'; // c3 + updatedBoard[5][3] = 'wN'; // d3 + updatedBoard[5][4] = 'wK'; // e3 + updatedBoard[2][3] = 'bK'; // d6 + setScenarioDescription("Use your queen and knight to restrict the king and deliver checkmate. Mate in 5 if played perfectly."); + setTrainingStarted(true); + break; + + case 'queen_mate': + updatedBoard[7][4] = 'wQ'; // e1 + updatedBoard[5][4] = 'wK'; // e3 + updatedBoard[2][3] = 'bK'; // d6 + setScenarioDescription("Use your queen to restrict the king, force it to the edge of the board and deliver checkmate. The queen can't do it alone, so use your king to help. Mate in 6 if played perfectly."); + setTrainingStarted(true); + break; + + case 'rook_mate': + updatedBoard[7][4] = 'wR'; // e1 + updatedBoard[5][4] = 'wK'; // e3 + updatedBoard[2][3] = 'bK'; // d6 + setScenarioDescription("Use your rook to restrict the king, force it to the edge of the board and deliver checkmate. The rook can't do it alone, so use your king to help. Mate in 11 if played perfectly."); + setTrainingStarted(true); + break; + + default: + console.error("Scenario not found."); + break; + } + break; + + + default: + break; + } + setBoard(updatedBoard); + setHighlightedSquares([]); // clear highlight + }; + + // Button click handlers + // Generic function to handle all piece button clicks + const handlePieceClick = (piece: string) => { + setShowScenarios({ + pawn: piece === 'pawn', + rook: piece === 'rook', + bishop: piece === 'bishop', + knight: piece === 'knight', + queen: piece === 'queen', + king: piece === 'king', + }); + }; + + const handlePawnClick = () => handlePieceClick('pawn'); + const handleRookClick = () => handlePieceClick('rook'); + const handleBishopClick = () => handlePieceClick('bishop'); + const handleKnightClick = () => handlePieceClick('knight'); + const handleQueenClick = () => handlePieceClick('queen'); + const handleKingClick = () => handlePieceClick('king'); + + // Helper function to get possible moves for a piece + const getPieceMoves = (piece: any[], position: { split: any; }) => { + const color = piece[0]; // Get color from the piece (first character) + switch (piece[1]) { + case 'P': + return getPawnMoves(position, color === 'w', board); + case 'R': + return getRookMoves(position, color === 'w', board); // Pass color directly + case 'N': + return getKnightMoves(position, color === 'w', board); // Pass color directly + case 'B': + return getBishopMoves(position, color === 'w', board); // Pass color directly + case 'K': + return getKingMoves(position, color === 'w', board); // Pass color directly + case 'Q': + return getQueenMoves(position, color === 'w', board); // Pass color directly + default: + return []; + } + }; + + // Handle hover to show possible moves + const handleSquareHover = (key: { split: any; }) => { + const [row, col] = key.split('-').map(Number); + const piece = board[row][col]; + + // Clear previous highlights + setHighlightedSquares([]); + + if (piece) { + const possibleMoves = getPieceMoves(piece, key); + setHighlightedSquares(possibleMoves); // Highlight valid move squares + } else { + // Check if the square has an opponent's piece + const targetPiece = board[row][col]; + if (targetPiece && targetPiece[0] !== draggingPiece?.piece[0]) { + setHighlightedSquares((prev: any) => [...prev, key]); // Highlight the opponent's piece square + } + } + }; + + // Handle drag start + const handleDragStart = (e: any, piece: any, position: any) => { + setDraggingPiece({ piece, position }); + e.dataTransfer.setDragImage(e.target, 20, 20); // Set the drag image with a specified offset + }; + + // Handle drop on a square + const handleDrop = (key: any) => { + if (highlightedSquares.includes(key)) { + const [startRow, startCol] = draggingPiece.position.split('-').map(Number); + const [endRow, endCol] = key.split('-').map(Number); + + const targetPiece = board[endRow][endCol]; + + if (targetPiece && targetPiece.color !== draggingPiece.piece.color) { + console.log(`Captured ${targetPiece.type}`); + } + + const updatedBoard = [...board]; + updatedBoard[endRow][endCol] = draggingPiece.piece; // Move piece to new square + updatedBoard[startRow][startCol] = null; // Clear old square + + // Check if the moved piece is a pawn reaching the promotion rank + if (draggingPiece.piece[1] === 'P' && (endRow === 0 || endRow === 7)) { + promotePawn(key); // Call promote function + } else { + setBoard(updatedBoard); // Update board state + } + } + setDraggingPiece(null); + setHighlightedSquares([]); + }; + + // Handle drag over a square (allow dropping) + const handleDragOver = (e: any) => { + e.preventDefault(); // Prevent default behavior to allow dropping + }; + + // Update promotePawn function to set the board state + function promotePawn(position: any) { + const [row, col] = position.split('-').map(Number); + const updatedBoard = [...board]; + const color = board[row][col][0]; // Determine color of the pawn + const newPiece = color === 'w' ? 'wQ' : 'bQ'; // Promote to Queen + + updatedBoard[row][col] = newPiece; // Update the board with the new queen + setBoard(updatedBoard); // Set the new board state + } + + const [activeTab, setActiveTab] = useState("activity"); + + const handleTabClick = (tab: any) => { + setActiveTab(tab); + }; + + const renderTabContent = () => { + switch (activeTab) { + case "activity": + return ( +
+
+

Activity

+

May 2024

+
+
+
+
+
+
+

May 24 2024

+

7:00 PM

+
+
+

Solved 2 tactical puzzles.

+
+
+
+
+
+

May 19 2024

+

3:00 PM

+
+
+

Practiced 7 positions on Piece Checkmates I.

+
+
+
+
+
+

May 16 2024

+

4:00 PM

+
+
+

Completed 100 games of chess.

+
+
+
+
+ ); + 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 ( +
+

Learning

+

This is the content for the 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.

+
+ ); + default: + return ( +
+

Select a tab to view its content.

+
+ ); + } + }; + + return ( +
+
+
+ user portrait + user portrait camera icon +
+
+

Hello, {userName}!

+
+
+ +
+
+

Your Progress

+
+
+ + +
{renderTabContent()}
+
+
+
+ ); +}; + +export default StudentInventory; diff --git a/react-ystemandchess/src/Pages/Student-Inventory/StudentInventory.scss b/react-ystemandchess/src/features/student/student-inventory/StudentInventory.scss similarity index 99% rename from react-ystemandchess/src/Pages/Student-Inventory/StudentInventory.scss rename to react-ystemandchess/src/features/student/student-inventory/StudentInventory.scss index 279c1471..a99b4f42 100644 --- a/react-ystemandchess/src/Pages/Student-Inventory/StudentInventory.scss +++ b/react-ystemandchess/src/features/student/student-inventory/StudentInventory.scss @@ -15,7 +15,7 @@ $inventory-tab-active: linear-gradient( #main-inventory-content { background-color: $brand-color-primary; - background-image: url("../../images/chess-piece-pattern.png"); + background-image: url("../../../assets/images/chess-piece-pattern.png"); background-size: 95%; background-repeat: repeat; font-family: "Roboto", sans-serif; diff --git a/react-ystemandchess/src/Pages/Student-Inventory/StudentInventory.tsx b/react-ystemandchess/src/features/student/student-inventory/StudentInventory.tsx similarity index 99% rename from react-ystemandchess/src/Pages/Student-Inventory/StudentInventory.tsx rename to react-ystemandchess/src/features/student/student-inventory/StudentInventory.tsx index ed4d402e..900c2ccc 100644 --- a/react-ystemandchess/src/Pages/Student-Inventory/StudentInventory.tsx +++ b/react-ystemandchess/src/features/student/student-inventory/StudentInventory.tsx @@ -1,9 +1,9 @@ import React, { useState, useEffect } from "react"; import "./StudentInventory.scss"; -import Images from "../../images/imageImporter"; -import { createChessBoard, isInBounds, getPawnMoves, getRookMoves, getKnightMoves, getBishopMoves, getKingMoves, getQueenMoves } from '../Lessons/Lessons' -import LessonSelection from "../LessonsSelection/LessonsSelection"; -import Lessons from '../Lessons/Lessons'; +import Images from "../../../assets/images/imageImporter"; +import { createChessBoard, isInBounds, getPawnMoves, getRookMoves, getKnightMoves, getBishopMoves, getKingMoves, getQueenMoves } from '../../lessons/lessons-main/Lessons' +import LessonSelection from "../../lessons/lessons-selection/LessonsSelection"; +import Lessons from '../../lessons/lessons-main/Lessons'; type Board = (string | null)[][]; type Piece = { diff --git a/react-ystemandchess/src/Pages/Student/Student.scss b/react-ystemandchess/src/features/student/student-page/Student.scss similarity index 100% rename from react-ystemandchess/src/Pages/Student/Student.scss rename to react-ystemandchess/src/features/student/student-page/Student.scss diff --git a/react-ystemandchess/src/Pages/Student/Student.tsx b/react-ystemandchess/src/features/student/student-page/Student.tsx similarity index 92% rename from react-ystemandchess/src/Pages/Student/Student.tsx rename to react-ystemandchess/src/features/student/student-page/Student.tsx index 889540c4..aadffde3 100644 --- a/react-ystemandchess/src/Pages/Student/Student.tsx +++ b/react-ystemandchess/src/features/student/student-page/Student.tsx @@ -1,6 +1,6 @@ import React, {useState} from "react"; import "./Student.scss"; -import {environment} from "../../environments/environment"; +import {environment} from "../../../core/environments/environment"; const Student = () => { const chessSrc = environment.urls.chessClientURL; diff --git a/react-ystemandchess/src/Pages/NewStudentProfile/Modals/ActivitiesModal.scss b/react-ystemandchess/src/features/student/student-profile/Modals/ActivitiesModal.scss similarity index 98% rename from react-ystemandchess/src/Pages/NewStudentProfile/Modals/ActivitiesModal.scss rename to react-ystemandchess/src/features/student/student-profile/Modals/ActivitiesModal.scss index 07a82ee1..98b8ee12 100644 --- a/react-ystemandchess/src/Pages/NewStudentProfile/Modals/ActivitiesModal.scss +++ b/react-ystemandchess/src/features/student/student-profile/Modals/ActivitiesModal.scss @@ -25,7 +25,7 @@ box-shadow: 0 8px 30px rgba(0, 0, 0, 0.25); animation: slideUp 0.3s ease; background-color: #E5F3D2; - background-image: url("../../../images/ActivitiesAssets/vine_background.png"); + background-image: url("../../../../assets/images/ActivitiesAssets/vine_background.png"); background-repeat: no-repeat; background-size: cover; background-position: center; diff --git a/react-ystemandchess/src/Pages/NewStudentProfile/Modals/ActivitiesModal.tsx b/react-ystemandchess/src/features/student/student-profile/Modals/ActivitiesModal.tsx similarity index 80% rename from react-ystemandchess/src/Pages/NewStudentProfile/Modals/ActivitiesModal.tsx rename to react-ystemandchess/src/features/student/student-profile/Modals/ActivitiesModal.tsx index a8cb35a3..851d98a3 100644 --- a/react-ystemandchess/src/Pages/NewStudentProfile/Modals/ActivitiesModal.tsx +++ b/react-ystemandchess/src/features/student/student-profile/Modals/ActivitiesModal.tsx @@ -16,18 +16,18 @@ import React, { useEffect, useState } from "react"; import "./ActivitiesModal.scss"; -import { ReactComponent as GrowthBox } from "../../../images/ActivitiesAssets/growth_box.svg"; -import { ReactComponent as WaterMeter } from "../../../images/ActivitiesAssets/water_meter.svg"; -import { ReactComponent as MiddleVine} from "../../../images/ActivitiesAssets/middle_vine.svg"; -import { ReactComponent as TopVine} from "../../../images/ActivitiesAssets/top_vine.svg"; -import { ReactComponent as HangingVine} from "../../../images/ActivitiesAssets/hanging_vine.svg"; -import { ReactComponent as TopicBag } from "../../../images/ActivitiesAssets/topic_bag.svg"; -import { ReactComponent as ShortBottomVine} from "../../../images/ActivitiesAssets/short_bottom_vine.svg"; -import { ReactComponent as BottomVine} from "../../../images/ActivitiesAssets/bottom_vine.svg"; -import { ReactComponent as Stemmy} from "../../../images/ActivitiesAssets/stemmy.svg"; -import { environment } from "../../../environments/environment"; +import { ReactComponent as GrowthBox } from "../../../../assets/images/ActivitiesAssets/growth_box.svg"; +import { ReactComponent as WaterMeter } from "../../../../assets/images/ActivitiesAssets/water_meter.svg"; +import { ReactComponent as MiddleVine} from "../../../../assets/images/ActivitiesAssets/middle_vine.svg"; +import { ReactComponent as TopVine} from "../../../../assets/images/ActivitiesAssets/top_vine.svg"; +import { ReactComponent as HangingVine} from "../../../../assets/images/ActivitiesAssets/hanging_vine.svg"; +import { ReactComponent as TopicBag } from "../../../../assets/images/ActivitiesAssets/topic_bag.svg"; +import { ReactComponent as ShortBottomVine} from "../../../../assets/images/ActivitiesAssets/short_bottom_vine.svg"; +import { ReactComponent as BottomVine} from "../../../../assets/images/ActivitiesAssets/bottom_vine.svg"; +import { ReactComponent as Stemmy} from "../../../../assets/images/ActivitiesAssets/stemmy.svg"; +import { environment } from "../../../../core/environments/environment"; import { useCookies } from "react-cookie"; -import { parseActivities } from "../../../utils/activityNames"; +import { parseActivities } from "../../../../core/utils/activityNames"; /** * ActivitiesModal component - displays daily activities in garden theme diff --git a/react-ystemandchess/src/Pages/NewStudentProfile/Modals/BadgesModal.scss b/react-ystemandchess/src/features/student/student-profile/Modals/BadgesModal.scss similarity index 100% rename from react-ystemandchess/src/Pages/NewStudentProfile/Modals/BadgesModal.scss rename to react-ystemandchess/src/features/student/student-profile/Modals/BadgesModal.scss diff --git a/react-ystemandchess/src/Pages/NewStudentProfile/Modals/BadgesModal.tsx b/react-ystemandchess/src/features/student/student-profile/Modals/BadgesModal.tsx similarity index 96% rename from react-ystemandchess/src/Pages/NewStudentProfile/Modals/BadgesModal.tsx rename to react-ystemandchess/src/features/student/student-profile/Modals/BadgesModal.tsx index 1dde8a3e..54abf338 100644 --- a/react-ystemandchess/src/Pages/NewStudentProfile/Modals/BadgesModal.tsx +++ b/react-ystemandchess/src/features/student/student-profile/Modals/BadgesModal.tsx @@ -15,7 +15,7 @@ import React, { useEffect, useState, useMemo } from "react"; import "./BadgesModal.scss"; -import { getBadgeCatalog, getUserBadges } from "../../../services/badgesApi"; +import { getBadgeCatalog, getUserBadges } from "../../../../core/services/badgesApi"; /** * BadgesModal component - displays user's badge achievements diff --git a/react-ystemandchess/src/Pages/NewStudentProfile/Modals/LeaderboardModal.scss b/react-ystemandchess/src/features/student/student-profile/Modals/LeaderboardModal.scss similarity index 100% rename from react-ystemandchess/src/Pages/NewStudentProfile/Modals/LeaderboardModal.scss rename to react-ystemandchess/src/features/student/student-profile/Modals/LeaderboardModal.scss diff --git a/react-ystemandchess/src/Pages/NewStudentProfile/Modals/LeaderboardModal.tsx b/react-ystemandchess/src/features/student/student-profile/Modals/LeaderboardModal.tsx similarity index 94% rename from react-ystemandchess/src/Pages/NewStudentProfile/Modals/LeaderboardModal.tsx rename to react-ystemandchess/src/features/student/student-profile/Modals/LeaderboardModal.tsx index 1c2ef837..f6ec2884 100644 --- a/react-ystemandchess/src/Pages/NewStudentProfile/Modals/LeaderboardModal.tsx +++ b/react-ystemandchess/src/features/student/student-profile/Modals/LeaderboardModal.tsx @@ -1,10 +1,10 @@ import React, { useEffect, useMemo, useState } from "react"; import "./LeaderboardModal.scss"; -import { ReactComponent as LeaderboardIcon } from "../../../images/student/leaderboard_sidebar_icon.svg"; +import { ReactComponent as LeaderboardIcon } from "../../../../assets/images/student/leaderboard_sidebar_icon.svg"; -import rank1Img from "../../../images/student/Leaderboard_rank_1.svg"; -import rank2Img from "../../../images/student/Leaderboard_rank_2.svg"; -import rank3Img from "../../../images/student/Leaderboard_rank_3.svg"; +import rank1Img from "../../../../assets/images/student/Leaderboard_rank_1.svg"; +import rank2Img from "../../../../assets/images/student/Leaderboard_rank_2.svg"; +import rank3Img from "../../../../assets/images/student/Leaderboard_rank_3.svg"; type Props = { onClose: () => void }; diff --git a/react-ystemandchess/src/Pages/NewStudentProfile/Modals/StreakModal.scss b/react-ystemandchess/src/features/student/student-profile/Modals/StreakModal.scss similarity index 100% rename from react-ystemandchess/src/Pages/NewStudentProfile/Modals/StreakModal.scss rename to react-ystemandchess/src/features/student/student-profile/Modals/StreakModal.scss diff --git a/react-ystemandchess/src/Pages/NewStudentProfile/Modals/StreakModal.tsx b/react-ystemandchess/src/features/student/student-profile/Modals/StreakModal.tsx similarity index 81% rename from react-ystemandchess/src/Pages/NewStudentProfile/Modals/StreakModal.tsx rename to react-ystemandchess/src/features/student/student-profile/Modals/StreakModal.tsx index 5349b55b..3e520489 100644 --- a/react-ystemandchess/src/Pages/NewStudentProfile/Modals/StreakModal.tsx +++ b/react-ystemandchess/src/features/student/student-profile/Modals/StreakModal.tsx @@ -14,14 +14,14 @@ import React from "react"; import "./StreakModal.scss"; -import { ReactComponent as Polygon } from "../../../images/StreakProgressAssets/polygon.svg"; -import { ReactComponent as Polygon_2 } from "../../../images/StreakProgressAssets/polygon_2.svg"; -import streakClock from "../../../images/StreakProgressAssets/streak_progress_clock.png"; -import { ReactComponent as Stemette } from "../../../images/StreakProgressAssets/stemette.svg"; -import { ReactComponent as Stemmy } from "../../../images/StreakProgressAssets/stemmy.svg"; +import { ReactComponent as Polygon } from "../../../../assets/images/StreakProgressAssets/polygon.svg"; +import { ReactComponent as Polygon_2 } from "../../../../assets/images/StreakProgressAssets/polygon_2.svg"; +import streakClock from "../../../../assets/images/StreakProgressAssets/streak_progress_clock.png"; +import { ReactComponent as Stemette } from "../../../../assets/images/StreakProgressAssets/stemette.svg"; +import { ReactComponent as Stemmy } from "../../../../assets/images/StreakProgressAssets/stemmy.svg"; // Calendar placeholder. Delete once an actual calendar is implemented -import calendarIcon from "../../../images/StreakProgressAssets/Calendar.png"; +import calendarIcon from "../../../../assets/images/StreakProgressAssets/Calendar.png"; /** * StreakModal component - displays user's streak progress diff --git a/react-ystemandchess/src/Pages/NewStudentProfile/NewStudentProfile.scss b/react-ystemandchess/src/features/student/student-profile/NewStudentProfile.scss similarity index 99% rename from react-ystemandchess/src/Pages/NewStudentProfile/NewStudentProfile.scss rename to react-ystemandchess/src/features/student/student-profile/NewStudentProfile.scss index 187873f6..79659172 100644 --- a/react-ystemandchess/src/Pages/NewStudentProfile/NewStudentProfile.scss +++ b/react-ystemandchess/src/features/student/student-profile/NewStudentProfile.scss @@ -20,7 +20,7 @@ $brand-color-background-grey: #d4dddd; #main-inventory-content { background-color: $brand-color-primary; - background-image: url("../../images/chess-piece-pattern.png"); + background-image: url("../../../assets/images/chess-piece-pattern.png"); background-size: 95%; background-repeat: repeat; font-family: "Roboto", sans-serif; diff --git a/react-ystemandchess/src/Pages/NewStudentProfile/NewStudentProfile.test.tsx b/react-ystemandchess/src/features/student/student-profile/NewStudentProfile.test.tsx similarity index 98% rename from react-ystemandchess/src/Pages/NewStudentProfile/NewStudentProfile.test.tsx rename to react-ystemandchess/src/features/student/student-profile/NewStudentProfile.test.tsx index e4ac4454..6698f179 100644 --- a/react-ystemandchess/src/Pages/NewStudentProfile/NewStudentProfile.test.tsx +++ b/react-ystemandchess/src/features/student/student-profile/NewStudentProfile.test.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { render, screen, act } from '@testing-library/react'; import { MemoryRouter } from 'react-router'; import { useCookies } from 'react-cookie'; -import { SetPermissionLevel } from '../../globals'; +import { SetPermissionLevel } from '../../../globals'; import NewStudentProfile from './NewStudentProfile'; // ------------- MOCKS ------------- diff --git a/react-ystemandchess/src/Pages/NewStudentProfile/NewStudentProfile.tsx b/react-ystemandchess/src/features/student/student-profile/NewStudentProfile.tsx similarity index 91% rename from react-ystemandchess/src/Pages/NewStudentProfile/NewStudentProfile.tsx rename to react-ystemandchess/src/features/student/student-profile/NewStudentProfile.tsx index ee5ed419..252e2a19 100644 --- a/react-ystemandchess/src/Pages/NewStudentProfile/NewStudentProfile.tsx +++ b/react-ystemandchess/src/features/student/student-profile/NewStudentProfile.tsx @@ -1,38 +1,38 @@ import React, { useState, useEffect, useRef, useMemo, lazy, Suspense } from "react"; import "./NewStudentProfile.scss"; -import Images from "../../images/imageImporter"; -import { SetPermissionLevel } from '../../globals'; +import Images from "../../../assets/images/imageImporter"; +import { SetPermissionLevel } from '../../../globals'; import { useCookies } from 'react-cookie'; -import { environment } from '../../environments/environment'; +import { environment } from "../../../core/environments/environment"; import { useNavigate } from "react-router"; import { useLocation } from "react-router"; import StatsChart from "./StatsChart"; -import Puzzles from "../Puzzles/Puzzles"; +import Puzzles from "../../puzzles/puzzles-page/Puzzles"; import StreakModal from "./Modals/StreakModal"; import ActivitiesModal from "./Modals/ActivitiesModal"; import BadgesModal from "./Modals/BadgesModal"; import LeaderboardModal from "./Modals/LeaderboardModal"; // Toolbar buttons -import { ReactComponent as StreakIcon } from "../../images/student/streak_button.svg"; -import { ReactComponent as ActivitiesIcon } from "../../images/student/activities_button.svg"; -import { ReactComponent as BadgesIcon } from "../../images/student/badges_button.svg"; -import { ReactComponent as LeaderboardIcon } from "../../images/student/leaderboard_button.svg"; +import { ReactComponent as StreakIcon } from "../../../assets/images/student/streak_button.svg"; +import { ReactComponent as ActivitiesIcon } from "../../../assets/images/student/activities_button.svg"; +import { ReactComponent as BadgesIcon } from "../../../assets/images/student/badges_button.svg"; +import { ReactComponent as LeaderboardIcon } from "../../../assets/images/student/leaderboard_button.svg"; // Tab images -import activityTab from "../../images/student/activity_tab.png"; -import mentorTab from "../../images/student/mento_tab.png"; -import prodevTab from "../../images/student/prodev_tab.png"; -import chessTab from "../../images/student/chess_tab.png"; -import mathTab from "../../images/student/math_tab.png"; -import gamesTab from "../../images/student/games_tab.png"; -import puzzlesTab from "../../images/student/puzzles_tab.png"; -import playTab from "../../images/student/play_tab.png"; -import recordingsTab from "../../images/student/recordings_tab.png"; - -const Lessons = lazy(() => import("../Lessons/Lessons")); -const LessonsSelection = lazy(() => import("../LessonsSelection/LessonsSelection")); -const LessonOverlay = lazy(() => import("../piece-lessons/lesson-overlay/Lesson-overlay")); +import activityTab from "../../../assets/images/student/activity_tab.png"; +import mentorTab from "../../../assets/images/student/mento_tab.png"; +import prodevTab from "../../../assets/images/student/prodev_tab.png"; +import chessTab from "../../../assets/images/student/chess_tab.png"; +import mathTab from "../../../assets/images/student/math_tab.png"; +import gamesTab from "../../../assets/images/student/games_tab.png"; +import puzzlesTab from "../../../assets/images/student/puzzles_tab.png"; +import playTab from "../../../assets/images/student/play_tab.png"; +import recordingsTab from "../../../assets/images/student/recordings_tab.png"; + +const Lessons = lazy(() => import("../../lessons/lessons-main/Lessons")); +const LessonsSelection = lazy(() => import("../../lessons/lessons-selection/LessonsSelection")); +const LessonOverlay = lazy(() => import("../../lessons/piece-lessons/lesson-overlay/Lesson-overlay")); // Main Student Profile Component const NewStudentProfile = ({ userPortraitSrc }: any) => { diff --git a/react-ystemandchess/src/features/student/student-profile/NewStudentProfile/Modals/BadgesModal.tsx b/react-ystemandchess/src/features/student/student-profile/NewStudentProfile/Modals/BadgesModal.tsx new file mode 100644 index 00000000..a2ab3e36 --- /dev/null +++ b/react-ystemandchess/src/features/student/student-profile/NewStudentProfile/Modals/BadgesModal.tsx @@ -0,0 +1,89 @@ +/** + * Badges Modal Component + * + * Displays a modal showing all available badges and which ones the user has earned. + * Fetches badge catalog and user's earned badges from the API. + * Earned badges are displayed in color, unearned badges are grayed out. + * + * Features: + * - Fetches badge catalog and user's earned badges + * - Visual distinction between earned and unearned badges + * - Badge details including name, description, and icon + * - Loading state while fetching data + * - Click outside to close functionality + */ + +import React, { useEffect, useState, useMemo } from "react"; +import "./BadgesModal.scss"; +import { getBadgeCatalog, getUserBadges } from "../../../../../core/services/badgesApi"; + +/** + * BadgesModal component - displays user's badge achievements + * @param {Function} onClose - Callback to close the modal + */ +const BadgesModal = ({ onClose }: { onClose: () => void }) => { + const [catalog, setCatalog] = useState([]); + const [earnedIds, setEarnedIds] = useState([]); + const [loading, setLoading] = useState(true); + + const handleOverlayClick = (e: React.MouseEvent) => { + if (e.target === e.currentTarget) { + onClose(); + } + }; + + useEffect(() => { + (async () => { + try { + const [badges, earned] = await Promise.all([ + getBadgeCatalog(), + getUserBadges("teststudent") // replace with dynamic userId later if needed + ]); + setCatalog(badges); + setEarnedIds(earned.map((b: any) => b.badgeId)); + } finally { + setLoading(false); + } + })(); + }, []); + + const badgeList = useMemo(() => { + return catalog.map(b => ({ + ...b, + isEarned: earnedIds.includes(b.id) + })); + }, [catalog, earnedIds]); + + console.log(" catalog:", catalog); + console.log(" earnedIds:", earnedIds); + console.log(" badgeList:", badgeList); + + return ( +
+
+ +

Badges

+ + {loading ? ( +

Loading...

+ ) : ( +
+ {badgeList.map(b => ( +
+
+ {b.name} +
+
{b.name}
+ {!b.isEarned &&
Locked
} +
+ ))} +
+ )} +
+
+ ); +}; + +export default BadgesModal; diff --git a/react-ystemandchess/src/Pages/NewStudentProfile/StatsChart.tsx b/react-ystemandchess/src/features/student/student-profile/StatsChart.tsx similarity index 100% rename from react-ystemandchess/src/Pages/NewStudentProfile/StatsChart.tsx rename to react-ystemandchess/src/features/student/student-profile/StatsChart.tsx diff --git a/react-ystemandchess/src/globals.ts b/react-ystemandchess/src/globals.ts index 9cc4a323..ed668f5a 100644 --- a/react-ystemandchess/src/globals.ts +++ b/react-ystemandchess/src/globals.ts @@ -5,7 +5,7 @@ * components, particularly for authentication and permission management. */ -import { environment } from "./environments/environment"; +import { environment } from "./core/environments/environment"; /** * Global variable to store user information after authentication diff --git a/stockfishServer/package.json b/stockfishServer/package.json index 44634ce6..f154aab4 100644 --- a/stockfishServer/package.json +++ b/stockfishServer/package.json @@ -2,9 +2,9 @@ "name": "stockfishserver", "version": "1.0.0", "description": "", - "main": "index.js", + "main": "src/index.js", "scripts": { - "start": "nodemon index.js", + "start": "nodemon src/index.js", "test": "jest --detectOpenHandles --forceExit" }, "author": "", diff --git a/stockfishServer/index_new.js b/stockfishServer/src/archive/index_new.js similarity index 100% rename from stockfishServer/index_new.js rename to stockfishServer/src/archive/index_new.js diff --git a/stockfishServer/bin/stockfish_11_linux b/stockfishServer/src/bin/stockfish_11_linux similarity index 100% rename from stockfishServer/bin/stockfish_11_linux rename to stockfishServer/src/bin/stockfish_11_linux diff --git a/stockfishServer/bin/stockfish_11_mac b/stockfishServer/src/bin/stockfish_11_mac similarity index 100% rename from stockfishServer/bin/stockfish_11_mac rename to stockfishServer/src/bin/stockfish_11_mac diff --git a/stockfishServer/bin/stockfish_11_win.exe b/stockfishServer/src/bin/stockfish_11_win.exe similarity index 100% rename from stockfishServer/bin/stockfish_11_win.exe rename to stockfishServer/src/bin/stockfish_11_win.exe diff --git a/stockfishServer/index.js b/stockfishServer/src/index.js similarity index 100% rename from stockfishServer/index.js rename to stockfishServer/src/index.js diff --git a/stockfishServer/StockfishManager.js b/stockfishServer/src/managers/StockfishManager.js similarity index 100% rename from stockfishServer/StockfishManager.js rename to stockfishServer/src/managers/StockfishManager.js diff --git a/stockfishServer/socket.js b/stockfishServer/src/managers/socket.js similarity index 100% rename from stockfishServer/socket.js rename to stockfishServer/src/managers/socket.js diff --git a/stockfishServer/__tests__/StockfishManager.test.js b/stockfishServer/src/tests/StockfishManager.test.js similarity index 100% rename from stockfishServer/__tests__/StockfishManager.test.js rename to stockfishServer/src/tests/StockfishManager.test.js diff --git a/stockfishServer/__tests__/index.test.js b/stockfishServer/src/tests/index.test.js similarity index 100% rename from stockfishServer/__tests__/index.test.js rename to stockfishServer/src/tests/index.test.js From 44d85bd1f7988e0d044788cc2581941a6c957d49 Mon Sep 17 00:00:00 2001 From: Lahari Gandrapu Date: Sat, 15 Nov 2025 03:54:51 -0500 Subject: [PATCH 07/23] fix: test cases --- stockfishServer/src/tests/StockfishManager.test.js | 2 +- stockfishServer/src/tests/index.test.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/stockfishServer/src/tests/StockfishManager.test.js b/stockfishServer/src/tests/StockfishManager.test.js index 15b38b5a..d9933fe5 100644 --- a/stockfishServer/src/tests/StockfishManager.test.js +++ b/stockfishServer/src/tests/StockfishManager.test.js @@ -6,7 +6,7 @@ jest.mock("child_process", () => ({ })), })); -const StockfishManager = require("../StockfishManager"); +const StockfishManager = require("../managers/StockfishManager"); const { spawn } = require("child_process"); const newSocket = () => ({ diff --git a/stockfishServer/src/tests/index.test.js b/stockfishServer/src/tests/index.test.js index 481a56da..9f6d3b29 100644 --- a/stockfishServer/src/tests/index.test.js +++ b/stockfishServer/src/tests/index.test.js @@ -1,7 +1,7 @@ const ioClient = require("socket.io-client"); const http = require("http"); const express = require("express"); -const socketHandler = require("../socket"); +const socketHandler = require("../managers/socket"); describe("Server and socket", () => { let server, ioServer, clientSocket; From 3f79bfd4f7a4607c00e569b0189ee8ff9f10cdc5 Mon Sep 17 00:00:00 2001 From: Lahari Gandrapu Date: Sat, 15 Nov 2025 04:09:54 -0500 Subject: [PATCH 08/23] fix: test build --- .github/workflows/ci.yml | 4 ++-- create_travis_envs.sh | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2ff37386..9a10fa81 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -70,8 +70,8 @@ jobs: - name: Create environment file run: | - mkdir -p src/environments - cat < src/environments/environment.js + mkdir -p src/core/environments + cat < src/core/environments/environment.ts export const environment = { production: false, agora: { diff --git a/create_travis_envs.sh b/create_travis_envs.sh index 5594fef8..966cd980 100644 --- a/create_travis_envs.sh +++ b/create_travis_envs.sh @@ -4,8 +4,8 @@ printf "Creating environment files and variables\n\n" #Creating environment files and variables for react-ystemandchess printf "Creating environment files for react-ystemandchess\n" -cd react-ystemandchess/src && mkdir environments -cd environments +cd react-ystemandchess/src && mkdir -p core/environments +cd core/environments #Creating and adding environment.js file and variables touch environment.js From 078ac349a8f4d1ace7258e78dbbc2fe7356d4b07 Mon Sep 17 00:00:00 2001 From: Lahari Gandrapu Date: Sat, 15 Nov 2025 04:17:44 -0500 Subject: [PATCH 09/23] fix: test build --- .../lessons/piece-lessons/lesson-overlay/Lesson-overlay.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/react-ystemandchess/src/features/lessons/piece-lessons/lesson-overlay/Lesson-overlay.tsx b/react-ystemandchess/src/features/lessons/piece-lessons/lesson-overlay/Lesson-overlay.tsx index 228ea3b6..0320ef3a 100644 --- a/react-ystemandchess/src/features/lessons/piece-lessons/lesson-overlay/Lesson-overlay.tsx +++ b/react-ystemandchess/src/features/lessons/piece-lessons/lesson-overlay/Lesson-overlay.tsx @@ -4,7 +4,7 @@ import pageStyles from './Lesson-overlay.module.scss'; import profileStyles from './Lesson-overlay-profile.module.scss'; // @ts-ignore import MoveTracker from '../move-tracker/MoveTracker'; -import ChessBoard from '../../../../components/chessboard/ChessBoard'; +import ChessBoard from '../../../../components/ChessBoard/ChessBoard'; import { ReactComponent as RedoIcon } from "../../../../assets/images/icons/icon_redo.svg"; import { ReactComponent as BackIcon } from "../../../../assets/images/icons/icon_back.svg"; import { ReactComponent as BackIconInactive } from "../../../../assets/images/icons/icon_back_inactive.svg"; From 80faf801d7a1b8ba907384e949023d17f22ee8f4 Mon Sep 17 00:00:00 2001 From: Lahari Gandrapu Date: Sat, 15 Nov 2025 04:22:21 -0500 Subject: [PATCH 10/23] fix: test build --- react-ystemandchess/src/components/ChessBoard/ChessBoard.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/react-ystemandchess/src/components/ChessBoard/ChessBoard.tsx b/react-ystemandchess/src/components/ChessBoard/ChessBoard.tsx index 2c7b1e98..038c81f4 100644 --- a/react-ystemandchess/src/components/ChessBoard/ChessBoard.tsx +++ b/react-ystemandchess/src/components/ChessBoard/ChessBoard.tsx @@ -1,7 +1,7 @@ import React, { useState, useRef, useImperativeHandle, useEffect, forwardRef } from "react"; import Chessboard from "chessboardjsx"; import { Chess, Square } from "chess.js"; -import "./chessboard.css"; +import "./ChessBoard.css"; interface Move { from: string; From 378dc69346d34f7f1c89d22aba42dacdc20254a0 Mon Sep 17 00:00:00 2001 From: Lahari Gandrapu Date: Sat, 15 Nov 2025 04:28:12 -0500 Subject: [PATCH 11/23] fix: test build --- .github/workflows/ci.yml | 4 ++++ create_travis_envs.sh | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9a10fa81..5fad6fd4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -77,6 +77,10 @@ jobs: agora: { appId: '${{ secrets.APP_ID }}', }, + email: { + user: '${{ secrets.EMAIL_USER || '' }}', + pass: '${{ secrets.EMAIL_PASS || '' }}' + }, urls: { middlewareURL: '${{ secrets.MIDDLEWARE_URL }}', chessClientURL: '${{ secrets.CHESS_CLIENT_URL }}', diff --git a/create_travis_envs.sh b/create_travis_envs.sh index 966cd980..4ebf9864 100644 --- a/create_travis_envs.sh +++ b/create_travis_envs.sh @@ -14,6 +14,10 @@ printf " production: false,\n" >> environment.js printf " agora: {\n" >> environment.js printf " appId: ' ',\n" >> environment.js printf " },\n" >> environment.js +printf " email: {\n" >> environment.js +printf " user: '',\n" >> environment.js +printf " pass: ''\n" >> environment.js +printf " },\n" >> environment.js printf " urls: {\n" >> environment.js printf " middlewareURL: 'http://127.0.0.1:8000',\n" >> environment.js printf " chessClientURL: 'http://localhost',\n" >> environment.js @@ -29,6 +33,10 @@ printf " production: false,\n" >> environment.prod.js printf " agora: {\n" >> environment.prod.js printf " appId: ' ',\n" >> environment.prod.js printf " },\n" >> environment.prod.js +printf " email: {\n" >> environment.prod.js +printf " user: '',\n" >> environment.prod.js +printf " pass: ''\n" >> environment.prod.js +printf " },\n" >> environment.prod.js printf " urls: {\n" >> environment.prod.js printf " middlewareURL: 'http://127.0.0.1:8000',\n" >> environment.prod.js printf " chessClientURL: 'http://localhost',\n" >> environment.prod.js From 582d381a8ffff49e6e7d893b04d8a8f9285b564a Mon Sep 17 00:00:00 2001 From: Lahari Gandrapu Date: Sat, 15 Nov 2025 04:31:38 -0500 Subject: [PATCH 12/23] fix: test build --- .../src/features/puzzles/puzzles-page/Puzzles.test.tsx | 2 +- .../features/student/student-profile/NewStudentProfile.test.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/react-ystemandchess/src/features/puzzles/puzzles-page/Puzzles.test.tsx b/react-ystemandchess/src/features/puzzles/puzzles-page/Puzzles.test.tsx index 8a6d110b..1029e8d0 100644 --- a/react-ystemandchess/src/features/puzzles/puzzles-page/Puzzles.test.tsx +++ b/react-ystemandchess/src/features/puzzles/puzzles-page/Puzzles.test.tsx @@ -5,7 +5,7 @@ import { MemoryRouter } from "react-router"; import Swal from "sweetalert2"; // Mock environment and chessClientURL for iframe src -jest.mock("../../environments/environment", () => ({ +jest.mock("../../../core/environments/environment", () => ({ environment: { urls: { chessClientURL: "http://localhost:3000", diff --git a/react-ystemandchess/src/features/student/student-profile/NewStudentProfile.test.tsx b/react-ystemandchess/src/features/student/student-profile/NewStudentProfile.test.tsx index 6698f179..df4b1f33 100644 --- a/react-ystemandchess/src/features/student/student-profile/NewStudentProfile.test.tsx +++ b/react-ystemandchess/src/features/student/student-profile/NewStudentProfile.test.tsx @@ -13,7 +13,7 @@ jest.mock('react-cookie', () => ({ })); // mock globals (SetPermissionLevel) -jest.mock('../../globals', () => ({ +jest.mock('../../../globals', () => ({ __esModule: true, SetPermissionLevel: jest.fn(), })); From 095d54dfccaeca9295a25240f6b323cd309ef6e5 Mon Sep 17 00:00:00 2001 From: f-hejazi Date: Mon, 17 Nov 2025 23:02:50 +0100 Subject: [PATCH 13/23] fix: unlock all lessons for guests and simplify backend handling --- middlewareNode/routes/lessons.js | 634 +++++++----------- .../LessonsSelection/LessonsSelection.jsx | 48 +- 2 files changed, 288 insertions(+), 394 deletions(-) diff --git a/middlewareNode/routes/lessons.js b/middlewareNode/routes/lessons.js index d72df93c..c64c2188 100644 --- a/middlewareNode/routes/lessons.js +++ b/middlewareNode/routes/lessons.js @@ -40,9 +40,9 @@ async function getDb() { */ router.get( "/stick", - async(req, res) => { + async (req, res) => { const db = await getDb(); - const lessons= db.collection("newLessons"); + const lessons = db.collection("newLessons"); const doc = await lessons.findOne({ piece: "Undermining Remove the defending piece" }); res.json(doc); @@ -88,21 +88,19 @@ router.get( router.get( "/getCompletedLessonCount", async (req, res, next) => { - passport.authenticate("jwt", { session: false }, async (err, user, info) => { + passport.authenticate("jwt", { session: false }, async (err, user) => { req.user = user || null; next(); })(req, res, next) // authenticate jwt }, async (req, res) => { - const piece = decodeURIComponent(req.query.piece); - - if (!piece) { - return res.status(400).json("Error: 400. Please provide a piece."); - } try { + const piece = req.query.piece ? decodeURIComponent(req.query.piece) : null; + if (!piece) { + return res.status(400).json("Error: 400. Please provide a piece."); + } const db = await getDb(); const users = db.collection("users"); // get users collection - const guests = db.collection("guest"); // get guests collection if (req.user) { const { username } = req.user; // get username from jwt @@ -115,125 +113,13 @@ router.get( if (!userDoc.lessonsCompleted) throw new Error("User does not have lesson record"); // the number of lessons completed for the piece - let lessonNum = 0; - for (const chessPiece of userDoc.lessonsCompleted) { - if (chessPiece.piece === piece) { // find the piece - lessonNum = chessPiece.lessonNumber; - break; - } - } + const entry = userDoc.lessonsCompleted.find(e => e.piece === piece); + const lessonNum = entry ? (Number(entry.lessonNumber) || 0) : 0; + return res.json(lessonNum); - res.json(lessonNum); } else { - const clientIp = getClientIp(req); // get client ip - const expiresAt = new Date(Date.now() + 24 * 60 * 60 * 1000); // new expiration date - - await guests.updateOne( - { ip: clientIp }, - { - $set: { - ip: clientIp, - updatedAt: new Date(), // update date - expiresAt, // update expiration date - }, - $setOnInsert: { // if this ip is not in db, add lessonsCompelted field - lessonsCompleted: [ - { - piece: 'Piece Checkmate 1 Basic checkmates', - lessonNumber: 0 - }, - { - piece: 'Checkmate Pattern 1 Recognize the patterns', - lessonNumber: 0 - }, - { - piece: 'Checkmate Pattern 2 Recognize the patterns', - lessonNumber: 0 - }, - { - piece: 'Checkmate Pattern 3 Recognize the patterns', - lessonNumber: 0 - }, - { - piece: 'Checkmate Pattern 4 Recognize the patterns', - lessonNumber: 0 - }, - { - piece: 'Piece checkmates 2 Challenging checkmates', - lessonNumber: 0 - }, - { - piece: 'Knight and Bishop Mate interactive lesson', - lessonNumber: 0 - }, - { piece: 'The Pin Pin it to win it', lessonNumber: 0 }, - { piece: 'The Skewer Yum - Skewers!', lessonNumber: 0 }, - { piece: 'The Fork Use the fork, Luke', lessonNumber: 0 }, - { - piece: 'Discovered Attacks Including discovered checks', - lessonNumber: 0 - }, - { piece: 'Double Check A very powerfull tactic', lessonNumber: 0 }, - { - piece: 'Overloaded Pieces They have too much work', - lessonNumber: 0 - }, - { piece: 'Zwischenzug In-between moves', lessonNumber: 0 }, - { piece: 'X-Ray Attacking through an enemy piece', lessonNumber: 0 }, - { piece: 'Zugzwang Being forced to move', lessonNumber: 0 }, - { - piece: 'Interference Interpose a piece to great effect', - lessonNumber: 0 - }, - { - piece: 'Greek Gift Study the greek gift scrifice', - lessonNumber: 0 - }, - { piece: 'Deflection Distracting a defender', lessonNumber: 0 }, - { piece: 'Attraction Lure a piece to bad square', lessonNumber: 0 }, - { - piece: 'Underpromotion Promote - but not to a queen!', - lessonNumber: 0 - }, - { - piece: 'Desperado A piece is lost, but it can still help', - lessonNumber: 0 - }, - { - piece: 'Counter Check Respond to a check with a check', - lessonNumber: 0 - }, - { piece: 'Undermining Remove the defending piece', lessonNumber: 0 }, - { piece: 'Clearance Get out of the way!', lessonNumber: 0 }, - { piece: 'Key Squares Reach the key square', lessonNumber: 0 }, - { piece: 'Opposition take the opposition', lessonNumber: 0 }, - { piece: '7th-Rank Rook Pawn Versus a Queen', lessonNumber: 0 }, - { - piece: '7th-Rank Rook Pawn And Passive Rook vs Rook', - lessonNumber: 0 - }, - { piece: 'Basic Rook Endgames Lucena and Philidor', lessonNumber: 0 } - ], - }, - }, - { upsert: true } - ); - - const guestDoc = await guests.findOne( // get guestDoc by ip - { ip: clientIp } - ); - if (!guestDoc) throw new Error("Guest does not exist"); - - let lessonNum = -1; - for (const chessPiece of guestDoc.lessonsCompleted) { - if (chessPiece.piece === piece) { - lessonNum = chessPiece.lessonNumber; // the number of lessons completed for the piece - break; - } - } - if(lessonNum == -1) return res.status(400).json("Error: 400. Invalid piece."); - - else res.json(lessonNum); + // guest: always return 0 (frontend will show all lessons) + return res.json(0); } } catch (err) { console.error(err); @@ -269,7 +155,7 @@ router.get( try { const db = await getDb(); - const lessons= db.collection("newLessons"); // get lessons collection + const lessons = db.collection("newLessons"); // get lessons collection const lessonDoc = await lessons.findOne({ piece: piece }); // all lessons for that piece res.json(lessonDoc.lessons.length); // respond with length of lessons @@ -362,7 +248,7 @@ router.get( const users = db.collection("users"); // get users collection const guests = db.collection("guest"); // get users collection - if (req.user){ + if (req.user) { const { username } = req.user; // get username const userDoc = await users.findOne( // get userDoc by username @@ -383,7 +269,7 @@ router.get( return res.status(404).json("Piece not found in lessonsCompleted"); } - const updateResult = await users.updateOne( + const updateResult = await users.updateOne( { username, $or: [ @@ -408,7 +294,7 @@ router.get( res.status(304).json("No changes made"); } } else { - const clientIp = getClientIp(req); + const clientIp = getClientIp(req); const expiresAt = new Date(Date.now() + 24 * 60 * 60 * 1000); await guests.updateOne( @@ -517,7 +403,7 @@ router.get( return res.status(404).json("Piece not found in lessonsCompleted"); } - const updateResult = await guests.updateOne( + const updateResult = await guests.updateOne( { ip: clientIp, $or: [ @@ -574,7 +460,7 @@ router.get( const users = db.collection("users"); // get users collection const guests = db.collection("guest"); // get users collection - if (req.user){ + if (req.user) { const { username } = req.user; const userDoc = await users.findOne( // get userDoc by username @@ -723,249 +609,249 @@ module.exports = router; * Contains lesson completion states for various chess tactics and pieces */ list = [ - { - name: "Piece Checkmate 1 Basic checkmates", - list: ["8/8/7R/3k4/3Q4/4K3/8/8 b - - 5 3", - "8/8/R7/1R6/8/1k1K4/8/8 b - - 7 4", - "8/5Q2/5k2/8/2B2K2/8/8/8 b - - 9 5", - "8/kQ6/8/2N5/8/3K4/8/8 b - - 9 5", - "8/8/8/8/2K5/kQ6/8/8 b - - 11 6", - "R7/8/k1K5/8/8/8/8/8 b - - 21 11" - ] - }, - { - name: "The Pin Pin it to win it", - list: ["8/6k1/8/4B3/4P3/8/8/7K b - - 0 2", - "4k3/p1p2pp1/7p/2B5/8/1P3P2/P1P3PP/1K6 b - - 0 2", - "1k6/ppp3q1/8/4r3/8/2B5/5PPP/R4QK1 b - - 1 1", - "8/4k1p1/5p1p/4P3/8/7P/6P1/4R1K1 b - - 0 2", - "r4rk1/pp1p1ppp/1qp2B2/8/4P3/1P1P2Q1/P1P2PPP/R4RK1 b - - 0 1", - "4r1r1/2p5/1p1kn3/p1p1R1N1/P6p/7P/1PP1R1PK/8 b - - 0 1", - "1r1n1rk1/ppq2pQ1/2b5/2pB3p/2P4P/4P3/PB3PP1/1R3RK1 b - - 0 2", - "q5k1/5pp1/8/1pb1P3/2p5/2P3p1/1P3P2/1N3RK1 w - - 0 4" - ] - }, - { - name: "The Skewer Yum - Skewers!", - list: ["8/1Bq2k2/4ppp1/8/5P2/4P3/4QK2/5R2 b - - 0 2", - "r2r2k1/2p2ppp/5n2/4p3/p3P3/P6P/3B1PP1/2RQ2K1 b - - 0 2", - "5r1k/ppq3p1/3b4/2p2n2/2Pp1P1P/PP1Q2P1/3BN3/R3K2b w Q - 0 25", - "8/3qk3/8/8/5B2/4Kb2/8/8 w - - 0 3", - "8/1p4Q1/p2k4/6p1/P3b3/7P/5PP1/6K1 b - - 0 53", - "3k4/5R2/3b1P2/3p4/3P1p2/2p4P/2P3P1/7K b - - 0 3", - "8/pp1b4/5pp1/3k4/2p5/Q1P2P2/5KP1/8 b - - 0 42", - "B7/6p1/7p/2k5/p7/8/2P3P1/2K5 b - - 0 3" - ] - }, - { - name: "The Fork Use the fork, Luke", - list: ["2N5/5k2/8/8/6P1/7K/8/8 b - - 0 2", - "7k/5N1p/p7/nppP2q1/2P5/1P2N3/P6P/7K b - - 0 2", - "7k/5n2/8/4P3/8/8/6PP/5R1K b - - 0 2", - "r1bqkb1r/ppp2ppp/2n5/4p3/4p3/3B1N2/PPPP1PPP/R1BQK2R w KQkq - 0 4", - "8/8/R7/5k2/8/8/1K6/8 b - - 0 2", - "8/5k2/8/8/8/B6P/8/6K1 b - - 0 2", - "7Q/2nk1p1p/6p1/3n4/8/8/5PPP/6K1 b - - 0 2", - "N7/3k3p/6p1/5p2/r7/3P4/PPP2PPP/R5K1 b - - 0 3", - "3r1k2/pp1n2pb/2p2p1N/2P2r2/2QPp2p/P1P1B2P/6P1/1R1R2K1 b - - 0 2", - "8/5pk1/8/4p3/pp2P3/5P2/PP3K2/2n5 w - - 0 4", - "R7/5bN1/4k3/p3P3/8/5K2/8/8 b - - 0 4", - "r5k1/ppp2p1p/6pB/8/3bP2q/2NB2RP/PPP2nP1/R2Q3K w - - 1 5", - "6k1/1q6/p3p3/2P5/P3P2P/2P5/4Q1PK/8 b - - 0 3", - "5Bk1/1q1r2p1/5p1p/8/2P5/6PP/P4P2/4R1K1 w - - 0 34", - "r1bq1rk1/4p1bp/p2p1p2/1PpPn1B1/4PQ2/2N5/PP1N2PP/R3KB1R w KQ - 1 4", - "4b2r/5kP1/4p2n/pp1p3P/2pP1R2/P1P2B1N/2PK1P2/8 b - - 0 3" - ] - }, - { - name: "Discovered Attacks Including discovered checks", - list: [ - "4kR2/6pp/8/4N3/8/8/6PP/6K1 b - - 0 2", - "8/3Nk1pp/8/8/8/8/6PP/5RK1 b - - 0 2", - "B4k2/3r1pp1/3P3p/8/8/5N2/6PP/5RK1 b - - 0 2", - "r2q1bnN/pp3kpp/3p1p2/1Bp3B1/8/2Pp4/PP3PPP/RN1bR1K1 b - - 0 13", - "r1b2rk1/pp1n1p1p/6p1/3p4/3bP3/1PqB3P/P2N2PN/R2Q1R1K w - - 2 17", - "2k5/8/p2P4/2p1b3/8/2P4r/P4R2/1K2R3 b - - 0 43", - "8/2N5/4np2/4pk1p/R6P/P3KP2/1P6/8 b - - 0 2", - "r1bq2rk/1p1p1N2/p1n1pP1p/3n4/8/1N1Bb3/PPP3PP/R4R1K b - - 3 3", - "8/5ppk/p3p2p/1p1b4/3Pp3/1P2b1P1/P6P/2R2K2 w - - 0 4", - "4r3/1R2qk1p/1Q4p1/1Pp5/2P5/6P1/6KP/8 b - - 0 53" - ] - }, - { - name: "Double Check A very powerfull tactic", - list: [ - "", - "r3k3/ppp2pp1/2np4/2B1p3/2B1P1N1/3P2n1/PPP2PP1/RN1Q1RKr w q - 3 14", - "", - "", - "3r2k1/pp6/6p1/2P1q2p/4p3/4BK2/PP2P2r/R1Q1R2B w - - 0 30", - "B6r/2qk1P1p/p5p1/1p2p3/8/2P1B3/P1PR2PP/5RK1 b - - 0 25" - ] - }, - { - name: "Overloaded Pieces They have too much work", - list: [ - "6k1/5pp1/4R1n1/8/8/3B4/5PPP/6K1 b - - 0 1", - "2r1rbk1/3P1pp1/5n2/8/8/3Q3P/2B2PPK/8 b - - 0 1", - "6b1/4k2p/7P/1p1pKBP1/1P1P4/8/5P2/8 b - - 2 4", - "3q3k/pp2R1pp/8/2P5/1P3BQ1/2P5/P4rPp/7K b - - 0 29", - "8/6Q1/p3p1k1/3nB1r1/8/3q3P/PP6/K1R5 b - - 0 36", - "4R3/pb1R1p1k/1pn2qpp/8/4B3/P4NP1/1P3PP1/6K1 b - - 0 26", - "5R2/1p5k/p2pp3/8/7p/8/PP4P1/6K1 b - - 0 4", - "1r3k1r/p4p2/7p/3pP3/8/4BPN1/6P1/2R3K1 b - - 0 3", - "5k2/1pp4p/p1n3p1/8/1P2q3/P3P1Pb/3N3P/6K1 w - - 0 4", - "rk2Q3/5p1p/p1n2p2/P1b5/2p5/2P3P1/5P1P/6K1 b - - 0 32" - ] - }, - { - name: "Zwischenzug In-between moves", - list: [ - "1rbqk2r/pp3ppp/8/3n4/1bpP4/8/PP2BKPP/RN1Q2NR w k - 0 11", - "5rk1/pp1b1ppp/4p3/3pP3/1q3Pn1/3B1N2/P2K2PP/RN3Q2 w - - 0 19", - "B3k3/3b1q2/p2bp3/6Q1/8/4B1P1/PPP4P/6K1 b - - 0 31", - "2r3k1/B5pp/4p3/1Q1p1p2/1p3P2/1P2P3/P1r3PP/6K1 b - - 0 29", - "2B2r1k/1pN1Qpbp/p4pp1/q7/8/8/PP3PPP/3R2K1 b - - 0 25" - ] - }, - { - name: "Interference Interpose a piece to great effect", - list: [ - "4r1k1/p1p1qppp/3b1n2/1r1p4/P2P4/2P5/1P2BPPP/R1B1KN1R w KQ - 0 16", - "1k6/1pp2pp1/p1p5/8/8/2Pp1Pp1/PP2q1P1/R1BK1N2 w - - 4 27", - "1R4k1/p3bppp/4p3/8/3r4/6P1/P3PP1P/5RK1 b - - 0 19", - "3r2k1/pp3p1p/6p1/8/4P3/5P2/PP2nKPP/2B5 w - - 0 26", - "3B2k1/6p1/3b4/1p1p3q/3P4/2P1pNPb/1P3P1P/R5K1 w - - 0 32", - "2r4k/5pR1/7p/5q2/4p2P/1Qn1P3/5P1K/8 w - - 0 38", - "5q2/1b4pk/1p2p1n1/1P1pPp2/P2P1P1p/1N3R1P/1Q4PK/8 b - - 0 47" - ] - }, - { - name: "Greek Gift Study the greek gift scrifice", - list: [ - "rnb2rk1/pppn1pp1/4p3/3pP1B1/1b1P4/2NQ4/PPP2PPP/R3K2R b KQ - 0 4", - "rnb2rk1/pp3p1Q/4p3/3pn1N1/3p4/2NB4/PPP2PP1/R3K2R b KQ - 5 16", - "r3r2k/1b3Qp1/p7/1p1P1R2/1P6/P3q3/6PP/3R3K b - - 4 26", - "r3rbk1/6p1/pn4p1/np2p1B1/3p4/5Q2/PP3PP1/2R1R1K1 b - - 1 25", - "3r1B1Q/bpq2k2/p1b1pp2/2P5/1P6/P7/5PPP/2R2RK1 b - - 0 22", - "r1b2rk1/ppq2pp1/4pn2/2p3NQ/1p1P4/8/PP1N1PPP/R4RK1 w - - 0 16" - ] - }, - { - name: "Deflection Distracting a defender", - list: [ - "5R2/5ppk/4b3/8/8/7P/5PP1/6K1 b - - 0 2", - "8/8/8/1k4Q1/8/8/5K2/8 b - - 0 3", - "4r1k1/1p1Q1p1p/p2p1Pp1/1n1P4/1P6/6P1/P4PKP/4R3 b - - 0 4", - "rnbQ1b1r/pp2pkpp/5n2/8/4P3/2N5/PPP2PPP/R1B1K2R b - - 0 2", - "2b2qk1/7Q/3r2p1/8/8/3r3R/6PP/6K1 b - - 0 2", - "6k1/5p2/3q2pp/8/6P1/5QNP/5P2/4r1K1 w - - 0 3", - "r3r1k1/p4pp1/1p1Q3p/8/P7/7P/1P3PP1/R5K1 b - - 0 2", - "r5rk/6qQ/p1p2B1p/PpP5/1P6/2PB2P1/5PKP/8 b - - 1 3", - "r1bk3r/pppp2p1/1n3p1p/7n/2N4Q/5P2/PPP3PP/R3R1K1 b - - 0 2", - "6k1/2r2pp1/5q1p/Np6/8/1P5Q/3pbPPR/1R4K1 w - - 0 6" - ] - }, - { - name: "Attraction Lure a piece to bad square", - list: [ - "3R1k2/5p1p/8/5N2/8/5p1q/8/6K1 b - - 0 3", - "rnbB1b1r/ppk2ppp/2p5/4q3/4n3/8/PPP2PPP/2KR1BNR b - - 3 11", - "r2B3r/3n2pp/p2bR3/1b1k1P2/1qpPB3/4P1PP/5P1K/8 b - - 1 2", - "", - "", - "8/5pk1/4p3/1p6/6P1/4P3/PR2KP2/7q w - - 0 4", - "", - "6k1/pp4bp/2n2np1/5p2/2P2q2/4KBN1/PP5P/RQ6 w - - 0 24", - "", - "7r/6kp/5Rp1/8/8/8/6PP/2B3K1 b - - 0 1" - ] - }, - { - name: "Underpromotion Promote - but not to a queen!", - list: [ - "5N1n/r6k/5b2/5N1p/8/1q6/PP6/K5R1 b - - 0 1", - "5R2/7k/8/7K/8/8/8/8 b - - 0 1", - "1R1B4/8/k7/8/8/5K2/8/8 b - - 0 1", - "5R2/7k/5K2/8/8/8/8/8 b - - 0 1", - "8/7p/7B/5k1p/7P/5K2/8/8 b - - 0 2", - "8/8/8/8/8/k7/1b1n4/KB6 w - - 4 4", - "B3Q3/1q4pk/5p1p/5P1K/6PP/8/8/8 b - - 0 1", - "5N2/3q3k/8/8/6p1/6Pp/7P/7K b - - 0 3", - "6K1/8/5k2/8/8/8/8/8 b - - 0 2", - "3N4/k7/P7/1K6/8/8/8/8 b - - 0 1" - ] - }, - { - name: "Desperado A piece is lost, but it can still help", - list: [ - "r3kb1r/pp3ppp/2N1pn2/8/3P4/2P5/P4PPP/R1Bb1RK1 w - - 0 3", - "r2B2rk/2p2p2/p2p3p/1p1N4/3bP1n1/PB3P2/1P3P2/R3RK2 b - - 0 2", - "r5k1/ppp1p1rp/8/3P3b/4P3/2N5/PP1nN1P1/2K4R w - - 0 4", - "r5k1/ppN2pPp/6p1/5R2/1p6/1P2n3/P3K1PP/3R4 b - - 2 4", - "4br2/6k1/4pn1p/1p1P4/p2BB3/6P1/PP3P2/6K1 w - - 0 4" - ] - }, - { - name: "Counter Check Respond to a check with a check", - list: [ - "", - "8/6P1/8/8/1q1QK3/8/8/k7 b - - 1 1", - "", - "8/8/8/8/8/1k6/2r5/K7 w - - 0 96", - "8/5Npp/p1P5/P1R3rk/1p4b1/3r2K1/4pP1P/7R w - - 0 34" - ] - }, - { - name: "Undermining Remove the defending piece", - list: [ - "4rrk1/R5bp/3qp1p1/3p3Q/2pB1P2/6PP/1P3PB1/4R1K1 b - - 0 24", - "1b4k1/1p5p/8/1N1p4/P1nBn3/4P3/5q1N/5K1Q w - - 0 33", - "3qRrk1/1p3ppp/8/p4N2/8/P5QP/1P3PP1/6K1 b - - 0 1", - "1q3r1k/r4ppp/5Q2/8/5N2/p6R/PPP5/1K5R b - - 0 1", - "2q1rk2/1p3ppp/p7/2N5/1P6/5RP1/P1Q3KP/8 b - - 2 2" - ] - }, - { - name: "Clearance Get out of the way!", - list: [ - "8/2k5/5Np1/1p4K1/5P2/8/1R6/3r4 b - - 0 58", - "8/k7/p1p5/2P1p3/1P6/P3PB2/3K4/6q1 w - - 0 50", - "1k1r3r/pp1b4/5Ppp/3p4/P2R4/3B2q1/2PB1PPP/R5K1 b - - 0 24", - "4k2r/1p6/2b1p1pp/2N1P2N/5P1Q/pPp5/Pn4PK/4R3 b - - 0 41", - "" - ] - }, - { - name: "7th-Rank Rook Pawn And Passive Rook vs Rook", - list: [ - "8/6k1/8/4K2p/4P2p/5P2/6P1/8 b - - 0 58", - "R7/P6k/r7/8/8/8/1K6/8 w - - 27 15", - "R7/P5k1/6P1/8/8/1K6/8/r7 b - - 22 14", - "8/R7/5k2/8/8/8/6K1/8 b - - 0 6", - "", - "", - "R7/P5k1/5P2/8/8/8/7K/r7 b - - 0 80", - "8/6k1/8/4K2p/4P2p/5P2/6P1/8 b - - 0 58", - "R7/P4k2/6p1/r3P2p/4K2P/6P1/8/8 b - - 1 62" - ] - }, - { - name: "Basic Rook Endgames Lucena and Philidor", - list: [ - "", - "", - "", - "", - "8/8/8/3k4/8/7r/2K5/R7 b - - 9 11", - "", - "", - "8/8/8/8/R5K1/4k3/8/1r6 w - - 5 21", - "8/8/4K3/8/2k5/1R6/1p6/8 w - - 4 8", - "" - ] + { + name: "Piece Checkmate 1 Basic checkmates", + list: ["8/8/7R/3k4/3Q4/4K3/8/8 b - - 5 3", + "8/8/R7/1R6/8/1k1K4/8/8 b - - 7 4", + "8/5Q2/5k2/8/2B2K2/8/8/8 b - - 9 5", + "8/kQ6/8/2N5/8/3K4/8/8 b - - 9 5", + "8/8/8/8/2K5/kQ6/8/8 b - - 11 6", + "R7/8/k1K5/8/8/8/8/8 b - - 21 11" + ] + }, + { + name: "The Pin Pin it to win it", + list: ["8/6k1/8/4B3/4P3/8/8/7K b - - 0 2", + "4k3/p1p2pp1/7p/2B5/8/1P3P2/P1P3PP/1K6 b - - 0 2", + "1k6/ppp3q1/8/4r3/8/2B5/5PPP/R4QK1 b - - 1 1", + "8/4k1p1/5p1p/4P3/8/7P/6P1/4R1K1 b - - 0 2", + "r4rk1/pp1p1ppp/1qp2B2/8/4P3/1P1P2Q1/P1P2PPP/R4RK1 b - - 0 1", + "4r1r1/2p5/1p1kn3/p1p1R1N1/P6p/7P/1PP1R1PK/8 b - - 0 1", + "1r1n1rk1/ppq2pQ1/2b5/2pB3p/2P4P/4P3/PB3PP1/1R3RK1 b - - 0 2", + "q5k1/5pp1/8/1pb1P3/2p5/2P3p1/1P3P2/1N3RK1 w - - 0 4" + ] + }, + { + name: "The Skewer Yum - Skewers!", + list: ["8/1Bq2k2/4ppp1/8/5P2/4P3/4QK2/5R2 b - - 0 2", + "r2r2k1/2p2ppp/5n2/4p3/p3P3/P6P/3B1PP1/2RQ2K1 b - - 0 2", + "5r1k/ppq3p1/3b4/2p2n2/2Pp1P1P/PP1Q2P1/3BN3/R3K2b w Q - 0 25", + "8/3qk3/8/8/5B2/4Kb2/8/8 w - - 0 3", + "8/1p4Q1/p2k4/6p1/P3b3/7P/5PP1/6K1 b - - 0 53", + "3k4/5R2/3b1P2/3p4/3P1p2/2p4P/2P3P1/7K b - - 0 3", + "8/pp1b4/5pp1/3k4/2p5/Q1P2P2/5KP1/8 b - - 0 42", + "B7/6p1/7p/2k5/p7/8/2P3P1/2K5 b - - 0 3" + ] + }, + { + name: "The Fork Use the fork, Luke", + list: ["2N5/5k2/8/8/6P1/7K/8/8 b - - 0 2", + "7k/5N1p/p7/nppP2q1/2P5/1P2N3/P6P/7K b - - 0 2", + "7k/5n2/8/4P3/8/8/6PP/5R1K b - - 0 2", + "r1bqkb1r/ppp2ppp/2n5/4p3/4p3/3B1N2/PPPP1PPP/R1BQK2R w KQkq - 0 4", + "8/8/R7/5k2/8/8/1K6/8 b - - 0 2", + "8/5k2/8/8/8/B6P/8/6K1 b - - 0 2", + "7Q/2nk1p1p/6p1/3n4/8/8/5PPP/6K1 b - - 0 2", + "N7/3k3p/6p1/5p2/r7/3P4/PPP2PPP/R5K1 b - - 0 3", + "3r1k2/pp1n2pb/2p2p1N/2P2r2/2QPp2p/P1P1B2P/6P1/1R1R2K1 b - - 0 2", + "8/5pk1/8/4p3/pp2P3/5P2/PP3K2/2n5 w - - 0 4", + "R7/5bN1/4k3/p3P3/8/5K2/8/8 b - - 0 4", + "r5k1/ppp2p1p/6pB/8/3bP2q/2NB2RP/PPP2nP1/R2Q3K w - - 1 5", + "6k1/1q6/p3p3/2P5/P3P2P/2P5/4Q1PK/8 b - - 0 3", + "5Bk1/1q1r2p1/5p1p/8/2P5/6PP/P4P2/4R1K1 w - - 0 34", + "r1bq1rk1/4p1bp/p2p1p2/1PpPn1B1/4PQ2/2N5/PP1N2PP/R3KB1R w KQ - 1 4", + "4b2r/5kP1/4p2n/pp1p3P/2pP1R2/P1P2B1N/2PK1P2/8 b - - 0 3" + ] + }, + { + name: "Discovered Attacks Including discovered checks", + list: [ + "4kR2/6pp/8/4N3/8/8/6PP/6K1 b - - 0 2", + "8/3Nk1pp/8/8/8/8/6PP/5RK1 b - - 0 2", + "B4k2/3r1pp1/3P3p/8/8/5N2/6PP/5RK1 b - - 0 2", + "r2q1bnN/pp3kpp/3p1p2/1Bp3B1/8/2Pp4/PP3PPP/RN1bR1K1 b - - 0 13", + "r1b2rk1/pp1n1p1p/6p1/3p4/3bP3/1PqB3P/P2N2PN/R2Q1R1K w - - 2 17", + "2k5/8/p2P4/2p1b3/8/2P4r/P4R2/1K2R3 b - - 0 43", + "8/2N5/4np2/4pk1p/R6P/P3KP2/1P6/8 b - - 0 2", + "r1bq2rk/1p1p1N2/p1n1pP1p/3n4/8/1N1Bb3/PPP3PP/R4R1K b - - 3 3", + "8/5ppk/p3p2p/1p1b4/3Pp3/1P2b1P1/P6P/2R2K2 w - - 0 4", + "4r3/1R2qk1p/1Q4p1/1Pp5/2P5/6P1/6KP/8 b - - 0 53" + ] + }, + { + name: "Double Check A very powerfull tactic", + list: [ + "", + "r3k3/ppp2pp1/2np4/2B1p3/2B1P1N1/3P2n1/PPP2PP1/RN1Q1RKr w q - 3 14", + "", + "", + "3r2k1/pp6/6p1/2P1q2p/4p3/4BK2/PP2P2r/R1Q1R2B w - - 0 30", + "B6r/2qk1P1p/p5p1/1p2p3/8/2P1B3/P1PR2PP/5RK1 b - - 0 25" + ] + }, + { + name: "Overloaded Pieces They have too much work", + list: [ + "6k1/5pp1/4R1n1/8/8/3B4/5PPP/6K1 b - - 0 1", + "2r1rbk1/3P1pp1/5n2/8/8/3Q3P/2B2PPK/8 b - - 0 1", + "6b1/4k2p/7P/1p1pKBP1/1P1P4/8/5P2/8 b - - 2 4", + "3q3k/pp2R1pp/8/2P5/1P3BQ1/2P5/P4rPp/7K b - - 0 29", + "8/6Q1/p3p1k1/3nB1r1/8/3q3P/PP6/K1R5 b - - 0 36", + "4R3/pb1R1p1k/1pn2qpp/8/4B3/P4NP1/1P3PP1/6K1 b - - 0 26", + "5R2/1p5k/p2pp3/8/7p/8/PP4P1/6K1 b - - 0 4", + "1r3k1r/p4p2/7p/3pP3/8/4BPN1/6P1/2R3K1 b - - 0 3", + "5k2/1pp4p/p1n3p1/8/1P2q3/P3P1Pb/3N3P/6K1 w - - 0 4", + "rk2Q3/5p1p/p1n2p2/P1b5/2p5/2P3P1/5P1P/6K1 b - - 0 32" + ] + }, + { + name: "Zwischenzug In-between moves", + list: [ + "1rbqk2r/pp3ppp/8/3n4/1bpP4/8/PP2BKPP/RN1Q2NR w k - 0 11", + "5rk1/pp1b1ppp/4p3/3pP3/1q3Pn1/3B1N2/P2K2PP/RN3Q2 w - - 0 19", + "B3k3/3b1q2/p2bp3/6Q1/8/4B1P1/PPP4P/6K1 b - - 0 31", + "2r3k1/B5pp/4p3/1Q1p1p2/1p3P2/1P2P3/P1r3PP/6K1 b - - 0 29", + "2B2r1k/1pN1Qpbp/p4pp1/q7/8/8/PP3PPP/3R2K1 b - - 0 25" + ] + }, + { + name: "Interference Interpose a piece to great effect", + list: [ + "4r1k1/p1p1qppp/3b1n2/1r1p4/P2P4/2P5/1P2BPPP/R1B1KN1R w KQ - 0 16", + "1k6/1pp2pp1/p1p5/8/8/2Pp1Pp1/PP2q1P1/R1BK1N2 w - - 4 27", + "1R4k1/p3bppp/4p3/8/3r4/6P1/P3PP1P/5RK1 b - - 0 19", + "3r2k1/pp3p1p/6p1/8/4P3/5P2/PP2nKPP/2B5 w - - 0 26", + "3B2k1/6p1/3b4/1p1p3q/3P4/2P1pNPb/1P3P1P/R5K1 w - - 0 32", + "2r4k/5pR1/7p/5q2/4p2P/1Qn1P3/5P1K/8 w - - 0 38", + "5q2/1b4pk/1p2p1n1/1P1pPp2/P2P1P1p/1N3R1P/1Q4PK/8 b - - 0 47" + ] + }, + { + name: "Greek Gift Study the greek gift scrifice", + list: [ + "rnb2rk1/pppn1pp1/4p3/3pP1B1/1b1P4/2NQ4/PPP2PPP/R3K2R b KQ - 0 4", + "rnb2rk1/pp3p1Q/4p3/3pn1N1/3p4/2NB4/PPP2PP1/R3K2R b KQ - 5 16", + "r3r2k/1b3Qp1/p7/1p1P1R2/1P6/P3q3/6PP/3R3K b - - 4 26", + "r3rbk1/6p1/pn4p1/np2p1B1/3p4/5Q2/PP3PP1/2R1R1K1 b - - 1 25", + "3r1B1Q/bpq2k2/p1b1pp2/2P5/1P6/P7/5PPP/2R2RK1 b - - 0 22", + "r1b2rk1/ppq2pp1/4pn2/2p3NQ/1p1P4/8/PP1N1PPP/R4RK1 w - - 0 16" + ] + }, + { + name: "Deflection Distracting a defender", + list: [ + "5R2/5ppk/4b3/8/8/7P/5PP1/6K1 b - - 0 2", + "8/8/8/1k4Q1/8/8/5K2/8 b - - 0 3", + "4r1k1/1p1Q1p1p/p2p1Pp1/1n1P4/1P6/6P1/P4PKP/4R3 b - - 0 4", + "rnbQ1b1r/pp2pkpp/5n2/8/4P3/2N5/PPP2PPP/R1B1K2R b - - 0 2", + "2b2qk1/7Q/3r2p1/8/8/3r3R/6PP/6K1 b - - 0 2", + "6k1/5p2/3q2pp/8/6P1/5QNP/5P2/4r1K1 w - - 0 3", + "r3r1k1/p4pp1/1p1Q3p/8/P7/7P/1P3PP1/R5K1 b - - 0 2", + "r5rk/6qQ/p1p2B1p/PpP5/1P6/2PB2P1/5PKP/8 b - - 1 3", + "r1bk3r/pppp2p1/1n3p1p/7n/2N4Q/5P2/PPP3PP/R3R1K1 b - - 0 2", + "6k1/2r2pp1/5q1p/Np6/8/1P5Q/3pbPPR/1R4K1 w - - 0 6" + ] + }, + { + name: "Attraction Lure a piece to bad square", + list: [ + "3R1k2/5p1p/8/5N2/8/5p1q/8/6K1 b - - 0 3", + "rnbB1b1r/ppk2ppp/2p5/4q3/4n3/8/PPP2PPP/2KR1BNR b - - 3 11", + "r2B3r/3n2pp/p2bR3/1b1k1P2/1qpPB3/4P1PP/5P1K/8 b - - 1 2", + "", + "", + "8/5pk1/4p3/1p6/6P1/4P3/PR2KP2/7q w - - 0 4", + "", + "6k1/pp4bp/2n2np1/5p2/2P2q2/4KBN1/PP5P/RQ6 w - - 0 24", + "", + "7r/6kp/5Rp1/8/8/8/6PP/2B3K1 b - - 0 1" + ] + }, + { + name: "Underpromotion Promote - but not to a queen!", + list: [ + "5N1n/r6k/5b2/5N1p/8/1q6/PP6/K5R1 b - - 0 1", + "5R2/7k/8/7K/8/8/8/8 b - - 0 1", + "1R1B4/8/k7/8/8/5K2/8/8 b - - 0 1", + "5R2/7k/5K2/8/8/8/8/8 b - - 0 1", + "8/7p/7B/5k1p/7P/5K2/8/8 b - - 0 2", + "8/8/8/8/8/k7/1b1n4/KB6 w - - 4 4", + "B3Q3/1q4pk/5p1p/5P1K/6PP/8/8/8 b - - 0 1", + "5N2/3q3k/8/8/6p1/6Pp/7P/7K b - - 0 3", + "6K1/8/5k2/8/8/8/8/8 b - - 0 2", + "3N4/k7/P7/1K6/8/8/8/8 b - - 0 1" + ] + }, + { + name: "Desperado A piece is lost, but it can still help", + list: [ + "r3kb1r/pp3ppp/2N1pn2/8/3P4/2P5/P4PPP/R1Bb1RK1 w - - 0 3", + "r2B2rk/2p2p2/p2p3p/1p1N4/3bP1n1/PB3P2/1P3P2/R3RK2 b - - 0 2", + "r5k1/ppp1p1rp/8/3P3b/4P3/2N5/PP1nN1P1/2K4R w - - 0 4", + "r5k1/ppN2pPp/6p1/5R2/1p6/1P2n3/P3K1PP/3R4 b - - 2 4", + "4br2/6k1/4pn1p/1p1P4/p2BB3/6P1/PP3P2/6K1 w - - 0 4" + ] + }, + { + name: "Counter Check Respond to a check with a check", + list: [ + "", + "8/6P1/8/8/1q1QK3/8/8/k7 b - - 1 1", + "", + "8/8/8/8/8/1k6/2r5/K7 w - - 0 96", + "8/5Npp/p1P5/P1R3rk/1p4b1/3r2K1/4pP1P/7R w - - 0 34" + ] + }, + { + name: "Undermining Remove the defending piece", + list: [ + "4rrk1/R5bp/3qp1p1/3p3Q/2pB1P2/6PP/1P3PB1/4R1K1 b - - 0 24", + "1b4k1/1p5p/8/1N1p4/P1nBn3/4P3/5q1N/5K1Q w - - 0 33", + "3qRrk1/1p3ppp/8/p4N2/8/P5QP/1P3PP1/6K1 b - - 0 1", + "1q3r1k/r4ppp/5Q2/8/5N2/p6R/PPP5/1K5R b - - 0 1", + "2q1rk2/1p3ppp/p7/2N5/1P6/5RP1/P1Q3KP/8 b - - 2 2" + ] + }, + { + name: "Clearance Get out of the way!", + list: [ + "8/2k5/5Np1/1p4K1/5P2/8/1R6/3r4 b - - 0 58", + "8/k7/p1p5/2P1p3/1P6/P3PB2/3K4/6q1 w - - 0 50", + "1k1r3r/pp1b4/5Ppp/3p4/P2R4/3B2q1/2PB1PPP/R5K1 b - - 0 24", + "4k2r/1p6/2b1p1pp/2N1P2N/5P1Q/pPp5/Pn4PK/4R3 b - - 0 41", + "" + ] + }, + { + name: "7th-Rank Rook Pawn And Passive Rook vs Rook", + list: [ + "8/6k1/8/4K2p/4P2p/5P2/6P1/8 b - - 0 58", + "R7/P6k/r7/8/8/8/1K6/8 w - - 27 15", + "R7/P5k1/6P1/8/8/1K6/8/r7 b - - 22 14", + "8/R7/5k2/8/8/8/6K1/8 b - - 0 6", + "", + "", + "R7/P5k1/5P2/8/8/8/7K/r7 b - - 0 80", + "8/6k1/8/4K2p/4P2p/5P2/6P1/8 b - - 0 58", + "R7/P4k2/6p1/r3P2p/4K2P/6P1/8/8 b - - 1 62" + ] + }, + { + name: "Basic Rook Endgames Lucena and Philidor", + list: [ + "", + "", + "", + "", + "8/8/8/3k4/8/7r/2K5/R7 b - - 9 11", + "", + "", + "8/8/8/8/R5K1/4k3/8/1r6 w - - 5 21", + "8/8/4K3/8/2k5/1R6/1p6/8 w - - 4 8", + "" + ] - } + } ] module.exports = router; \ No newline at end of file diff --git a/react-ystemandchess/src/Pages/LessonsSelection/LessonsSelection.jsx b/react-ystemandchess/src/Pages/LessonsSelection/LessonsSelection.jsx index 9133faab..130eca24 100644 --- a/react-ystemandchess/src/Pages/LessonsSelection/LessonsSelection.jsx +++ b/react-ystemandchess/src/Pages/LessonsSelection/LessonsSelection.jsx @@ -86,26 +86,6 @@ export default function LessonSelection({ onGo, styleType = "page" }) { // what return; } - let unlocked = 0; - try { - const response = await fetch( - `${environment.urls.middlewareURL}/lessons/getCompletedLessonCount?piece=${selectedScenario}`, - { - method: 'GET', - headers: { 'Authorization': `Bearer ${cookies.login}` } - } - ); - - if (!response.ok) { - throw new Error(`HTTP error! status: ${response.status}`); - } - unlocked = await response.json(); - } catch (error) { - console.error('Error fetching unlocked lesson count:', error); - // Optionally set an error state here if needed for display - unlocked = 0; // Default to 0 unlocked lessons on error - } - const currentScenario = scenarios.find(s => s.name === selectedScenario); if (!currentScenario) { setLessons([]); @@ -113,6 +93,34 @@ export default function LessonSelection({ onGo, styleType = "page" }) { // what return; } + setLoadingLessons(true); + + let unlocked = 0; + if (!cookies.login) { + // Non-logged users: expose all lessons + unlocked = currentScenario.subSections.length; + console.log("No login cookie detected. Granting full access. unlocked:", unlocked); + } else { + // Logged users: ask backend for how many lessons they have completed + try { + const response = await fetch( + `${environment.urls.middlewareURL}/lessons/getCompletedLessonCount?piece=${selectedScenario}`, + { + method: 'GET', + headers: { 'Authorization': `Bearer ${cookies.login}` } + } + ); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + unlocked = await response.json(); + } catch (error) { + console.error('Error fetching unlocked lesson count:', error); + unlocked = 0; // Default to 0 unlocked lessons on error + } + } + // Determine available lessons const maxIndex = Math.min(unlocked, currentScenario.subSections.length - 1); const availableLessons = currentScenario.subSections.slice(0, maxIndex + 1); From f8e81074b5b5b3912f01279805aae32e05179deb Mon Sep 17 00:00:00 2001 From: f-hejazi Date: Tue, 18 Nov 2025 01:41:10 +0100 Subject: [PATCH 14/23] feat: replace alert with modal for lesson completion --- .../Lesson-overlay-profile.module.scss | 10 ++++++++-- .../lesson-overlay/Lesson-overlay.module.scss | 9 +++++++-- .../lesson-overlay/Lesson-overlay.tsx | 20 +++++++++++++++++-- 3 files changed, 33 insertions(+), 6 deletions(-) diff --git a/react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/Lesson-overlay-profile.module.scss b/react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/Lesson-overlay-profile.module.scss index 11e6f500..9529535d 100644 --- a/react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/Lesson-overlay-profile.module.scss +++ b/react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/Lesson-overlay-profile.module.scss @@ -250,11 +250,17 @@ .popupContent { width: 450px; - height: fit-content; + height: 250px; background-color: white; - padding: 20px; + padding: 30px; border-radius: 10px; text-align: center; + display: flex; + flex-direction: column; + justify-content: space-between; + align-items: center; + padding: 30px; + gap: 10px; } .popupButton { diff --git a/react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/Lesson-overlay.module.scss b/react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/Lesson-overlay.module.scss index 3e9f2504..77932df7 100644 --- a/react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/Lesson-overlay.module.scss +++ b/react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/Lesson-overlay.module.scss @@ -272,10 +272,15 @@ .popupContent { width: 450px; - height: fit-content; + height: 250px; background-color: white; - padding: 20px; border-radius: 10px; + display: flex; + flex-direction: column; + justify-content: space-between; + align-items: center; + padding: 30px; + gap: 10px; text-align: center; } diff --git a/react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/Lesson-overlay.tsx b/react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/Lesson-overlay.tsx index b836805e..a44c7b6a 100644 --- a/react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/Lesson-overlay.tsx +++ b/react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/Lesson-overlay.tsx @@ -71,6 +71,7 @@ const LessonOverlay: React.FC = ({ const [ShowError, setShowError] = useState(false); const [showLPopup, setShowLPopup] = useState(true); const [showInstruction, setShowInstruction] = useState(false); + const [allLessonsDone, setAllLessonsDone] = useState(false); const [isPromoting, setIsPromoting] = useState(false); const [promotionSource, setPromotionSource] = useState(""); @@ -174,9 +175,12 @@ const LessonOverlay: React.FC = ({ setShowLPopup(false); setShowInstruction(true); + // TEMPORARY for testing + lessonData.lessonNum = 0; + // Check if we've reached the end of lessons if (!lessonData.lessonNum) { - alert('Congratulations! You have completed all lessons for this piece.'); + setAllLessonsDone(true); return } @@ -532,7 +536,19 @@ const LessonOverlay: React.FC = ({
)} - {/* */} + {allLessonsDone && ( +
+
+

🎉 Congratulations!

+

+ You have completed all lessons for this scenario. +

+ +
+
+ )} {isPromoting ? : null /* Show promotion popup if needed */}
From 445b1eaa7ff890d54a7cc8d0923718dd79b5ec37 Mon Sep 17 00:00:00 2001 From: f-hejazi Date: Tue, 18 Nov 2025 01:50:08 +0100 Subject: [PATCH 15/23] fix(knight): update Training 1 FEN to remove illegal pawns --- react-ystemandchess/src/Pages/Lessons/Scenarios.js | 2 +- .../src/Pages/piece-lessons/lesson-overlay/Lesson-overlay.tsx | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/react-ystemandchess/src/Pages/Lessons/Scenarios.js b/react-ystemandchess/src/Pages/Lessons/Scenarios.js index e24b2ad5..4292e1f4 100644 --- a/react-ystemandchess/src/Pages/Lessons/Scenarios.js +++ b/react-ystemandchess/src/Pages/Lessons/Scenarios.js @@ -82,7 +82,7 @@ export const scenariosArray = [ }, { name: 'Training 1', - fen: 'k6p/5p2/8/6p1/3p4/2p2p2/4p3/KN6 w - - 0 1', + fen: 'k7/5p2/8/6p1/3p4/2p2p2/4p3/KN6 w - - 0 1', info: `Grab all the pawns!`, }, { diff --git a/react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/Lesson-overlay.tsx b/react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/Lesson-overlay.tsx index a44c7b6a..d46a3081 100644 --- a/react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/Lesson-overlay.tsx +++ b/react-ystemandchess/src/Pages/piece-lessons/lesson-overlay/Lesson-overlay.tsx @@ -175,9 +175,6 @@ const LessonOverlay: React.FC = ({ setShowLPopup(false); setShowInstruction(true); - // TEMPORARY for testing - lessonData.lessonNum = 0; - // Check if we've reached the end of lessons if (!lessonData.lessonNum) { setAllLessonsDone(true); From f2b978b4a7d131c4cbc9566cb49b1b4e9694be0e Mon Sep 17 00:00:00 2001 From: f-hejazi Date: Tue, 18 Nov 2025 03:13:04 +0100 Subject: [PATCH 16/23] test: mock SweetAlert2 in Jest to prevent CI import errors --- .../LessonsSelection.test.tsx | 33 ++++++++++++++++--- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/react-ystemandchess/src/Pages/LessonsSelection/LessonsSelection.test.tsx b/react-ystemandchess/src/Pages/LessonsSelection/LessonsSelection.test.tsx index 9f6efaee..d86a8a3b 100644 --- a/react-ystemandchess/src/Pages/LessonsSelection/LessonsSelection.test.tsx +++ b/react-ystemandchess/src/Pages/LessonsSelection/LessonsSelection.test.tsx @@ -1,9 +1,13 @@ -import React from "react"; import { render, screen, fireEvent, waitFor } from "@testing-library/react"; import LessonSelection from "./LessonsSelection.jsx"; import { MemoryRouter } from "react-router"; import { useNavigate } from 'react-router'; +// Prevent SweetAlert2 from executing browser code in Jest +jest.mock('sweetalert2', () => ({ + fire: jest.fn(), +})); + // mock navigating to lessons jest.mock('react-router', () => ({ ...jest.requireActual('react-router'), @@ -13,17 +17,38 @@ jest.mock('react-router', () => ({ // mock fetching from database beforeEach(() => { global.fetch = jest.fn((url) => { - // fetching number of lessons completed for each scenario + // fetch for scenario list + if (url.includes('/api/scenarios') || url.includes('/scenarios')) { + return Promise.resolve({ + ok: true, + json: () => Promise.resolve([ + { id: 'Piece Checkmate 1 Basic checkmates', title: 'Piece Checkmate 1 Basic checkmates' }, + { id: 'Piece checkmates 2 Challenging checkmates', title: 'Piece checkmates 2 Challenging checkmates' }, + { id: 'Zugzwang Being forced to move', title: 'Zugzwang Being forced to move' }, + ]), + }); + } + + // original mock for lessons-completed if (url.includes('Piece Checkmate 1 Basic checkmates')) { return Promise.resolve({ ok: true, - json: () => Promise.resolve(1), // completed just one lesson + json: () => Promise.resolve(1), }); } - return Promise.reject(new Error('Unhandled fetch request: ' + url)); + + // fallback to safe empty response for other endpoints + return Promise.resolve({ + ok: true, + json: () => Promise.resolve({}), + }); }) as jest.Mock; }); +afterEach(() => { + jest.resetAllMocks(); +}); + test("renders lesson selection page", () => { render( From 693f56311815977fd210a734609575ad3bf2de96 Mon Sep 17 00:00:00 2001 From: f-hejazi Date: Tue, 18 Nov 2025 03:24:27 +0100 Subject: [PATCH 17/23] test: update LessonsSelection test to remove outdated Loading assertion --- .../src/Pages/LessonsSelection/LessonsSelection.test.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/react-ystemandchess/src/Pages/LessonsSelection/LessonsSelection.test.tsx b/react-ystemandchess/src/Pages/LessonsSelection/LessonsSelection.test.tsx index d86a8a3b..7917a13c 100644 --- a/react-ystemandchess/src/Pages/LessonsSelection/LessonsSelection.test.tsx +++ b/react-ystemandchess/src/Pages/LessonsSelection/LessonsSelection.test.tsx @@ -108,9 +108,6 @@ test("choosing lessons", async () => { fireEvent.click(basicScenario); // try displaying lessons fireEvent.click(lessonSelector); - // loading for lessons - const loadingText = await screen.findByText("Loading..."); - expect(loadingText).toBeInTheDocument(); // check if the first two lessons are displayed const qrMateText = await screen.findByText("Queen and rook mate"); expect(qrMateText).toBeInTheDocument(); From 31fcf7b9385235fb3b4f4897e0595eaa031df296 Mon Sep 17 00:00:00 2001 From: f-hejazi Date: Tue, 18 Nov 2025 03:31:23 +0100 Subject: [PATCH 18/23] test: update LessonsSelection test to remove outdated Loading assertion --- .../LessonsSelection.test.tsx | 32 ++----------------- 1 file changed, 3 insertions(+), 29 deletions(-) diff --git a/react-ystemandchess/src/Pages/LessonsSelection/LessonsSelection.test.tsx b/react-ystemandchess/src/Pages/LessonsSelection/LessonsSelection.test.tsx index 7917a13c..b24ffdbb 100644 --- a/react-ystemandchess/src/Pages/LessonsSelection/LessonsSelection.test.tsx +++ b/react-ystemandchess/src/Pages/LessonsSelection/LessonsSelection.test.tsx @@ -3,11 +3,6 @@ import LessonSelection from "./LessonsSelection.jsx"; import { MemoryRouter } from "react-router"; import { useNavigate } from 'react-router'; -// Prevent SweetAlert2 from executing browser code in Jest -jest.mock('sweetalert2', () => ({ - fire: jest.fn(), -})); - // mock navigating to lessons jest.mock('react-router', () => ({ ...jest.requireActual('react-router'), @@ -17,38 +12,17 @@ jest.mock('react-router', () => ({ // mock fetching from database beforeEach(() => { global.fetch = jest.fn((url) => { - // fetch for scenario list - if (url.includes('/api/scenarios') || url.includes('/scenarios')) { - return Promise.resolve({ - ok: true, - json: () => Promise.resolve([ - { id: 'Piece Checkmate 1 Basic checkmates', title: 'Piece Checkmate 1 Basic checkmates' }, - { id: 'Piece checkmates 2 Challenging checkmates', title: 'Piece checkmates 2 Challenging checkmates' }, - { id: 'Zugzwang Being forced to move', title: 'Zugzwang Being forced to move' }, - ]), - }); - } - - // original mock for lessons-completed + // fetching number of lessons completed for each scenario if (url.includes('Piece Checkmate 1 Basic checkmates')) { return Promise.resolve({ ok: true, - json: () => Promise.resolve(1), + json: () => Promise.resolve(1), // completed just one lesson }); } - - // fallback to safe empty response for other endpoints - return Promise.resolve({ - ok: true, - json: () => Promise.resolve({}), - }); + return Promise.reject(new Error('Unhandled fetch request: ' + url)); }) as jest.Mock; }); -afterEach(() => { - jest.resetAllMocks(); -}); - test("renders lesson selection page", () => { render( From 575dae2159f643aff03cdd2cc7496fcd0d4fd584 Mon Sep 17 00:00:00 2001 From: f-hejazi Date: Tue, 18 Nov 2025 03:45:22 +0100 Subject: [PATCH 19/23] test: update lesson visibility expectation for guests --- .../src/Pages/LessonsSelection/LessonsSelection.test.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/react-ystemandchess/src/Pages/LessonsSelection/LessonsSelection.test.tsx b/react-ystemandchess/src/Pages/LessonsSelection/LessonsSelection.test.tsx index b24ffdbb..b4665099 100644 --- a/react-ystemandchess/src/Pages/LessonsSelection/LessonsSelection.test.tsx +++ b/react-ystemandchess/src/Pages/LessonsSelection/LessonsSelection.test.tsx @@ -87,9 +87,8 @@ test("choosing lessons", async () => { expect(qrMateText).toBeInTheDocument(); const r2MateText = await screen.findByText("Two rook mate"); expect(r2MateText).toBeInTheDocument(); - // unlocked lessons will not appear await waitFor(() => { - expect(screen.queryByText("Queen and bishop mate")).not.toBeInTheDocument(); + expect(screen.getByText("Queen and bishop mate")).toBeInTheDocument(); }); }); From fbc42e4adf7544d5649e6f64e4597835fc8412c9 Mon Sep 17 00:00:00 2001 From: Sri Sai Lahari Gandrapu Date: Tue, 25 Nov 2025 21:49:54 -0500 Subject: [PATCH 20/23] feat: add student profile animations and interactions (#103) Co-authored-by: spoortip02 --- .../animations/Confetti/Confetti.scss | 25 ++++++++++ .../animations/Confetti/Confetti.tsx | 32 ++++++++++++ .../student-profile/NewStudentProfile.scss | 50 +++++++++++++++++++ .../student-profile/NewStudentProfile.tsx | 36 +++++++++++-- 4 files changed, 139 insertions(+), 4 deletions(-) create mode 100644 react-ystemandchess/src/components/animations/Confetti/Confetti.scss create mode 100644 react-ystemandchess/src/components/animations/Confetti/Confetti.tsx diff --git a/react-ystemandchess/src/components/animations/Confetti/Confetti.scss b/react-ystemandchess/src/components/animations/Confetti/Confetti.scss new file mode 100644 index 00000000..7abbfd1c --- /dev/null +++ b/react-ystemandchess/src/components/animations/Confetti/Confetti.scss @@ -0,0 +1,25 @@ +.confetti-container { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + pointer-events: none; + z-index: 1000; + overflow: hidden; +} + +.confetti-piece { + position: absolute; + width: 10px; + height: 10px; + animation: confetti-fall 3s linear forwards; +} + +@keyframes confetti-fall { + to { + transform: translateY(100vh) rotate(360deg); + opacity: 0; + } +} + diff --git a/react-ystemandchess/src/components/animations/Confetti/Confetti.tsx b/react-ystemandchess/src/components/animations/Confetti/Confetti.tsx new file mode 100644 index 00000000..1c04340d --- /dev/null +++ b/react-ystemandchess/src/components/animations/Confetti/Confetti.tsx @@ -0,0 +1,32 @@ +import React from 'react'; +import './Confetti.scss'; + +interface ConfettiProps { + show: boolean; + pieceCount?: number; +} + +const Confetti: React.FC = ({ show, pieceCount = 50 }) => { + if (!show) return null; + + const colors = ['#3a7cca', '#d64309', '#ffd700', '#ff6b6b', '#4ecdc4']; + + return ( +
); @@ -383,9 +408,12 @@ const NewStudentProfile = ({ userPortraitSrc }: any) => {
+ {/* Confetti effect */} + + {/* Welcome section with portrait */}
-
+
user portrait user portrait camera icon
@@ -395,7 +423,7 @@ const NewStudentProfile = ({ userPortraitSrc }: any) => {
{/* Analytics section: graph and metrics */} -
+

Your Progress

From a9a04aa85faea9d56919b8c1af1d9d08959ac085 Mon Sep 17 00:00:00 2001 From: Sri Sai Lahari Gandrapu Date: Sat, 6 Dec 2025 01:38:56 -0500 Subject: [PATCH 21/23] feat: update UI styling across profile and auth pages (#104) * Updated Home page * basic face cards added to the pages * Fix critical issues: restore SignUp functionality, remove devMode, restore tabs * Apply format-ui styling updates Co-authored-by: spoortip02 * fix: test cases * fix: test cases * remove bundle.js * add: change forgot password ui --------- Co-authored-by: spoortip02 --- .../src/features/auth/login/Login.scss | 229 +++--- .../src/features/auth/login/Login.tsx | 24 +- .../reset-password.component.scss | 163 +++-- .../Reset-Password/reset-password.test.tsx | 24 +- .../Reset-Password/reset-password.tsx | 53 +- .../src/features/auth/signup/SignUp.scss | 297 +++----- .../src/features/auth/signup/SignUp.test.tsx | 48 +- .../src/features/auth/signup/SignUp.tsx | 673 +++++++++--------- .../features/mentor/mentor-page/Mentor.scss | 197 +++-- .../mentor-profile/NewMentorProfile.scss | 477 ++++++++++++- .../mentor-profile/NewMentorProfile.test.tsx | 35 + .../src/features/programs/Programs.scss | 252 +++++-- .../student-profile/NewStudentProfile.scss | 244 ++++--- .../NewStudentProfile.test.tsx | 41 +- .../student-profile/NewStudentProfile.tsx | 60 +- 15 files changed, 1623 insertions(+), 1194 deletions(-) diff --git a/react-ystemandchess/src/features/auth/login/Login.scss b/react-ystemandchess/src/features/auth/login/Login.scss index 7d62bcd0..07302aae 100644 --- a/react-ystemandchess/src/features/auth/login/Login.scss +++ b/react-ystemandchess/src/features/auth/login/Login.scss @@ -1,159 +1,114 @@ -#login-h1 { - margin-top: 5rem; +body { + margin: 0; + font-family: 'Poppins', sans-serif; + background: linear-gradient(to bottom right, #fef9c3, #bbf7d0); } -// #loginError-h3 { -// display: none; // Hide the element by default - -// &.show { -// display: block; // Show the element when it has content -// } -// } - -#loginError-h3 { - color: red; +.login-page { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + min-height: 100vh; + padding: 1rem; } +.login-title { + font-size: 2.5rem; + color: #1e293b; + margin-bottom: 2rem; + text-align: center; +} -footer { - margin-top: 5% ; +.login-error { + color: #ef4444; + font-weight: 600; + margin-bottom: 1rem; + text-align: center; } -.login-input-container { + +.login-form { display: flex; flex-direction: column; - align-items: center; - justify-content: center; gap: 1.5rem; + width: 100%; + max-width: 360px; + background: white; + padding: 2rem; + border-radius: 20px; + box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1); +} - .login-input-field { - width: 100%; - height: 40px; - margin-top: 20px; - position: relative; - width: 20rem; - - label { - position: absolute; - width: 1px; - height: 1px; - padding: 0; - margin: -1px; - overflow: hidden; - clip: rect(0, 0, 0, 0); - white-space: nowrap; - border: 0; - } +.input-wrapper { + display: flex; + flex-direction: column; +} - input { - // width: 100%; - // height: 140%; - // border: none; - // border-bottom: 2px solid silver; - // font-size: 1.1rem; - // outline: none; +.input-wrapper label { + font-size: 1rem; + font-weight: 600; + color: #1e293b; + margin-bottom: 0.4rem; +} - outline-style: none; - margin-top: 20px; - padding: 15px 32px; - font-size: 22px; - font-family: Roboto !important; - font-weight: 500; - font-family: normal; - background-color: #fff; - color: #000; - border: 3px solid #d64309; - border-radius: 8px; - width: 75%; - } +.input-wrapper input { + padding: 12px 16px; + font-size: 1rem; + width: 100%; + border-radius: 8px; + border: 2px solid #cbd5e1; + transition: border 0.3s ease; + background-color: #fff; + font-family: 'Comic Sans MS', cursive; + color: #334155; + box-sizing: border-box; +} - input:focus ~ label, - input:valid ~ label { - transform: translateY(-15px); - border: none; - color: black; - } +.input-wrapper input:focus { + border-color: #3b82f6; + outline: none; +} - .underline { - position: absolute; - bottom: 0px; - height: 2px; - width: 100%; - } - .underline:before { - position: absolute; - content: ""; - height: 80%; - width: 80%; - background: black; - transform: scale(0); - bottom: -12px; - left: 32px; - } +.button-wrapper { + display: flex; + justify-content: center; + margin-top: 1rem; +} - input:focus ~ .underline:before, - input:valid ~ .underline:before { - transform: scale(1.01); - transition: transform 0.4s ease; - } +.login-form button { + padding: 12px 40px; + background-color: #3b82f6; + color: white; + font-weight: bold; + font-size: 1.1rem; + border: none; + border-radius: 25px; + box-shadow: 0 6px 10px rgba(0, 0, 0, 0.15); + transition: 0.3s; + cursor: pointer; +} - label { - position: absolute; - bottom: 0px; - left: 35px; - color: grey; - pointer-events: none; - transition: all 0.3s ease; - } - } - #button-login { - border: 2px solid; // Sets the border width and style - border-color: #3a7cca; - width: 15%; - outline-style: none; - padding-left: 2%; - padding-right: 2%; - font-family: Roboto; - font-size: 22px; - font-style: normal; - font-weight: 700; - background-color: #fff; - color: #1a63ab; - border-radius: 33px; - margin-top: 35px; - } - - button:hover { - background-color: #3a7cca; - color: #fff; - } +.login-form button:hover { + background-color: #2563eb; + transform: scale(1.05); } -.additional-options { +.login-links { + margin-top: 1.5rem; display: flex; - gap: 3rem; justify-content: center; - margin-top: 1.5rem; - - font-weight: bold; + gap: 2rem; font-size: 1rem; + font-weight: 600; +} + +.login-links a { + color: #1e293b; + text-decoration: none; + border-bottom: 2px solid transparent; + transition: border-color 0.3s; +} - a { - position: relative; - text-decoration: none; - color: black; - letter-spacing: 0.4px; - } - a::after { - content: ""; - position: absolute; - background-color: black; - height: 3px; - width: 0; - left: 0; - bottom: -5px; - transition: 0.4s; - } - a:hover::after { - width: 100%; - } -} \ No newline at end of file +.login-links a:hover { + border-color: #1e293b; +} diff --git a/react-ystemandchess/src/features/auth/login/Login.tsx b/react-ystemandchess/src/features/auth/login/Login.tsx index c15cea1c..2841ad41 100644 --- a/react-ystemandchess/src/features/auth/login/Login.tsx +++ b/react-ystemandchess/src/features/auth/login/Login.tsx @@ -109,12 +109,12 @@ const Login = () => { }; return ( -
-

Login

- {loginError && } +
+

Login

+ {loginError &&
{loginError}
} -
-
+ +
{ required />
-
+
{ required />
- +
-
+
); }; diff --git a/react-ystemandchess/src/features/auth/reset-password/Reset-Password/reset-password.component.scss b/react-ystemandchess/src/features/auth/reset-password/Reset-Password/reset-password.component.scss index c7e03184..313bc09b 100644 --- a/react-ystemandchess/src/features/auth/reset-password/Reset-Password/reset-password.component.scss +++ b/react-ystemandchess/src/features/auth/reset-password/Reset-Password/reset-password.component.scss @@ -1,99 +1,108 @@ -body { - margin: 0; - text-align: center; - padding-top: 75px; - font-family: "Roboto", sans-serif; +@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@400;600;700&display=swap"); + +.reset-page { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + min-height: 100vh; + padding: 1rem; + background: linear-gradient(to bottom right, #fef9c3, #bbf7d0); + font-family: 'Poppins', sans-serif; } -.input-container-rp { - display: inline-block; +.reset-title { + font-size: 2.5rem; + color: #1e293b; + margin-bottom: 2rem; text-align: center; - width: 100%; // Center container within body - max-width: 500px; // Set a max width for better alignment - margin: 0 auto; } -.input-container-rp li { - list-style: none; - margin-bottom: 15px; // Spacing between input fields -} -#email-rp { - outline-style: none; - margin-top: 20px; - padding: 15px 32px; - font-size: 22px; - font-family: Roboto !important; - font-weight: 500; - font-family: normal; - background-color: #fff; - color: #000; - border: 3px solid #d64309; - border-radius: 8px; - width: 75%; +.reset-error { + color: #ef4444; + font-weight: 600; + margin-bottom: 1rem; + text-align: center; } +.reset-form { + display: flex; + flex-direction: column; + gap: 1.5rem; + width: 100%; + max-width: 360px; + background: white; + padding: 2rem; + border-radius: 20px; + box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1); +} -#username-rp { - outline-style: none; - margin-top: 20px; - padding: 15px 32px; - font-size: 22px; - font-family: Roboto !important; - font-weight: 500; - font-family: normal; - background-color: #fff; - color: #000; - border: 3px solid #d64309; - border-radius: 8px; - width: 75%; +.input-wrapper { + display: flex; + flex-direction: column; + text-align: left; } -input { - outline: none; - padding: 10px 20px; // Reduced padding to better fit fields - font-size: 18px; - font-weight: 500; - background-color: white; - color: black; - border: 2px solid #d64309; - border-radius: 8px; - width: 100%; // Ensuring input takes full width of container - box-sizing: border-box; // Prevents padding overflow +.input-wrapper label { + font-size: 1rem; + font-weight: 600; + color: #1e293b; + margin-bottom: 0.5rem; } -#button-rp { - border: 2px solid; // Sets the border width and style - border-color: #3a7cca; - width: 35%; - outline-style: none; - padding-left: 2%; - padding-right: 2%; - font-family: Roboto; - font-size: 22px; - font-style: normal; - font-weight: 700; - background-color: #fff; - color: #1a63ab; - border-radius: 33px; +.reset-input { + padding: 0.75rem 1rem; + border: 2px solid #3a7cca; + border-radius: 8px; + font-size: 1rem; + font-family: 'Poppins', sans-serif; + transition: border-color 0.2s, box-shadow 0.2s; + + &:focus { + outline: none; + border-color: #3a7cca; + box-shadow: 0 0 0 3px rgba(58, 124, 202, 0.1); + } } -button:hover { - background-color: #3a7cca; +.reset-button { + padding: 0.875rem 1.5rem; + background: #3a7cca; color: #fff; + border: none; + border-radius: 8px; + font-size: 1rem; + font-weight: 600; + font-family: 'Poppins', sans-serif; + cursor: pointer; + transition: background-color 0.2s, transform 0.1s; + box-shadow: 0 2px 4px rgba(58, 124, 202, 0.2); + + &:hover { + background: #2563eb; + transform: translateY(-1px); + box-shadow: 0 4px 8px rgba(58, 124, 202, 0.3); + } + + &:active { + transform: translateY(0); + } } -h4 { - color: #333; - font-size: 20px; - margin-bottom: 20px; // Adjust spacing for header +.reset-links { + margin-top: 1.5rem; + text-align: center; } -#err-reset, #h6-reset { - color: #d64309; - font-size: 14px; - margin-top: 5px; +.reset-links a { + color: #1e293b; + text-decoration: none; + font-weight: 600; + font-family: 'Poppins', sans-serif; + transition: color 0.2s; } -body a { - padding-left: 10px; +.reset-links a:hover { + color: #3a7cca; + text-decoration: underline; } diff --git a/react-ystemandchess/src/features/auth/reset-password/Reset-Password/reset-password.test.tsx b/react-ystemandchess/src/features/auth/reset-password/Reset-Password/reset-password.test.tsx index ac30d4ae..282c9386 100644 --- a/react-ystemandchess/src/features/auth/reset-password/Reset-Password/reset-password.test.tsx +++ b/react-ystemandchess/src/features/auth/reset-password/Reset-Password/reset-password.test.tsx @@ -35,10 +35,10 @@ test('failed verification', async () => { }) as jest.Mock // input username & email - const usernameInput = screen.getByPlaceholderText('UserName'); - const emailInput = screen.getByPlaceholderText('Email'); - fireEvent.blur(usernameInput, { target: { value: 'validusername' } }); - fireEvent.blur(emailInput, { target: { value: 'validemail@example.com' } }); + const usernameInput = screen.getByPlaceholderText('Enter your username'); + const emailInput = screen.getByPlaceholderText('Enter your email'); + fireEvent.change(usernameInput, { target: { value: 'validusername' } }); + fireEvent.change(emailInput, { target: { value: 'validemail@example.com' } }); // submit credentials const button = screen.getByTestId('reset-submit'); @@ -65,10 +65,10 @@ test('network error', async () => { }) as jest.Mock // input username & email - const usernameInput = screen.getByPlaceholderText('UserName'); - const emailInput = screen.getByPlaceholderText('Email'); - fireEvent.blur(usernameInput, { target: { value: 'validusername' } }); - fireEvent.blur(emailInput, { target: { value: 'validemail@example.com' } }); + const usernameInput = screen.getByPlaceholderText('Enter your username'); + const emailInput = screen.getByPlaceholderText('Enter your email'); + fireEvent.change(usernameInput, { target: { value: 'validusername' } }); + fireEvent.change(emailInput, { target: { value: 'validemail@example.com' } }); // submit credentials const button = screen.getByTestId('reset-submit'); @@ -98,10 +98,10 @@ test('successful verification', async () => { }) as jest.Mock // input username & email - const usernameInput = screen.getByPlaceholderText('UserName'); - const emailInput = screen.getByPlaceholderText('Email'); - fireEvent.blur(usernameInput, { target: { value: 'validusername' } }); - fireEvent.blur(emailInput, { target: { value: 'validemail@example.com' } }); + const usernameInput = screen.getByPlaceholderText('Enter your username'); + const emailInput = screen.getByPlaceholderText('Enter your email'); + fireEvent.change(usernameInput, { target: { value: 'validusername' } }); + fireEvent.change(emailInput, { target: { value: 'validemail@example.com' } }); // submit credentials const button = screen.getByTestId('reset-submit'); diff --git a/react-ystemandchess/src/features/auth/reset-password/Reset-Password/reset-password.tsx b/react-ystemandchess/src/features/auth/reset-password/Reset-Password/reset-password.tsx index 10302d71..b9d6031b 100644 --- a/react-ystemandchess/src/features/auth/reset-password/Reset-Password/reset-password.tsx +++ b/react-ystemandchess/src/features/auth/reset-password/Reset-Password/reset-password.tsx @@ -1,5 +1,6 @@ import React, { useState } from 'react'; import { useNavigate } from 'react-router'; +import './reset-password.component.scss'; const ResetPassword = () => { const [username, setUsername] = useState(''); @@ -42,64 +43,58 @@ const ResetPassword = () => { }; return ( -
-

Reset Password

+
+

Reset Password

- {error != '' && ( -
+ {error && ( +
{error}
)} -
-
- + +
+ setUsername(e.target.value)} - className='w-full p-2 border rounded' + className="reset-input" required disabled={isLoading} />
-
- +
+ setEmail(e.target.value)} - className='w-full p-2 border rounded' + className="reset-input" required disabled={isLoading} />
+ +
); }; diff --git a/react-ystemandchess/src/features/auth/signup/SignUp.scss b/react-ystemandchess/src/features/auth/signup/SignUp.scss index ba1bec43..8b48861a 100644 --- a/react-ystemandchess/src/features/auth/signup/SignUp.scss +++ b/react-ystemandchess/src/features/auth/signup/SignUp.scss @@ -1,254 +1,123 @@ -h2 { - margin-top: 5rem; +body { + margin: 0; + font-family: 'Poppins', sans-serif; + background: linear-gradient(to bottom right, #fef9c3, #bbf7d0); } -.dropdown-users { - height: 40vh; - width: 37vw; - background-color: white; - overflow-y: auto; - border: 0.1rem solid black; - margin-top: -1rem; -} - - - -.signupForm { +.signup-page { display: flex; flex-direction: column; align-items: center; justify-content: center; - min-height: 100vh; /* Centers form vertically */ - width: 100%; - row-gap: 1rem; - - .sign-up-title { - font-size: 3rem; - font-weight: bold; - font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; - } + min-height: 100vh; + padding: 1rem; +} - .submit-btn { - border: 1px solid black; - color: lightgreen; - width: 30%; - background-color: whitesmoke; - } +.signup-title { + font-size: 2.5rem; + color: #1e293b; + margin-bottom: 2rem; + text-align: center; +} - .submit-btn:hover { - background-color: lightgreen; - color: whitesmoke; - } +.signup-error { + color: #ef4444; + font-weight: 600; + margin-bottom: 1rem; + text-align: center; } -div.student-form input{ +.signup-form { display: flex; - width: 20rem; - border: 2px solid black; - border-radius: 1rem; - row-gap: 1rem; + flex-direction: column; + gap: 1.5rem; + width: 100%; + max-width: 360px; + background: white; + padding: 2rem; + border-radius: 20px; + box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1); } -.student-form { +.input-wrapper { display: flex; flex-direction: column; - align-items: center; - justify-content: center; - - .remove-student { - margin-top: 0.5rem; - border: 1px solid black; - color: white; - font-size: 1rem; - width: 11rem; - background-color: lightcoral; - } - - .remove-student:hover { - color: lightcoral; - background-color: white; - } } -input[name="setMentee"] { - width: 41vw; - height: 7vh; - border-radius: 1rem; - border: 0.1rem solid black; +.input-wrapper label { + font-size: 1rem; + font-weight: 600; + color: #1e293b; + margin-bottom: 0.4rem; } -input[name="setMentee"]::placeholder { - opacity: 0.5; - font-size: 1.5rem; +.input-wrapper input, +.input-wrapper select { + padding: 12px 16px; + font-size: 1rem; + width: 100%; + border-radius: 8px; + border: 2px solid #cbd5e1; + transition: border 0.3s ease; + background-color: #fff; + font-family: 'Comic Sans MS', cursive; + color: #334155; + box-sizing: border-box; +} +.input-wrapper input:focus, +.input-wrapper select:focus { + border-color: #3b82f6; + outline: none; } -.student-section { +.terms-wrapper { display: flex; align-items: center; - justify-content: center; - - .add-student-btn { - border: 1px solid black; - color: lightgreen; - height: 3rem; - font-size: 1rem; - width: 11rem; - background-color: whitesmoke; - margin-top: 0.5rem; - } - - .add-student-btn:hover { - background-color: lightgreen; - color: whitesmoke; - } - + gap: 0.5rem; + font-size: 0.9rem; } -div.form-fields input { +.button-wrapper { display: flex; - width: 20rem; - height: 3rem; - border: 2px solid black; - border-radius: 1rem; + justify-content: center; margin-top: 1rem; } -.termsCheckbox { - display: flex; // Use flexbox for alignment - align-items: center; // Center items vertically - justify-content: center; // Center items horizontally (optional) - margin: 15px 0; // Space above and below the terms checkbox - - input[type="checkbox"] { - margin-right: 10px; // Space between checkbox and label - } +.signup-form button { + padding: 12px 40px; + background-color: #3b82f6; + color: white; + font-weight: bold; + font-size: 1.1rem; + border: none; + border-radius: 25px; + box-shadow: 0 6px 10px rgba(0, 0, 0, 0.15); + transition: 0.3s; + cursor: pointer; } -.errorMessages { - color: red; - text-align: center; - margin-bottom: 1rem; +.signup-form button:hover { + background-color: #2563eb; + transform: scale(1.05); } -.errorMessages { - display: none; // Default to not displaying any error messages - - &.visible { - display: block; // Only show when the .visible class is added - } - - h3 { - color: red; // Styling for error messages - text-align: center; // Center the error message text - } -} - -.input-container { +.signup-links { + margin-top: 1.5rem; display: flex; - flex-direction: column; - align-items: center; justify-content: center; gap: 2rem; + font-size: 1rem; + font-weight: 600; +} - .email-detail { - min-width: 41.5rem; - - #email { - min-width: 41.5rem; - } - } - - .terms-container { - font-size: 1.2rem; - display: flex; - gap: 0.5rem; - display: flex; - align-items: center; - - input { - width: 1.2rem; - height: 1.2rem; - } - } - .account-details-container { - display: flex; - gap: 1.5rem; - align-items: center; - - .account-type-container { - display: flex; - gap: 0.5rem; - font-size: 1.2rem; - align-items: center; - position: relative; - - select { - border-radius: 0.5rem; - font-size: 1rem; - padding: 0.5rem; - - option { - padding: 0.5rem; - } - } - } - } - .account-detail { - width: 100%; - height: 40px; - position: relative; - width: 20rem; - display: flex; - justify-content: center; - - input { - width: 100%; - height: 100%; - border: none; - border-bottom: 2px solid silver; - font-size: 1.1rem; - outline: none; - } - - input:focus ~ label, - input:valid ~ label { - transform: translateY(-25px); - border: none; - color: black; - } - - .underline { - position: absolute; - bottom: -2px; - height: 3px; - width: 100%; - } - .underline:before { - position: absolute; - content: ""; - height: 100%; - width: 100%; - background: black; - transform: scale(0); - bottom: -3px; - left: 2px; - } - - input:focus ~ .underline:before, - input:valid ~ .underline:before { - width: 100%; - transform: scale(1.01); - transition: transform 0.4s ease; - } +.signup-links a { + color: #1e293b; + text-decoration: none; + border-bottom: 2px solid transparent; + transition: border-color 0.3s; +} - label { - position: absolute; - bottom: 5px; - left: 1px; - color: grey; - pointer-events: none; - transition: all 0.3s ease; - } - } +.signup-links a:hover { + border-color: #1e293b; } diff --git a/react-ystemandchess/src/features/auth/signup/SignUp.test.tsx b/react-ystemandchess/src/features/auth/signup/SignUp.test.tsx index 62eae7ec..f5f98107 100644 --- a/react-ystemandchess/src/features/auth/signup/SignUp.test.tsx +++ b/react-ystemandchess/src/features/auth/signup/SignUp.test.tsx @@ -2,7 +2,6 @@ import React from "react"; import { render, screen, fireEvent } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { MemoryRouter } from "react-router"; -import { useNavigate } from 'react-router'; import SignUp from './SignUp' // mock fetching from database @@ -30,19 +29,22 @@ test("renders sign up page", () => { ); // Check if the sign up title is present - const title = screen.getByTestId("title"); + const title = screen.getByText("Create Account"); expect(title).toBeInTheDocument(); // Check if all the fields are present - const formFields = screen.getByTestId("form-fields"); - expect(formFields).toBeInTheDocument(); - const accountType = screen.getByTestId("account-type"); - expect(accountType).toBeInTheDocument(); - const terms = screen.getByTestId("terms"); - expect(terms).toBeInTheDocument(); + expect(screen.getByPlaceholderText("Enter your first name")).toBeInTheDocument(); + expect(screen.getByPlaceholderText("Enter your last name")).toBeInTheDocument(); + expect(screen.getByPlaceholderText("you@example.com")).toBeInTheDocument(); + expect(screen.getByPlaceholderText("Choose a username")).toBeInTheDocument(); + expect(screen.getByPlaceholderText("Create a password")).toBeInTheDocument(); + expect(screen.getByPlaceholderText("Re-type your password")).toBeInTheDocument(); + expect(screen.getByText("Account Type")).toBeInTheDocument(); + expect(screen.getByRole("combobox")).toBeInTheDocument(); + expect(screen.getByLabelText(/I accept the terms and conditions/)).toBeInTheDocument(); // Check if submission button is present - const submitBtn = screen.getByTestId("submit-btn"); + const submitBtn = screen.getByRole("button", { name: "Sign Up" }); expect(submitBtn).toBeInTheDocument(); }); @@ -54,49 +56,55 @@ test("field text validation", async () => { ); // check for first names that are too short - const firstName = screen.getByPlaceholderText('First name'); + const firstName = screen.getByPlaceholderText('Enter your first name'); await userEvent.type(firstName, 'f'); const firstNameError = await screen.findByText("Invalid First Name") expect(firstNameError).toBeInTheDocument(); + await userEvent.clear(firstName); await userEvent.type(firstName, 'firstname'); // check for last names that include numbers - const lastName = screen.getByPlaceholderText('Last name'); + const lastName = screen.getByPlaceholderText('Enter your last name'); await userEvent.type(lastName, '123'); const lastNameError = await screen.findByText("Invalid Last Name") expect(lastNameError).toBeInTheDocument(); + await userEvent.clear(lastName); await userEvent.type(lastName, 'lastname'); // check for invalid emails - const email = screen.getByPlaceholderText('Email'); + const email = screen.getByPlaceholderText('you@example.com'); await userEvent.type(email, 'invalid@email'); const emailError = await screen.findByText("Invalid Email") expect(emailError).toBeInTheDocument(); + await userEvent.clear(email); await userEvent.type(email, 'valid@email.com'); // check for usernames that are too long - const username = screen.getByPlaceholderText('Username'); + const username = screen.getByPlaceholderText('Choose a username'); await userEvent.type(username, '123456789012345'); const usernameError = await screen.findByText("Invalid Username") expect(usernameError).toBeInTheDocument(); + await userEvent.clear(username); await userEvent.type(username, 'username'); // check for passwords that are too short - const password = screen.getByPlaceholderText('Password'); + const password = screen.getByPlaceholderText('Create a password'); await userEvent.type(password, 'short'); const passwordError = await screen.findByText("Password must be at least 8 characters") expect(passwordError).toBeInTheDocument(); - await userEvent.type(password, 'password'); + await userEvent.clear(password); + await userEvent.type(password, 'password123'); - // check for passwords that are too short - const retype = screen.getByPlaceholderText('Re-type password'); + // check for passwords that don't match + const retype = screen.getByPlaceholderText('Re-type your password'); await userEvent.type(retype, 'different'); const retypeError = await screen.findByText("Passwords do not match") expect(retypeError).toBeInTheDocument(); - await userEvent.type(password, 'password'); + await userEvent.clear(retype); + await userEvent.type(retype, 'password123'); // when submitting without checking terms & conditions - const submitBtn = screen.getByTestId('submit-btn'); + const submitBtn = screen.getByRole("button", { name: "Sign Up" }); fireEvent.click(submitBtn); await screen.findByText("Please accept the terms and conditions."); }); @@ -129,7 +137,7 @@ test("adding children", async () => { ); // select the parent account - const selector = screen.getByTestId("account-selector"); + const selector = screen.getByRole("combobox"); fireEvent.change(selector, { target: { value: 'parent' } }); // create new student diff --git a/react-ystemandchess/src/features/auth/signup/SignUp.tsx b/react-ystemandchess/src/features/auth/signup/SignUp.tsx index c191aebe..5c01df2c 100644 --- a/react-ystemandchess/src/features/auth/signup/SignUp.tsx +++ b/react-ystemandchess/src/features/auth/signup/SignUp.tsx @@ -1,37 +1,35 @@ -import React, { useState } from 'react'; -// import { Cookie } from 'react-router'; // 'react-router' does not export 'Cookie'. This line should probably be removed or corrected. -import './SignUp.scss'; // Imports the stylesheet for this component. -import { environment } from "../../../core/environments/environment"; // Imports environment variables, likely containing API URLs. -// import StudentProfile from '../StudentProfile/Student-Profile'; // Only import if actively used in this component +import React, { useState, useEffect, useRef } from 'react'; +import './SignUp.scss'; +import { environment } from '../../../core/environments/environment'; // Define the interface for the props of the StudentTemplate component interface StudentTemplateProps { - studentUsername: string; // The student prop is a string (username) - onClick: (username: string) => void; // onClick takes the username as an argument + studentUsername: string; + onClick: (username: string) => void; } -// Renamed to start with a capital letter and typed its props +// Component for displaying student search results const StudentTemplate: React.FC = ({ studentUsername, onClick }) => { return ( -
onClick(studentUsername)} role="option"> +
onClick(studentUsername)}>
{studentUsername}
); }; 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'. - }); - - // State flags to track the validity of individual input fields. + // State to manage the form data for the user + const [formData, setFormData] = useState({ + firstName: '', + lastName: '', + email: '', + username: '', + password: '', + retypedPassword: '', + accountType: 'mentor', + }); + + // State flags to track the validity of individual input fields const [firstNameFlag, setFirstNameFlag] = useState(false); const [lastNameFlag, setLastNameFlag] = useState(false); const [emailFlag, setEmailFlag] = useState(false); @@ -41,13 +39,13 @@ const Signup = () => { const [termsFlag, setTermsFlag] = useState(false); // States for the student search dropdown - const [matchingStudents, setMatchingStudents] = useState([]); // Array of strings (usernames) - const [usernameToSearch, setUserToSearch] = useState(''); // Text in the "Find a student" input - const [activeDropdown, setActiveDropdown] = useState(false); // Controls dropdown visibility - const [dropdownLoading, setDropdownLoading] = useState(false); // Loading state for dropdown search + const [matchingStudents, setMatchingStudents] = useState([]); + const [usernameToSearch, setUserToSearch] = useState(''); + const [activeDropdown, setActiveDropdown] = useState(false); + const [dropdownLoading, setDropdownLoading] = useState(false); - // State to store any validation errors for the form fields. - const [errors, setErrors] = useState({ + // State to store any validation errors for the form fields + const [errors, setErrors] = useState({ firstName: '', lastName: '', email: '', @@ -55,25 +53,46 @@ const Signup = () => { password: '', retypePassword: '', terms: '', - general: '', // Added for general signup errors - }); - - // State to manage the parent account specific UI and data. - const [parentAccountFlag, setParentAccountFlag] = useState(false); // Flag to indicate if the selected account type is 'parent'. - const [showStudentForm, setShowStudentForm] = useState(false); // Flag to control the visibility of the student creation form. - const [students, setStudents] = useState([]); // State to store data for student accounts under a parent. - const [assignedMenteeUsername, setAssignedMenteeUsername] = useState(null); // To store the selected mentee's username - - // Handles changes to input fields in the main form. - const handleInputChange = (e: React.ChangeEvent) => { - const { name, value } = e.target; - // Updates the formData state with the new value for the changed field. - setFormData((prev) => ({ - ...prev, - [name]: value, - })); + general: '', + }); + + // State to manage the parent account specific UI and data + const [parentAccountFlag, setParentAccountFlag] = useState(false); + const [showStudentForm, setShowStudentForm] = useState(false); + const [students, setStudents] = useState([]); + const [assignedMenteeUsername, setAssignedMenteeUsername] = useState(null); + + // Handle click outside dropdown to close it + const dropdownRef = useRef(null); + const inputRef = useRef(null); + + useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + if ( + dropdownRef.current && + !dropdownRef.current.contains(event.target as Node) && + inputRef.current && + !inputRef.current.contains(event.target as Node) + ) { + setActiveDropdown(false); + } + }; + + document.addEventListener('mousedown', handleClickOutside); + return () => { + document.removeEventListener('mousedown', handleClickOutside); + }; + }, []); + + // Handles changes to input fields in the main form + const handleInputChange = (e: React.ChangeEvent) => { + const { name, value } = e.target; + setFormData((prev) => ({ + ...prev, + [name]: value, + })); - // Performs specific validation based on the input field that changed. + // Performs specific validation based on the input field that changed switch (name) { case 'firstName': firstNameVerification(value); @@ -98,7 +117,7 @@ const Signup = () => { } }; - // Verifies the format of the first name. + // Verifies the format of the first name const firstNameVerification = (firstName: string) => { const isValid = /^[A-Za-z ]{2,15}$/.test(firstName); setFirstNameFlag(isValid); @@ -109,7 +128,7 @@ const Signup = () => { return isValid; }; - // Verifies the format of the last name. + // Verifies the format of the last name const lastNameVerification = (lastName: string) => { const isValid = /^[A-Za-z]{2,15}$/.test(lastName); setLastNameFlag(isValid); @@ -120,7 +139,7 @@ const Signup = () => { return isValid; }; - // Verifies the format of the email address. + // Verifies the format of the email address const emailVerification = (email: string) => { const isValid = /^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,4}/.test(email); setEmailFlag(isValid); @@ -131,7 +150,7 @@ const Signup = () => { return isValid; }; - // Verifies the format of the username. + // Verifies the format of the username const usernameVerification = (username: string) => { const isValid = /^[a-zA-Z](\S){1,14}$/.test(username); setUserNameFlag(isValid); @@ -142,7 +161,7 @@ const Signup = () => { return isValid; }; - // Verifies the length of the password. + // Verifies the length of the password const passwordVerification = (password: string) => { const isValid = password.length >= 8; setPasswordFlag(isValid); @@ -153,7 +172,7 @@ const Signup = () => { return isValid; }; - // Verifies if the retyped password matches the original password. + // Verifies if the retyped password matches the original password const retypePasswordVerification = (retypedPassword: string, password: string) => { const isValid = retypedPassword === password; setRetypeFlag(isValid); @@ -164,16 +183,15 @@ const Signup = () => { return isValid; }; - // Verifies if the retyped password matches the original password. + // Handles terms checkbox change const termsCheckChange = (e: React.ChangeEvent) => { - setTermsFlag(e.target.checked) + setTermsFlag(e.target.checked); }; - // Handles changes to the account type dropdown. + // Handles changes to the account type dropdown const handleAccountTypeChange = (e: React.ChangeEvent) => { const isParent = e.target.value === 'parent'; setParentAccountFlag(isParent); - // Updates the accountType in the form data. setFormData((prev) => ({ ...prev, accountType: e.target.value, @@ -185,8 +203,7 @@ const Signup = () => { setMatchingStudents([]); }; - - // Adds a new student form to the UI for parent accounts. + // Adds a new student form to the UI for parent accounts const handleAddStudent = () => { const newStudent = { id: Date.now(), @@ -199,12 +216,11 @@ const Signup = () => { errors: {}, }; setStudents((prev: any) => [...prev, newStudent]); - setShowStudentForm(true); // Makes the student form visible. + setShowStudentForm(true); }; - // Handles changes to input fields within a student's form. + // Handles changes to input fields within a student's form const handleStudentInputChange = (studentId: any, field: string, value: string) => { - // Performs specific validation based on the input field that changed. switch (field) { case 'firstName': firstNameVerification(value); @@ -222,15 +238,14 @@ const Signup = () => { passwordVerification(value); break; case 'retypedPassword': - const student = students.find((s) => s.id === studentId); // ge the student from id - const password = student?.password; // get its password - retypePasswordVerification(value, password); // verify if the retype is the same + const student = students.find((s) => s.id === studentId); + const password = student?.password; + retypePasswordVerification(value, password); break; default: break; } - // Updates the specific student's data in the students array. setStudents((prev: any) => prev.map((student: any) => student.id === studentId ? { ...student, [field]: value } : student @@ -238,20 +253,18 @@ const Signup = () => { ); }; - // Removes a student form from the UI. + // 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)); - // Hides the student form if no students are present. - if (students.length === 1) { // If only one student left, and it's removed, hide the form + if (students.length === 1) { setShowStudentForm(false); } }; // Handles changes in the "Find a student" input and triggers API call const handleMenteeSearchChange = async (searchText: string) => { - setUserToSearch(searchText); // Update the controlled input's value - setAssignedMenteeUsername(null); // Clear any previously assigned mentee + setUserToSearch(searchText); + setAssignedMenteeUsername(null); if (searchText.trim() === "") { setActiveDropdown(false); @@ -263,7 +276,6 @@ const Signup = () => { setActiveDropdown(true); setDropdownLoading(true); try { - // Using query parameter for keyword const response = await fetch( `${environment.urls.middlewareURL}/user/mentorless?keyword=${searchText}`, { @@ -275,16 +287,13 @@ const Signup = () => { throw new Error(`HTTP error! status: ${response.status}`); } const usernames = await response.json(); - - // Slice the array to limit results to top 10 const top10Usernames = usernames.slice(0, 10); setMatchingStudents(top10Usernames); - setDropdownLoading(false); } catch (error) { console.error('Error fetching mentorless students:', error); setDropdownLoading(false); - setMatchingStudents([]); // Clear matches on error + setMatchingStudents([]); setErrors((prev) => ({ ...prev, general: 'Failed to fetch student list.', @@ -295,23 +304,23 @@ const Signup = () => { // Handles selecting a mentee from the dropdown const handleSelectMentee = (selectedUsername: string) => { setAssignedMenteeUsername(selectedUsername); - setUserToSearch(selectedUsername); // Set the input field to the selected username - setActiveDropdown(false); // Hide the dropdown - setMatchingStudents([]); // Clear the matching students + setUserToSearch(selectedUsername); + setActiveDropdown(false); + setMatchingStudents([]); }; - - // Handles the submission of the signup form. - const handleSubmit = async () => { + // Handles the submission of the signup form + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); console.log('Submit clicked', formData); - // check if the terms and conditions are checked + // Check if the terms and conditions are checked if (!termsFlag) { setErrors((prev) => ({ ...prev, general: 'Please accept the terms and conditions.' })); return; } - // Checks if all main form fields are valid based on their flags. + // Checks if all main form fields are valid based on their flags const isValid = firstNameFlag && lastNameFlag && @@ -320,14 +329,14 @@ const Signup = () => { passwordFlag && retypeFlag; - // If the main form is not valid, prevents submission. + // If the main form is not valid, prevents submission if (!isValid) { console.log('Form validation failed'); setErrors((prev) => ({ ...prev, general: 'Please correct the form errors.' })); return; } - // if user is a mentor but has not selected mentee + // If user is a mentor but has not selected mentee if (formData.accountType === 'mentor' && !assignedMenteeUsername) { setErrors((prev) => ({ ...prev, general: 'Please select your mentee' })); return; @@ -337,7 +346,7 @@ const Signup = () => { let signupParams: URLSearchParams; if (parentAccountFlag) { - // Maps student data into the required format for the API. + // Maps student data into the required format for the API const studentsData = students.map((student: any) => ({ first: student.firstName, last: student.lastName, @@ -354,10 +363,10 @@ const Signup = () => { password: formData.password, username: formData.username, role: formData.accountType, - students: JSON.stringify(studentsData), // Students array sent as a stringified JSON in query + students: JSON.stringify(studentsData), }); } else { - // Prepare params for non-parent accounts. + // Prepare params for non-parent accounts signupParams = new URLSearchParams({ first: formData.firstName, last: formData.lastName, @@ -370,15 +379,12 @@ const Signup = () => { // Append query parameters to the URL for the signup request signupUrl = `${signupUrl}?${signupParams.toString()}`; - - console.log('Signup Request URL:', signupUrl); // Log the full URL for debugging + console.log('Signup Request URL:', signupUrl); try { - // --- STEP 1: Perform User Signup (POST request with ALL data in query params) --- + // STEP 1: Perform User Signup const signupResponse = await fetch(signupUrl, { method: 'POST', - // IMPORTANT: Removed headers and body here, as data is now in query params. - // This prevents sending an empty body with 'Content-Type: application/json' header. }); console.log('Signup Response status:', signupResponse.status); @@ -412,15 +418,13 @@ const Signup = () => { let jwtToken: string | null = null; - // --- STEP 2: Perform Login to get JWT Token (POST request with query params) --- + // STEP 2: Perform Login to get JWT Token try { - // Construct Login URL with username and password as query parameters const loginUrl = `${environment.urls.middlewareURL}/auth/login?username=${encodeURIComponent(formData.username)}&password=${encodeURIComponent(formData.password)}`; - console.log('Login URL for token acquisition:', loginUrl); // Log the full URL for debugging + console.log('Login URL for token acquisition:', loginUrl); const loginResponse = await fetch(loginUrl, { method: 'POST', - // No 'Content-Type' header or body needed as per backend expecting query params }); console.log('Login Response status:', loginResponse.status); @@ -433,7 +437,6 @@ const Signup = () => { const loginData = await loginResponse.json(); jwtToken = loginData.token; console.log('Login successful, JWT token obtained.'); - } catch (loginError: any) { console.error('Error during login after signup:', loginError); setErrors((prev) => ({ @@ -441,21 +444,19 @@ const Signup = () => { general: `Signup successful, but failed to log in to assign mentee: ${loginError.message || 'Login network error'}`, })); window.location.href = '/'; - return; - } + return; + } - // --- STEP 3: Conditionally Perform Mentee Assignment (PUT request for mentors with query params) --- + // STEP 3: Conditionally Perform Mentee Assignment if (formData.accountType === 'mentor' && assignedMenteeUsername && jwtToken) { - // Construct URL with 'mentorship' query parameter const updateMentorshipUrl = `${environment.urls.middlewareURL}/user/updateMentorship?mentorship=${encodeURIComponent(assignedMenteeUsername)}`; try { const updateMentorshipResponse = await fetch(updateMentorshipUrl, { method: 'PUT', headers: { - 'Authorization': `Bearer ${jwtToken}`, // Bearer token is still in headers + 'Authorization': `Bearer ${jwtToken}`, }, - // No body needed as per your backend's current PUT route definition expecting query param }); console.log('Update Mentorship Response status:', updateMentorshipResponse.status); @@ -480,9 +481,8 @@ const Signup = () => { } } - // --- Final Step: Redirect to homepage after all operations --- + // Final Step: Redirect to homepage after all operations window.location.href = '/'; - } catch (error: any) { console.error('Signup error:', error); setErrors((prev) => ({ @@ -490,241 +490,246 @@ const Signup = () => { general: error.message || 'Signup failed. Please try again.', })); } - }; + }; + + return ( +
+

Create Account

+ + {errors.general &&

{errors.general}

} + +
+
+ + + {errors.firstName && {errors.firstName}} +
- return ( - e.preventDefault()} aria-labelledby="signup-title"> -

Sign up

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

{error}

: null - )} -
- -
- - - - - - - - - - - - -
- -
-

Select Account Type

- - -
- - {!parentAccountFlag && ( - <> {/* Using a React Fragment to wrap without an extra div */} - - handleMenteeSearchChange(e.target.value)} - autoComplete="off" // Prevent browser's default autocomplete - /> - {activeDropdown && ( -
{/* Keep ID for click outside handler */} - {dropdownLoading ? ( -
Loading...
- ) : ( - matchingStudents.length > 0 ? ( - matchingStudents.map((username) => ( - - )) +
+ + + {errors.email && {errors.email}} +
+ +
+ + + {errors.username && {errors.username}} +
+ +
+ + + {errors.password && {errors.password}} +
+ +
+ + + {errors.retypePassword && {errors.retypePassword}} +
+ +
+ + +
+ + {!parentAccountFlag && ( +
+ + handleMenteeSearchChange(e.target.value)} + autoComplete="off" + /> + {activeDropdown && ( +
+ {dropdownLoading ? ( +
Loading...
) : ( -
No matching students found.
- ) - )} -
- )} - - )} - - {/* 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 && ( - - )} - - {/* Maps through the students array and renders a form for each student. */} - {students.map((student: any) => ( -
- {/* Button to remove a student form. */} + matchingStudents.length > 0 ? ( + matchingStudents.map((username) => ( + + )) + ) : ( +
No matching students found.
+ ) + )} +
+ )} +
+ )} + + {parentAccountFlag && ( +
+ {!showStudentForm && ( + )} + + {students.map((student: any) => ( +
+ + + handleStudentInputChange( + student.id, + 'firstName', + e.target.value + ) + } + /> + + handleStudentInputChange( + student.id, + 'lastName', + e.target.value + ) + } + /> + + handleStudentInputChange( + student.id, + 'username', + e.target.value + ) + } + /> + + handleStudentInputChange(student.id, 'email', e.target.value) + } + /> + + handleStudentInputChange( + student.id, + 'password', + e.target.value + ) + } + /> + + handleStudentInputChange( + student.id, + 'retypedPassword', + e.target.value + ) + } + /> +
+ ))} +
+ )} - - handleStudentInputChange( - student.id, - 'firstName', - e.target.value - ) - } - /> - - handleStudentInputChange( - student.id, - 'lastName', - e.target.value - ) - } - /> - - handleStudentInputChange( - student.id, - 'username', - e.target.value - ) - } - /> - - handleStudentInputChange(student.id, 'email', e.target.value) - } - /> - - handleStudentInputChange( - student.id, - 'password', - e.target.value - ) - } - /> - - handleStudentInputChange( - student.id, - 'retypedPassword', - e.target.value - ) - } - /> -
- ))} -
- )} - -
- - -
- - {/* Submit button for the signup form. */} - -
- ); +
+ + + {errors.terms && {errors.terms}} +
+ +
+ +
+ + + +
+ ); }; export default Signup; diff --git a/react-ystemandchess/src/features/mentor/mentor-page/Mentor.scss b/react-ystemandchess/src/features/mentor/mentor-page/Mentor.scss index 713d1a04..9a964547 100644 --- a/react-ystemandchess/src/features/mentor/mentor-page/Mentor.scss +++ b/react-ystemandchess/src/features/mentor/mentor-page/Mentor.scss @@ -1,145 +1,124 @@ -.board-container { +.mentor-roles { + display: flex; + flex-wrap: wrap; + justify-content: center; + gap: 3rem; + margin-bottom: 3rem; +} + +.mentor-card { + flex: 1 1 300px; + max-width: 400px; + min-width: 280px; + padding: 2.5rem; + border-radius: 20px; + display: flex; + flex-direction: column; + align-items: center; + backdrop-filter: blur(10px); + transition: all 0.4s cubic-bezier(0.23, 1, 0.32, 1); + box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05); text-align: center; - padding: 20px; +} - .flex-container { +.mentor-card:hover { + transform: translateY(-10px) scale(1.02); + box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2); +} + +.icon-container { + width: 80px; + height: 80px; + border-radius: 50%; + background: rgba(255, 255, 255, 0.2); display: flex; align-items: center; - justify-content: space-between; - - .text-content { - flex: 1; - text-align: left; - - h1 { - font-size: 2em; - color: #333; - margin-bottom: 10px; - } + justify-content: center; + margin-bottom: 1.5rem; +} - p { - font-size: 1.2em; - color: #666; - margin-bottom: 20px; - } +.icon-container span { + font-size: 2rem; + color: white; +} - .apply-button { - @extend .apply-button; // Reuse the same button styling +.transform-icon:hover span { + transform: rotate(360deg); + transition: transform 0.6s ease-in-out; } - } - .image-content { - flex: 1; - text-align: right; +.breathe-icon span { + animation: breathe 2.5s ease-in-out infinite; +} - img { - max-width: 100%; - height: auto; - } +@keyframes breathe { + 0%, 100% { + transform: scale(1); + } + 50% { + transform: scale(1.15); } } - .line-break { - margin-top: 20px; - margin-bottom: 20px; +.mentor-card h3 { + font-size: 1.8rem; + font-weight: 700; + margin-bottom: 1rem; } - .mentor-details img { - width: 100%; - height: auto; - margin-bottom: 20px; +.mentor-card p { + font-size: 1.1rem; + line-height: 1.6; +} + +.green-card { + background: linear-gradient(145deg, #73b313 0%, #8bc34a 100%); + color: #ffffff; } - .mentor-roles { - display: flex; - justify-content: center; - margin-bottom: 20px; +.white-card { + background: linear-gradient(145deg, #ffffff 0%, #f8f9ff 100%); + border: 2px solid #73b313; + color: #333; +} - img { - width: 45%; - height: auto; - margin: 0 5px; - } - } +.apply-wrapper { + text-align: center; } .apply-button { - background-color: #ead94c; /* Same color as view-button */ + background-color: #0f172a; border: none; - border-radius: 5px; - padding: 10px 20px; - font-size: 1em; + border-radius: 9999px; + padding: 0.8rem 2rem; + font-size: 1.1rem; + color: #fff; cursor: pointer; - font-weight: bold; - transition: background-color 0.3s, transform 0.2s; + font-weight: 600; + transition: transform 0.2s ease, box-shadow 0.2s ease; +} - &:hover { - background-color: #ffe066; /* Brighter yellow on hover */ - transform: translateY(-1px); /* Slight push up on hover */ +.apply-button:hover { + transform: translateY(-2px); + box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2); } - &:active { - transform: translateY(1px); /* Slight push down on click */ +.apply-button:active { + transform: translateY(1px); } -} -@media screen and (max-width: 768px) { - .board-container { - padding: 10px; - .flex-container { +@media (max-width: 768px) { + .hero-section { flex-direction: column; - align-items: center; - gap: 1.5rem; - - .text-content { text-align: center; - - h1 { - font-size: 1.5em; - } - - p { - font-size: 1em; - } - - .apply-button { - width: 100%; } - } - .image-content { + .hero-text { text-align: center; - - img { - width: 100%; - max-width: 300px; - } - } - } - - .mentor-details img { - margin-bottom: 10px; - } - - .mentor-roles { - flex-direction: column; - align-items: center; - gap: 10px; - - img { - width: 80%; - margin: 0; - } - } - - .line-break { - margin-top: 10px; - margin-bottom: 10px; - } } - .apply-button { - font-size: 1.1em; - padding: 12px; + .mentor-card { + width: 100%; + max-width: 350px; } } diff --git a/react-ystemandchess/src/features/mentor/mentor-profile/NewMentorProfile.scss b/react-ystemandchess/src/features/mentor/mentor-profile/NewMentorProfile.scss index 349d5699..e0c48df8 100644 --- a/react-ystemandchess/src/features/mentor/mentor-profile/NewMentorProfile.scss +++ b/react-ystemandchess/src/features/mentor/mentor-profile/NewMentorProfile.scss @@ -1,29 +1,472 @@ +// ===================================== +// Font Imports +// ===================================== + +@import url("https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,400;0,700;0,900;1,400;1,700;1,900&display=swap"); +@import url("https://fonts.googleapis.com/css2?family=Lato:wght@700&display=swap"); + +// ===================================== +// Color Variables +// ===================================== + +$brand-color-primary: #ffffff; +$brand-color-secondary: #eaf4f4; +$brand-color-tertiary: #3a7cca; +$brand-color-accent: #d64309; +$brand-color-background-grey: #f7f7f7; +$inventory-tab-color: #ffffff; +$inventory-tab-active: #3a7cca; + +// ===================================== +// Main Container +// ===================================== + +#main-inventory-content { + background-color: $brand-color-primary; + font-family: "Roboto", sans-serif; + min-height: 100vh; + position: relative; + + // =========================== + // Toolbar Section + // =========================== + + .inv-toolbar { + width: 100%; + height: 8.3rem; + background-color: $brand-color-tertiary; + display: flex; + align-items: center; + justify-content: center; + } + + .inv-toolbar-buttons { + width: clamp(1200px, 80%, 1700px); + display: flex; + justify-content: space-between; + } + + .toolbar-button { + position: relative; + width: 21.6675rem; + height: 6.75rem; + padding: 0; + margin: 0; + border: none; + background: none; + border-radius: 8px; + cursor: pointer; + overflow: hidden; + + .toolbar-icon { + width: 100%; + height: 100%; + transition: filter 0.2s ease; + display: block; + color: #FDD835; + object-fit: contain; + } + + &:hover .toolbar-icon, + &.active .toolbar-icon { + color: #FFFF00; + } + } + + // =========================== + // Intro Section + // =========================== + + .inv-intro { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + padding: 0; + + .inv-intro-portrait { + position: relative; + width: 120px; + height: 120px; + border-radius: 50%; + background: #ffffff; + border: 4px solid #3a7cca; + display: flex; + align-items: center; + justify-content: center; + box-shadow: 0 4px 12px rgba(58, 124, 202, 0.3); + margin-top: 2rem; + + .inv-intro-portrait-face { + width: 60%; + height: 60%; + object-fit: contain; + filter: brightness(0) saturate(100%) invert(29%) sepia(81%) saturate(746%) hue-rotate(189deg) brightness(95%) contrast(91%); + } + + .inv-intro-portrait-camera { + position: absolute; + bottom: 0; + right: 0; + transform: translate(30%, 30%); + width: 30px; + height: 30px; + background: #ffffff; + border: 2px solid #3a7cca; + border-radius: 50%; + padding: 4px; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); + } + } + + .inv-intro-welcome { + margin-top: 1.5rem; + + h1 { + font-size: 1.8rem; + font-weight: 700; + color: #333; + margin: 0 0 1rem 0; + padding: 0; + } + } + } + + // =========================== + // Inventory Section + // =========================== + + .inv-inventory { + background: $brand-color-background-grey; + width: clamp(300px, 80%, 1200px); + margin: 2rem auto; + border-radius: 1rem; + overflow: hidden; + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); + + .inv-inventory-topbar { + background: $brand-color-tertiary; + padding: 1rem 0; + margin: 0; + + .progress-heading { + font-family: "Lato", sans-serif; + font-weight: 700; + font-size: 2.25rem; + color: #ffffff; + margin: 0; + } + } + + .inv-inventory-analytics { + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: center; + padding: 2rem; + + .inv-inventory-analytics-graph { + height: 18rem; + width: 40rem; + padding: 0.8rem; + margin-right: 3rem; + } + + .inv-inventory-analytics-metrics { + text-align: left; + + h3 { + font-size: 1.2rem; + font-weight: bold; + margin: 0 0 1rem 0; + color: #333; + } + + ul { + list-style: none; + padding: 0; + + li { + margin-bottom: 0.5rem; + color: #333; + font-weight: 500; + + strong { + color: $brand-color-accent; + } + } + } + } + } + + // =========================== + // Inventory Tab Layout + // =========================== + + .inv-inventory-content-section { + display: grid; + grid-template-columns: 30% 70%; + background: $brand-color-primary; + + .inv-inventory-content-tabs { + position: relative; + + ul { + list-style: none; + padding: 1rem; + background: $brand-color-secondary; + border-right: 1px solid #ddd; + margin: 0; + + li { + &:first-child .inventory-tab { + border-top-left-radius: 0.5rem; + } + + &:last-child .inventory-tab { + border-bottom-left-radius: 0.5rem; + margin-bottom: 0; + } + } + } + } + + .inventory-tab { + all: unset; + position: relative; + display: flex; + align-items: center; + cursor: pointer; + padding: 1rem; + margin-bottom: 1rem; + border-radius: 0.5rem; + transition: background 0.3s; + + img { + width: 32px; + height: 32px; + max-width: 32px; + max-height: 32px; + object-fit: contain; + margin-right: 0.75rem; + flex-shrink: 0; + filter: grayscale(1); + transition: filter 0.3s, transform 0.3s; + } + + li { + list-style: none; + font-size: 1rem; + font-weight: 500; + color: #333; + } + + &:hover { + background: lighten($brand-color-tertiary, 40%); + } + + &.active-tab { + background: $brand-color-tertiary; + + img { + filter: none; + } + + li { + color: white; + } + } + } + + .inv-inventory-content-content { + padding: 2rem; + overflow-y: auto; + } + + .inventory-content { + position: relative; + display: none; + height: 100%; + width: 100%; + + &.active-content { + display: block; + } + + .inventory-content-headingbar { + display: flex; + justify-content: space-between; + align-items: baseline; + border-bottom: 1px solid #ccc; + margin-bottom: 1rem; + padding: 0; + + h2 { + font-size: 1.5rem; + font-weight: 700; + color: #333; + margin: 0; + padding: 0; + } + + h4 { + font-size: 0.9rem; + color: #666; + margin: 0; + padding: 0; + } + } + + .inventory-content-body { + position: relative; + display: grid; + max-height: 500px; + overflow-y: auto; + scrollbar-width: none; + } + + .inventory-content-line { + position: absolute; + height: 78%; + top: 20%; + left: 3.2%; + + &::after { + content: ""; + position: absolute; + z-index: 0; + top: 0; + bottom: 0; + left: 50%; + border-left: 3px dotted #222; + } + } + + .inventory-content-timecard { + display: flex; + justify-content: space-between; + align-items: center; + background: #fff; + border: 1px solid #ddd; + padding: 1rem; + border-radius: 0.5rem; + margin-bottom: 1rem; + + p { + margin: 0; + + strong { + text-decoration: underline; + cursor: pointer; + + &:hover { + color: $brand-color-tertiary; + } + } + } + } + + .inventory-date { + font-family: "Roboto", sans-serif; + font-weight: 400; + font-size: 1.0rem; + color: #000; + } + + .inventory-time { + font-family: "Roboto", sans-serif; + font-weight: 400; + font-size: 0.8125rem; + color: #000; + } + } + } + } + + // =========================== + // Animation States + // =========================== + + // Celebration pulse animation + .inv-inventory.celebrate { + animation: celebrate-pulse 1s ease-in-out; + } + + @keyframes celebrate-pulse { + 0%, + 100% { + transform: scale(1); + } + 50% { + transform: scale(1.02); + } + } + + // Portrait click animation + .inv-intro-portrait { + cursor: pointer; + transition: transform 0.2s ease; + + &:hover { + transform: scale(1.05); + } + + &:active { + transform: scale(0.95); + } + } + + // Enhanced loading spinner + .loading-spinner { + display: inline-block; + width: 20px; + height: 20px; + border: 3px solid rgba(58, 124, 202, 0.3); + border-radius: 50%; + border-top-color: $brand-color-tertiary; + animation: spin 1s ease-in-out infinite; + } + + @keyframes spin { + to { + transform: rotate(360deg); + } + } +} + +// =========================== +// Mentor-specific styles +// =========================== + .topbar-greeting { - color: black; - font-size: 20px; + color: black; + font-size: 20px; } .no-student-message { - color: black; - font-size: 20px; - margin-top: 20px; - border: 1px solid rgb(209, 86, 86); - width: 60%; - margin: 20px auto; - padding: 20px; - background-color: rgba(248, 46, 46, 0.2); - border-radius: 20px; + color: black; + font-size: 20px; + margin-top: 20px; + border: 1px solid rgb(209, 86, 86); + width: 60%; + margin: 20px auto; + padding: 20px; + background-color: rgba(248, 46, 46, 0.2); + border-radius: 20px; } .inventory-tab-img { - max-width: 50px; - height: auto; + max-width: 32px; + max-height: 32px; + width: 32px; + height: 32px; + object-fit: contain; display: inline-block; vertical-align: middle; } .no-student-message h1 { - font-size: 24px; - margin-bottom: 10px; - font-weight: bold; -} \ No newline at end of file + font-size: 24px; + margin-bottom: 10px; + font-weight: bold; +} diff --git a/react-ystemandchess/src/features/mentor/mentor-profile/NewMentorProfile.test.tsx b/react-ystemandchess/src/features/mentor/mentor-profile/NewMentorProfile.test.tsx index e83ca584..7824c77b 100644 --- a/react-ystemandchess/src/features/mentor/mentor-profile/NewMentorProfile.test.tsx +++ b/react-ystemandchess/src/features/mentor/mentor-profile/NewMentorProfile.test.tsx @@ -17,6 +17,41 @@ jest.mock('react-chartjs-2', () => ({ Line: () =>
, })); +// mock SweetAlert2 to avoid CSS parsing errors in jsdom +jest.mock('sweetalert2', () => { + const mockSwal = { + fire: jest.fn(() => Promise.resolve({ isConfirmed: true, isDenied: false, isDismissed: false })), + mixin: jest.fn(), + bindClickHandler: jest.fn(), + stopTimer: jest.fn(), + resumeTimer: jest.fn(), + toggleTimer: jest.fn(), + isTimerRunning: jest.fn(), + incrementTimer: jest.fn(), + showLoading: jest.fn(), + hideLoading: jest.fn(), + clickConfirm: jest.fn(), + clickCancel: jest.fn(), + clickDeny: jest.fn(), + close: jest.fn(), + enableButtons: jest.fn(), + disableButtons: jest.fn(), + showValidationMessage: jest.fn(), + resetValidationMessage: jest.fn(), + getInput: jest.fn(), + }; + return { + __esModule: true, + default: mockSwal, + }; +}); + +// mock Puzzles component to avoid SweetAlert2 CSS parsing issues +jest.mock('../../puzzles/puzzles-page/Puzzles', () => ({ + __esModule: true, + default: () =>
, +})); + // ------------- HELPER FUNCTIONS ------------- // helper to for date formatting to match with component diff --git a/react-ystemandchess/src/features/programs/Programs.scss b/react-ystemandchess/src/features/programs/Programs.scss index b59a0ec6..735b0340 100644 --- a/react-ystemandchess/src/features/programs/Programs.scss +++ b/react-ystemandchess/src/features/programs/Programs.scss @@ -1,100 +1,194 @@ +.programs-container { + max-width: 1200px; + margin: 0 auto; + padding: 2rem 1rem; +} + +.hero-wrapper { + background: linear-gradient(145deg, #f0f8ec 0%, #ffffff 100%); + border-radius: 20px; + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.07); + padding: 4rem 2rem; + margin-bottom: 5rem; + position: relative; +} + +.hero-wrapper::after { + content: ""; + position: absolute; + bottom: -20px; + left: 50%; + transform: translateX(-50%); + width: 60px; + height: 4px; + border-radius: 2px; + background: #73b313; +} + .hero-section { display: flex; - justify-content: center; align-items: center; - gap: 8rem; - margin: 5rem 7rem; - border-radius: 1rem; - background-color: #3f8cdf; - padding: 2rem; - - img { - object-fit: contain; - border-radius: 1rem; - box-shadow: 0.1rem 0.1rem 0.1rem black; - } + justify-content: space-between; + flex-wrap: wrap; + gap: 4rem; + position: relative; +} - .programs-text { - text-align: left; - color: rgb(255, 250, 250); - max-width: 65%; - display: flex; - flex-direction: column; - gap: 0.4rem; +.hero-section img { + flex: 1 1 400px; + min-width: 300px; + max-width: 500px; + width: 100%; + border-radius: 20px; + object-fit: cover; + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15); +} - p { - font-size: 1.2rem; - } - ul { - margin: 0; - li { - font-size: 1.2rem; - } - } +.programs-text { + flex: 1 1 400px; + min-width: 300px; + max-width: 600px; + display: flex; + flex-direction: column; + gap: 1.2rem; + text-align: left; + color: #0f172a; + line-height: 1.7; +} - h2 { - font-size: 2.5rem; - margin: 0; - } - h4 { - margin: 0; - font-size: 1.5rem; - } - } +.programs-text h2 { + font-size: 2.5rem; + font-weight: 700; + margin: 0; +} - a { - margin-top: 0.4rem; - button { - border: none; - border-radius: 0.5rem; - background: transparent; - width: 12rem; - height: 3rem; - cursor: pointer; - font-size: 1.2rem; - background-color: #eef36a; - } - button:hover { - transition: 0.3s; - transform: scale(1.1); - } - } +.programs-text h4 { + font-size: 1.2rem; + font-weight: 500; + margin: 0; +} + +.programs-text p { + font-size: 1.1rem; + margin: 0; +} + +.programs-text ul { + margin: 0; + padding-left: 1.5rem; +} + +.programs-text li { + font-size: 1.1rem; + margin-bottom: 0.4rem; +} + +.programs-text a button { + margin-top: 1rem; + background: #0f172a; + color: #fff; + border: none; + border-radius: 9999px; + padding: 0.8rem 2rem; + font-size: 1rem; + cursor: pointer; + transition: transform 0.2s ease, box-shadow 0.2s ease; +} + +.programs-text a button:hover { + transform: translateY(-2px); + box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2); } .sub-terms { display: flex; - margin: 5rem 7rem; - gap: 10rem; + flex-wrap: wrap; + gap: 3rem; + justify-content: center; +} - .sub-terms-left { - height: 80%; - } +.sub-terms-left, +.sub-terms-right { + position: relative; + display: flex; + flex-direction: column; + flex: 1 1 350px; + max-width: 500px; + min-width: 300px; + padding: 2.5rem; + border-radius: 20px; + backdrop-filter: blur(10px); + transition: all 0.4s cubic-bezier(0.23, 1, 0.32, 1); + transform-origin: center; + will-change: transform; + overflow: hidden; + box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05); +} - .sub-terms-left, - .sub-terms-right { - text-align: left; - background-color: #e2aa03; - border-radius: 1rem; - padding: 2rem; - font-size: 1.4rem; - flex: 1; - color: white; - display: flex; +.sub-terms-left:hover, +.sub-terms-right:hover { + transform: translateY(-10px) scale(1.02); + box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3); +} + +.sub-terms-left { + background: linear-gradient(145deg, #73b313 0%, #8bc34a 100%); + color: #ffffff; +} + +.sub-terms-right { + background: linear-gradient(145deg, #ffffff 0%, #f8f9ff 100%); + color: #333; + border: 2px solid #73b313; +} + +.sub-terms-left h3, +.sub-terms-right h3 { + font-size: 2rem; + font-weight: 700; + text-align: center; + margin: 0 0 1rem 0; +} + +.sub-terms-left h5, +.sub-terms-right h5 { + font-size: 1.3rem; + font-weight: 600; + text-align: center; + margin: 0 0 1rem 0; +} + +.sub-terms-left p, +.sub-terms-right p { + font-size: 1.1rem; + line-height: 1.6; + margin: 0 0 1rem 0; +} + +@media (max-width: 768px) { + .hero-section { flex-direction: column; - gap: 0.8rem; + text-align: center; + } - p { - margin: 0; - } + .programs-text { + text-align: center; + align-items: center; } - h3 { - font-size: 2.4rem; - margin: 0; + .programs-text ul { + text-align: left; + } + + .sub-terms { + flex-direction: column; } - h5 { - font-size: 1.7rem; - margin: 0; + + .sub-terms-left, + .sub-terms-right { + width: 100%; + max-width: 500px; + margin: 0 auto; } } diff --git a/react-ystemandchess/src/features/student/student-profile/NewStudentProfile.scss b/react-ystemandchess/src/features/student/student-profile/NewStudentProfile.scss index cc8a9908..9b684035 100644 --- a/react-ystemandchess/src/features/student/student-profile/NewStudentProfile.scss +++ b/react-ystemandchess/src/features/student/student-profile/NewStudentProfile.scss @@ -9,10 +9,13 @@ // Color Variables // ===================================== -$brand-color-primary: #e5f3d2; -$brand-color-secondary: #C8F2AE; -$brand-color-tertiary: #7fcc26; -$brand-color-background-grey: #d4dddd; +$brand-color-primary: #ffffff; +$brand-color-secondary: #eaf4f4; +$brand-color-tertiary: #3a7cca; +$brand-color-accent: #d64309; +$brand-color-background-grey: #f7f7f7; +$inventory-tab-color: #ffffff; +$inventory-tab-active: #3a7cca; // ===================================== // Main Container @@ -20,11 +23,8 @@ $brand-color-background-grey: #d4dddd; #main-inventory-content { background-color: $brand-color-primary; - background-image: url("../../../assets/images/chess-piece-pattern.png"); - background-size: 95%; - background-repeat: repeat; font-family: "Roboto", sans-serif; - padding-bottom: 3.0rem; + min-height: 100vh; position: relative; // =========================== @@ -86,38 +86,49 @@ $brand-color-background-grey: #d4dddd; .inv-intro-portrait { position: relative; - border: 2px solid #000; - background: $brand-color-background-grey; - border-radius: 6px; - width: 9.375rem; - height: 9.375rem; + width: 120px; + height: 120px; + border-radius: 50%; + background: #ffffff; + border: 4px solid #3a7cca; + display: flex; + align-items: center; + justify-content: center; + box-shadow: 0 4px 12px rgba(58, 124, 202, 0.3); margin-top: 2rem; .inv-intro-portrait-face { - width: 100%; - height: 100%; + width: 60%; + height: 60%; + object-fit: contain; + filter: brightness(0) saturate(100%) invert(29%) sepia(81%) saturate(746%) hue-rotate(189deg) brightness(95%) contrast(91%); } .inv-intro-portrait-camera { position: absolute; - background: rgba(255, 255, 255, 0.85); - border-radius: 6px; bottom: 0; right: 0; - width: 2.9869rem; - height: 2.9869rem; - padding: 0.0625rem; - margin: 0.25rem; + transform: translate(30%, 30%); + width: 30px; + height: 30px; + background: #ffffff; + border: 2px solid #3a7cca; + border-radius: 50%; + padding: 4px; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); } } - .inv-intro-welcome > h1 { - font-family: "Lato", sans-serif; + .inv-intro-welcome { + margin-top: 1.5rem; + + h1 { + font-size: 1.8rem; + font-weight: 700; + color: #333; margin: 0 0 1rem 0; padding: 0; - font-size: 2.5rem; - font-weight: bold; - color: #000; + } } } @@ -127,29 +138,32 @@ $brand-color-background-grey: #d4dddd; .inv-inventory { background: $brand-color-background-grey; - width: clamp(1100px, 90%, 1500px); - margin: auto; - border-radius: 0.8rem; + width: clamp(300px, 80%, 1200px); + margin: 2rem auto; + border-radius: 1rem; + overflow: hidden; + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); .inv-inventory-topbar { background: $brand-color-tertiary; - padding: 0.2em 0; + padding: 1rem 0; margin: 0; .progress-heading { font-family: "Lato", sans-serif; font-weight: 700; font-size: 2.25rem; - color: #000; + color: #ffffff; margin: 0; } } .inv-inventory-analytics { display: flex; + flex-wrap: wrap; align-items: center; justify-content: center; - padding: 3% 0 0; + padding: 2rem; .inv-inventory-analytics-graph { height: 18rem; @@ -164,27 +178,21 @@ $brand-color-background-grey: #d4dddd; h3 { font-size: 1.2rem; font-weight: bold; - margin: 0 0 1.5rem 0; + margin: 0 0 1rem 0; + color: #333; } ul { - padding: 0 0.2rem; + list-style: none; + padding: 0; li { - position: relative; - margin: 0 0 12px 0; - list-style: none; - - &::before { - content: ""; - position: relative; - display: inline-block; - width: 0.9375rem; - height: 0.9375rem; - border-radius: 50%; - margin-right: 1rem; - background-color: $brand-color-tertiary; - border: 4px solid #000; + margin-bottom: 0.5rem; + color: #333; + font-weight: 500; + + strong { + color: $brand-color-accent; } } } @@ -196,30 +204,27 @@ $brand-color-background-grey: #d4dddd; // =========================== .inv-inventory-content-section { - background: $brand-color-secondary; - width: 100%; - height: 100%; - margin: 2rem auto; - border-radius: 1rem; display: grid; - grid-template-columns: 35% 65%; + grid-template-columns: 30% 70%; + background: $brand-color-primary; .inv-inventory-content-tabs { position: relative; ul { - background: $brand-color-background-grey; - padding: 0; - margin: 0; list-style: none; + padding: 1rem; + background: $brand-color-secondary; + border-right: 1px solid #ddd; + margin: 0; li { &:first-child .inventory-tab { - border-top-left-radius: 1rem; + border-top-left-radius: 0.5rem; } &:last-child .inventory-tab { - border-bottom-left-radius: 1rem; + border-bottom-left-radius: 0.5rem; margin-bottom: 0; } } @@ -231,35 +236,51 @@ $brand-color-background-grey: #d4dddd; position: relative; display: flex; align-items: center; - height: 4.6875rem; - width: 100%; - margin-bottom: 1rem; - overflow: hidden; cursor: pointer; + padding: 1rem; + margin-bottom: 1rem; + border-radius: 0.5rem; + transition: background 0.3s; img { - width: 100%; - height: 100%; - object-fit: cover; - margin-right: 0.25rem; - transition: width 0.2s ease; - filter: none !important; + width: 32px; + height: 32px; + max-width: 32px; + max-height: 32px; + object-fit: contain; + margin-right: 0.75rem; + flex-shrink: 0; + filter: grayscale(1); + transition: filter 0.3s, transform 0.3s; + } + + li { + list-style: none; + font-size: 1rem; + font-weight: 500; + color: #333; + } + + &:hover { + background: lighten($brand-color-tertiary, 40%); } &.active-tab { - background-color: $brand-color-secondary; + background: $brand-color-tertiary; img { - transform: none; - margin-right: 0; + filter: none; + } + + li { + color: white; } } } .inv-inventory-content-content { - padding: 1rem 4rem; - display: flex; - align-items: center; + padding: 2rem; + overflow-y: auto; } .inventory-content { @@ -273,37 +294,33 @@ $brand-color-background-grey: #d4dddd; } .inventory-content-headingbar { - min-width: 35rem; display: flex; justify-content: space-between; - align-items: flex-end; - padding: 1rem 0 0.7rem 0; - border-bottom: 1px solid rgb(120, 120, 120); + align-items: baseline; + border-bottom: 1px solid #ccc; + margin-bottom: 1rem; + padding: 0; h2 { - font-family: "Roboto", sans-serif; + font-size: 1.5rem; font-weight: 700; - font-size: 2.0rem; + color: #333; margin: 0; padding: 0; - position: relative; - top: 0.6875rem; } h4 { - color: #B0B0B0; - font-family: "Roboto", sans-serif; - font-weight: 500; - font-size: 1.0rem; - position: relative; - top: 0.3125rem; + font-size: 0.9rem; + color: #666; + margin: 0; + padding: 0; } } .inventory-content-body { position: relative; display: grid; - height: 38.55rem; + max-height: 500px; overflow-y: auto; scrollbar-width: none; } @@ -326,44 +343,25 @@ $brand-color-background-grey: #d4dddd; } .inventory-content-timecard { - display: grid; - grid-template-columns: 10% 45% 45%; - text-align: left; - margin: 3rem 0; - - > div { display: flex; - justify-content: flex-start; + justify-content: space-between; align-items: center; - } + background: #fff; + border: 1px solid #ddd; + padding: 1rem; + border-radius: 0.5rem; + margin-bottom: 1rem; - .inventory-content-col1 { - &::before { - content: ""; - position: relative; - display: inline-block; - width: 2.375rem; - height: 2.375rem; - border-radius: 50%; - margin-right: 1rem; - background-color: $brand-color-tertiary; - border: 9px solid #000; - } - } - - .inventory-content-col2 { - margin-left: 2rem; - position: relative; - top: 0.25rem; - } - - .inventory-content-col3 { - position: relative; - top: 0.1875rem; + p { + margin: 0; - p > strong { + strong { text-decoration: underline; cursor: pointer; + + &:hover { + color: $brand-color-tertiary; + } } } } @@ -423,7 +421,7 @@ $brand-color-background-grey: #d4dddd; display: inline-block; width: 20px; height: 20px; - border: 3px solid rgba(127, 204, 38, 0.3); + border: 3px solid rgba(58, 124, 202, 0.3); border-radius: 50%; border-top-color: $brand-color-tertiary; animation: spin 1s ease-in-out infinite; diff --git a/react-ystemandchess/src/features/student/student-profile/NewStudentProfile.test.tsx b/react-ystemandchess/src/features/student/student-profile/NewStudentProfile.test.tsx index df4b1f33..6124cd95 100644 --- a/react-ystemandchess/src/features/student/student-profile/NewStudentProfile.test.tsx +++ b/react-ystemandchess/src/features/student/student-profile/NewStudentProfile.test.tsx @@ -18,12 +18,47 @@ jest.mock('../../../globals', () => ({ SetPermissionLevel: jest.fn(), })); +// mock SweetAlert2 to avoid CSS parsing errors in jsdom +jest.mock('sweetalert2', () => { + const mockSwal = { + fire: jest.fn(() => Promise.resolve({ isConfirmed: true, isDenied: false, isDismissed: false })), + mixin: jest.fn(), + bindClickHandler: jest.fn(), + stopTimer: jest.fn(), + resumeTimer: jest.fn(), + toggleTimer: jest.fn(), + isTimerRunning: jest.fn(), + incrementTimer: jest.fn(), + showLoading: jest.fn(), + hideLoading: jest.fn(), + clickConfirm: jest.fn(), + clickCancel: jest.fn(), + clickDeny: jest.fn(), + close: jest.fn(), + enableButtons: jest.fn(), + disableButtons: jest.fn(), + showValidationMessage: jest.fn(), + resetValidationMessage: jest.fn(), + getInput: jest.fn(), + }; + return { + __esModule: true, + default: mockSwal, + }; +}); + // mock the chart jest.mock('react-chartjs-2', () => ({ __esModule: true, Line: () =>
, })); +// mock Puzzles component to avoid SweetAlert2 CSS parsing issues +jest.mock('../../puzzles/puzzles-page/Puzzles', () => ({ + __esModule: true, + default: () =>
, +})); + // ------------- HELPER FUNCTIONS ------------- // helper to for date formatting to match with component @@ -141,9 +176,9 @@ describe('NewStudentProfile', () => { expect(await screen.findByText(/Time Spent:/i)).toBeInTheDocument(); // check if some of the tabs (by aria-label) are rendered - expect(await screen.findByRole('button', { name: /activity/i })).toBeInTheDocument(); - expect(await screen.findByRole('button', { name: /games/i })).toBeInTheDocument(); - expect(await screen.findByRole('button', { name: /mentor/i })).toBeInTheDocument(); + expect(await screen.findByLabelText(/activity/i)).toBeInTheDocument(); + expect(await screen.findByLabelText(/games/i)).toBeInTheDocument(); + expect(await screen.findByLabelText(/mentor/i)).toBeInTheDocument(); }); test('renders time stats', async () => { diff --git a/react-ystemandchess/src/features/student/student-profile/NewStudentProfile.tsx b/react-ystemandchess/src/features/student/student-profile/NewStudentProfile.tsx index 329a7659..163535e3 100644 --- a/react-ystemandchess/src/features/student/student-profile/NewStudentProfile.tsx +++ b/react-ystemandchess/src/features/student/student-profile/NewStudentProfile.tsx @@ -20,16 +20,7 @@ import { ReactComponent as ActivitiesIcon } from "../../../assets/images/student import { ReactComponent as BadgesIcon } from "../../../assets/images/student/badges_button.svg"; import { ReactComponent as LeaderboardIcon } from "../../../assets/images/student/leaderboard_button.svg"; -// Tab images -import activityTab from "../../../assets/images/student/activity_tab.png"; -import mentorTab from "../../../assets/images/student/mento_tab.png"; -import prodevTab from "../../../assets/images/student/prodev_tab.png"; -import chessTab from "../../../assets/images/student/chess_tab.png"; -import mathTab from "../../../assets/images/student/math_tab.png"; -import gamesTab from "../../../assets/images/student/games_tab.png"; -import puzzlesTab from "../../../assets/images/student/puzzles_tab.png"; -import playTab from "../../../assets/images/student/play_tab.png"; -import recordingsTab from "../../../assets/images/student/recordings_tab.png"; +// Tab images - using Images from imageImporter (same as mentor) const Lessons = lazy(() => import("../../lessons/lessons-main/Lessons")); const LessonsSelection = lazy(() => import("../../lessons/lessons-selection/LessonsSelection")); @@ -81,18 +72,8 @@ const NewStudentProfile = ({ userPortraitSrc }: any) => { const [showConfetti, setShowConfetti] = useState(false); const [celebrateAction, setCelebrateAction] = useState(false); - // Mapping of tab keys to custom image imports - const tabImages: Record = { - activity: activityTab, - mentor: mentorTab, - prodev: prodevTab, - chessLessons: chessTab, - mathLessons: mathTab, - games: gamesTab, - puzzles: puzzlesTab, - playComputer: playTab, - recordings: recordingsTab, - }; + // Tab keys - using Images from imageImporter (same pattern as mentor) + const tabKeys = ["activity", "mentor", "prodev", "chessLessons", "mathLessons", "games", "puzzles", "playComputer", "recordings"]; // states for lessons tab const [lessonSelected, setLessonSelected] = useState(false); // whether user has navigated into a lesson @@ -447,17 +428,38 @@ const NewStudentProfile = ({ userPortraitSrc }: any) => {
+ ); + })}
{tabContent}
From a6e680270a14d9c0e826e30691df1ae076aa1f94 Mon Sep 17 00:00:00 2001 From: Yousif Alrubaye Date: Mon, 15 Dec 2025 21:41:56 -0800 Subject: [PATCH 22/23] Fix environment import paths and configuration --- react-ystemandchess/src/App.tsx | 2 +- react-ystemandchess/src/core/services/badgesApi.ts | 3 +-- react-ystemandchess/src/features/auth/login/Login.tsx | 2 +- .../auth/reset-password/Reset-Password/resetPasswordService.ts | 2 +- react-ystemandchess/src/features/auth/signup/SignUp.tsx | 2 +- .../features/lessons/lessons-selection/LessonsSelection.jsx | 2 +- .../piece-lessons/lesson-overlay/hooks/useLessonManager.ts | 2 +- .../piece-lessons/lesson-overlay/hooks/useSocketChessEngine.ts | 2 +- .../piece-lessons/lesson-overlay/hooks/useTimeTracking.test.ts | 2 +- .../piece-lessons/lesson-overlay/hooks/useTimeTracking.ts | 2 +- .../src/features/mentor/mentor-profile/NewMentorProfile.tsx | 2 +- .../mentor-profile/NewMentorProfile/NewMentorProfile.tsx | 2 +- .../src/features/puzzles/puzzles-page/Puzzles.tsx | 2 +- .../src/features/student/student-page/Student.tsx | 2 +- .../student/student-profile/Modals/ActivitiesModal.tsx | 2 +- .../src/features/student/student-profile/NewStudentProfile.tsx | 2 +- react-ystemandchess/src/globals.ts | 2 +- 17 files changed, 17 insertions(+), 18 deletions(-) diff --git a/react-ystemandchess/src/App.tsx b/react-ystemandchess/src/App.tsx index f0be45f5..aac50eaa 100644 --- a/react-ystemandchess/src/App.tsx +++ b/react-ystemandchess/src/App.tsx @@ -9,7 +9,7 @@ import "./App.css"; import React, { useEffect } from "react"; import { BrowserRouter as Router } from "react-router-dom"; -import { environment } from "./core/environments/environment"; +import { environment } from "./environments/environment"; import { useCookies } from "react-cookie"; import { SetPermissionLevel } from "./globals"; import NavBar from "./components/navbar/NavBar"; diff --git a/react-ystemandchess/src/core/services/badgesApi.ts b/react-ystemandchess/src/core/services/badgesApi.ts index f5d282fc..289a04c7 100644 --- a/react-ystemandchess/src/core/services/badgesApi.ts +++ b/react-ystemandchess/src/core/services/badgesApi.ts @@ -9,8 +9,7 @@ * - getUserBadges: Fetches badges earned by a specific user */ -import { environment } from "../environments/environment"; - +import { environment } from "../../environments/environment"; /** * Fetches the complete catalog of all available badges * diff --git a/react-ystemandchess/src/features/auth/login/Login.tsx b/react-ystemandchess/src/features/auth/login/Login.tsx index 2841ad41..fe5de8d7 100644 --- a/react-ystemandchess/src/features/auth/login/Login.tsx +++ b/react-ystemandchess/src/features/auth/login/Login.tsx @@ -2,7 +2,7 @@ import React from 'react'; // import { Link } from 'react-router-dom'; import './Login.scss'; import { useState } from 'react'; -import { environment } from "../../../core/environments/environment"; +import { environment } from "../../../environments/environment"; import { useCookies } from 'react-cookie'; const Login = () => { diff --git a/react-ystemandchess/src/features/auth/reset-password/Reset-Password/resetPasswordService.ts b/react-ystemandchess/src/features/auth/reset-password/Reset-Password/resetPasswordService.ts index 97798183..cff77239 100644 --- a/react-ystemandchess/src/features/auth/reset-password/Reset-Password/resetPasswordService.ts +++ b/react-ystemandchess/src/features/auth/reset-password/Reset-Password/resetPasswordService.ts @@ -5,7 +5,7 @@ * Uses Nodemailer with Gmail to deliver reset links. */ -import { environment } from "../../../../core/environments/environment"; +import { environment } from "../../../../environments/environment"; const nodemailer = require('nodemailer'); // Configure email transporter with Gmail credentials diff --git a/react-ystemandchess/src/features/auth/signup/SignUp.tsx b/react-ystemandchess/src/features/auth/signup/SignUp.tsx index 5c01df2c..dfe33ed5 100644 --- a/react-ystemandchess/src/features/auth/signup/SignUp.tsx +++ b/react-ystemandchess/src/features/auth/signup/SignUp.tsx @@ -1,6 +1,6 @@ import React, { useState, useEffect, useRef } from 'react'; import './SignUp.scss'; -import { environment } from '../../../core/environments/environment'; +import { environment } from '../../../environments/environment'; // Define the interface for the props of the StudentTemplate component interface StudentTemplateProps { diff --git a/react-ystemandchess/src/features/lessons/lessons-selection/LessonsSelection.jsx b/react-ystemandchess/src/features/lessons/lessons-selection/LessonsSelection.jsx index 8b87c60f..fa888646 100644 --- a/react-ystemandchess/src/features/lessons/lessons-selection/LessonsSelection.jsx +++ b/react-ystemandchess/src/features/lessons/lessons-selection/LessonsSelection.jsx @@ -2,7 +2,7 @@ import profileStyles from "./ProfileStyle.module.scss"; import pageStyles from "./LessonsStyle.module.scss"; import { useNavigate } from "react-router"; import { useState, useEffect, useRef, useCallback, useMemo } from 'react'; -import { environment } from "../../../core/environments/environment"; +import { environment } from "../../../environments/environment"; import { getAllScenarios } from "../lessons-main/Scenarios"; import { useCookies } from "react-cookie"; import ScenarioTemplate from "./ScenarioTemplate/ScenarioTemplate.jsx"; // Importing the ScenarioTemplate component diff --git a/react-ystemandchess/src/features/lessons/piece-lessons/lesson-overlay/hooks/useLessonManager.ts b/react-ystemandchess/src/features/lessons/piece-lessons/lesson-overlay/hooks/useLessonManager.ts index 4a45d808..71dd2194 100644 --- a/react-ystemandchess/src/features/lessons/piece-lessons/lesson-overlay/hooks/useLessonManager.ts +++ b/react-ystemandchess/src/features/lessons/piece-lessons/lesson-overlay/hooks/useLessonManager.ts @@ -1,5 +1,5 @@ import { useState, useCallback } from "react"; -import { environment } from "../../../../../core/environments/environment"; +import { environment } from "../../../../../environments/environment"; export function useLessonManager(piece: string, cookies: any, initialLessonNum?: number) { const [lessonNum, setLessonNum] = useState(initialLessonNum ?? 0); diff --git a/react-ystemandchess/src/features/lessons/piece-lessons/lesson-overlay/hooks/useSocketChessEngine.ts b/react-ystemandchess/src/features/lessons/piece-lessons/lesson-overlay/hooks/useSocketChessEngine.ts index a5f26124..b26aaf97 100644 --- a/react-ystemandchess/src/features/lessons/piece-lessons/lesson-overlay/hooks/useSocketChessEngine.ts +++ b/react-ystemandchess/src/features/lessons/piece-lessons/lesson-overlay/hooks/useSocketChessEngine.ts @@ -1,4 +1,4 @@ -import { environment } from "../../../../../core/environments/environment"; +import { environment } from "../../../../../environments/environment"; import { useEffect, useRef } from "react"; import io from "socket.io-client"; diff --git a/react-ystemandchess/src/features/lessons/piece-lessons/lesson-overlay/hooks/useTimeTracking.test.ts b/react-ystemandchess/src/features/lessons/piece-lessons/lesson-overlay/hooks/useTimeTracking.test.ts index 48e1a73b..58c48dd0 100644 --- a/react-ystemandchess/src/features/lessons/piece-lessons/lesson-overlay/hooks/useTimeTracking.test.ts +++ b/react-ystemandchess/src/features/lessons/piece-lessons/lesson-overlay/hooks/useTimeTracking.test.ts @@ -1,7 +1,7 @@ import { renderHook, act } from "@testing-library/react"; import { useTimeTracking } from "./useTimeTracking"; import { SetPermissionLevel } from "../../../../../globals"; -import { environment } from "../../../../../core/environments/environment"; +import { environment } from "../../../../../environments/environment"; // mock SetPermissionLevel jest.mock("../../../../../globals", () => ({ diff --git a/react-ystemandchess/src/features/lessons/piece-lessons/lesson-overlay/hooks/useTimeTracking.ts b/react-ystemandchess/src/features/lessons/piece-lessons/lesson-overlay/hooks/useTimeTracking.ts index 8762ec05..f58b182d 100644 --- a/react-ystemandchess/src/features/lessons/piece-lessons/lesson-overlay/hooks/useTimeTracking.ts +++ b/react-ystemandchess/src/features/lessons/piece-lessons/lesson-overlay/hooks/useTimeTracking.ts @@ -1,5 +1,5 @@ import { useEffect, useRef, useState } from "react"; -import { environment } from "../../../../../core/environments/environment"; +import { environment } from "../../../../../environments/environment"; import { SetPermissionLevel } from "../../../../../globals"; export function useTimeTracking(piece: string, cookies: any) { diff --git a/react-ystemandchess/src/features/mentor/mentor-profile/NewMentorProfile.tsx b/react-ystemandchess/src/features/mentor/mentor-profile/NewMentorProfile.tsx index 220bb75e..20379019 100644 --- a/react-ystemandchess/src/features/mentor/mentor-profile/NewMentorProfile.tsx +++ b/react-ystemandchess/src/features/mentor/mentor-profile/NewMentorProfile.tsx @@ -3,7 +3,7 @@ import "./NewMentorProfile.scss"; import Images from "../../../assets/images/imageImporter"; import { SetPermissionLevel } from '../../../globals'; import { useCookies } from 'react-cookie'; -import { environment } from "../../../core/environments/environment"; +import { environment } from "../../../environments/environment"; import { useNavigate } from "react-router"; import StatsChart from "../../student/student-profile/StatsChart"; import Lessons from "../../lessons/lessons-main/Lessons"; diff --git a/react-ystemandchess/src/features/mentor/mentor-profile/NewMentorProfile/NewMentorProfile.tsx b/react-ystemandchess/src/features/mentor/mentor-profile/NewMentorProfile/NewMentorProfile.tsx index 29147100..1c77cde5 100644 --- a/react-ystemandchess/src/features/mentor/mentor-profile/NewMentorProfile/NewMentorProfile.tsx +++ b/react-ystemandchess/src/features/mentor/mentor-profile/NewMentorProfile/NewMentorProfile.tsx @@ -3,7 +3,7 @@ import "./NewMentorProfile.scss"; import Images from "../../../../assets/images/imageImporter"; import { SetPermissionLevel } from '../../../../globals'; import { useCookies } from 'react-cookie'; -import { environment } from "../../../../core/environments/environment"; +import { environment } from "../../../../environments/environment"; import { useNavigate } from "react-router"; import StatsChart from "../../../student/student-profile/StatsChart"; import Lessons from "../../../lessons/lessons-main/Lessons"; diff --git a/react-ystemandchess/src/features/puzzles/puzzles-page/Puzzles.tsx b/react-ystemandchess/src/features/puzzles/puzzles-page/Puzzles.tsx index d926cbc4..36518693 100644 --- a/react-ystemandchess/src/features/puzzles/puzzles-page/Puzzles.tsx +++ b/react-ystemandchess/src/features/puzzles/puzzles-page/Puzzles.tsx @@ -4,7 +4,7 @@ import profileStyles from "./Puzzles-profile.module.scss"; import { Chess } from "chess.js"; import { themesName, themesDescription } from "../../../core/services/themesService"; import Swal from 'sweetalert2'; -import { environment } from "../../../core/environments/environment"; +import { environment } from "../../../environments/environment"; import { v4 as uuidv4 } from "uuid"; import { SetPermissionLevel } from "../../../globals"; import { useCookies } from 'react-cookie'; diff --git a/react-ystemandchess/src/features/student/student-page/Student.tsx b/react-ystemandchess/src/features/student/student-page/Student.tsx index aadffde3..619bf108 100644 --- a/react-ystemandchess/src/features/student/student-page/Student.tsx +++ b/react-ystemandchess/src/features/student/student-page/Student.tsx @@ -1,6 +1,6 @@ import React, {useState} from "react"; import "./Student.scss"; -import {environment} from "../../../core/environments/environment"; +import {environment} from "../../../environments/environment"; const Student = () => { const chessSrc = environment.urls.chessClientURL; diff --git a/react-ystemandchess/src/features/student/student-profile/Modals/ActivitiesModal.tsx b/react-ystemandchess/src/features/student/student-profile/Modals/ActivitiesModal.tsx index 851d98a3..f7b26883 100644 --- a/react-ystemandchess/src/features/student/student-profile/Modals/ActivitiesModal.tsx +++ b/react-ystemandchess/src/features/student/student-profile/Modals/ActivitiesModal.tsx @@ -25,7 +25,7 @@ import { ReactComponent as TopicBag } from "../../../../assets/images/Activities import { ReactComponent as ShortBottomVine} from "../../../../assets/images/ActivitiesAssets/short_bottom_vine.svg"; import { ReactComponent as BottomVine} from "../../../../assets/images/ActivitiesAssets/bottom_vine.svg"; import { ReactComponent as Stemmy} from "../../../../assets/images/ActivitiesAssets/stemmy.svg"; -import { environment } from "../../../../core/environments/environment"; +import { environment } from "../../../../environments/environment"; import { useCookies } from "react-cookie"; import { parseActivities } from "../../../../core/utils/activityNames"; diff --git a/react-ystemandchess/src/features/student/student-profile/NewStudentProfile.tsx b/react-ystemandchess/src/features/student/student-profile/NewStudentProfile.tsx index 163535e3..527e7f41 100644 --- a/react-ystemandchess/src/features/student/student-profile/NewStudentProfile.tsx +++ b/react-ystemandchess/src/features/student/student-profile/NewStudentProfile.tsx @@ -3,7 +3,7 @@ import "./NewStudentProfile.scss"; import Images from "../../../assets/images/imageImporter"; import { SetPermissionLevel } from '../../../globals'; import { useCookies } from 'react-cookie'; -import { environment } from "../../../core/environments/environment"; +import { environment } from "../../../environments/environment"; import { useNavigate } from "react-router"; import { useLocation } from "react-router"; import StatsChart from "./StatsChart"; diff --git a/react-ystemandchess/src/globals.ts b/react-ystemandchess/src/globals.ts index ed668f5a..9cc4a323 100644 --- a/react-ystemandchess/src/globals.ts +++ b/react-ystemandchess/src/globals.ts @@ -5,7 +5,7 @@ * components, particularly for authentication and permission management. */ -import { environment } from "./core/environments/environment"; +import { environment } from "./environments/environment"; /** * Global variable to store user information after authentication From a998df334c9adf856158beba5519228717085d7d Mon Sep 17 00:00:00 2001 From: Yousif Alrubaye Date: Tue, 16 Dec 2025 13:43:25 -0800 Subject: [PATCH 23/23] Add environment configuration files --- .gitignore | 3 ++- react-ystemandchess/src/environments/environment.js | 13 +++++++++++++ .../src/environments/environment.prod.js | 12 ++++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 react-ystemandchess/src/environments/environment.js create mode 100644 react-ystemandchess/src/environments/environment.prod.js diff --git a/.gitignore b/.gitignore index 1ae98ad2..07e1fe56 100644 --- a/.gitignore +++ b/.gitignore @@ -15,7 +15,8 @@ react-ystemandchess/environment.prod.ts react-ystemandchess/environment.ts environment.php .env -environment.* +environment.*.local +environment.secret.* create_envs.sh create_env.sh create_dev_envs.sh diff --git a/react-ystemandchess/src/environments/environment.js b/react-ystemandchess/src/environments/environment.js new file mode 100644 index 00000000..2a84a330 --- /dev/null +++ b/react-ystemandchess/src/environments/environment.js @@ -0,0 +1,13 @@ +export const environment = { + production: false, + agora: { + appId: '6b7772f2a76f406192d8167460181be0', + }, + urls: { + middlewareURL: 'http://localhost:8000', + chessClientURL: 'http://localhost', + stockFishURL: 'http://localhost:8080/stockfishserver/', + chessServer: 'http://localhost:3001/', + }, + productionType: 'development', // development/production +}; \ No newline at end of file diff --git a/react-ystemandchess/src/environments/environment.prod.js b/react-ystemandchess/src/environments/environment.prod.js new file mode 100644 index 00000000..f86e300f --- /dev/null +++ b/react-ystemandchess/src/environments/environment.prod.js @@ -0,0 +1,12 @@ +export const environment = { + production: false, + agora: { + appId: '6c368b93b82a4b3e9fb8e57da830f2a4', + }, + urls: { + middlewareURL: 'http://localhost/middleware/', + chessClientURL: 'http://localhost/chessclient/', + stockFishURL: 'http://localhost/stockfishserver/', + chessServer: 'http://localhost/chessserver/', + }, +}; \ No newline at end of file