From b0510db4a95296ad7d8a510822d7405cb21b0190 Mon Sep 17 00:00:00 2001 From: Nisarg Doshi Date: Tue, 19 Mar 2024 15:54:59 -0400 Subject: [PATCH 01/18] migrated HeatMap functionality for review table from Ruby on Rails to React --- package-lock.json | 107 +++++++++++++- package.json | 6 +- src/App.tsx | 25 ++-- src/layout/Header.tsx | 5 +- src/pages/ViewTeamGrades/ReviewTable.tsx | 150 ++++++++++++++++++++ src/pages/ViewTeamGrades/ShowSubmission.tsx | 45 ++++++ src/pages/ViewTeamGrades/grades.scss | 143 +++++++++++++++++++ tsconfig.json | 2 +- 8 files changed, 464 insertions(+), 19 deletions(-) create mode 100644 src/pages/ViewTeamGrades/ReviewTable.tsx create mode 100644 src/pages/ViewTeamGrades/ShowSubmission.tsx create mode 100644 src/pages/ViewTeamGrades/grades.scss diff --git a/package-lock.json b/package-lock.json index e902b38..2d63c82 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,13 +23,15 @@ "@types/react-redux": "^7.1.25", "@types/react-router-dom": "^5.3.3", "axios": "^1.4.0", - "bootstrap": "^5.2.3", + "bootstrap": "^5.3.3", "formik": "^2.2.9", + "jquery": "^3.7.1", "jwt-decode": "^3.1.2", "react": "^18.2.0", "react-bootstrap": "^2.7.4", "react-datepicker": "^4.11.0", "react-dom": "^18.2.0", + "react-i18next": "^14.1.0", "react-icons": "^4.9.0", "react-redux": "^8.0.5", "react-router-dom": "^6.11.1", @@ -42,6 +44,8 @@ "yup": "^1.1.1" }, "devDependencies": { + "@types/jquery": "^3.5.29", + "@types/jqueryui": "^1.12.21", "@types/react-bootstrap": "^0.32.32", "@types/react-datepicker": "^4.10.0", "eslint": "^8.38.0", @@ -2098,9 +2102,9 @@ "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" }, "node_modules/@babel/runtime": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.2.tgz", - "integrity": "sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==", + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.0.tgz", + "integrity": "sha512-Chk32uHMg6TnQdvw2e9IlqPpFX/6NLuK0Ys2PqLb7/gL5uFn9mXvK715FGLlOLQrcO4qIkNHkvPGktzzXexsFw==", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -3962,6 +3966,24 @@ "pretty-format": "^27.0.0" } }, + "node_modules/@types/jquery": { + "version": "3.5.29", + "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.29.tgz", + "integrity": "sha512-oXQQC9X9MOPRrMhPHHOsXqeQDnWeCDT3PelUIg/Oy8FAbzSZtFHRjc7IpbfFVmpLtJ+UOoywpRsuO5Jxjybyeg==", + "dev": true, + "dependencies": { + "@types/sizzle": "*" + } + }, + "node_modules/@types/jqueryui": { + "version": "1.12.21", + "resolved": "https://registry.npmjs.org/@types/jqueryui/-/jqueryui-1.12.21.tgz", + "integrity": "sha512-hsTOaWPg963smNdoHbEN2anu4vVWj9k2xuaZMIajWERPikaBRG49RmaDA/tb2HldX9/a0qHvQYKipXHSLhM3qA==", + "dev": true, + "dependencies": { + "@types/jquery": "*" + } + }, "node_modules/@types/json-schema": { "version": "7.0.14", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.14.tgz", @@ -4147,6 +4169,12 @@ "@types/node": "*" } }, + "node_modules/@types/sizzle": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.8.tgz", + "integrity": "sha512-0vWLNK2D5MT9dg0iOo8GlKguPAU02QjmZitPEsXRuJXU/OGIOt9vT9Fc26wtYuavLxtO45v9PGleoL9Z0k1LHg==", + "dev": true + }, "node_modules/@types/sockjs": { "version": "0.3.35", "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.35.tgz", @@ -5411,9 +5439,9 @@ "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" }, "node_modules/bootstrap": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.2.tgz", - "integrity": "sha512-D32nmNWiQHo94BKHLmOrdjlL05q1c8oxbtBphQFb9Z5to6eGRDCm0QgeaZ4zFBHzfg2++rqa2JkqCcxDy0sH0g==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.3.tgz", + "integrity": "sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==", "funding": [ { "type": "github", @@ -8884,6 +8912,14 @@ "node": ">= 12" } }, + "node_modules/html-parse-stringify": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz", + "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==", + "dependencies": { + "void-elements": "3.1.0" + } + }, "node_modules/html-webpack-plugin": { "version": "5.5.3", "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.3.tgz", @@ -9055,6 +9091,29 @@ "node": ">=10.17.0" } }, + "node_modules/i18next": { + "version": "23.10.1", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-23.10.1.tgz", + "integrity": "sha512-NDiIzFbcs3O9PXpfhkjyf7WdqFn5Vq6mhzhtkXzj51aOcNuPNcTwuYNuXCpHsanZGHlHKL35G7huoFeVic1hng==", + "funding": [ + { + "type": "individual", + "url": "https://locize.com" + }, + { + "type": "individual", + "url": "https://locize.com/i18next.html" + }, + { + "type": "individual", + "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project" + } + ], + "peer": true, + "dependencies": { + "@babel/runtime": "^7.23.2" + } + }, "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -10888,6 +10947,11 @@ "jiti": "bin/jiti.js" } }, + "node_modules/jquery": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz", + "integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==" + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -13908,6 +13972,27 @@ "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-2.0.4.tgz", "integrity": "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw==" }, + "node_modules/react-i18next": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-14.1.0.tgz", + "integrity": "sha512-3KwX6LHpbvGQ+sBEntjV4sYW3Zovjjl3fpoHbUwSgFHf0uRBcbeCBLR5al6ikncI5+W0EFb71QXZmfop+J6NrQ==", + "dependencies": { + "@babel/runtime": "^7.23.9", + "html-parse-stringify": "^3.0.1" + }, + "peerDependencies": { + "i18next": ">= 23.2.3", + "react": ">= 16.8.0" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, "node_modules/react-icons": { "version": "4.11.0", "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.11.0.tgz", @@ -16376,6 +16461,14 @@ "node": ">= 0.8" } }, + "node_modules/void-elements": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", + "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/w3c-hr-time": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", diff --git a/package.json b/package.json index c8cb50f..ca465ca 100644 --- a/package.json +++ b/package.json @@ -18,13 +18,15 @@ "@types/react-redux": "^7.1.25", "@types/react-router-dom": "^5.3.3", "axios": "^1.4.0", - "bootstrap": "^5.2.3", + "bootstrap": "^5.3.3", "formik": "^2.2.9", + "jquery": "^3.7.1", "jwt-decode": "^3.1.2", "react": "^18.2.0", "react-bootstrap": "^2.7.4", "react-datepicker": "^4.11.0", "react-dom": "^18.2.0", + "react-i18next": "^14.1.0", "react-icons": "^4.9.0", "react-redux": "^8.0.5", "react-router-dom": "^6.11.1", @@ -61,6 +63,8 @@ ] }, "devDependencies": { + "@types/jquery": "^3.5.29", + "@types/jqueryui": "^1.12.21", "@types/react-bootstrap": "^0.32.32", "@types/react-datepicker": "^4.10.0", "eslint": "^8.38.0", diff --git a/src/App.tsx b/src/App.tsx index e3e7ab6..51faeb9 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,5 +1,5 @@ import React from "react"; -import {createBrowserRouter,Navigate,RouterProvider} from "react-router-dom"; +import { createBrowserRouter, Navigate, RouterProvider } from "react-router-dom"; import AdministratorLayout from "./layout/Administrator"; import ManageUserTypes, { loader as loadUsers } from "./pages/Administrator/ManageUserTypes"; import Login from "./pages/Authentication/Login"; @@ -30,6 +30,7 @@ import { loadCourseInstructorDataAndInstitutions } from "pages/Courses/CourseUti import TA from "pages/TA/TA"; import TAEditor from "pages/TA/TAEditor"; import { loadTAs } from "pages/TA/TAUtil"; +import ReviewTable from "./pages/ViewTeamGrades/ReviewTable"; function App() { const router = createBrowserRouter([ @@ -41,7 +42,15 @@ function App() { { index: true, element: } /> }, { path: "login", element: }, { path: "logout", element: } /> }, - { path: "edit-questionnaire", element: } /> }, + // Add the ViewTeamGrades route + { + path: "view-team-grades", + element: } />, + }, + { + path: "edit-questionnaire", + element: } />, + }, { path: "assignments", element: } leastPrivilegeRole={ROLE.TA} />, @@ -106,7 +115,6 @@ function App() { }, ], }, - // Fixed the missing comma and added an opening curly brace { path: "courses", element: } leastPrivilegeRole={ROLE.TA} />, @@ -132,7 +140,7 @@ function App() { }, ] }, - ], // Added the missing closing curly brace + ], }, { path: "administrator", @@ -183,13 +191,13 @@ function App() { path: "new", element: , }, + { path: "edit/:id", element: , }, ], }, - // Add the "Questionnaire" route here { path: "questionnaire", element: , @@ -197,13 +205,12 @@ function App() { ], }, { path: "*", element: }, - // Add the "Questionnaire" route here if it's not under the administrator section - { path: "questionnaire", element: }, + { path: "questionnaire", element: }, // Added the Questionnaire route ], }, ]); - + return ; } -export default App; +export default App; \ No newline at end of file diff --git a/src/layout/Header.tsx b/src/layout/Header.tsx index 8f6295f..fe06ba5 100644 --- a/src/layout/Header.tsx +++ b/src/layout/Header.tsx @@ -102,6 +102,9 @@ const Header: React.FC = () => { Student View + + Test + User: {auth.user.full_name} @@ -117,4 +120,4 @@ const Header: React.FC = () => { ); }; -export default Header; +export default Header; \ No newline at end of file diff --git a/src/pages/ViewTeamGrades/ReviewTable.tsx b/src/pages/ViewTeamGrades/ReviewTable.tsx new file mode 100644 index 0000000..973f0bd --- /dev/null +++ b/src/pages/ViewTeamGrades/ReviewTable.tsx @@ -0,0 +1,150 @@ +import React, { useState } from 'react'; +import './grades.scss'; +import ShowSubmission from './ShowSubmission'; // Import the ShowSubmission component + +interface ReviewData { + question: string; + reviews: number[]; + RowAvg: number; + maxScore: number; +} + +const dummyData: ReviewData[] = [ + { + question: '1', + reviews: [5, 4, 4, 4, 5, 5, 5, 5, 2, 5], + RowAvg: 0, + maxScore: 5 + }, + { + question: '2', + reviews: [5, 3, 5, 3, 5, 5, 5, 5, 5, 5], + RowAvg: 0, + maxScore: 5 + }, + { + question: '3', + reviews: [1, 5, 5, 4, 5, 5, 5, 5, 5, 5], + RowAvg: 0, + maxScore: 5 + }, + { + question: '4', + reviews: [1, 1, 1, 0, 1, 0, 1, 0, 1, 0], + RowAvg: 0, + maxScore: 1 + } + // Add more dummy data as needed +]; + +let totalAvg = 0; +let questionCount = 0; +let totalMaxScore = 0; +// Calculate average for each row +dummyData.forEach((row) => { + const sum = row.reviews.reduce((acc, val) => acc + val, 0); + row.RowAvg = sum / row.reviews.length; + totalAvg = row.RowAvg + totalAvg; + totalMaxScore = totalMaxScore + row.maxScore + questionCount++; +}); + +const averagePeerReviewScore = + questionCount > 0 + ? (((totalAvg / totalMaxScore) * 100) > 0 ? ((totalAvg / totalMaxScore) * 100).toFixed(2) : '0.00') + : '0.00'; + +const columnAverages: number[] = Array.from({ length: dummyData[0].reviews.length }, () => 0); + +// Calculate column averages +dummyData.forEach((row) => { + row.reviews.forEach((val, index) => { + columnAverages[index] += val; + }); +}); + +columnAverages.forEach((sum, index) => { + columnAverages[index] = (sum / totalMaxScore) * 5; +}); + +const ReviewTable: React.FC = () => { + const [filterValue, setFilterValue] = useState(null); + const [sortOrderRow, setsortOrderRow] = useState<'asc' | 'desc' | 'none'>('none'); + const toggleSortOrderRow = () => { + setsortOrderRow((prevSortOrder) => { + if (prevSortOrder === 'asc') return 'desc'; + if (prevSortOrder === 'desc') return 'none'; + return 'asc'; + }); + }; + + const getColorClass = (score: number, maxScore: number) => { + let scoreColor = score; + scoreColor = ((maxScore - scoreColor) / maxScore) * 100; + if (scoreColor >= 80) return 'c1'; + else if (scoreColor >= 60 && scoreColor < 80) return 'c2'; + else if (scoreColor >= 40 && scoreColor < 60) return 'c3'; + else if (scoreColor >= 20 && scoreColor < 40) return 'c4'; + else if (scoreColor >= 0 && scoreColor < 20) return 'c5'; + else return 'cf'; + }; + + const averageScoreColorClass = getColorClass(totalAvg , totalMaxScore); + let sortedData = [...dummyData]; + + if (sortOrderRow === 'asc') { + sortedData = dummyData.slice().sort((a, b) => a.RowAvg - b.RowAvg); + } else if (sortOrderRow === 'desc') { + sortedData = dummyData.slice().sort((a, b) => b.RowAvg - a.RowAvg); + } + + return ( +
+

Summary Report for assignment: Program 2

+
Team: Nisarg_Chaitanya_Sagar
+
Average peer review score: {averagePeerReviewScore}
+ +
+

+ + + + + {Array.from({ length: dummyData[0].reviews.length }, (_, i) => ( + + ))} + + + + + {sortedData.map((row, index) => ( + + + {row.reviews.map((review, idx) => ( + + ))} + + + ))} + + + {columnAverages.map((avg, index) => ( + + ))} + + +
Question No.{`Review ${i + 1}`} + Avg + {sortOrderRow === "none" && ▲▼} + {sortOrderRow === "asc" && } + {sortOrderRow === "desc" && } +
{row.question}{review}{row.RowAvg.toFixed(2)}
Avg{avg.toFixed(2)}
+
+

+ Team members: (Chaitanya Srusti) (Nisarg Nilesh Doshi) (Malick, Kashika) (Sagar Dama) +

+
+ ); +}; + +export default ReviewTable; diff --git a/src/pages/ViewTeamGrades/ShowSubmission.tsx b/src/pages/ViewTeamGrades/ShowSubmission.tsx new file mode 100644 index 0000000..03ae077 --- /dev/null +++ b/src/pages/ViewTeamGrades/ShowSubmission.tsx @@ -0,0 +1,45 @@ +import React, { useState } from 'react'; +import { Button, Collapse } from 'react-bootstrap'; + +const ShowSubmission = () => { + const [open, setOpen] = useState(false); + + return ( + <> + + +
+

+ + {open && ( // Render links only when open is true + <> + + https://github.ncsu.edu/Program-2-Ruby-on-Rails/WolfEvents + +
+ + http://152.7.177.44:8080/ + + + )} +
+
+ + ); +}; + +export default ShowSubmission; diff --git a/src/pages/ViewTeamGrades/grades.scss b/src/pages/ViewTeamGrades/grades.scss new file mode 100644 index 0000000..5bb624f --- /dev/null +++ b/src/pages/ViewTeamGrades/grades.scss @@ -0,0 +1,143 @@ +.table-container { + max-width: 70%; /* Set the maximum width of the table container */ +} + +/* These are the colors used for coloring + * score cells within the heatgrid for the + * grades view. + */ + +/* This is a null space in the table. Just leave + * it the way it is for now. + */ +.c0 { + background-color: #d3d3d3; +} + +/* This is a red, indicative of a poor score. */ +.c1 { + background-color: #ff8080; +} + +/* This is an orange. */ +.c2 { + background-color: #FD992D; +} + +/* This is a yellow, indicative of a median score. */ +.c3 { + background-color: #FFEC8B; +} + +/* This is a light green. */ +.c4 { + background-color: #BCED91; +} + +/* This is a green, indicative of a good score. */ +.c5 { + background-color: #2DE636; +} + +.cf { + background-color: #FFFFFF; +} + +/* To color the grades in the summary report */ +.grade-circle { + width: 30px; + height: 30px; + border-radius: 50%; + font-size: 15px; + color: black; + line-height: 30px; + text-align: center; +} + +/* To underline scores which have a comment. */ +.underlined { + text-decoration: underline; + font-weight: bold; +} + +.tbl_heat { + border: 1px solid black; + width: 100%; /* Set the width of the table to 100% */ + font-size: 10px; /* Adjust font size for table content */ + text-align: center; /* Center align table content */ + table-layout: fixed; /* Fix the layout of the table */ +} + +.tbl_heat td { + cursor: pointer; + padding: 8px; /* Adjust padding of table cells */ + border: 1px black solid; + width: auto; /* Set the width of table cells to auto */ + font-size: 11px; /* Adjust font size for table data */ + table-layout: fixed; +} + +.tbl_heat th { + border: 1px black solid; + padding: 10px; /* Adjust padding of table headers */ + font-size: 11px; /* Adjust font size for table headers */ + background-color: #f2f2f2; /* Background color for table headers */ + //white-space: nowrap; /* Prevent wrapping of content */ + width: auto; /* Set the width of table headers to auto */ + table-layout: fixed; +} + +.hiddenRow { + padding: 0 !important; +} + +.spn_tooltip { + padding-left: 30px; + color: grey; + font-size: small; +} + +.spn_qsttog { + padding-left: 30px; + cursor: pointer; + text-decoration: underline; + color: blue; + font-size: small; +} + + +// Add classes for E2100 Tag Reports for Students to style the new HeatGrid of review tags + +.action_row { + border: 1px black solid; + padding: 1px 2px 2px 1px; + font-size: 11px; + text-align: center; +} + +.tag_heat_grid { + padding: 0; + spacing: 0; + border: 1px solid black; + position: relative; + float: right; + top: 0px; + right: 0px; + z-index: 2; +} + +.tag_heat_grid th { + border: 1px solid black; + font-size: 12px; + cursor: pointer; +} + +.tag_heat_grid td { + border: 0.5px solid black; + font-size: 8px; +} + +.tag_heat_grid_criterion { + font-size: 11px !important; + font-weight: bold !important; +} diff --git a/tsconfig.json b/tsconfig.json index ec5b6f5..885fce5 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,7 +4,7 @@ "lib": [ "dom", "dom.iterable", - "esnext" + "esnext", ], "baseUrl": "src", "allowJs": true, From 6f90fce7d1ceb1220f8feb29ac72a2486a8de14c Mon Sep 17 00:00:00 2001 From: ChaitanyaS182k <141549134+ChaitanyaS182k@users.noreply.github.com> Date: Wed, 20 Mar 2024 11:10:09 -0400 Subject: [PATCH 02/18] Update ReviewTable.tsx --- src/pages/ViewTeamGrades/ReviewTable.tsx | 132 ++++++++++++++++------- 1 file changed, 91 insertions(+), 41 deletions(-) diff --git a/src/pages/ViewTeamGrades/ReviewTable.tsx b/src/pages/ViewTeamGrades/ReviewTable.tsx index 973f0bd..71e9b1b 100644 --- a/src/pages/ViewTeamGrades/ReviewTable.tsx +++ b/src/pages/ViewTeamGrades/ReviewTable.tsx @@ -3,38 +3,86 @@ import './grades.scss'; import ShowSubmission from './ShowSubmission'; // Import the ShowSubmission component interface ReviewData { - question: string; - reviews: number[]; + questionNumber: string; + questionText: string; // New property to hold the question text + reviews: { score: number; comment?: string }[]; RowAvg: number; maxScore: number; } const dummyData: ReviewData[] = [ { - question: '1', - reviews: [5, 4, 4, 4, 5, 5, 5, 5, 2, 5], + questionNumber: '1', + questionText: 'What is the main purpose of this feature?', + reviews: [ + { score: 5, comment: 'Great explanation!' }, + { score: 4, comment: 'Good, but could be clearer' }, + { score: 4 }, + { score: 4 }, + { score: 5 }, + { score: 5 }, + { score: 5 }, + { score: 5 }, + { score: 2, comment: 'Needs improvement' }, + { score: 5 } + ], RowAvg: 0, maxScore: 5 }, { - question: '2', - reviews: [5, 3, 5, 3, 5, 5, 5, 5, 5, 5], + questionNumber: '2', + questionText: 'How user-friendly is this feature?', + reviews: [ + { score: 5 }, + { score: 3, comment: 'Confusing UI' }, + { score: 5 }, + { score: 3 }, + { score: 5 }, + { score: 5 }, + { score: 5 }, + { score: 5 }, + { score: 5 }, + { score: 5 } + ], RowAvg: 0, maxScore: 5 }, { - question: '3', - reviews: [1, 5, 5, 4, 5, 5, 5, 5, 5, 5], + questionNumber: '3', + questionText: 'Does this feature meet the project requirements?', + reviews: [ + { score: 1 }, + { score: 5 }, + { score: 5 }, + { score: 4 }, + { score: 5 }, + { score: 5 }, + { score: 5 }, + { score: 5 }, + { score: 5 }, + { score: 5 } + ], RowAvg: 0, maxScore: 5 }, { - question: '4', - reviews: [1, 1, 1, 0, 1, 0, 1, 0, 1, 0], + questionNumber: '4', + questionText: 'How would you rate the performance of this feature?', + reviews: [ + { score: 1 }, + { score: 1, comment: 'Very slow response time' }, + { score: 1 }, + { score: 0 }, + { score: 1 }, + { score: 0 }, + { score: 1 }, + { score: 0 }, + { score: 1 }, + { score: 0 } + ], RowAvg: 0, maxScore: 1 } - // Add more dummy data as needed ]; let totalAvg = 0; @@ -42,10 +90,10 @@ let questionCount = 0; let totalMaxScore = 0; // Calculate average for each row dummyData.forEach((row) => { - const sum = row.reviews.reduce((acc, val) => acc + val, 0); + const sum = row.reviews.reduce((acc, val) => acc + val.score, 0); row.RowAvg = sum / row.reviews.length; totalAvg = row.RowAvg + totalAvg; - totalMaxScore = totalMaxScore + row.maxScore + totalMaxScore = totalMaxScore + row.maxScore; questionCount++; }); @@ -59,7 +107,7 @@ const columnAverages: number[] = Array.from({ length: dummyData[0].reviews.lengt // Calculate column averages dummyData.forEach((row) => { row.reviews.forEach((val, index) => { - columnAverages[index] += val; + columnAverages[index] += val.score; }); }); @@ -89,7 +137,7 @@ const ReviewTable: React.FC = () => { else return 'cf'; }; - const averageScoreColorClass = getColorClass(totalAvg , totalMaxScore); + const averageScoreColorClass = getColorClass(totalAvg, totalMaxScore); let sortedData = [...dummyData]; if (sortOrderRow === 'asc') { @@ -108,35 +156,37 @@ const ReviewTable: React.FC = () => {

- - - {Array.from({ length: dummyData[0].reviews.length }, (_, i) => ( - - ))} - - + + + {Array.from({ length: dummyData[0].reviews.length }, (_, i) => ( + + ))} + + - {sortedData.map((row, index) => ( - - - {row.reviews.map((review, idx) => ( - + {sortedData.map((row, index) => ( + + + {row.reviews.map((review, idx) => ( + + ))} + + + ))} + + + {columnAverages.map((avg, index) => ( + ))} - - ))} - - - {columnAverages.map((avg, index) => ( - - ))} -
Question No.{`Review ${i + 1}`} - Avg - {sortOrderRow === "none" && ▲▼} - {sortOrderRow === "asc" && } - {sortOrderRow === "desc" && } -
Question No.{`Review ${i + 1}`} + Avg + {sortOrderRow === "none" && ▲▼} + {sortOrderRow === "asc" && } + {sortOrderRow === "desc" && } +
{row.question}{review}
{row.questionNumber} + {review.score} + {row.RowAvg.toFixed(2)}
Avg{avg.toFixed(2)}{row.RowAvg.toFixed(2)}
Avg{avg.toFixed(2)}
@@ -147,4 +197,4 @@ const ReviewTable: React.FC = () => { ); }; -export default ReviewTable; +export default ReviewTable; \ No newline at end of file From 6eb6203965e6eadab955a765653354469a14277e Mon Sep 17 00:00:00 2001 From: Aniruddha <46026542+Aniruddha-Rajnekar@users.noreply.github.com> Date: Wed, 20 Mar 2024 14:24:21 -0400 Subject: [PATCH 03/18] Added Button to HomePage as well as Grade and Comment Section at the Bottom --- src/pages/ViewTeamGrades/ReviewTable.tsx | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/pages/ViewTeamGrades/ReviewTable.tsx b/src/pages/ViewTeamGrades/ReviewTable.tsx index 71e9b1b..8ad3f4e 100644 --- a/src/pages/ViewTeamGrades/ReviewTable.tsx +++ b/src/pages/ViewTeamGrades/ReviewTable.tsx @@ -1,6 +1,7 @@ import React, { useState } from 'react'; import './grades.scss'; import ShowSubmission from './ShowSubmission'; // Import the ShowSubmission component +import { Link } from 'react-router-dom'; interface ReviewData { questionNumber: string; @@ -149,7 +150,7 @@ const ReviewTable: React.FC = () => { return (

Summary Report for assignment: Program 2

-
Team: Nisarg_Chaitanya_Sagar
+
Team: Thala4AReason
Average peer review score: {averagePeerReviewScore}
@@ -191,10 +192,20 @@ const ReviewTable: React.FC = () => {

- Team members: (Chaitanya Srusti) (Nisarg Nilesh Doshi) (Malick, Kashika) (Sagar Dama) + Team members: (Chaitanya Srusti) (Nisarg Nilesh Doshi) (Aniruddha Rajnekar)(Malick, Kashika)

+

+

+

Grade and comment for submission

+ Grade: Grade for submission

+ Comment: Comment for submission

+ Late Penalty: 0

+

+ + Back +
); }; -export default ReviewTable; \ No newline at end of file +export default ReviewTable; From f22198ef9c70dc25d0854a573d3d340c462ed5fd Mon Sep 17 00:00:00 2001 From: ChaitanyaS182k <141549134+ChaitanyaS182k@users.noreply.github.com> Date: Wed, 20 Mar 2024 17:44:52 -0400 Subject: [PATCH 04/18] Heat Map Hovering effect fix Fixed the hovering effects on the reviews and questions for the heatmap table --- src/pages/ViewTeamGrades/ReviewTable.tsx | 7 ++++--- src/pages/ViewTeamGrades/grades.scss | 24 ++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/pages/ViewTeamGrades/ReviewTable.tsx b/src/pages/ViewTeamGrades/ReviewTable.tsx index 71e9b1b..9e955cb 100644 --- a/src/pages/ViewTeamGrades/ReviewTable.tsx +++ b/src/pages/ViewTeamGrades/ReviewTable.tsx @@ -136,6 +136,7 @@ const ReviewTable: React.FC = () => { else if (scoreColor >= 0 && scoreColor < 20) return 'c5'; else return 'cf'; }; + const averageScoreColorClass = getColorClass(totalAvg, totalMaxScore); let sortedData = [...dummyData]; @@ -172,10 +173,10 @@ const ReviewTable: React.FC = () => { {sortedData.map((row, index) => ( - {row.questionNumber} + {row.questionNumber} {row.reviews.map((review, idx) => ( - - {review.score} + + {review.score} ))} {row.RowAvg.toFixed(2)} diff --git a/src/pages/ViewTeamGrades/grades.scss b/src/pages/ViewTeamGrades/grades.scss index 5bb624f..7d262e6 100644 --- a/src/pages/ViewTeamGrades/grades.scss +++ b/src/pages/ViewTeamGrades/grades.scss @@ -68,6 +68,15 @@ table-layout: fixed; /* Fix the layout of the table */ } +// .tbl_heat td { +// cursor: pointer; +// padding: 8px; /* Adjust padding of table cells */ +// border: 1px black solid; +// width: auto; /* Set the width of table cells to auto */ +// font-size: 11px; /* Adjust font size for table data */ +// table-layout: fixed; +// } + .tbl_heat td { cursor: pointer; padding: 8px; /* Adjust padding of table cells */ @@ -75,8 +84,23 @@ width: auto; /* Set the width of table cells to auto */ font-size: 11px; /* Adjust font size for table data */ table-layout: fixed; + position: relative; /* Required for absolute positioning */ +} + +.tbl_heat td[data-question]:hover::after { + content: attr(data-question); /* Display the question text as a tooltip */ + position: absolute; + background-color: rgba($color: #000000, $alpha: 1); + color: #ffffff; + padding: 4px; + border-radius: 4px; + bottom: 130%; /* Position the tooltip above the td */ + left: 0%; /* Center the tooltip horizontally */ + //transform: translateX(-50%); /* Center the tooltip horizontally */ + white-space: nowrap; /* Prevent tooltip from wrapping */ } + .tbl_heat th { border: 1px black solid; padding: 10px; /* Adjust padding of table headers */ From d2561b59c6c440ccc222fbdb42a06e198e639b26 Mon Sep 17 00:00:00 2001 From: Nisarg Doshi Date: Wed, 20 Mar 2024 19:56:47 -0400 Subject: [PATCH 05/18] Modularized the code --- src/pages/ViewTeamGrades/App.tsx | 12 ++ src/pages/ViewTeamGrades/ReviewTableRow.tsx | 33 +++++ src/pages/ViewTeamGrades/RoundSelector.tsx | 30 +++++ src/pages/ViewTeamGrades/dummyData.ts | 142 ++++++++++++++++++++ src/pages/ViewTeamGrades/grades.scss | 34 +++++ src/pages/ViewTeamGrades/utils.ts | 67 +++++++++ 6 files changed, 318 insertions(+) create mode 100644 src/pages/ViewTeamGrades/App.tsx create mode 100644 src/pages/ViewTeamGrades/ReviewTableRow.tsx create mode 100644 src/pages/ViewTeamGrades/RoundSelector.tsx create mode 100644 src/pages/ViewTeamGrades/dummyData.ts create mode 100644 src/pages/ViewTeamGrades/utils.ts diff --git a/src/pages/ViewTeamGrades/App.tsx b/src/pages/ViewTeamGrades/App.tsx new file mode 100644 index 0000000..533d86a --- /dev/null +++ b/src/pages/ViewTeamGrades/App.tsx @@ -0,0 +1,12 @@ +import React from 'react'; +import ReviewTable from './ReviewTable'; + +const App: React.FC = () => { + return ( +
+ +
+ ); +}; + +export default App; \ No newline at end of file diff --git a/src/pages/ViewTeamGrades/ReviewTableRow.tsx b/src/pages/ViewTeamGrades/ReviewTableRow.tsx new file mode 100644 index 0000000..c10e26f --- /dev/null +++ b/src/pages/ViewTeamGrades/ReviewTableRow.tsx @@ -0,0 +1,33 @@ +import React from 'react'; +import { getColorClass, getWordCount10, getWordCount20 } from './utils'; +import { ReviewData } from './dummyData'; + +interface ReviewTableRowProps { + row: ReviewData; + showWordCount10: boolean; + showWordCount20: boolean; +} + +const ReviewTableRow: React.FC = ({ row, showWordCount10, showWordCount20 }) => { + return ( + + + {row.questionNumber} + + {row.reviews.map((review, idx) => ( + + {review.score} + + ))} + {row.RowAvg.toFixed(2)} + {showWordCount10 && {getWordCount10(row)}} + {showWordCount20 && {getWordCount20(row)}} + + ); +}; + +export default ReviewTableRow; \ No newline at end of file diff --git a/src/pages/ViewTeamGrades/RoundSelector.tsx b/src/pages/ViewTeamGrades/RoundSelector.tsx new file mode 100644 index 0000000..3904216 --- /dev/null +++ b/src/pages/ViewTeamGrades/RoundSelector.tsx @@ -0,0 +1,30 @@ +import React from 'react'; +import { dummyDataRounds } from './dummyData'; + +interface RoundSelectorProps { + currentRound: number; + handleRoundChange: (roundIndex: number) => void; +} + +const RoundSelector: React.FC = ({ currentRound, handleRoundChange }) => { + return ( +
+
+ {dummyDataRounds.map((round, index) => ( + + ))} + + Team members: (Chaitanya Srusti) (Nisarg Nilesh Doshi) (Aniruddha Rajnekar)(Malick, Kashika) + +
+
+ ); +}; + +export default RoundSelector; \ No newline at end of file diff --git a/src/pages/ViewTeamGrades/dummyData.ts b/src/pages/ViewTeamGrades/dummyData.ts new file mode 100644 index 0000000..1be7f93 --- /dev/null +++ b/src/pages/ViewTeamGrades/dummyData.ts @@ -0,0 +1,142 @@ +export interface ReviewData { + questionNumber: string; + questionText: string; + reviews: { score: number; comment?: string }[]; + RowAvg: number; + maxScore: number; +} + +export const dummyDataRounds: ReviewData[][] = [ + [ + { + questionNumber: '1', + questionText: 'What is the main purpose of this feature?', + reviews: [ + { score: 5, comment: 'Great explanation!' }, + { score: 4, comment: 'Good, but could be clearer' }, + { score: 4 }, + { score: 4 }, + { score: 5 }, + { score: 5 }, + { score: 5 }, + { score: 5 }, + { score: 2, comment: 'Needs improvement' }, + { score: 5 } + ], + RowAvg: 0, + maxScore: 5 + }, + { + questionNumber: '2', + questionText: 'How user-friendly is this feature?', + reviews: [ + { score: 5 }, + { score: 3, comment: 'Confusing UI' }, + { score: 5 }, + { score: 3 }, + { score: 5 }, + { score: 5 }, + { score: 5 }, + { score: 5 }, + { score: 5 }, + { score: 5 } + ], + RowAvg: 0, + maxScore: 5 + }, + { + questionNumber: '3', + questionText: 'Does this feature meet the project requirements?', + reviews: [ + { score: 1 }, + { score: 5 }, + { score: 5 }, + { score: 4 }, + { score: 5 }, + { score: 5 }, + { score: 5 }, + { score: 5 }, + { score: 5 }, + { score: 5 } + ], + RowAvg: 0, + maxScore: 5 + }, + { + questionNumber: '4', + questionText: 'How would you rate the performance of this feature?', + reviews: [ + { score: 1 }, + { score: 1, comment: 'Very slow response time' }, + { score: 1 }, + { score: 0 }, + { score: 1 }, + { score: 0 }, + { score: 1 }, + { score: 0 }, + { score: 1 }, + { score: 0 } + ], + RowAvg: 0, + maxScore: 1 + } + ], + // Round 2 dummy data + [ + { + questionNumber: '1', + questionText: 'What is the main purpose of this feature?', + reviews: [ + { score: 4, comment: 'Good explanation' }, + { score: 3, comment: 'Could be better' }, + { score: 5 }, + { score: 4 }, + { score: 4 }, + { score: 5 }, + { score: 4 }, + { score: 5 }, + { score: 3, comment: 'Needs more clarity' }, + { score: 4 } + ], + RowAvg: 0, + maxScore: 5 + }, + { + questionNumber: '2', + questionText: 'How user-friendly is this feature?', + reviews: [ + { score: 4 }, + { score: 2 }, + { score: 4 }, + { score: 4 }, + { score: 4 }, + { score: 4 }, + { score: 5 }, + { score: 4 }, + { score: 4 }, + { score: 5 } + ], + RowAvg: 0, + maxScore: 5 + }, + { + questionNumber: '3', + questionText: 'Does this feature meet the project requirements?', + reviews: [ + { score: 3 }, + { score: 4 }, + { score: 4 }, + { score: 5 }, + { score: 4 }, + { score: 4 }, + { score: 4 }, + { score: 5 }, + { score: 4 }, + { score: 5 } + ], + RowAvg: 0, + maxScore: 5 + }, + ], + // Add more rounds as needed... +]; diff --git a/src/pages/ViewTeamGrades/grades.scss b/src/pages/ViewTeamGrades/grades.scss index 7d262e6..c841893 100644 --- a/src/pages/ViewTeamGrades/grades.scss +++ b/src/pages/ViewTeamGrades/grades.scss @@ -165,3 +165,37 @@ font-size: 11px !important; font-weight: bold !important; } + +// grades.scss + +.round-selector { + display: flex; +} + +.round-button { + padding: 7px 7px; + margin: 5px; + border: 2px solid #4a90e2; + border-radius: 10px; + background-color: #4a90e2; + color: white; + font-size: 10px; + font-weight: bold; + cursor: pointer; + transition: all 0.3s ease; + + &:hover { + background-color: #357bd8; + border-color: #357bd8; + } + + &.current { + background-color: #2ecc71; + border-color: #2ecc71; + } + .round-selector > div { + display: flex; + align-items: center; + margin: auto; + } +} diff --git a/src/pages/ViewTeamGrades/utils.ts b/src/pages/ViewTeamGrades/utils.ts new file mode 100644 index 0000000..0751a36 --- /dev/null +++ b/src/pages/ViewTeamGrades/utils.ts @@ -0,0 +1,67 @@ +import { ReviewData } from './dummyData'; + +export const getColorClass = (score: number, maxScore: number) => { + let scoreColor = score; + scoreColor = ((maxScore - scoreColor) / maxScore) * 100; + if (scoreColor >= 80) return 'c1'; + else if (scoreColor >= 60 && scoreColor < 80) return 'c2'; + else if (scoreColor >= 40 && scoreColor < 60) return 'c3'; + else if (scoreColor >= 20 && scoreColor < 40) return 'c4'; + else if (scoreColor >= 0 && scoreColor < 20) return 'c5'; + else return 'cf'; +}; + +export const getWordCount10 = (row: ReviewData) => { + return row.reviews.filter( + (review) => review.comment && review.comment.trim().split(' ').length > 10 + ).length; +}; + +export const getWordCount20 = (row: ReviewData) => { + return row.reviews.filter( + (review) => review.comment && review.comment.trim().split(' ').length > 20 + ).length; +}; + +export const calculateAverages = ( + currentRoundData: ReviewData[], + sortOrderRow: 'asc' | 'desc' | 'none' +) => { + let totalAvg = 0; + let questionCount = 0; + let totalMaxScore = 0; + currentRoundData.forEach((row) => { + const sum = row.reviews.reduce((acc, val) => acc + val.score, 0); + row.RowAvg = sum / row.reviews.length; + totalAvg = row.RowAvg + totalAvg; + totalMaxScore = totalMaxScore + row.maxScore; + questionCount++; + }); + + const averagePeerReviewScore = + questionCount > 0 + ? (((totalAvg / totalMaxScore) * 100) > 0 ? ((totalAvg / totalMaxScore) * 100).toFixed(2) : '0.00') + : '0.00'; + + const columnAverages: number[] = Array.from({ length: currentRoundData[0].reviews.length }, () => 0); + + currentRoundData.forEach((row) => { + row.reviews.forEach((val, index) => { + columnAverages[index] += val.score; + }); + }); + + columnAverages.forEach((sum, index) => { + columnAverages[index] = (sum / totalMaxScore) * 5; + }); + + let sortedData = [...currentRoundData]; + + if (sortOrderRow === 'asc') { + sortedData = currentRoundData.slice().sort((a, b) => a.RowAvg - b.RowAvg); + } else if (sortOrderRow === 'desc') { + sortedData = currentRoundData.slice().sort((a, b) => b.RowAvg - a.RowAvg); + } + + return { averagePeerReviewScore, columnAverages, sortedData }; +}; \ No newline at end of file From 15d337010741b9a282cbf7db48fc7595a57922ed Mon Sep 17 00:00:00 2001 From: Nisarg Doshi Date: Wed, 20 Mar 2024 19:56:51 -0400 Subject: [PATCH 06/18] Update ReviewTable.tsx --- src/pages/ViewTeamGrades/ReviewTable.tsx | 110 ++++++++++++++++++++--- 1 file changed, 97 insertions(+), 13 deletions(-) diff --git a/src/pages/ViewTeamGrades/ReviewTable.tsx b/src/pages/ViewTeamGrades/ReviewTable.tsx index 4cbca17..f7879f5 100644 --- a/src/pages/ViewTeamGrades/ReviewTable.tsx +++ b/src/pages/ViewTeamGrades/ReviewTable.tsx @@ -1,5 +1,10 @@ import React, { useState } from 'react'; +import ReviewTableRow from './ReviewTableRow'; +import RoundSelector from './RoundSelector'; +import { dummyDataRounds} from './dummyData'; +import { calculateAverages, getColorClass } from './utils'; import './grades.scss'; +<<<<<<< Updated upstream import ShowSubmission from './ShowSubmission'; // Import the ShowSubmission component import { Link } from 'react-router-dom'; @@ -115,30 +120,38 @@ dummyData.forEach((row) => { columnAverages.forEach((sum, index) => { columnAverages[index] = (sum / totalMaxScore) * 5; }); +======= +import { Link } from 'react-router-dom'; +>>>>>>> Stashed changes const ReviewTable: React.FC = () => { - const [filterValue, setFilterValue] = useState(null); - const [sortOrderRow, setsortOrderRow] = useState<'asc' | 'desc' | 'none'>('none'); + const [currentRound, setCurrentRound] = useState(0); + const [sortOrderRow, setSortOrderRow] = useState<'asc' | 'desc' | 'none'>('none'); + const [showWordCount10, setShowWordCount10] = useState(false); + const [showWordCount20, setShowWordCount20] = useState(false); + const toggleSortOrderRow = () => { - setsortOrderRow((prevSortOrder) => { + setSortOrderRow((prevSortOrder) => { if (prevSortOrder === 'asc') return 'desc'; if (prevSortOrder === 'desc') return 'none'; return 'asc'; }); }; - const getColorClass = (score: number, maxScore: number) => { - let scoreColor = score; - scoreColor = ((maxScore - scoreColor) / maxScore) * 100; - if (scoreColor >= 80) return 'c1'; - else if (scoreColor >= 60 && scoreColor < 80) return 'c2'; - else if (scoreColor >= 40 && scoreColor < 60) return 'c3'; - else if (scoreColor >= 20 && scoreColor < 40) return 'c4'; - else if (scoreColor >= 0 && scoreColor < 20) return 'c5'; - else return 'cf'; + const currentRoundData = dummyDataRounds[currentRound]; + const { averagePeerReviewScore, columnAverages, sortedData } = calculateAverages( + currentRoundData, + sortOrderRow + ); + + const handleRoundChange = (roundIndex: number) => { + setCurrentRound(roundIndex); + setShowWordCount10(false); + setShowWordCount20(false); }; +<<<<<<< Updated upstream const averageScoreColorClass = getColorClass(totalAvg, totalMaxScore); let sortedData = [...dummyData]; @@ -148,16 +161,44 @@ const ReviewTable: React.FC = () => { sortedData = dummyData.slice().sort((a, b) => b.RowAvg - a.RowAvg); } +======= +>>>>>>> Stashed changes return (

Summary Report for assignment: Program 2

Team: Thala4AReason
+<<<<<<< Updated upstream
Average peer review score: {averagePeerReviewScore}
+======= +
+ Average peer review score:{' '} + {averagePeerReviewScore} +
+
+ setShowWordCount10(e.target.checked)} + /> + + setShowWordCount20(e.target.checked)} + /> + +
+>>>>>>> Stashed changes


+<<<<<<< Updated upstream {Array.from({ length: dummyData[0].reviews.length }, (_, i) => ( @@ -182,6 +223,38 @@ const ReviewTable: React.FC = () => { ))} +======= + + + {Array.from({ length: currentRoundData[0].reviews.length }, (_, i) => ( + + ))} + + {showWordCount10 && } + {showWordCount20 && } + + + + {sortedData.map((row, index) => ( + + ))} + + + {columnAverages.map((avg, index) => ( + +>>>>>>> Stashed changes ))} @@ -191,8 +264,11 @@ const ReviewTable: React.FC = () => {
Question No.{row.RowAvg.toFixed(2)}
Question No.{`Review ${i + 1}`} + Avg + {sortOrderRow === "none" && ▲▼} + {sortOrderRow === "asc" && } + {sortOrderRow === "desc" && } + 10+ Words20+ Words
Avg + {avg.toFixed(2)} +
Avg
+

+

+<<<<<<< Updated upstream Team members: (Chaitanya Srusti) (Nisarg Nilesh Doshi) (Aniruddha Rajnekar)(Malick, Kashika)



@@ -205,8 +281,16 @@ const ReviewTable: React.FC = () => { Back +======= +

Grade and comment for submission

+ Grade: Grade for submission

+ Comment: Comment for submission

+ Late Penalty: 0

+

+ Back +>>>>>>> Stashed changes
); }; -export default ReviewTable; +export default ReviewTable; \ No newline at end of file From 90e09b52665ef4921ca30667c4fb6a6367d426db Mon Sep 17 00:00:00 2001 From: Nisarg Nilesh Doshi <70905787+Nisarg20@users.noreply.github.com> Date: Wed, 20 Mar 2024 22:36:27 -0400 Subject: [PATCH 07/18] Update ReviewTable.tsx --- src/pages/ViewTeamGrades/ReviewTable.tsx | 187 +---------------------- 1 file changed, 2 insertions(+), 185 deletions(-) diff --git a/src/pages/ViewTeamGrades/ReviewTable.tsx b/src/pages/ViewTeamGrades/ReviewTable.tsx index f7879f5..916b0e4 100644 --- a/src/pages/ViewTeamGrades/ReviewTable.tsx +++ b/src/pages/ViewTeamGrades/ReviewTable.tsx @@ -4,126 +4,8 @@ import RoundSelector from './RoundSelector'; import { dummyDataRounds} from './dummyData'; import { calculateAverages, getColorClass } from './utils'; import './grades.scss'; -<<<<<<< Updated upstream -import ShowSubmission from './ShowSubmission'; // Import the ShowSubmission component import { Link } from 'react-router-dom'; -interface ReviewData { - questionNumber: string; - questionText: string; // New property to hold the question text - reviews: { score: number; comment?: string }[]; - RowAvg: number; - maxScore: number; -} - -const dummyData: ReviewData[] = [ - { - questionNumber: '1', - questionText: 'What is the main purpose of this feature?', - reviews: [ - { score: 5, comment: 'Great explanation!' }, - { score: 4, comment: 'Good, but could be clearer' }, - { score: 4 }, - { score: 4 }, - { score: 5 }, - { score: 5 }, - { score: 5 }, - { score: 5 }, - { score: 2, comment: 'Needs improvement' }, - { score: 5 } - ], - RowAvg: 0, - maxScore: 5 - }, - { - questionNumber: '2', - questionText: 'How user-friendly is this feature?', - reviews: [ - { score: 5 }, - { score: 3, comment: 'Confusing UI' }, - { score: 5 }, - { score: 3 }, - { score: 5 }, - { score: 5 }, - { score: 5 }, - { score: 5 }, - { score: 5 }, - { score: 5 } - ], - RowAvg: 0, - maxScore: 5 - }, - { - questionNumber: '3', - questionText: 'Does this feature meet the project requirements?', - reviews: [ - { score: 1 }, - { score: 5 }, - { score: 5 }, - { score: 4 }, - { score: 5 }, - { score: 5 }, - { score: 5 }, - { score: 5 }, - { score: 5 }, - { score: 5 } - ], - RowAvg: 0, - maxScore: 5 - }, - { - questionNumber: '4', - questionText: 'How would you rate the performance of this feature?', - reviews: [ - { score: 1 }, - { score: 1, comment: 'Very slow response time' }, - { score: 1 }, - { score: 0 }, - { score: 1 }, - { score: 0 }, - { score: 1 }, - { score: 0 }, - { score: 1 }, - { score: 0 } - ], - RowAvg: 0, - maxScore: 1 - } -]; - -let totalAvg = 0; -let questionCount = 0; -let totalMaxScore = 0; -// Calculate average for each row -dummyData.forEach((row) => { - const sum = row.reviews.reduce((acc, val) => acc + val.score, 0); - row.RowAvg = sum / row.reviews.length; - totalAvg = row.RowAvg + totalAvg; - totalMaxScore = totalMaxScore + row.maxScore; - questionCount++; -}); - -const averagePeerReviewScore = - questionCount > 0 - ? (((totalAvg / totalMaxScore) * 100) > 0 ? ((totalAvg / totalMaxScore) * 100).toFixed(2) : '0.00') - : '0.00'; - -const columnAverages: number[] = Array.from({ length: dummyData[0].reviews.length }, () => 0); - -// Calculate column averages -dummyData.forEach((row) => { - row.reviews.forEach((val, index) => { - columnAverages[index] += val.score; - }); -}); - -columnAverages.forEach((sum, index) => { - columnAverages[index] = (sum / totalMaxScore) * 5; -}); -======= -import { Link } from 'react-router-dom'; ->>>>>>> Stashed changes - const ReviewTable: React.FC = () => { const [currentRound, setCurrentRound] = useState(0); const [sortOrderRow, setSortOrderRow] = useState<'asc' | 'desc' | 'none'>('none'); @@ -149,28 +31,11 @@ const ReviewTable: React.FC = () => { setShowWordCount10(false); setShowWordCount20(false); }; - - -<<<<<<< Updated upstream - const averageScoreColorClass = getColorClass(totalAvg, totalMaxScore); - let sortedData = [...dummyData]; - - if (sortOrderRow === 'asc') { - sortedData = dummyData.slice().sort((a, b) => a.RowAvg - b.RowAvg); - } else if (sortOrderRow === 'desc') { - sortedData = dummyData.slice().sort((a, b) => b.RowAvg - a.RowAvg); - } -======= ->>>>>>> Stashed changes return (

Summary Report for assignment: Program 2

Team: Thala4AReason
-<<<<<<< Updated upstream -
Average peer review score: {averagePeerReviewScore}
- -=======
Average peer review score:{' '} {averagePeerReviewScore} @@ -193,37 +58,10 @@ const ReviewTable: React.FC = () => { /> ->>>>>>> Stashed changes


-<<<<<<< Updated upstream - - - {Array.from({ length: dummyData[0].reviews.length }, (_, i) => ( - - ))} - - - - - {sortedData.map((row, index) => ( - - - {row.reviews.map((review, idx) => ( - - ))} - - -======= {Array.from({ length: currentRoundData[0].reviews.length }, (_, i) => ( @@ -254,43 +92,22 @@ const ReviewTable: React.FC = () => { ->>>>>>> Stashed changes ))} - - - {columnAverages.map((avg, index) => ( - - ))} - +
Question No.{`Review ${i + 1}`} - Avg - {sortOrderRow === "none" && ▲▼} - {sortOrderRow === "asc" && } - {sortOrderRow === "desc" && } -
{row.questionNumber} - {review.score} - {row.RowAvg.toFixed(2)}
Question No. {avg.toFixed(2)}
Avg{avg.toFixed(2)}


-<<<<<<< Updated upstream - Team members: (Chaitanya Srusti) (Nisarg Nilesh Doshi) (Aniruddha Rajnekar)(Malick, Kashika) -

-

-

-

Grade and comment for submission

- Grade: Grade for submission

- Comment: Comment for submission

- Late Penalty: 0

-

- - Back - -=======

Grade and comment for submission

Grade: Grade for submission

Comment: Comment for submission

Late Penalty: 0

Back ->>>>>>> Stashed changes
); }; -export default ReviewTable; \ No newline at end of file +export default ReviewTable; From 56a3b3717c1b65b192502bc3cc459007971970ff Mon Sep 17 00:00:00 2001 From: Nisarg Doshi Date: Sun, 24 Mar 2024 17:20:44 -0400 Subject: [PATCH 08/18] Updated Dummy data from type script file to json file. Added a visual representation of total marks per question --- src/pages/ViewTeamGrades/App.tsx | 16 +- src/pages/ViewTeamGrades/Data/dummyData.json | 7 + .../ViewTeamGrades/Data/heatMapData.json | 371 ++++++++++++++++++ src/pages/ViewTeamGrades/ReviewTableRow.tsx | 30 +- src/pages/ViewTeamGrades/RoundSelector.tsx | 24 +- src/pages/ViewTeamGrades/ShowSubmission.tsx | 9 +- src/pages/ViewTeamGrades/dummyData.ts | 142 ------- src/pages/ViewTeamGrades/grades.scss | 117 +++--- src/pages/ViewTeamGrades/utils.ts | 9 +- 9 files changed, 518 insertions(+), 207 deletions(-) create mode 100644 src/pages/ViewTeamGrades/Data/dummyData.json create mode 100644 src/pages/ViewTeamGrades/Data/heatMapData.json delete mode 100644 src/pages/ViewTeamGrades/dummyData.ts diff --git a/src/pages/ViewTeamGrades/App.tsx b/src/pages/ViewTeamGrades/App.tsx index 533d86a..61139fd 100644 --- a/src/pages/ViewTeamGrades/App.tsx +++ b/src/pages/ViewTeamGrades/App.tsx @@ -1,12 +1,22 @@ import React from 'react'; -import ReviewTable from './ReviewTable'; +import ReviewTable from './ReviewTable'; // Importing the ReviewTable component +// Interface defining the structure of ReviewData +export interface ReviewData { + questionNumber: string; + questionText: string; + reviews: { score: number; comment?: string }[]; // Array of objects with score and optional comment + RowAvg: number; // Average score for the row + maxScore: number; // Maximum possible score +} + +// Functional component App, which renders the ReviewTable const App: React.FC = () => { return (
- + {/* Rendering the ReviewTable component */}
); }; -export default App; \ No newline at end of file +export default App; // Exporting the App component as default diff --git a/src/pages/ViewTeamGrades/Data/dummyData.json b/src/pages/ViewTeamGrades/Data/dummyData.json new file mode 100644 index 0000000..432a1df --- /dev/null +++ b/src/pages/ViewTeamGrades/Data/dummyData.json @@ -0,0 +1,7 @@ +{ + "team": "Straw Hat Pirates", + "members": ["Chaitanya Srusti", "Nisarg Nilesh Doshi", "Aniruddha Rajnekar", "Malick, Kashika"], + "grade": "Grade for submission", + "comment": "Comment for submission", + "late_penalty": 0 +} \ No newline at end of file diff --git a/src/pages/ViewTeamGrades/Data/heatMapData.json b/src/pages/ViewTeamGrades/Data/heatMapData.json new file mode 100644 index 0000000..3a7c4dc --- /dev/null +++ b/src/pages/ViewTeamGrades/Data/heatMapData.json @@ -0,0 +1,371 @@ +[ + [ + { + "questionNumber": "1", + "questionText": "What is the main purpose of this feature?", + "reviews": [ + { "score": 4, "comment": "Great work on this aspect!" }, + { "score": 3, "comment": "Could use some improvement here." }, + { "score": 4, "comment": "The presentation was well-organized and clear. However, some points could have been elaborated further to provide a deeper understanding of the topic." }, + { "score": 5, "comment": "The speaker demonstrated a profound understanding of the subject matter, making the session engaging and informative." }, + { "score": 4, "comment": "The visuals were compelling and helped in understanding complex concepts easily. However, there were a few slides with too much text, which made it hard to follow at times." }, + { "score": 5, "comment": "The use of real-world examples made the concepts more relatable and easier to grasp. Additionally, the speaker was engaging and kept the audience hooked throughout." }, + { "score": 4, "comment": "The interactive exercises were beneficial in reinforcing the learning. However, there were a few technical glitches that disrupted the flow." }, + { "score": 5, "comment": "The hands-on activities were the highlight of the session, providing practical experience that complemented the theoretical learning." }, + { "score": 4, "comment": "The guest speaker brought a fresh perspective to the topic, offering valuable insights that sparked further discussions among the participants." }, + { "score": 5, "comment": "The case studies presented were enlightening, providing practical examples that showcased the application of theoretical concepts." } + ], + "RowAvg": 0, + "maxScore": 5 + }, + { + "questionNumber": "2", + "questionText": "How user-friendly is this feature?", + "reviews": [ + { "score": 4, "comment": "The interface was intuitive and easy to navigate." }, + { "score": 2, "comment": "There were some confusing elements that could be simplified." }, + { "score": 5, "comment": "The feature was straightforward to use, with clear instructions." }, + { "score": 2, "comment": "The user experience could be improved, especially for new users." }, + { "score": 3, "comment": "Some aspects were user-friendly, but others required a learning curve." }, + { "score": 2, "comment": "More tooltips or hints could enhance the user-friendliness." }, + { "score": 3, "comment": "Overall, the feature was easy to grasp, but minor improvements could enhance the user experience." }, + { "score": 4, "comment": "The feature was generally user-friendly, with a few areas for improvement." }, + { "score": 3, "comment": "Certain functions were straightforward, while others could use simplification." }, + { "score": 2, "comment": "The feature would benefit from clearer labels and instructions." } + ], + "RowAvg": 0, + "maxScore": 5 + }, + { + "questionNumber": "3", + "questionText": "Does this feature meet the project requirements?", + "reviews": [ + { "score": 1}, + { "score": 1}, + { "score": 1}, + { "score": 0}, + { "score": 1}, + { "score": 0}, + { "score": 1}, + { "score": 1}, + { "score": 1}, + { "score": 0} + ], + "RowAvg": 0, + "maxScore": 1 + }, + { + "questionNumber": "4", + "questionText": "How would you rate the performance of this feature?", + "reviews": [ + { "score": 4, "comment": "The feature performs adequately under normal conditions." }, + { "score": 2, "comment": "Performance could be improved, especially for larger datasets." }, + { "score": 4, "comment": "The feature's performance is generally satisfactory." }, + { "score": 1, "comment": "Performance issues were encountered during testing." }, + { "score": 3, "comment": "Overall, the feature performs well, but some optimizations could enhance speed." }, + { "score": 2, "comment": "The feature's performance is acceptable but could be faster." }, + { "score": 3, "comment": "The feature handles most tasks efficiently, but a few functions could be optimized." }, + { "score": 4, "comment": "Performance is stable and meets expectations for regular use." }, + { "score": 3, "comment": "The feature's performance meets the needs for the intended tasks." }, + { "score": 2, "comment": "There were occasional lags in performance during heavy usage." } + ], + "RowAvg": 0, + "maxScore": 5 + }, + { + "questionNumber": "5", + "questionText": "What are your thoughts on the design of this feature?", + "reviews": [ + { "score": 4, "comment": "The design is sleek and modern, enhancing usability." }, + { "score": 3, "comment": "Some design elements could be more cohesive." }, + { "score": 5, "comment": "The feature's design is intuitive and visually appealing." }, + { "score": 2, "comment": "The design could be more user-centric." }, + { "score": 4, "comment": "Overall, the design facilitates ease of use." }, + { "score": 3, "comment": "Certain design choices enhance functionality, while others could be refined." }, + { "score": 4, "comment": "The design aligns well with the feature's purpose." }, + { "score": 5, "comment": "The design elements contribute to a seamless user experience." }, + { "score": 4, "comment": "Design considerations are apparent, benefiting user interaction." }, + { "score": 2, "comment": "Some design aspects may confuse new users." } + ], + "RowAvg": 0, + "maxScore": 5 + }, + { + "questionNumber": "6", + "questionText": "Were the documentation and help resources helpful?", + "reviews": [ + { "score": 3, "comment": "The design is average, with room for improvement." }, + { "score": 5, "comment": "Certain design elements enhance usability effectively." }, + { "score": 5, "comment": "The design stands out with its intuitive layout." }, + { "score": 3, "comment": "Some design aspects could be more cohesive." }, + { "score": 5, "comment": "The feature's design is modern and visually appealing." }, + { "score": 5, "comment": "Design considerations are apparent, benefiting user interaction." }, + { "score": 3, "comment": "The design offers room for improvement in certain areas." }, + { "score": 4, "comment": "The feature's design is clean and uncluttered." }, + { "score": 5, "comment": "Certain design elements contribute significantly to usability." }, + { "score": 3, "comment": "The design could be more user-centric." } + ], + + "RowAvg": 0, + "maxScore": 5 + }, + { + "questionNumber": "7", + "questionText": "Did the feature perform well under stress/load?", + "reviews": [ + { "score": 5, "comment": "The design is sleek and modern, enhancing usability." }, + { "score": 5, "comment": "The feature's design is intuitive and visually appealing." }, + { "score": 3, "comment": "Some design elements could be streamlined for clarity." }, + { "score": 5, "comment": "Overall, the design facilitates ease of use." }, + { "score": 5, "comment": "The design elements contribute to a seamless user experience." }, + { "score": 3, "comment": "Certain design choices enhance functionality, while others could be refined." }, + { "score": 5, "comment": "The design aligns well with the feature's purpose." }, + { "score": 5, "comment": "The design delights users with its attention to detail." }, + { "score": 3, "comment": "Some design aspects may confuse new users." }, + { "score": 4, "comment": "The design balances aesthetics with functionality effectively." } + ], + + "RowAvg": 0, + "maxScore": 5 + }, + { + "questionNumber": "8", + "questionText": "How satisfied are you with the support provided for this feature?", + "reviews": [ + { "score": 3 }, + { "score": 4 }, + { "score": 5 }, + { "score": 2 }, + { "score": 4 }, + { "score": 3 }, + { "score": 4 }, + { "score": 5 }, + { "score": 4 }, + { "score": 2 } + ], + "RowAvg": 0, + "maxScore": 5 + }, + { + "questionNumber": "9", + "questionText": "Would you recommend this feature to others?", + "reviews": [ + { "score": 5, "comment": "The design is exceptional, exceeding expectations." }, + { "score": 3, "comment": "Certain design aspects could be polished further." }, + { "score": 5, "comment": "Overall, the design enhances user experience effectively." }, + { "score": 5, "comment": "The feature's design is top-notch, setting a new standard." }, + { "score": 3, "comment": "Some design elements could be more intuitive." }, + { "score": 5, "comment": "The design offers a pleasant user journey." }, + { "score": 5, "comment": "Design considerations are evident, making tasks straightforward." }, + { "score": 3, "comment": "Certain design choices may require further refinement." }, + { "score": 5, "comment": "The design adapts well to different screen sizes and devices." }, + { "score": 5, "comment": "The feature's design is a joy to interact with." } + ], + + "RowAvg": 0, + "maxScore": 5 + }, + { + "questionNumber": "10", + "questionText": "Overall, how would you rate this feature?", + "reviews": [ + { "score": 4, "comment": "The design is polished and professional." }, + { "score": 5, "comment": "Certain design elements make the feature a joy to use." }, + { "score": 3, "comment": "Some design aspects could benefit from refinement." }, + { "score": 5, "comment": "The design is user-friendly, with intuitive navigation." }, + { "score": 5, "comment": "Certain design elements enhance user interaction effectively." }, + { "score": 3, "comment": "Some design aspects may require further attention." }, + { "score": 5, "comment": "The design encourages exploration and discovery." }, + { "score": 5, "comment": "The feature's design sets a new standard for user interfaces." }, + { "score": 3, "comment": "Certain design elements are confusing and could be clarified." }, + { "score": 5, "comment": "The design offers an inviting and engaging experience." } + ], + + "RowAvg": 0, + "maxScore": 5 + } + ], + [ + { + "questionNumber": "1", + "questionText": "What is the main purpose of this feature?", + "reviews": [ + { "score": 4, "comment": "The design is polished and professional." }, + { "score": 5, "comment": "Certain design elements make the feature a joy to use." }, + { "score": 3, "comment": "Some design aspects could benefit from refinement." }, + { "score": 4, "comment": "The design is user-friendly, with intuitive navigation." }, + { "score": 5, "comment": "Certain design elements enhance user interaction effectively." }, + { "score": 4, "comment": "Some design aspects may require further attention." }, + { "score": 4, "comment": "The design encourages exploration and discovery." }, + { "score": 5, "comment": "The feature's design sets a new standard for user interfaces." }, + { "score": 4, "comment": "Certain design elements are confusing and could be clarified." }, + { "score": 4, "comment": "The design offers an inviting and engaging experience." } + ], + "RowAvg": 0, + "maxScore": 5 + }, + { + "questionNumber": "2", + "questionText": "How user-friendly is this feature?", + "reviews": [ + { "score": 5, "comment": "The design is flawless, making tasks effortless." }, + { "score": 2, "comment": "Some design aspects could be more user-oriented." }, + { "score": 4, "comment": "The feature's design is inviting and approachable." }, + { "score": 5, "comment": "Certain design elements provide a delightful user journey." }, + { "score": 2, "comment": "Some design choices could enhance user engagement." }, + { "score": 4, "comment": "The design adapts well to varying user needs." }, + { "score": 5, "comment": "The feature's design excels in simplicity and effectiveness." }, + { "score": 3, "comment": "Certain design elements could benefit from more visual hierarchy." }, + { "score": 4, "comment": "The design offers a pleasing aesthetic while being functional." }, + { "score": 5, "comment": "The feature's design is intuitive and user-centric." } + ], + "RowAvg": 0, + "maxScore": 5 + }, + { + "questionNumber": "3", + "questionText": "Does this feature meet the project requirements?", + "reviews": [ + { "score": 1}, + { "score": 1}, + { "score": 1}, + { "score": 0}, + { "score": 1}, + { "score": 0}, + { "score": 1}, + { "score": 0}, + { "score": 0}, + { "score": 1 } + ], + "RowAvg": 0, + "maxScore": 1 + }, + { + "questionNumber": "4", + "questionText": "How would you rate the performance of this feature?", + "reviews": [ + { "score": 5, "comment": "The design is exceptional, exceeding expectations." }, + { "score": 5, "comment": "Certain design aspects could be polished further." }, + { "score": 4, "comment": "Overall, the design enhances user experience effectively." }, + { "score": 5, "comment": "The feature's design is top-notch, setting a new standard." }, + { "score": 0, "comment": "Some design elements could be more intuitive." }, + { "score": 4, "comment": "The design offers a pleasant user journey." }, + { "score": 5, "comment": "Design considerations are evident, making tasks straightforward." }, + { "score": 5, "comment": "Certain design choices may require further refinement." }, + { "score": 5, "comment": "The design adapts well to different screen sizes and devices." }, + { "score": 5, "comment": "The feature's design is a joy to interact with." } + ], + "RowAvg": 0, + "maxScore": 5 + }, + { + "questionNumber": "5", + "questionText": "What are your thoughts on the design of this feature?", + "reviews": [ + { "score": 4, "comment": "The design is polished and professional." }, + { "score": 5, "comment": "Certain design elements make the feature a joy to use." }, + { "score": 3, "comment": "Some design aspects could benefit from refinement." }, + { "score": 4, "comment": "The design is user-friendly, with intuitive navigation." }, + { "score": 5, "comment": "Certain design elements enhance user interaction effectively." }, + { "score": 2, "comment": "Some design aspects may require further attention." }, + { "score": 4, "comment": "The design encourages exploration and discovery." }, + { "score": 5, "comment": "The feature's design sets a new standard for user interfaces." }, + { "score": 4, "comment": "Certain design elements are confusing and could be clarified." }, + { "score": 4, "comment": "The design offers an inviting and engaging experience." } + ], + "RowAvg": 0, + "maxScore": 5 + }, + { + "questionNumber": "6", + "questionText": "Were the documentation and help resources helpful?", + "reviews": [ + { "score": 5, "comment": "The design is flawless, making tasks effortless." }, + { "score": 3, "comment": "Some design aspects could be more user-oriented." }, + { "score": 5, "comment": "The feature's design is inviting and approachable." }, + { "score": 5, "comment": "Certain design elements provide a delightful user journey." }, + { "score": 3, "comment": "Some design choices could enhance user engagement." }, + { "score": 4, "comment": "The design adapts well to varying user needs." }, + { "score": 5, "comment": "The feature's design excels in simplicity and effectiveness." }, + { "score": 1, "comment": "Certain design elements could benefit from more visual hierarchy." }, + { "score": 5, "comment": "The design offers a pleasing aesthetic while being functional." }, + { "score": 5, "comment": "The feature's design is intuitive and user-centric." } + ], + "RowAvg": 0, + "maxScore": 5 + }, + { + "questionNumber": "7", + "questionText": "Did the feature perform well under stress/load?", + "reviews": [ + { "score": 4, "comment": "The design is sleek and modern, enhancing usability." }, + { "score": 5, "comment": "The feature's design is intuitive and visually appealing." }, + { "score": 3, "comment": "Some design elements could be streamlined for clarity." }, + { "score": 4, "comment": "Overall, the design facilitates ease of use." }, + { "score": 5, "comment": "The design elements contribute to a seamless user experience." }, + { "score": 2, "comment": "Certain design choices enhance functionality, while others could be refined." }, + { "score": 4, "comment": "The design aligns well with the feature's purpose." }, + { "score": 5, "comment": "The design delights users with its attention to detail." }, + { "score": 2, "comment": "Some design aspects may confuse new users." }, + { "score": 4, "comment": "The design balances aesthetics with functionality effectively." } + ], + + "RowAvg": 0, + "maxScore": 5 + }, + { + "questionNumber": "8", + "questionText": "How satisfied are you with the support provided for this feature?", + "reviews": [ + { "score": 5, "comment": "The design is exceptional, exceeding expectations." }, + { "score": 4, "comment": "Certain design aspects could be polished further." }, + { "score": 4, "comment": "Overall, the design enhances user experience effectively." }, + { "score": 5, "comment": "The feature's design is top-notch, setting a new standard." }, + { "score": 2, "comment": "Some design elements could be more intuitive." }, + { "score": 4, "comment": "The design offers a pleasant user journey." }, + { "score": 5, "comment": "Design considerations are evident, making tasks straightforward." }, + { "score": 3, "comment": "Certain design choices may require further refinement." }, + { "score": 4, "comment": "The design adapts well to different screen sizes and devices." }, + { "score": 5, "comment": "The feature's design is a joy to interact with." } + ], + "RowAvg": 0, + "maxScore": 5 + }, + { + "questionNumber": "9", + "questionText": "Would you recommend this feature to others?", + "reviews": [ + { "score": 5, "comment": "The design is flawless, making tasks effortless." }, + { "score": 3, "comment": "Some design aspects could be more user-oriented." }, + { "score": 4, "comment": "The feature's design is inviting and approachable." }, + { "score": 5, "comment": "Certain design elements provide a delightful user journey." }, + { "score": 2, "comment": "Some design choices could enhance user engagement." }, + { "score": 4, "comment": "The design adapts well to varying user needs." }, + { "score": 5, "comment": "The feature's design excels in simplicity and effectiveness." }, + { "score": 2, "comment": "Certain design elements could benefit from more visual hierarchy." }, + { "score": 4, "comment": "The design offers a pleasing aesthetic while being functional." }, + { "score": 5, "comment": "The feature's design is intuitive and user-centric." } + ], + "RowAvg": 0, + "maxScore": 5 + }, + { + "questionNumber": "10", + "questionText": "Overall, how would you rate this feature?", + "reviews": [ + { "score": 4, "comment": "The design is sleek and modern, enhancing usability." }, + { "score": 5, "comment": "The feature's design is intuitive and visually appealing." }, + { "score": 3, "comment": "Some design elements could be streamlined for clarity." }, + { "score": 4, "comment": "Overall, the design facilitates ease of use." }, + { "score": 3, "comment": "The design elements contribute to a seamless user experience." }, + { "score": 3, "comment": "Certain design choices enhance functionality, while others could be refined. Overall scope of improvement" }, + { "score": 4, "comment": "The design aligns well with the feature's purpose." }, + { "score": 5, "comment": "The design delights users with its attention to detail." }, + { "score": 4, "comment": "Some design aspects may confuse new users." }, + { "score": 4, "comment": "The design balances aesthetics with functionality effectively." } + ], + "RowAvg": 0, + "maxScore": 5 + } + ] +] \ No newline at end of file diff --git a/src/pages/ViewTeamGrades/ReviewTableRow.tsx b/src/pages/ViewTeamGrades/ReviewTableRow.tsx index c10e26f..78798ed 100644 --- a/src/pages/ViewTeamGrades/ReviewTableRow.tsx +++ b/src/pages/ViewTeamGrades/ReviewTableRow.tsx @@ -1,19 +1,31 @@ import React from 'react'; -import { getColorClass, getWordCount10, getWordCount20 } from './utils'; -import { ReviewData } from './dummyData'; +import { getColorClass, getWordCount10, getWordCount20 } from './utils'; // Importing utility functions +import { ReviewData } from './App'; // Importing the ReviewData interface from App +// Props interface for ReviewTableRow component interface ReviewTableRowProps { - row: ReviewData; - showWordCount10: boolean; - showWordCount20: boolean; + row: ReviewData; // Data for the row + showWordCount10: boolean; // Flag to show reviews with 10+ words + showWordCount20: boolean; // Flag to show reviews with 20+ words } +// Functional component ReviewTableRow const ReviewTableRow: React.FC = ({ row, showWordCount10, showWordCount20 }) => { return ( + {/* Question Number */} - {row.questionNumber} +
+ {row.maxScore !== 1 ? ( + {row.maxScore} + ) : ( + + )} +       {row.questionNumber} +
+ + {/* Review Cells */} {row.reviews.map((review, idx) => ( = ({ row, showWordCount10, s {review.score} ))} + + {/* Row Average */} {row.RowAvg.toFixed(2)} + + {/* Optional columns for word count */} {showWordCount10 && {getWordCount10(row)}} {showWordCount20 && {getWordCount20(row)}} ); }; -export default ReviewTableRow; \ No newline at end of file +export default ReviewTableRow; // Exporting the ReviewTableRow component as default diff --git a/src/pages/ViewTeamGrades/RoundSelector.tsx b/src/pages/ViewTeamGrades/RoundSelector.tsx index 3904216..fd87daf 100644 --- a/src/pages/ViewTeamGrades/RoundSelector.tsx +++ b/src/pages/ViewTeamGrades/RoundSelector.tsx @@ -1,15 +1,25 @@ -import React from 'react'; -import { dummyDataRounds } from './dummyData'; +import React, { useState, useEffect } from 'react'; +import dummyDataRounds from './Data/heatMapData.json'; +import teamData from './Data/dummyData.json'; interface RoundSelectorProps { currentRound: number; handleRoundChange: (roundIndex: number) => void; } +// RoundSelector component to display buttons for selecting rounds const RoundSelector: React.FC = ({ currentRound, handleRoundChange }) => { + const [teamMembers, setTeamMembers] = useState([]); + + // Fetch team members from the teamData.json file on component mount + useEffect(() => { + setTeamMembers(teamData.members); + }, []); // Empty dependency array means it runs only once on component mount + return (
+ {/* Mapping over dummyDataRounds to render round buttons */} {dummyDataRounds.map((round, index) => ( ))} + {/* Displaying team members */} - Team members: (Chaitanya Srusti) (Nisarg Nilesh Doshi) (Aniruddha Rajnekar)(Malick, Kashika) + Team members: {teamMembers.map((member, index) => ( + + ({member}) + {index !== teamMembers.length - 1 && ' '} + + ))}
); }; -export default RoundSelector; \ No newline at end of file +export default RoundSelector; diff --git a/src/pages/ViewTeamGrades/ShowSubmission.tsx b/src/pages/ViewTeamGrades/ShowSubmission.tsx index 03ae077..2906ae7 100644 --- a/src/pages/ViewTeamGrades/ShowSubmission.tsx +++ b/src/pages/ViewTeamGrades/ShowSubmission.tsx @@ -1,11 +1,13 @@ import React, { useState } from 'react'; import { Button, Collapse } from 'react-bootstrap'; +// Component to show submission links with collapsible functionality const ShowSubmission = () => { - const [open, setOpen] = useState(false); + const [open, setOpen] = useState(false); // State to manage collapsible content return ( <> + {/* Button to toggle the collapsible content */} + + {/* Collapsible content */}


- {open && ( // Render links only when open is true + {/* Render links only when open is true */} + {open && ( <> div { display: flex; align-items: center; diff --git a/src/pages/ViewTeamGrades/utils.ts b/src/pages/ViewTeamGrades/utils.ts index 0751a36..1567b83 100644 --- a/src/pages/ViewTeamGrades/utils.ts +++ b/src/pages/ViewTeamGrades/utils.ts @@ -1,7 +1,9 @@ -import { ReviewData } from './dummyData'; +import { ReviewData } from './App'; +// Function to get color class based on score and maxScore export const getColorClass = (score: number, maxScore: number) => { let scoreColor = score; + scoreColor = ((maxScore - scoreColor) / maxScore) * 100; if (scoreColor >= 80) return 'c1'; else if (scoreColor >= 60 && scoreColor < 80) return 'c2'; @@ -11,18 +13,21 @@ export const getColorClass = (score: number, maxScore: number) => { else return 'cf'; }; +// Function to get count of reviews with more than 10 words export const getWordCount10 = (row: ReviewData) => { return row.reviews.filter( (review) => review.comment && review.comment.trim().split(' ').length > 10 ).length; }; +// Function to get count of reviews with more than 20 words export const getWordCount20 = (row: ReviewData) => { return row.reviews.filter( (review) => review.comment && review.comment.trim().split(' ').length > 20 ).length; }; +// Function to calculate averages for rows and columns export const calculateAverages = ( currentRoundData: ReviewData[], sortOrderRow: 'asc' | 'desc' | 'none' @@ -64,4 +69,4 @@ export const calculateAverages = ( } return { averagePeerReviewScore, columnAverages, sortedData }; -}; \ No newline at end of file +}; From 11ebcb50922a6356c1c29122bbb054a02b0be370 Mon Sep 17 00:00:00 2001 From: Nisarg Doshi Date: Sun, 24 Mar 2024 17:20:52 -0400 Subject: [PATCH 09/18] Update ReviewTable.tsx --- src/pages/ViewTeamGrades/ReviewTable.tsx | 46 ++++++++++++++++++++---- 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/src/pages/ViewTeamGrades/ReviewTable.tsx b/src/pages/ViewTeamGrades/ReviewTable.tsx index 916b0e4..a9f6dc2 100644 --- a/src/pages/ViewTeamGrades/ReviewTable.tsx +++ b/src/pages/ViewTeamGrades/ReviewTable.tsx @@ -1,4 +1,5 @@ import React, { useState } from 'react'; +<<<<<<< Updated upstream import ReviewTableRow from './ReviewTableRow'; import RoundSelector from './RoundSelector'; import { dummyDataRounds} from './dummyData'; @@ -6,12 +7,24 @@ import { calculateAverages, getColorClass } from './utils'; import './grades.scss'; import { Link } from 'react-router-dom'; +======= +import ReviewTableRow from './ReviewTableRow'; // Importing the ReviewTableRow component +import RoundSelector from './RoundSelector'; // Importing the RoundSelector component +import dummyDataRounds from './Data/heatMapData.json'; // Importing dummy data for rounds +import dummyData from './Data/dummyData.json'; // Importing dummy data +import { calculateAverages, getColorClass } from './utils'; // Importing utility functions +import './grades.scss'; // Importing styles +import { Link } from 'react-router-dom'; // Importing Link from react-router-dom + +// Functional component ReviewTable +>>>>>>> Stashed changes const ReviewTable: React.FC = () => { - const [currentRound, setCurrentRound] = useState(0); - const [sortOrderRow, setSortOrderRow] = useState<'asc' | 'desc' | 'none'>('none'); - const [showWordCount10, setShowWordCount10] = useState(false); - const [showWordCount20, setShowWordCount20] = useState(false); + const [currentRound, setCurrentRound] = useState(0); // State for current round + const [sortOrderRow, setSortOrderRow] = useState<'asc' | 'desc' | 'none'>('none'); // State for row sort order + const [showWordCount10, setShowWordCount10] = useState(false); // State for showing reviews with more than 10 words + const [showWordCount20, setShowWordCount20] = useState(false); // State for showing reviews with more than 20 words + // Function to toggle the sort order for rows const toggleSortOrderRow = () => { setSortOrderRow((prevSortOrder) => { if (prevSortOrder === 'asc') return 'desc'; @@ -20,26 +33,38 @@ const ReviewTable: React.FC = () => { }); }; + // Calculating averages and sorting data based on the current round and sort order const currentRoundData = dummyDataRounds[currentRound]; const { averagePeerReviewScore, columnAverages, sortedData } = calculateAverages( currentRoundData, sortOrderRow ); + // Function to handle round change const handleRoundChange = (roundIndex: number) => { setCurrentRound(roundIndex); setShowWordCount10(false); setShowWordCount20(false); }; +<<<<<<< Updated upstream return (

Summary Report for assignment: Program 2

Team: Thala4AReason
+======= + // JSX rendering of the ReviewTable component + return ( +
+

Summary Report for assignment: Program 2

+
Team: {dummyData.team}
+>>>>>>> Stashed changes
- Average peer review score:{' '} + Average peer review score:{" "} {averagePeerReviewScore}
+

Review (Round: {currentRound + 1} of {dummyDataRounds.length})

+

{
-

@@ -101,13 +125,23 @@ const ReviewTable: React.FC = () => {

Grade and comment for submission

+<<<<<<< Updated upstream Grade: Grade for submission

Comment: Comment for submission

Late Penalty: 0

+======= + Grade: {dummyData.grade}

+ Comment: {dummyData.comment}

+ Late Penalty: {dummyData.late_penalty}

+>>>>>>> Stashed changes

Back ); }; +<<<<<<< Updated upstream export default ReviewTable; +======= +export default ReviewTable; // Exporting the ReviewTable component as default +>>>>>>> Stashed changes From ab40e2d918ca94da62ae50a310c948434c073d08 Mon Sep 17 00:00:00 2001 From: Nisarg Nilesh Doshi <70905787+Nisarg20@users.noreply.github.com> Date: Sun, 24 Mar 2024 17:26:18 -0400 Subject: [PATCH 10/18] Update ReviewTable.tsx --- src/pages/ViewTeamGrades/ReviewTable.tsx | 27 ------------------------ 1 file changed, 27 deletions(-) diff --git a/src/pages/ViewTeamGrades/ReviewTable.tsx b/src/pages/ViewTeamGrades/ReviewTable.tsx index a9f6dc2..6049c2f 100644 --- a/src/pages/ViewTeamGrades/ReviewTable.tsx +++ b/src/pages/ViewTeamGrades/ReviewTable.tsx @@ -1,13 +1,4 @@ import React, { useState } from 'react'; -<<<<<<< Updated upstream -import ReviewTableRow from './ReviewTableRow'; -import RoundSelector from './RoundSelector'; -import { dummyDataRounds} from './dummyData'; -import { calculateAverages, getColorClass } from './utils'; -import './grades.scss'; -import { Link } from 'react-router-dom'; - -======= import ReviewTableRow from './ReviewTableRow'; // Importing the ReviewTableRow component import RoundSelector from './RoundSelector'; // Importing the RoundSelector component import dummyDataRounds from './Data/heatMapData.json'; // Importing dummy data for rounds @@ -17,7 +8,6 @@ import './grades.scss'; // Importing styles import { Link } from 'react-router-dom'; // Importing Link from react-router-dom // Functional component ReviewTable ->>>>>>> Stashed changes const ReviewTable: React.FC = () => { const [currentRound, setCurrentRound] = useState(0); // State for current round const [sortOrderRow, setSortOrderRow] = useState<'asc' | 'desc' | 'none'>('none'); // State for row sort order @@ -47,18 +37,11 @@ const ReviewTable: React.FC = () => { setShowWordCount20(false); }; -<<<<<<< Updated upstream - return ( -
-

Summary Report for assignment: Program 2

-
Team: Thala4AReason
-======= // JSX rendering of the ReviewTable component return (

Summary Report for assignment: Program 2

Team: {dummyData.team}
->>>>>>> Stashed changes
Average peer review score:{" "} {averagePeerReviewScore} @@ -125,23 +108,13 @@ const ReviewTable: React.FC = () => {

Grade and comment for submission

-<<<<<<< Updated upstream - Grade: Grade for submission

- Comment: Comment for submission

- Late Penalty: 0

-======= Grade: {dummyData.grade}

Comment: {dummyData.comment}

Late Penalty: {dummyData.late_penalty}

->>>>>>> Stashed changes

Back
); }; -<<<<<<< Updated upstream -export default ReviewTable; -======= export default ReviewTable; // Exporting the ReviewTable component as default ->>>>>>> Stashed changes From b2eb31ec2594e3fd11b29c93c3e34af2ca3442df Mon Sep 17 00:00:00 2001 From: Aniruddha <46026542+Aniruddha-Rajnekar@users.noreply.github.com> Date: Sun, 24 Mar 2024 22:27:39 -0400 Subject: [PATCH 11/18] Renamed the Variable "test" to "ViewGrades" --- src/layout/Header.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/layout/Header.tsx b/src/layout/Header.tsx index fe06ba5..8e511a0 100644 --- a/src/layout/Header.tsx +++ b/src/layout/Header.tsx @@ -103,7 +103,7 @@ const Header: React.FC = () => { Student View - Test + ViewGrades @@ -120,4 +120,4 @@ const Header: React.FC = () => { ); }; -export default Header; \ No newline at end of file +export default Header; From dc08b4152ae28730447378d8a6c1be87cf128920 Mon Sep 17 00:00:00 2001 From: ChaitanyaS182k <141549134+ChaitanyaS182k@users.noreply.github.com> Date: Sun, 21 Apr 2024 12:04:06 -0400 Subject: [PATCH 12/18] Added Show Submission Button and Color Legend --- src/App.tsx | 6 ++++- src/pages/ViewTeamGrades/App.tsx | 1 + src/pages/ViewTeamGrades/ReviewTable.tsx | 9 +++++++ src/pages/ViewTeamGrades/grades.scss | 32 ++++++++++++++++++++++++ 4 files changed, 47 insertions(+), 1 deletion(-) diff --git a/src/App.tsx b/src/App.tsx index 51faeb9..29b5d62 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -45,7 +45,11 @@ function App() { // Add the ViewTeamGrades route { path: "view-team-grades", - element: } />, + element: + + + } />, }, { path: "edit-questionnaire", diff --git a/src/pages/ViewTeamGrades/App.tsx b/src/pages/ViewTeamGrades/App.tsx index 61139fd..1720245 100644 --- a/src/pages/ViewTeamGrades/App.tsx +++ b/src/pages/ViewTeamGrades/App.tsx @@ -1,5 +1,6 @@ import React from 'react'; import ReviewTable from './ReviewTable'; // Importing the ReviewTable component +import ShowSubmission from './ShowSubmission'; // Interface defining the structure of ReviewData export interface ReviewData { diff --git a/src/pages/ViewTeamGrades/ReviewTable.tsx b/src/pages/ViewTeamGrades/ReviewTable.tsx index 6049c2f..96c930f 100644 --- a/src/pages/ViewTeamGrades/ReviewTable.tsx +++ b/src/pages/ViewTeamGrades/ReviewTable.tsx @@ -6,6 +6,7 @@ import dummyData from './Data/dummyData.json'; // Importing dummy data import { calculateAverages, getColorClass } from './utils'; // Importing utility functions import './grades.scss'; // Importing styles import { Link } from 'react-router-dom'; // Importing Link from react-router-dom +import ShowSubmission from './ShowSubmission'; // Functional component ReviewTable const ReviewTable: React.FC = () => { @@ -46,6 +47,7 @@ const ReviewTable: React.FC = () => { Average peer review score:{" "} {averagePeerReviewScore} +

Review (Round: {currentRound + 1} of {dummyDataRounds.length})



@@ -65,7 +67,14 @@ const ReviewTable: React.FC = () => { onChange={(e) => setShowWordCount20(e.target.checked)} /> + +   Color Legend   + + Colors are scaled from Poor to Excellent in the following order: Red, Orange, Yellow, Light Green, Dark Green + + +
diff --git a/src/pages/ViewTeamGrades/grades.scss b/src/pages/ViewTeamGrades/grades.scss index 7aa03bd..daa7e10 100644 --- a/src/pages/ViewTeamGrades/grades.scss +++ b/src/pages/ViewTeamGrades/grades.scss @@ -222,3 +222,35 @@ margin: auto; } } + +.color-legend { + position: relative; + display: inline-block; + cursor: pointer; + + &:hover .tooltip-text { + visibility: visible; + opacity: 1; + } +} + +.tooltip-text { + visibility: hidden; + width: 280px; + background-color: black; + color: #fff; + text-align: center; + border-radius: 6px; + padding: 5px 0; + + /* Position the tooltip text */ + position: absolute; + z-index: 1; + bottom: 100%; + left: 150%; + margin-left: -140px; /* Use half of the width (280px/2), to center the tooltip */ + + /* Fade in tooltip */ + opacity: 0; + transition: opacity 0.3s; +} From f967a6ea0746d64d11ea184d798698de8b532c6d Mon Sep 17 00:00:00 2001 From: ChaitanyaS182k <141549134+ChaitanyaS182k@users.noreply.github.com> Date: Sun, 21 Apr 2024 17:20:59 -0400 Subject: [PATCH 13/18] Added Toggle Question Button and modified the Color Legend --- src/pages/ViewTeamGrades/ReviewTable.tsx | 59 +++++++++++++++++---- src/pages/ViewTeamGrades/ReviewTableRow.tsx | 19 ++++--- src/pages/ViewTeamGrades/grades.scss | 56 +++++++++++++++---- 3 files changed, 107 insertions(+), 27 deletions(-) diff --git a/src/pages/ViewTeamGrades/ReviewTable.tsx b/src/pages/ViewTeamGrades/ReviewTable.tsx index 96c930f..dfea9aa 100644 --- a/src/pages/ViewTeamGrades/ReviewTable.tsx +++ b/src/pages/ViewTeamGrades/ReviewTable.tsx @@ -14,6 +14,7 @@ const ReviewTable: React.FC = () => { const [sortOrderRow, setSortOrderRow] = useState<'asc' | 'desc' | 'none'>('none'); // State for row sort order const [showWordCount10, setShowWordCount10] = useState(false); // State for showing reviews with more than 10 words const [showWordCount20, setShowWordCount20] = useState(false); // State for showing reviews with more than 20 words + const [showFullQuestion, setShowFullQuestion] = useState(false); // State to toggle between question number and full question text // Function to toggle the sort order for rows const toggleSortOrderRow = () => { @@ -38,6 +39,15 @@ const ReviewTable: React.FC = () => { setShowWordCount20(false); }; + const colorLegend = [ + { color: 'Red', description: 'Poor', className: 'c1' }, + { color: 'Orange', description: 'Fair', className: 'c2' }, + { color: 'Yellow', description: 'Average', className: 'c3' }, + { color: 'LightGreen', description: 'Good', className: 'c4' }, + { color: 'DarkGreen', description: 'Excellent', className: 'c5' }, + ]; + + // JSX rendering of the ReviewTable component return (
@@ -58,7 +68,7 @@ const ReviewTable: React.FC = () => { checked={showWordCount10} onChange={(e) => setShowWordCount10(e.target.checked)} /> - + { checked={showWordCount20} onChange={(e) => setShowWordCount20(e.target.checked)} /> - - -   Color Legend   - - Colors are scaled from Poor to Excellent in the following order: Red, Orange, Yellow, Light Green, Dark Green - - + +          + setShowFullQuestion(e.target.checked)} + /> + - +
@@ -100,6 +113,7 @@ const ReviewTable: React.FC = () => { row={row} showWordCount10={showWordCount10} showWordCount20={showWordCount20} + showFullQuestion={showFullQuestion} // Pass this as a prop /> ))} @@ -115,6 +129,33 @@ const ReviewTable: React.FC = () => {

+
+ +   Color Legend   + + Colors are scaled from Poor to Excellent in the following order: Red, Orange, Yellow, Light Green, Dark Green + + +
+
+ + + + + + + + {colorLegend.map((item) => ( + + + + + ))} + +
ColorRating
{item.description}
+
+
+

Grade and comment for submission

Grade: {dummyData.grade}

diff --git a/src/pages/ViewTeamGrades/ReviewTableRow.tsx b/src/pages/ViewTeamGrades/ReviewTableRow.tsx index 78798ed..e85be4a 100644 --- a/src/pages/ViewTeamGrades/ReviewTableRow.tsx +++ b/src/pages/ViewTeamGrades/ReviewTableRow.tsx @@ -7,21 +7,26 @@ interface ReviewTableRowProps { row: ReviewData; // Data for the row showWordCount10: boolean; // Flag to show reviews with 10+ words showWordCount20: boolean; // Flag to show reviews with 20+ words + showFullQuestion: boolean; // New prop to toggle between question number and full question text + } // Functional component ReviewTableRow -const ReviewTableRow: React.FC = ({ row, showWordCount10, showWordCount20 }) => { +const ReviewTableRow: React.FC = ({ row, showWordCount10, showWordCount20, showFullQuestion }) => { return ( {/* Question Number */} - +
- {row.maxScore !== 1 ? ( - {row.maxScore} - ) : ( - + {!showFullQuestion && ( // Only show circle or tick when not showing full questions + row.maxScore !== 1 ? ( + {row.maxScore} + ) : ( + + ) )} -       {row.questionNumber} +        + {showFullQuestion ? row.questionText : row.questionNumber}
diff --git a/src/pages/ViewTeamGrades/grades.scss b/src/pages/ViewTeamGrades/grades.scss index daa7e10..8dd3e7e 100644 --- a/src/pages/ViewTeamGrades/grades.scss +++ b/src/pages/ViewTeamGrades/grades.scss @@ -91,7 +91,7 @@ width: 100%; font-size: 10px; text-align: center; - table-layout: fixed; + table-layout: auto; } .tbl_heat td { @@ -223,16 +223,6 @@ } } -.color-legend { - position: relative; - display: inline-block; - cursor: pointer; - - &:hover .tooltip-text { - visibility: visible; - opacity: 1; - } -} .tooltip-text { visibility: hidden; @@ -254,3 +244,47 @@ opacity: 0; transition: opacity 0.3s; } + +.question-cell { + text-align: left; // Align text to the left of the cell + padding-left: 10px; // Add padding on the left for better spacing + word-wrap: break-word; // Ensures long words do not overflow + overflow-wrap: break-word; + white-space: normal; // Allows text to wrap normally +} + + +.review-container { + display: flex; + justify-content: space-between; // Adjust as necessary to fit your design + + .table-container { + flex: 1 0 70%; // Your existing max-width but as flex basis + } + + .color-legend-container { + align-self: flex-start; // Align the legend container to the start of the flex container (top right) + width: auto; // Set the width as required by the content + text-align: center; // Center-align the text inside the legend container + + .color-legend { + margin-bottom: 5px; // Space between the label and the table + font-size: 16px; // Optional: Adjust font size for visibility + } + + table { + border-collapse: collapse; + width: 100%; + + th, td { + border: 1px solid black; + padding: 8px; + text-align: left; + } + + td { + color: #000; // Ensure text is readable, adjust as needed + } + } + } +} \ No newline at end of file From 8ef4a37be45aacd40f3b33c5782222b251debde3 Mon Sep 17 00:00:00 2001 From: ChaitanyaS182k <141549134+ChaitanyaS182k@users.noreply.github.com> Date: Mon, 22 Apr 2024 12:57:54 -0400 Subject: [PATCH 14/18] Added multiple rounds button --- src/pages/ViewTeamGrades/ReviewTable.tsx | 215 +++++++++++---------- src/pages/ViewTeamGrades/RoundSelector.tsx | 18 +- src/pages/ViewTeamGrades/utils.ts | 59 +++--- 3 files changed, 160 insertions(+), 132 deletions(-) diff --git a/src/pages/ViewTeamGrades/ReviewTable.tsx b/src/pages/ViewTeamGrades/ReviewTable.tsx index dfea9aa..e484646 100644 --- a/src/pages/ViewTeamGrades/ReviewTable.tsx +++ b/src/pages/ViewTeamGrades/ReviewTable.tsx @@ -1,22 +1,22 @@ import React, { useState } from 'react'; -import ReviewTableRow from './ReviewTableRow'; // Importing the ReviewTableRow component -import RoundSelector from './RoundSelector'; // Importing the RoundSelector component -import dummyDataRounds from './Data/heatMapData.json'; // Importing dummy data for rounds -import dummyData from './Data/dummyData.json'; // Importing dummy data -import { calculateAverages, getColorClass } from './utils'; // Importing utility functions -import './grades.scss'; // Importing styles -import { Link } from 'react-router-dom'; // Importing Link from react-router-dom +import ReviewTableRow from './ReviewTableRow'; +import RoundSelector from './RoundSelector'; +import dummyDataRounds from './Data/heatMapData.json'; // Ensure this import aligns with actual data structure +import dummyData from './Data/dummyData.json'; +import { calculateAverages, getColorClass } from './utils'; +import './grades.scss'; +import { Link } from 'react-router-dom'; import ShowSubmission from './ShowSubmission'; +import { ReviewData } from './App'; // Adjust the import path as necessary -// Functional component ReviewTable const ReviewTable: React.FC = () => { - const [currentRound, setCurrentRound] = useState(0); // State for current round - const [sortOrderRow, setSortOrderRow] = useState<'asc' | 'desc' | 'none'>('none'); // State for row sort order - const [showWordCount10, setShowWordCount10] = useState(false); // State for showing reviews with more than 10 words - const [showWordCount20, setShowWordCount20] = useState(false); // State for showing reviews with more than 20 words - const [showFullQuestion, setShowFullQuestion] = useState(false); // State to toggle between question number and full question text + const [currentRound, setCurrentRound] = useState(0); + const [sortOrderRow, setSortOrderRow] = useState<'asc' | 'desc' | 'none'>('none'); + const [showWordCount10, setShowWordCount10] = useState(false); + const [showWordCount20, setShowWordCount20] = useState(false); + const [showFullQuestion, setShowFullQuestion] = useState(false); + const [showAll, setShowAll] = useState(false); - // Function to toggle the sort order for rows const toggleSortOrderRow = () => { setSortOrderRow((prevSortOrder) => { if (prevSortOrder === 'asc') return 'desc'; @@ -24,21 +24,21 @@ const ReviewTable: React.FC = () => { return 'asc'; }); }; - - // Calculating averages and sorting data based on the current round and sort order + const currentRoundData = dummyDataRounds[currentRound]; - const { averagePeerReviewScore, columnAverages, sortedData } = calculateAverages( - currentRoundData, - sortOrderRow - ); + const { averagePeerReviewScore } = showAll + ? calculateAverages(dummyDataRounds, 'none') + : calculateAverages([dummyDataRounds[currentRound]], 'none'); - // Function to handle round change const handleRoundChange = (roundIndex: number) => { setCurrentRound(roundIndex); - setShowWordCount10(false); - setShowWordCount20(false); + setShowAll(false); }; + const showAllRounds = () => { + setShowAll(true); + }; + const colorLegend = [ { color: 'Red', description: 'Poor', className: 'c1' }, { color: 'Orange', description: 'Fair', className: 'c2' }, @@ -47,18 +47,93 @@ const ReviewTable: React.FC = () => { { color: 'DarkGreen', description: 'Excellent', className: 'c5' }, ]; + const renderTableForRound = (roundData: ReviewData[], roundIndex: number) => { + const { columnAverages, sortedData } = calculateAverages([roundData], sortOrderRow); + + return ( + <> +

Review (Round: {roundIndex + 1} of {dummyDataRounds.length})

+
+
+ + + + + {Array.from({ length: roundData[0].reviews.length }, (_, i) => ( + + ))} + + {showWordCount10 && } + {showWordCount20 && } + + + + {sortedData.map((row, index) => ( + + ))} + + + {columnAverages.map((avg, index) => ( + + ))} + + +
Question No.{`Review ${i + 1}`} + Avg + {sortOrderRow === "none" && ▲▼} + {sortOrderRow === "asc" && } + {sortOrderRow === "desc" && } + 10+ Words20+ Words
Avg + {avg.toFixed(2)} +
+
+
+ +   Color Legend   + + Colors are scaled from Poor to Excellent in the following order: Red, Orange, Yellow, Light Green, Dark Green + + +
+ + + + + + + + + {colorLegend.map((item) => ( + + + + + ))} + +
ColorRating
{item.description}
+
+
+
+ + + ); + }; - // JSX rendering of the ReviewTable component return (

Summary Report for assignment: Program 2

-
Team: {dummyData.team}
+
Team: {dummyData.team}
Average peer review score:{" "} {averagePeerReviewScore}
- -

Review (Round: {currentRound + 1} of {dummyDataRounds.length})

+

{ />
-
-
- - - - - {Array.from({ length: currentRoundData[0].reviews.length }, (_, i) => ( - - ))} - - {showWordCount10 && } - {showWordCount20 && } - - - - {sortedData.map((row, index) => ( - + + {showAll ? ( + <> + {dummyDataRounds.map((roundData, index) => ( +
+ {renderTableForRound(roundData, index)} +
))} -
- - {columnAverages.map((avg, index) => ( - - ))} - - -
Question No.{`Review ${i + 1}`} - Avg - {sortOrderRow === "none" && ▲▼} - {sortOrderRow === "asc" && } - {sortOrderRow === "desc" && } - 10+ Words20+ Words
Avg - {avg.toFixed(2)} -
-

- -
-
- -   Color Legend   - - Colors are scaled from Poor to Excellent in the following order: Red, Orange, Yellow, Light Green, Dark Green - - -
- - - - - - - - - {colorLegend.map((item) => ( - - - - - ))} - -
ColorRating
{item.description}
-
-
-
-

+ + ) : ( +

+ {renderTableForRound(dummyDataRounds[currentRound], currentRound)} +
+ )} + +

Grade and comment for submission

Grade: {dummyData.grade}

Comment: {dummyData.comment}

@@ -167,4 +188,4 @@ const ReviewTable: React.FC = () => { ); }; -export default ReviewTable; // Exporting the ReviewTable component as default +export default ReviewTable; diff --git a/src/pages/ViewTeamGrades/RoundSelector.tsx b/src/pages/ViewTeamGrades/RoundSelector.tsx index fd87daf..1ad6052 100644 --- a/src/pages/ViewTeamGrades/RoundSelector.tsx +++ b/src/pages/ViewTeamGrades/RoundSelector.tsx @@ -5,21 +5,19 @@ import teamData from './Data/dummyData.json'; interface RoundSelectorProps { currentRound: number; handleRoundChange: (roundIndex: number) => void; + showAllRounds: () => void; // Added for showing all rounds } -// RoundSelector component to display buttons for selecting rounds -const RoundSelector: React.FC = ({ currentRound, handleRoundChange }) => { +const RoundSelector: React.FC = ({ currentRound, handleRoundChange, showAllRounds }) => { const [teamMembers, setTeamMembers] = useState([]); - // Fetch team members from the teamData.json file on component mount useEffect(() => { setTeamMembers(teamData.members); - }, []); // Empty dependency array means it runs only once on component mount + }, []); return (
- {/* Mapping over dummyDataRounds to render round buttons */} {dummyDataRounds.map((round, index) => ( ))} - {/* Displaying team members */} + Team members: {teamMembers.map((member, index) => ( - + ({member}) - {index !== teamMembers.length - 1 && ' '} + {index !== teamMembers.length - 1 && ' '} - ))} + ))}
diff --git a/src/pages/ViewTeamGrades/utils.ts b/src/pages/ViewTeamGrades/utils.ts index 1567b83..846285d 100644 --- a/src/pages/ViewTeamGrades/utils.ts +++ b/src/pages/ViewTeamGrades/utils.ts @@ -27,46 +27,53 @@ export const getWordCount20 = (row: ReviewData) => { ).length; }; -// Function to calculate averages for rows and columns + +// Function to calculate averages for rows and columns, handling multiple rounds export const calculateAverages = ( - currentRoundData: ReviewData[], + roundsData: ReviewData[][], sortOrderRow: 'asc' | 'desc' | 'none' -) => { +): { averagePeerReviewScore: string; columnAverages: number[]; sortedData: ReviewData[] } => { let totalAvg = 0; - let questionCount = 0; let totalMaxScore = 0; - currentRoundData.forEach((row) => { - const sum = row.reviews.reduce((acc, val) => acc + val.score, 0); - row.RowAvg = sum / row.reviews.length; - totalAvg = row.RowAvg + totalAvg; - totalMaxScore = totalMaxScore + row.maxScore; - questionCount++; + let totalQuestions = 0; + + roundsData.forEach((currentRoundData) => { + currentRoundData.forEach((row) => { + const sum = row.reviews.reduce((acc, val) => acc + val.score, 0); + row.RowAvg = sum / row.reviews.length; + totalAvg += row.RowAvg; + totalMaxScore += row.maxScore; + totalQuestions++; + }); }); - const averagePeerReviewScore = - questionCount > 0 - ? (((totalAvg / totalMaxScore) * 100) > 0 ? ((totalAvg / totalMaxScore) * 100).toFixed(2) : '0.00') - : '0.00'; + const averagePeerReviewScore = totalQuestions > 0 + ? (((totalAvg / totalMaxScore) * 100).toFixed(2)) + : '0.00'; - const columnAverages: number[] = Array.from({ length: currentRoundData[0].reviews.length }, () => 0); + let columnAverages: number[] = []; - currentRoundData.forEach((row) => { - row.reviews.forEach((val, index) => { - columnAverages[index] += val.score; + if (roundsData.length > 0 && roundsData[0].length > 0) { + columnAverages = Array.from({ length: roundsData[0][0].reviews.length }, () => 0); + roundsData.forEach(currentRoundData => { + currentRoundData.forEach(row => { + row.reviews.forEach((val, index) => { + columnAverages[index] += val.score; + }); + }); }); - }); - columnAverages.forEach((sum, index) => { - columnAverages[index] = (sum / totalMaxScore) * 5; - }); + columnAverages = columnAverages.map(sum => parseFloat((sum / totalQuestions).toFixed(2))); + } - let sortedData = [...currentRoundData]; + // Sorting data if necessary + let sortedData = roundsData.flat(); if (sortOrderRow === 'asc') { - sortedData = currentRoundData.slice().sort((a, b) => a.RowAvg - b.RowAvg); + sortedData.sort((a, b) => a.RowAvg - b.RowAvg); } else if (sortOrderRow === 'desc') { - sortedData = currentRoundData.slice().sort((a, b) => b.RowAvg - a.RowAvg); + sortedData.sort((a, b) => b.RowAvg - a.RowAvg); } return { averagePeerReviewScore, columnAverages, sortedData }; -}; +}; \ No newline at end of file From a245d71629ee150ee5c95fba5e881bab9204c7b2 Mon Sep 17 00:00:00 2001 From: Nisarg Nilesh Doshi <70905787+Nisarg20@users.noreply.github.com> Date: Mon, 22 Apr 2024 18:39:27 -0400 Subject: [PATCH 15/18] Update App.tsx --- src/pages/ViewTeamGrades/App.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/ViewTeamGrades/App.tsx b/src/pages/ViewTeamGrades/App.tsx index 1720245..61139fd 100644 --- a/src/pages/ViewTeamGrades/App.tsx +++ b/src/pages/ViewTeamGrades/App.tsx @@ -1,6 +1,5 @@ import React from 'react'; import ReviewTable from './ReviewTable'; // Importing the ReviewTable component -import ShowSubmission from './ShowSubmission'; // Interface defining the structure of ReviewData export interface ReviewData { From c9979b19a41c89b4ef544fc9431c42248bb5a64c Mon Sep 17 00:00:00 2001 From: ChaitanyaS182k <141549134+ChaitanyaS182k@users.noreply.github.com> Date: Mon, 22 Apr 2024 18:50:25 -0400 Subject: [PATCH 16/18] Color Legend table bug fixes --- src/pages/ViewTeamGrades/ReviewTable.tsx | 336 ++++++++++++++++----- src/pages/ViewTeamGrades/RoundSelector.tsx | 75 ++++- src/pages/ViewTeamGrades/grades.scss | 10 +- 3 files changed, 345 insertions(+), 76 deletions(-) diff --git a/src/pages/ViewTeamGrades/ReviewTable.tsx b/src/pages/ViewTeamGrades/ReviewTable.tsx index e484646..3abea64 100644 --- a/src/pages/ViewTeamGrades/ReviewTable.tsx +++ b/src/pages/ViewTeamGrades/ReviewTable.tsx @@ -1,3 +1,196 @@ +// import React, { useState } from 'react'; +// import ReviewTableRow from './ReviewTableRow'; +// import RoundSelector from './RoundSelector'; +// import dummyDataRounds from './Data/heatMapData.json'; // Ensure this import aligns with actual data structure +// import dummyData from './Data/dummyData.json'; +// import { calculateAverages, getColorClass } from './utils'; +// import './grades.scss'; +// import { Link } from 'react-router-dom'; +// import ShowSubmission from './ShowSubmission'; +// import { ReviewData } from './App'; // Adjust the import path as necessary + +// const ReviewTable: React.FC = () => { +// const [currentRound, setCurrentRound] = useState(0); +// const [sortOrderRow, setSortOrderRow] = useState<'asc' | 'desc' | 'none'>('none'); +// const [showWordCount10, setShowWordCount10] = useState(false); +// const [showWordCount20, setShowWordCount20] = useState(false); +// const [showFullQuestion, setShowFullQuestion] = useState(false); +// const [showAll, setShowAll] = useState(false); + +// const toggleSortOrderRow = () => { +// setSortOrderRow((prevSortOrder) => { +// if (prevSortOrder === 'asc') return 'desc'; +// if (prevSortOrder === 'desc') return 'none'; +// return 'asc'; +// }); +// }; + +// const currentRoundData = dummyDataRounds[currentRound]; +// const { averagePeerReviewScore } = showAll +// ? calculateAverages(dummyDataRounds, 'none') +// : calculateAverages([dummyDataRounds[currentRound]], 'none'); + +// const handleRoundChange = (roundIndex: number) => { +// setCurrentRound(roundIndex); +// setShowAll(false); +// }; + +// const showAllRounds = () => { +// setShowAll(true); +// }; + +// const colorLegend = [ +// { color: 'Red', description: 'Poor', className: 'c1' }, +// { color: 'Orange', description: 'Fair', className: 'c2' }, +// { color: 'Yellow', description: 'Average', className: 'c3' }, +// { color: 'LightGreen', description: 'Good', className: 'c4' }, +// { color: 'DarkGreen', description: 'Excellent', className: 'c5' }, +// ]; + +// const renderTableForRound = (roundData: ReviewData[], roundIndex: number) => { +// const { columnAverages, sortedData } = calculateAverages([roundData], sortOrderRow); + +// return ( +// <> +//

Review (Round: {roundIndex + 1} of {dummyDataRounds.length})

+//
+// +// +// +// +// {Array.from({ length: roundData[0].reviews.length }, (_, i) => ( +// +// ))} +// +// {showWordCount10 && } +// {showWordCount20 && } +// +// +// +// {sortedData.map((row, index) => ( +// +// ))} +// +// +// {columnAverages.map((avg, index) => ( +// +// ))} +// +// +//
Question No.{`Review ${i + 1}`} +// Avg +// {sortOrderRow === "none" && ▲▼} +// {sortOrderRow === "asc" && } +// {sortOrderRow === "desc" && } +// 10+ Words20+ Words
Avg +// {avg.toFixed(2)} +//
+//
+ +// +// ); +// }; + +// return ( +//
+//
+//
+// +//   Color Legend   +// +// Colors are scaled from Poor to Excellent in the following order: Red, Orange, Yellow, Light Green, Dark Green +// +// +//
+// +// +// +// +// +// +// +// +// {colorLegend.map((item) => ( +// +// +// +// +// ))} +// +//
ColorRating
{item.description}
+//
+//
+//
+ +//

Summary Report for assignment: Program 2

+//
Team: {dummyData.team}
+//
+// Average peer review score:{" "} +// {averagePeerReviewScore} +//
+// +//

+//
+// setShowWordCount10(e.target.checked)} +// /> +// +// setShowWordCount20(e.target.checked)} +// /> +// +//          +// setShowFullQuestion(e.target.checked)} +// /> +// +//
+ +// {showAll ? ( +// <> +// {dummyDataRounds.map((roundData, index) => ( +//
+// {renderTableForRound(roundData, index)} +//
+// ))} +// +// ) : ( +//
+// {renderTableForRound(dummyDataRounds[currentRound], currentRound)} +//
+// )} +// +//

+//

Grade and comment for submission

+// Grade: {dummyData.grade}

+// Comment: {dummyData.comment}

+// Late Penalty: {dummyData.late_penalty}

+//

+// Back +//
+// ); +// }; + +// export default ReviewTable; + import React, { useState } from 'react'; import ReviewTableRow from './ReviewTableRow'; import RoundSelector from './RoundSelector'; @@ -25,7 +218,7 @@ const ReviewTable: React.FC = () => { }); }; - const currentRoundData = dummyDataRounds[currentRound]; + // const currentRoundData = dummyDataRounds[currentRound]; const { averagePeerReviewScore } = showAll ? calculateAverages(dummyDataRounds, 'none') : calculateAverages([dummyDataRounds[currentRound]], 'none'); @@ -53,87 +246,84 @@ const ReviewTable: React.FC = () => { return ( <>

Review (Round: {roundIndex + 1} of {dummyDataRounds.length})

-
-
- - - - - {Array.from({ length: roundData[0].reviews.length }, (_, i) => ( - - ))} - - {showWordCount10 && } - {showWordCount20 && } - - - - {sortedData.map((row, index) => ( - - ))} - - - {columnAverages.map((avg, index) => ( - +
+
Question No.{`Review ${i + 1}`} - Avg - {sortOrderRow === "none" && ▲▼} - {sortOrderRow === "asc" && } - {sortOrderRow === "desc" && } - 10+ Words20+ Words
Avg - {avg.toFixed(2)} -
+ + + + {Array.from({ length: roundData[0].reviews.length }, (_, i) => ( + + ))} + + {showWordCount10 && } + {showWordCount20 && } + + + + {sortedData.map((row, index) => ( + ))} - - -
Question No.{`Review ${i + 1}`} + Avg + {sortOrderRow === "none" && ▲▼} + {sortOrderRow === "asc" && } + {sortOrderRow === "desc" && } + 10+ Words20+ Words
-
-
- -   Color Legend   - - Colors are scaled from Poor to Excellent in the following order: Red, Orange, Yellow, Light Green, Dark Green - - -
- - - - - - - - - {colorLegend.map((item) => ( - - - + + + {columnAverages.map((avg, index) => ( + + ))} - ))} - -
ColorRating
{item.description}
Avg + {avg.toFixed(2)} +
-
-
-
- + + +

+
); }; return (
+
+
+ +   Color Legend   + +
+ + + + + + + + + {colorLegend.map((item) => ( + + + + + ))} + +
ColorRating
{item.description}
+
+
+

Summary Report for assignment: Program 2

-
Team: {dummyData.team}
+
Team: {dummyData.team}
Average peer review score:{" "} {averagePeerReviewScore}
- +

{ />
- +

+ + {showAll ? ( <> {dummyDataRounds.map((roundData, index) => ( @@ -177,7 +369,7 @@ const ReviewTable: React.FC = () => {
)} -

+

Grade and comment for submission

Grade: {dummyData.grade}

Comment: {dummyData.comment}

@@ -188,4 +380,4 @@ const ReviewTable: React.FC = () => { ); }; -export default ReviewTable; +export default ReviewTable; \ No newline at end of file diff --git a/src/pages/ViewTeamGrades/RoundSelector.tsx b/src/pages/ViewTeamGrades/RoundSelector.tsx index 1ad6052..2bd6ac5 100644 --- a/src/pages/ViewTeamGrades/RoundSelector.tsx +++ b/src/pages/ViewTeamGrades/RoundSelector.tsx @@ -1,3 +1,51 @@ +// import React, { useState, useEffect } from 'react'; +// import dummyDataRounds from './Data/heatMapData.json'; +// import teamData from './Data/dummyData.json'; + +// interface RoundSelectorProps { +// currentRound: number; +// handleRoundChange: (roundIndex: number) => void; +// showAllRounds: () => void; // Added for showing all rounds +// } + +// const RoundSelector: React.FC = ({ currentRound, handleRoundChange, showAllRounds }) => { +// const [teamMembers, setTeamMembers] = useState([]); + +// useEffect(() => { +// setTeamMembers(teamData.members); +// }, []); + +// return ( +//
+//
+// {dummyDataRounds.map((round, index) => ( +// +// ))} +// +// +// Team members: {teamMembers.map((member, index) => ( +// +// ({member}) +// {index !== teamMembers.length - 1 && ' '} +// +// ))} +// +//
+//
+// ); +// }; + +// export default RoundSelector; + + import React, { useState, useEffect } from 'react'; import dummyDataRounds from './Data/heatMapData.json'; import teamData from './Data/dummyData.json'; @@ -15,6 +63,27 @@ const RoundSelector: React.FC = ({ currentRound, handleRound setTeamMembers(teamData.members); }, []); + const active = (clickedButton: HTMLElement) => { + // Remove 'current' class from all buttons + const buttons = document.querySelectorAll('.round-button'); + buttons.forEach(btn => { + btn.classList.remove('current'); + }); + + // Check if 'current' class is already applied to any button + const currentButton = document.querySelector('.round-button.current'); + + // If 'current' class is not applied to any button, add it to the clicked button + if (!currentButton) { + clickedButton.classList.add('current'); + } else { + // If 'current' class is applied to a button, remove it from that button and add it to the clicked button + currentButton.classList.remove('current'); + clickedButton.classList.add('current'); + } + }; + + return (
@@ -22,12 +91,12 @@ const RoundSelector: React.FC = ({ currentRound, handleRound ))} - @@ -43,4 +112,4 @@ const RoundSelector: React.FC = ({ currentRound, handleRound ); }; -export default RoundSelector; +export default RoundSelector; \ No newline at end of file diff --git a/src/pages/ViewTeamGrades/grades.scss b/src/pages/ViewTeamGrades/grades.scss index 8dd3e7e..c385cf2 100644 --- a/src/pages/ViewTeamGrades/grades.scss +++ b/src/pages/ViewTeamGrades/grades.scss @@ -255,15 +255,23 @@ .review-container { + position: relative; display: flex; justify-content: space-between; // Adjust as necessary to fit your design + flex-direction: column; // Align children horizontally + width: 100%; // Ensure the container takes full width + align-items: flex-start; .table-container { + order: 2; flex: 1 0 70%; // Your existing max-width but as flex basis } .color-legend-container { - align-self: flex-start; // Align the legend container to the start of the flex container (top right) + position: absolute; + order: 1; + flex: 0 1 auto; + align-self: flex-end; // Align the legend container to the start of the flex container (top right) width: auto; // Set the width as required by the content text-align: center; // Center-align the text inside the legend container From 3f3e80c7fda2cfe892305f12f791c4a679cea8c2 Mon Sep 17 00:00:00 2001 From: ChaitanyaS182k <141549134+ChaitanyaS182k@users.noreply.github.com> Date: Tue, 23 Apr 2024 21:46:01 -0400 Subject: [PATCH 17/18] Added test cases for the React Components --- src/App.test.tsx | 9 - src/pages/ViewTeamGrades/ReviewTable.test.tsx | 17 ++ src/pages/ViewTeamGrades/ReviewTable.tsx | 194 +----------------- .../ViewTeamGrades/ReviewTableRow.test.tsx | 44 ++++ .../ViewTeamGrades/RoundSelector.test.tsx | 45 ++++ src/pages/ViewTeamGrades/RoundSelector.tsx | 48 ----- .../ViewTeamGrades/ShowSubmission.test.tsx | 26 +++ 7 files changed, 133 insertions(+), 250 deletions(-) delete mode 100644 src/App.test.tsx create mode 100644 src/pages/ViewTeamGrades/ReviewTable.test.tsx create mode 100644 src/pages/ViewTeamGrades/ReviewTableRow.test.tsx create mode 100644 src/pages/ViewTeamGrades/RoundSelector.test.tsx create mode 100644 src/pages/ViewTeamGrades/ShowSubmission.test.tsx diff --git a/src/App.test.tsx b/src/App.test.tsx deleted file mode 100644 index 2a68616..0000000 --- a/src/App.test.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import React from 'react'; -import { render, screen } from '@testing-library/react'; -import App from './App'; - -test('renders learn react link', () => { - render(); - const linkElement = screen.getByText(/learn react/i); - expect(linkElement).toBeInTheDocument(); -}); diff --git a/src/pages/ViewTeamGrades/ReviewTable.test.tsx b/src/pages/ViewTeamGrades/ReviewTable.test.tsx new file mode 100644 index 0000000..5b95c1a --- /dev/null +++ b/src/pages/ViewTeamGrades/ReviewTable.test.tsx @@ -0,0 +1,17 @@ +import React from 'react'; +import { render, fireEvent } from '@testing-library/react'; +import { BrowserRouter as Router } from 'react-router-dom'; +import ReviewTable from './ReviewTable'; + +describe('ReviewTable component', () => { + test('renders without crashing', () => { + render( + {/* Wrap your component with Router */} + + + ); + }); + + + // Add more tests as needed +}); diff --git a/src/pages/ViewTeamGrades/ReviewTable.tsx b/src/pages/ViewTeamGrades/ReviewTable.tsx index 3abea64..092194b 100644 --- a/src/pages/ViewTeamGrades/ReviewTable.tsx +++ b/src/pages/ViewTeamGrades/ReviewTable.tsx @@ -1,196 +1,3 @@ -// import React, { useState } from 'react'; -// import ReviewTableRow from './ReviewTableRow'; -// import RoundSelector from './RoundSelector'; -// import dummyDataRounds from './Data/heatMapData.json'; // Ensure this import aligns with actual data structure -// import dummyData from './Data/dummyData.json'; -// import { calculateAverages, getColorClass } from './utils'; -// import './grades.scss'; -// import { Link } from 'react-router-dom'; -// import ShowSubmission from './ShowSubmission'; -// import { ReviewData } from './App'; // Adjust the import path as necessary - -// const ReviewTable: React.FC = () => { -// const [currentRound, setCurrentRound] = useState(0); -// const [sortOrderRow, setSortOrderRow] = useState<'asc' | 'desc' | 'none'>('none'); -// const [showWordCount10, setShowWordCount10] = useState(false); -// const [showWordCount20, setShowWordCount20] = useState(false); -// const [showFullQuestion, setShowFullQuestion] = useState(false); -// const [showAll, setShowAll] = useState(false); - -// const toggleSortOrderRow = () => { -// setSortOrderRow((prevSortOrder) => { -// if (prevSortOrder === 'asc') return 'desc'; -// if (prevSortOrder === 'desc') return 'none'; -// return 'asc'; -// }); -// }; - -// const currentRoundData = dummyDataRounds[currentRound]; -// const { averagePeerReviewScore } = showAll -// ? calculateAverages(dummyDataRounds, 'none') -// : calculateAverages([dummyDataRounds[currentRound]], 'none'); - -// const handleRoundChange = (roundIndex: number) => { -// setCurrentRound(roundIndex); -// setShowAll(false); -// }; - -// const showAllRounds = () => { -// setShowAll(true); -// }; - -// const colorLegend = [ -// { color: 'Red', description: 'Poor', className: 'c1' }, -// { color: 'Orange', description: 'Fair', className: 'c2' }, -// { color: 'Yellow', description: 'Average', className: 'c3' }, -// { color: 'LightGreen', description: 'Good', className: 'c4' }, -// { color: 'DarkGreen', description: 'Excellent', className: 'c5' }, -// ]; - -// const renderTableForRound = (roundData: ReviewData[], roundIndex: number) => { -// const { columnAverages, sortedData } = calculateAverages([roundData], sortOrderRow); - -// return ( -// <> -//

Review (Round: {roundIndex + 1} of {dummyDataRounds.length})

-//
-// -// -// -// -// {Array.from({ length: roundData[0].reviews.length }, (_, i) => ( -// -// ))} -// -// {showWordCount10 && } -// {showWordCount20 && } -// -// -// -// {sortedData.map((row, index) => ( -// -// ))} -// -// -// {columnAverages.map((avg, index) => ( -// -// ))} -// -// -//
Question No.{`Review ${i + 1}`} -// Avg -// {sortOrderRow === "none" && ▲▼} -// {sortOrderRow === "asc" && } -// {sortOrderRow === "desc" && } -// 10+ Words20+ Words
Avg -// {avg.toFixed(2)} -//
-//
- -// -// ); -// }; - -// return ( -//
-//
-//
-// -//   Color Legend   -// -// Colors are scaled from Poor to Excellent in the following order: Red, Orange, Yellow, Light Green, Dark Green -// -// -//
-// -// -// -// -// -// -// -// -// {colorLegend.map((item) => ( -// -// -// -// -// ))} -// -//
ColorRating
{item.description}
-//
-//
-//
- -//

Summary Report for assignment: Program 2

-//
Team: {dummyData.team}
-//
-// Average peer review score:{" "} -// {averagePeerReviewScore} -//
-// -//

-//
-// setShowWordCount10(e.target.checked)} -// /> -// -// setShowWordCount20(e.target.checked)} -// /> -// -//          -// setShowFullQuestion(e.target.checked)} -// /> -// -//
- -// {showAll ? ( -// <> -// {dummyDataRounds.map((roundData, index) => ( -//
-// {renderTableForRound(roundData, index)} -//
-// ))} -// -// ) : ( -//
-// {renderTableForRound(dummyDataRounds[currentRound], currentRound)} -//
-// )} -// -//

-//

Grade and comment for submission

-// Grade: {dummyData.grade}

-// Comment: {dummyData.comment}

-// Late Penalty: {dummyData.late_penalty}

-//

-// Back -//
-// ); -// }; - -// export default ReviewTable; - import React, { useState } from 'react'; import ReviewTableRow from './ReviewTableRow'; import RoundSelector from './RoundSelector'; @@ -325,6 +132,7 @@ const ReviewTable: React.FC = () => {

+

{ + test('renders question number by default', () => { + render(); + expect(screen.getByText('Q1')).toBeInTheDocument(); + }); + + test('renders full question text when showFullQuestion is true', () => { + render(); + expect(screen.getByText('How do you like the product?')).toBeInTheDocument(); + }); + + test('renders reviews with correct scores and comments', () => { + render(); + + // Find the score within the circle span + const circleScoreElement = screen.getByRole('cell', { name: '5' }); + + // Find the scores within the underlined spans + const underlinedScoreElements = screen.getAllByRole('cell', { name: /5/ }); + + // Assert that the elements are present + expect(circleScoreElement).toBeInTheDocument(); + expect(underlinedScoreElements.length).toBe(2); // Assuming all scores are underlined + // Add assertions for comments if needed + }); +}); diff --git a/src/pages/ViewTeamGrades/RoundSelector.test.tsx b/src/pages/ViewTeamGrades/RoundSelector.test.tsx new file mode 100644 index 0000000..caf16ef --- /dev/null +++ b/src/pages/ViewTeamGrades/RoundSelector.test.tsx @@ -0,0 +1,45 @@ +import React from 'react'; +import { render, screen, fireEvent } from '@testing-library/react'; +import '@testing-library/jest-dom'; +import RoundSelector from './RoundSelector'; +import dummyDataRounds from './Data/heatMapData.json'; + +describe('RoundSelector', () => { + const handleRoundChangeMock = jest.fn(); + const showAllRoundsMock = jest.fn(); + + beforeEach(() => { + render(); + }); + + test('renders without crashing', () => { + expect(screen.getByText(/Team members:/)).toBeInTheDocument(); + }); + + test('renders the correct number of round buttons', () => { + expect(screen.getAllByRole('button')).toHaveLength(dummyDataRounds.length + 1); // +1 for the 'Show All' button + }); + + test('calls handleRoundChange with correct index when a round button is clicked', () => { + const roundButtons = screen.getAllByRole('button'); + fireEvent.click(roundButtons[1]); // Click on "Round 2" + expect(handleRoundChangeMock).toHaveBeenCalledWith(1); + }); + + test('toggles current class correctly when a round button is clicked', () => { + const firstButton = screen.getAllByRole('button')[0]; + fireEvent.click(firstButton); + expect(firstButton).toHaveClass('current'); + const secondButton = screen.getAllByRole('button')[1]; + fireEvent.click(secondButton); + expect(secondButton).toHaveClass('current'); + expect(firstButton).not.toHaveClass('current'); + }); + + test('calls showAllRounds and toggles current class when "Show All" button is clicked', () => { + const showAllButton = screen.getByText('Show All'); + fireEvent.click(showAllButton); + expect(showAllRoundsMock).toHaveBeenCalled(); + expect(showAllButton).toHaveClass('current'); + }); +}); diff --git a/src/pages/ViewTeamGrades/RoundSelector.tsx b/src/pages/ViewTeamGrades/RoundSelector.tsx index 2bd6ac5..de0ed89 100644 --- a/src/pages/ViewTeamGrades/RoundSelector.tsx +++ b/src/pages/ViewTeamGrades/RoundSelector.tsx @@ -1,51 +1,3 @@ -// import React, { useState, useEffect } from 'react'; -// import dummyDataRounds from './Data/heatMapData.json'; -// import teamData from './Data/dummyData.json'; - -// interface RoundSelectorProps { -// currentRound: number; -// handleRoundChange: (roundIndex: number) => void; -// showAllRounds: () => void; // Added for showing all rounds -// } - -// const RoundSelector: React.FC = ({ currentRound, handleRoundChange, showAllRounds }) => { -// const [teamMembers, setTeamMembers] = useState([]); - -// useEffect(() => { -// setTeamMembers(teamData.members); -// }, []); - -// return ( -//
-//
-// {dummyDataRounds.map((round, index) => ( -// -// ))} -// -// -// Team members: {teamMembers.map((member, index) => ( -// -// ({member}) -// {index !== teamMembers.length - 1 && ' '} -// -// ))} -// -//
-//
-// ); -// }; - -// export default RoundSelector; - - import React, { useState, useEffect } from 'react'; import dummyDataRounds from './Data/heatMapData.json'; import teamData from './Data/dummyData.json'; diff --git a/src/pages/ViewTeamGrades/ShowSubmission.test.tsx b/src/pages/ViewTeamGrades/ShowSubmission.test.tsx new file mode 100644 index 0000000..d35d9e5 --- /dev/null +++ b/src/pages/ViewTeamGrades/ShowSubmission.test.tsx @@ -0,0 +1,26 @@ +import React from 'react'; +import { render, screen, fireEvent } from '@testing-library/react'; +import '@testing-library/jest-dom/extend-expect'; // Import jest-dom for custom assertions +import ShowSubmission from './ShowSubmission'; // Import the component to test + +describe('ShowSubmission', () => { + test('renders button with correct text', () => { + render(); + expect(screen.getByRole('button', { name: 'Show Submission' })).toBeInTheDocument(); + }); + + test('collapsible content is initially hidden', () => { + render(); + const collapsibleContent = screen.queryByTestId('example-collapse-text'); // Update test ID here + expect(collapsibleContent).toBeNull(); // Check if the collapsible content is initially null + }); + + + test('renders links when collapsible content is open', () => { + render(); + const button = screen.getByRole('button', { name: 'Show Submission' }); + fireEvent.click(button); + expect(screen.getByText('https://github.ncsu.edu/Program-2-Ruby-on-Rails/WolfEvents')).toBeInTheDocument(); + expect(screen.getByText('http://152.7.177.44:8080/')).toBeInTheDocument(); + }); +}); From d2d73b41a3e521e5693dbfa3f354618ad3a8f5b7 Mon Sep 17 00:00:00 2001 From: ChaitanyaS182k <141549134+ChaitanyaS182k@users.noreply.github.com> Date: Tue, 23 Apr 2024 21:56:27 -0400 Subject: [PATCH 18/18] Add files via upload --- src/pages/ViewTeamGrades/Data/dummy.json | 96 ++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 src/pages/ViewTeamGrades/Data/dummy.json diff --git a/src/pages/ViewTeamGrades/Data/dummy.json b/src/pages/ViewTeamGrades/Data/dummy.json new file mode 100644 index 0000000..59ade2a --- /dev/null +++ b/src/pages/ViewTeamGrades/Data/dummy.json @@ -0,0 +1,96 @@ +[ + [ + { + "reviewNumber": "1", + "reviews": [ + {"question": "What is the main purpose of this feature?", "score": 5, "comment": "Great work on this aspect!"}, + {"question": "How user-friendly is this feature?", "score": 2, "comment": "The interface was intuitive and easy to navigate." }, + {"question": "Does this feature meet the project requirements?", "score": 1}, + {"question": "How would you rate the performance of this feature?", "score": 4, "comment": "Performance could be improved, especially for larger datasets." } + ] + }, + { + "reviewNumber": "2", + "reviews": [ + {"question": "What is the main purpose of this feature?", "score": 5, "comment": "Could use some improvement here." }, + {"question": "How user-friendly is this feature?", "score": 5, "comment": "There were some confusing elements that could be simplified." }, + {"question": "Does this feature meet the project requirements?", "score": 1}, + {"question": "How would you rate the performance of this feature?", "score": 2, "comment": "The feature's performance is generally satisfactory." } + ] + }, + { + "reviewNumber": "3", + "reviews": [ + {"question": "What is the main purpose of this feature?", "comment": "The presentation was well-organized and clear. However, some points could have been elaborated further to provide a deeper understanding of the topic."}, + {"question": "How user-friendly is this feature?", "score": 5, "comment": "The feature was straightforward to use, with clear instructions."}, + {"question": "Does this feature meet the project requirements?", "score": 2}, + {"question": "How would you rate the performance of this feature?", "score": 3, "comment": "Performance issues were encountered during testing." } + ] + }, + { + "reviewNumber": "4", + "reviews": [ + {"question": "What is the main purpose of this feature?", "score": 3, "comment": "The speaker demonstrated a profound understanding of the subject matter, making the session engaging and informative."}, + {"question": "How user-friendly is this feature?", "score": 2, "comment": "The user experience could be improved, especially for new users." }, + {"question": "Does this feature meet the project requirements?", "score": 0}, + {"question": "How would you rate the performance of this feature?", "score": 1, "comment": "Overall, the feature performs well, but some optimizations could enhance speed." } + ] + }, + { + "reviewNumber": "5", + "reviews": [ + {"question": "What is the main purpose of this feature?", "score": 1, "comment": "The visuals were compelling and helped in understanding complex concepts easily. However, there were a few slides with too much text, which made it hard to follow at times."}, + {"question": "How user-friendly is this feature?", "score": 4, "comment": "Some aspects were user-friendly, but others required a learning curve." }, + {"question": "Does this feature meet the project requirements?", "score": 2}, + {"question": "How would you rate the performance of this feature?", "score": 4, "comment": "The feature's performance is acceptable but could be faster." } + ] + } + ], + [ + { + "reviewNumber": "1", + "reviews": [ + {"question": "What is the main purpose of this feature?", "score": 1}, + {"question": "How user-friendly is this feature?", "score": 1, "comment": "Certain design elements make the feature a joy to use." }, + {"question": "Does this feature meet the project requirements?", "score": 3}, + {"question": "How would you rate the performance of this feature?", "score": 4, "comment": "The feature's design is inviting and approachable." } + ] + }, + { + "reviewNumber": "2", + "reviews": [ + {"question": "What is the main purpose of this feature?", "score": 1, "comment": "Some design choices could enhance user engagement." }, + {"question": "How user-friendly is this feature?", "score": 5, "comment": "The feature's design excels in simplicity and effectiveness."}, + {"question": "Does this feature meet the project requirements?", "score": 2}, + {"question": "How would you rate the performance of this feature?", "score": 3, "comment": "The feature's performance is generally satisfactory." } + ] + }, + { + "reviewNumber": "3", + "reviews": [ + {"question": "What is the main purpose of this feature?", "comment": "The presentation was well-organized and clear. However, some points could have been elaborated further to provide a deeper understanding of the topic."}, + {"question": "How user-friendly is this feature?", "score": 3}, + {"question": "Does this feature meet the project requirements?", "score": 4}, + {"question": "How would you rate the performance of this feature?", "score": 5, "comment": "Performance issues were encountered during testing." } + ] + }, + { + "reviewNumber": "4", + "reviews": [ + {"question": "What is the main purpose of this feature?", "score": 5, "comment": "The speaker demonstrated a profound understanding of the subject matter, making the session engaging and informative."}, + {"question": "How user-friendly is this feature?", "score": 2}, + {"question": "Does this feature meet the project requirements?", "score": 0}, + {"question": "How would you rate the performance of this feature?", "score": 3, "comment": "Overall, the feature performs well, but some optimizations could enhance speed." } + ] + }, + { + "reviewNumber": "5", + "reviews": [ + {"question": "What is the main purpose of this feature?", "score": 4, "comment": "The visuals were compelling and helped in understanding complex concepts easily. However, there were a few slides with too much text, which made it hard to follow at times."}, + {"question": "How user-friendly is this feature?", "score": 3}, + {"question": "Does this feature meet the project requirements?", "score": 1}, + {"question": "How would you rate the performance of this feature?", "score": 2, "comment": "The feature's performance is acceptable but could be faster." } + ] + } + ] +] \ No newline at end of file