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