github.com/quickfeed/quickfeed@v0.0.0-20240507093252-ed8ca812a09c/public/src/components/manual-grading/GradeComment.tsx (about) 1 import React, { Dispatch, SetStateAction } from "react" 2 import { GradingBenchmark, GradingCriterion } from "../../../proto/qf/types_pb" 3 import { useActions, useAppState } from "../../overmind" 4 5 type GradeCommentProps = { 6 grade: GradingBenchmark | GradingCriterion, 7 editing: boolean, 8 setEditing: Dispatch<SetStateAction<boolean>> 9 } 10 11 const GradeComment = ({ grade, editing, setEditing }: GradeCommentProps): JSX.Element | null => { 12 const actions = useActions() 13 const state = useAppState() 14 15 /* Don't allow grading if user is not a teacher or editing is false */ 16 if (!state.isTeacher || !editing) { 17 return null 18 } 19 20 const updateComment = (value: string) => { 21 setEditing(false) 22 // Exit early if the value is unchanged 23 if (value === grade.comment) { 24 return 25 } 26 actions.review.updateComment({ grade: grade, comment: value }) 27 } 28 29 // handleBlur saves the comment when clicking outside the text area. 30 const handleBlur = (event: React.FocusEvent<HTMLTextAreaElement>) => { 31 const { value } = event.currentTarget 32 updateComment(value) 33 } 34 35 // handleKeyUp saves the comment when pressing Ctrl/Cmd+Enter or Ctrl/Cmd+Q/q. 36 // It also cancels the edit when pressing Escape. 37 const handleKeyUp = (event: React.KeyboardEvent<HTMLTextAreaElement>) => { 38 if (event.key === "Escape") { 39 setEditing(false) 40 return 41 } 42 if ((event.key === "Enter" || event.key === "q" || event.key === "Q") && (event.ctrlKey || event.metaKey)) { 43 const { value } = event.currentTarget 44 updateComment(value) 45 } 46 } 47 48 return ( 49 <tr> 50 <th colSpan={3}> 51 <textarea rows={20} autoFocus onBlur={handleBlur} onKeyUp={handleKeyUp} defaultValue={grade.comment} className="form-control"></textarea> 52 </th> 53 </tr> 54 ) 55 56 } 57 58 export default GradeComment