github.com/quickfeed/quickfeed@v0.0.0-20240507093252-ed8ca812a09c/public/src/components/Members.tsx (about) 1 import React, { useState } from "react" 2 import { Color, EnrollmentSort, EnrollmentStatus, EnrollmentStatusBadge, getCourseID, getFormattedTime, isPending, isTeacher, sortEnrollments } from "../Helpers" 3 import { useAppState, useActions } from "../overmind" 4 import { Enrollment, Enrollment_UserStatus } from "../../proto/qf/types_pb" 5 import Search from "./Search" 6 import DynamicTable, { Row } from "./DynamicTable" 7 import DynamicButton from "./DynamicButton" 8 import Button, { ButtonType } from "./admin/Button" 9 10 const Members = (): JSX.Element => { 11 const state = useAppState() 12 const actions = useActions() 13 const courseID = getCourseID() 14 15 const [sortBy, setSortBy] = useState<EnrollmentSort>(EnrollmentSort.Status) 16 const [descending, setDescending] = useState<boolean>(false) 17 const [edit, setEditing] = useState<boolean>(false) 18 19 20 const setSort = (sort: EnrollmentSort) => { 21 if (sortBy === sort) { 22 setDescending(!descending) 23 } 24 setSortBy(sort) 25 } 26 27 let enrollments: Enrollment[] = [] 28 if (state.courseEnrollments[courseID.toString()]) { 29 // Clone the enrollments so we can sort them 30 enrollments = state.courseEnrollments[courseID.toString()].slice() 31 } 32 33 const pending = state.pendingEnrollments 34 35 const header: Row = [ 36 { value: "Name", onClick: () => setSort(EnrollmentSort.Name) }, 37 { value: "Email", onClick: () => setSort(EnrollmentSort.Email) }, 38 { value: "Student ID", onClick: () => setSort(EnrollmentSort.StudentID) }, 39 { value: "Activity", onClick: () => setSort(EnrollmentSort.Activity) }, 40 { value: "Approved", onClick: () => setSort(EnrollmentSort.Approved) }, 41 { value: "Slipdays", onClick: () => { setSort(EnrollmentSort.Slipdays) } }, 42 { value: "Role", onClick: () => { setSort(EnrollmentSort.Status) } }, 43 ] 44 const members = sortEnrollments(enrollments, sortBy, descending).map(enrollment => { 45 const data: Row = [] 46 data.push(enrollment.user ? enrollment.user.Name : "") 47 data.push(enrollment.user ? enrollment.user.Email : "") 48 data.push(enrollment.user ? enrollment.user.StudentID : "") 49 data.push(getFormattedTime(enrollment.lastActivityDate)) 50 data.push(enrollment.totalApproved.toString()) 51 data.push(enrollment.slipDaysRemaining.toString()) 52 53 if (isPending(enrollment)) { 54 data.push( 55 <div className="d-flex"> 56 <DynamicButton 57 text={"Accept"} 58 color={Color.GREEN} 59 type={ButtonType.BADGE} 60 className="mr-2" 61 onClick={() => actions.updateEnrollment({ enrollment, status: Enrollment_UserStatus.STUDENT })} 62 /> 63 <DynamicButton 64 text={"Reject"} 65 color={Color.RED} 66 type={ButtonType.BADGE} 67 onClick={() => actions.updateEnrollment({ enrollment, status: Enrollment_UserStatus.NONE })} 68 /> 69 </div>) 70 } else { 71 data.push(edit ? ( 72 <div className="d-flex"> 73 <DynamicButton 74 text={isTeacher(enrollment) ? "Demote" : "Promote"} 75 color={isTeacher(enrollment) ? Color.YELLOW : Color.BLUE} 76 type={ButtonType.BADGE} 77 className="mr-2" 78 onClick={() => actions.updateEnrollment({ enrollment, status: isTeacher(enrollment) ? Enrollment_UserStatus.STUDENT : Enrollment_UserStatus.TEACHER })} 79 /> 80 <DynamicButton 81 text={"Reject"} 82 color={Color.RED} 83 type={ButtonType.BADGE} 84 onClick={() => actions.updateEnrollment({ enrollment, status: Enrollment_UserStatus.NONE })} 85 /> 86 </div>) : 87 <i className={EnrollmentStatusBadge[enrollment.status]}> 88 {EnrollmentStatus[enrollment.status]} 89 </i> 90 ) 91 } 92 return data 93 }) 94 95 return ( 96 <div className='container'> 97 <div className="row no-gutters pb-2"> 98 <div className="col-md-6"> 99 <Search /> 100 </div> 101 <div className="ml-auto"> 102 <Button 103 text={edit ? "Done" : "Edit"} 104 color={edit ? Color.RED : Color.BLUE} 105 type={ButtonType.BUTTON} 106 onClick={() => setEditing(!edit)} 107 /> 108 </div> 109 {pending?.length > 0 ? 110 <div style={{ marginLeft: "10px" }}> 111 <DynamicButton 112 text="Approve All" 113 color={Color.GREEN} 114 type={ButtonType.BUTTON} 115 onClick={() => actions.approvePendingEnrollments()} 116 /> 117 </div> : null} 118 </div> 119 120 <div> 121 <DynamicTable header={header} data={members} /> 122 </div> 123 </div> 124 ) 125 } 126 127 export default Members