github.com/quickfeed/quickfeed@v0.0.0-20240507093252-ed8ca812a09c/public/src/components/submissions/SubmissionScores.tsx (about) 1 import React, { useCallback } from 'react' 2 import { Submission } from "../../../proto/qf/types_pb" 3 import SubmissionScore from "./SubmissionScore" 4 5 type ScoreSort = "name" | "score" | "weight" | "percentage" 6 7 const SubmissionScores = ({submission}: {submission: Submission}) => { 8 const [sortKey, setSortKey] = React.useState<ScoreSort>("name") 9 const [sortAscending, setSortAscending] = React.useState<boolean>(true) 10 11 const sortScores = () => { 12 const sortBy = sortAscending ? 1 : -1 13 const scores = submission.clone().Scores 14 const totalWeight = scores.reduce((acc, score) => acc + score.Weight, 0) 15 return scores.sort((a, b) => { 16 switch (sortKey) { 17 case "name": 18 return sortBy * (a.TestName.localeCompare(b.TestName)) 19 case "score": 20 return sortBy * (a.Score - b.Score) 21 case "weight": 22 return sortBy * (a.Weight - b.Weight) 23 case "percentage": 24 return sortBy * ((a.Score / a.MaxScore) * (a.Weight / totalWeight) - (b.Score / b.MaxScore) * (b.Weight / totalWeight)) 25 default: 26 return 0 27 } 28 }) 29 } 30 31 const handleSort = useCallback((event: React.MouseEvent<HTMLTableCellElement>) => { 32 const key = event.currentTarget.dataset.key as ScoreSort 33 if (sortKey === key) { 34 setSortAscending(!sortAscending) 35 } else { 36 setSortKey(key) 37 setSortAscending(true) 38 } 39 }, [sortKey, sortAscending]) 40 41 const sortedScores = React.useMemo(sortScores, [submission, sortKey, sortAscending]) 42 const totalWeight = sortedScores.reduce((acc, score) => acc + score.Weight, 0) 43 return ( 44 <table className="table table-curved table-striped table-hover"> 45 <thead className="thead-dark"> 46 <tr> 47 <th colSpan={1} className="col-md-8" data-key={"name"} role="button" onClick={handleSort}>Test Name</th> 48 <th colSpan={1} className="text-right col-md-auto" data-key={"score"} role="button" onClick={handleSort}>Score</th> 49 <th colSpan={1} className="text-right col-md-auto" data-key={"percentage"} role="button" onClick={handleSort}>%</th> 50 <th colSpan={1} className="text-right col-md-auto" data-key={"weight"} data-toggle="tooltip" title={"Maximum % contribution to total score"} role="button" onClick={handleSort}>Max</th> 51 </tr> 52 </thead> 53 <tbody style={{"wordBreak": "break-word"}}> 54 {sortedScores.map(score => 55 <SubmissionScore key={score.ID.toString()} score={score} totalWeight={totalWeight} /> 56 )} 57 </tbody> 58 <tfoot> 59 <tr> 60 <th colSpan={2}>Total Score</th> 61 <th className="text-right">{submission.score}%</th> 62 <th className="text-right">100%</th> 63 </tr> 64 </tfoot> 65 </table> 66 ) 67 } 68 69 export default SubmissionScores