github.com/quickfeed/quickfeed@v0.0.0-20240507093252-ed8ca812a09c/public/src/components/manual-grading/Criterion.tsx (about) 1 import React, { useState } from "react" 2 import { GradingCriterion, GradingCriterion_Grade } from "../../../proto/qf/types_pb" 3 import { useAppState } from "../../overmind" 4 import GradeComment from "./GradeComment" 5 import CriteriaStatus from "./CriteriaStatus" 6 import CriterionComment from "./Comment" 7 import UnstyledButton from "../UnstyledButton" 8 9 10 /* Criteria component for the manual grading page */ 11 const Criteria = ({ criteria }: { criteria: GradingCriterion }): JSX.Element => { 12 13 // editing, setEditing is used to toggle the GradeComment component 14 const [editing, setEditing] = useState<boolean>(false) 15 const [showComment, setShowComment] = React.useState<boolean>(true) 16 const { isTeacher } = useAppState() 17 18 // classname is used to style the first column of the row returned by this component 19 // it adds a vertical line to the left of the row with color based on the grading criterion. 20 let className: string 21 switch (criteria.grade) { 22 case GradingCriterion_Grade.PASSED: 23 className = "passed" 24 break 25 case GradingCriterion_Grade.FAILED: 26 className = "failed" 27 break 28 case GradingCriterion_Grade.NONE: 29 className = "not-graded" 30 break 31 } 32 33 const passed = criteria.grade == GradingCriterion_Grade.PASSED 34 // manageOrShowPassed renders the ManageCriteriaStatus component if the user is a teacher, otherwise it renders a passed/failed icon 35 const criteriaStatusOrPassFailIcon = isTeacher 36 ? <CriteriaStatus criterion={criteria} /> 37 : <i className={passed ? "fa fa-check" : "fa fa-exclamation-circle"} /> 38 39 40 let comment: JSX.Element | null = null 41 let button: JSX.Element | null = null 42 if (isTeacher) { 43 // Display edit icon if comment is empty 44 // If comment is not empty, display the comment 45 button = <UnstyledButton onClick={() => setEditing(true)}><i className="fa fa-pencil-square-o" aria-hidden="true" /></UnstyledButton> 46 if (criteria.comment.length > 0) { 47 comment = <CriterionComment comment={criteria.comment} /> 48 } 49 } else { 50 comment = <CriterionComment comment={criteria.comment} /> 51 button = <UnstyledButton onClick={() => setShowComment(!showComment)}><i className={`fa fa-comment${!showComment ? "-o" : ""}`} /></UnstyledButton> 52 } 53 54 // Only display the comment if the comment is not empty 55 const displayComment = criteria.comment.length > 0 56 return ( 57 <> 58 <tr className="align-items-center"> 59 <td className={className}>{criteria.description}</td> 60 <td> 61 {criteriaStatusOrPassFailIcon} 62 </td> 63 <td> 64 { // Only display the comment button if the comment is not empty, or if the user is a teacher 65 (displayComment || isTeacher) ? button : null 66 } 67 </td> 68 </tr> 69 {displayComment ? 70 <tr className={`comment comment-${className}${!showComment ? " hidden" : ""} `}> 71 <td onClick={() => setEditing(true)} colSpan={3}> 72 {comment} 73 </td> 74 </tr> : null 75 } 76 <GradeComment grade={criteria} editing={editing} setEditing={setEditing} /> 77 </> 78 ) 79 } 80 81 export default Criteria