From 31852e33e5e92192bd59c509641a64e5e52964d6 Mon Sep 17 00:00:00 2001 From: Tuyisenge Tito <159807244+Tuyisenge2@users.noreply.github.com> Date: Wed, 6 Nov 2024 16:10:53 +0200 Subject: [PATCH] (fix): add coordinator dashboard page (#608) --- src/components/DataTable.tsx | 2 +- src/pages/CoordinatorDashboard.tsx | 235 ++++ src/pages/Dashboard.tsx | 3 +- src/pages/coordinatorTraineDashboard.tsx | 1587 ++++++++++++++++++++++ src/queries/ratings.queries.tsx | 10 + tests/components/Calendar.test.tsx | 2 +- 6 files changed, 1836 insertions(+), 3 deletions(-) create mode 100644 src/pages/CoordinatorDashboard.tsx create mode 100644 src/pages/coordinatorTraineDashboard.tsx diff --git a/src/components/DataTable.tsx b/src/components/DataTable.tsx index d99c38696..1b222d9bd 100644 --- a/src/components/DataTable.tsx +++ b/src/components/DataTable.tsx @@ -68,7 +68,7 @@ function DataTable({ data, columns, title, loading, className }: TableData) { return (
diff --git a/src/pages/CoordinatorDashboard.tsx b/src/pages/CoordinatorDashboard.tsx new file mode 100644 index 000000000..cd10a52ca --- /dev/null +++ b/src/pages/CoordinatorDashboard.tsx @@ -0,0 +1,235 @@ +/* eslint-disable jsx-a11y/no-redundant-roles */ + +import React, { useContext } from 'react'; +import { useTranslation } from 'react-i18next'; +// eslint-disable-next-line import/no-useless-path-segments +// import { Link } from 'react-router-dom'; +import { useQuery } from '@apollo/client'; +// import { use } from 'i18next'; +import { UserContext } from '../hook/useAuth'; +// import AdminTraineeDashboard from './AdminTraineeDashboard'; +import CoordinatorTraineeDashboard from './coordinatorTraineDashboard'; +import { FETCH_ALL_RATINGS } from '../queries/ratings.queries'; +import InvitationCardSkeleton from '../Skeletons/InvitationCardSkeleton'; + +interface Trainee { + id: string; + total: number; + count: number; + email: string; + profile: { + firstName: string; + lastName: string; + id: string; + profileImage: string; + }; + [key: string]: any; // for additional properties from rating.user +} + +function CoordinatorDashboard() { + const organizationToken = localStorage.getItem('orgToken'); + + const { user } = useContext(UserContext); + const { t }: any = useTranslation(); + + const { loading, error, data } = useQuery(FETCH_ALL_RATINGS, { + variables: { orgToken: organizationToken }, + skip: !organizationToken, + }); + + if (loading) { + return ( +
+ + + +
+ ); + } + if (error) { + return

Error loading data

; + } + + const traineeAverages = data?.fetchAllRatings.reduce( + (acc: Record, rating: any) => { + const { id } = rating.user; + if (!acc[id]) acc[id] = { ...rating.user, total: 0, count: 0 }; + acc[id].total += parseFloat(rating.average); + acc[id].count += 1; + return acc; + }, + {} as Record, + ); + + const trainees = Object.values(traineeAverages).map((trainee) => { + const typedTrainee = trainee as Trainee; // Cast to Trainee type + return { + ...typedTrainee, + average: typedTrainee.total / typedTrainee.count, + }; + }); + + const sortedTrainees = trainees.sort((a, b) => b.average - a.average); + const topThree = sortedTrainees.slice(0, 3); + const lastThree = sortedTrainees.slice(-3); + + const ratings = data?.fetchAllRatings || []; + + const cohorts = ratings.reduce((acc: any, rating: any) => { + const cohortName = rating.cohort.name; + const averageRating = parseFloat(rating.average); + + if (!acc[cohortName]) { + acc[cohortName] = { + totalRating: 0, + traineeCount: 0, + coordinator: rating.coordinator, + }; + } + acc[cohortName].totalRating += averageRating; + acc[cohortName].traineeCount += 1; + + return acc; + }, {}); + + const cohortPerformances = Object.keys(cohorts).map((cohortName) => ({ + cohortName, + averageRating: + cohorts[cohortName].totalRating / cohorts[cohortName].traineeCount, + coordinator: cohorts[cohortName].coordinator, + })); + + const topCohorts = cohortPerformances + .sort((a, b) => b.averageRating - a.averageRating) + .slice(0, 3); + + return ( +
+
+
+
+
+
+ Top Performing Cohorts +
+
+
+
    + {topCohorts.map((cohort) => ( +
  • +
    +
    +
    + {cohort.cohortName.charAt(0).toUpperCase()} +
    +
    +
    +

    + {cohort.cohortName} +

    +

    + Average Rating: {cohort.averageRating.toFixed(2)} +

    +
    +
    +
  • + ))} +
+
+
+ +
+
+
+ Top Performing Trainees +
+
+
+
    + {topThree.map((trainee) => ( +
  • +
    +
    +
    + {trainee.profile?.firstName?.charAt(0).toUpperCase()} +
    +
    +
    +

    + {trainee.profile?.firstName}{' '} + {trainee.profile?.lastName} +

    + {/*

    + Average Rating: {trainee.average.toFixed(2)} +

    */} +

    + {trainee.email} +

    +
    +
    +
  • + ))} +
+
+
+ +
+
+
+ Last Performing Trainees +
+
+
+
    + {lastThree.map((trainee) => ( +
  • +
    +
    + {trainee.profile?.firstName?.charAt(0).toUpperCase()} +
    +
    +

    + {trainee.profile?.firstName}{' '} + {trainee.profile?.lastName} +

    + {/*

    + Average Rating: {trainee.average.toFixed(2)} +

    */} +

    + {trainee.email} +

    +
    +
    +
  • + ))} +
+
+
+
+
+
+ +
+
+ ); +} + +export default CoordinatorDashboard; diff --git a/src/pages/Dashboard.tsx b/src/pages/Dashboard.tsx index 1931ce8bf..97e231bec 100644 --- a/src/pages/Dashboard.tsx +++ b/src/pages/Dashboard.tsx @@ -4,6 +4,7 @@ import SupAdDashboard from './SupAdDashboard'; import AdminDashboard from './AdminDashboard'; import TraineeDashboard from './TraineeDashboard'; import ManagerCard from '../components/ManagerCard'; +import CoordinatorDashboard from './CoordinatorDashboard'; export function Dashboard() { return ( @@ -21,7 +22,7 @@ export function Dashboard() { - + diff --git a/src/pages/coordinatorTraineDashboard.tsx b/src/pages/coordinatorTraineDashboard.tsx new file mode 100644 index 000000000..480f7723c --- /dev/null +++ b/src/pages/coordinatorTraineDashboard.tsx @@ -0,0 +1,1587 @@ +/* eslint-disable */ +/* istanbul ignore file */ +import React, { useState, useEffect, useContext, useRef } from 'react'; +import { Icon } from '@iconify/react'; +import { useTranslation } from 'react-i18next'; +import Dialog from '@mui/material/Dialog'; +import DialogContent from '@mui/material/DialogContent'; +import Paper, { PaperProps } from '@mui/material/Paper'; +import Draggable from 'react-draggable'; +import { toast } from 'react-toastify'; +import Select from 'react-select'; +import { useLazyQuery, useMutation, useQuery } from '@apollo/client'; +import DataTable from '../components/DataTable'; +import useDocumentTitle from '../hook/useDocumentTitle'; +import Button from '../components/Buttons'; +import Avatar from '../assets/avatar.png'; + +import { + REMOVE_MEMBER_FROM_COHORT_MUTATION, + DROP_TRAINEE, + EDIT_MEMBER_MUTATION, + INVITE_USER_MUTATION, + ADD_MEMBER_TO_TEAM, + UNDROP_TRAINEE, +} from '../Mutations/manageStudentMutations'; +import { + GET_USERS_QUERY, + GET_TRAINEES_QUERY, + GET_COHORTS_QUERY, + GET_GITHUB_STATISTICS, + GET_TEAM_QUERY, +} from '../queries/manageStudent.queries'; +import { useNavigate } from 'react-router-dom'; + +import ControlledSelect from '../components/ControlledSelect'; +import { UserContext } from '../hook/useAuth'; +import GitHubActivityChart from '../components/chartGitHub'; +import Spinner from '../components/Spinner'; +import { useTraineesContext } from '../hook/useTraineesData'; +import Dropdown from 'react-dropdown-select'; +import ViewWeeklyRatings from '../components/ratings/ViewWeeklyRatings'; +import { FaTimes } from 'react-icons/fa'; +import TtlSkeleton from '../Skeletons/ttl.skeleton'; +const organizationToken = localStorage.getItem('orgToken'); + +function CoordinatorTraineeDashboard() { + useDocumentTitle('Trainees'); + const { t }: any = useTranslation(); + const { user } = useContext(UserContext); + const navigate = useNavigate(); + const [registerTraineeModel, setRegisterTraineeModel] = useState(false); + const [removeTraineeModel, setRemoveTraineeModel] = useState(false); + const [editTraineeModel, setEditTraineeModel] = useState(false); + const [inviteTraineeModel, setInviteTraineeModel] = useState(false); + const [allUserEmail, setAllUserEmail] = useState([]); + const [cohorts, setCohorts] = useState([]); + const [cohortName, setCohortName] = useState(''); + const [teams, setTeams] = useState([]); + const [email, setEmail] = useState([]); + const [traineeDetails, setTraineeDetails] = useState({}); + const [selectedOption, setSelectedOption] = useState([]); + const [selectedOptionUpdate, setSelectedOptionUpdate] = useState({}); + const [dropTraineeModel, setDropTraineeModel] = useState(false); + const [dropTraineeID, setdropTraineeID] = useState(''); + const [selectedTeamOptionUpdate, setSelectedTeamOptionUpdate] = useState( + {}, + ); + const [selectedTeamOption, setSelectedTeamOption] = useState([]); + const [deleteEmail, setDeleteEmail] = useState(''); + const [editEmail, setEditEmail] = useState(''); + const [editCohort, setEditCohort] = useState(''); + const [editTeam, setEditTeam] = useState(''); + const [inviteEmail, setInviteEmail] = useState(''); + const [buttonLoading, setButtonLoading] = useState(false); + const [restoreTraineeModel, setRestoreTraineeModel] = useState(false); + + const [toggle, setToggle] = useState(false); + const [showOptions, setShowOptions] = useState(false); + const options: any = []; + const teamsOptions: any = []; + const traineeOptions: any = []; + const teamOptions: any = []; + const [isLoaded, setIsLoaded] = useState(false); + const [gitHubStatistics, setGitHubStatistics] = useState({}); + const { traineeData, setAllTrainees } = useTraineesContext() || []; + const [actionTraineeOptions, setActionTraineeOptions] = useState(null); + const modalRef = useRef(null); + // restoreTraineeModel + // restoreTraineeMod + // unDropTrainee + // restoreMemberFromCohort + const [selectedTraineeId, setSelectedTraineeId] = useState(); + + useEffect(() => { + const handleClickOutside = (event: any) => { + if (modalRef.current && !modalRef.current.contains(event.target)) { + setSelectedRow(null); + } + }; + document.addEventListener('mousedown', handleClickOutside); + return () => { + document.removeEventListener('mousedown', handleClickOutside); + }; + }, [modalRef]); + + function PaperComponent(props: PaperProps) { + return ( + + + + ); + } + + const [deleteFromCohort, setDeleteFromCohort] = useState(''); + + const [reason, setReason] = useState(''); + const currentDate = new Date().toISOString().split('T')[0]; // Get the current date + + // Function to handle the reason input change + const handleReasonChange = (event: { + target: { value: React.SetStateAction }; + }) => { + const newReason = event.target.value; + setReason(newReason); + }; + + const [getGitHubStatistics] = useLazyQuery(GET_GITHUB_STATISTICS, { + onCompleted: (data) => { + setGitHubStatistics(data.gitHubActivity); + setIsLoaded(false); + }, + onError: (error) => { + setIsLoaded(false); + }, + }); + + const [open, setOpen] = React.useState(false); + const [open2, setOpen2] = React.useState(false); + + const handleClickOpen = async (rowData: any) => { + setIsLoaded(true); + const filteredUser = traineeData.filter( + (item: any) => item.email == rowData, + ); + setTraineeDetails(filteredUser[0]); + setOpen(true); + getGitHubStatistics({ + variables: { + organisation: localStorage.getItem('orgName')?.split('.')[0], + username: filteredUser[0].profile?.githubUsername, + }, + }); + }; + + const handleClickOpen2 = async () => { + setIsLoaded(true); + + setOpen2(true); + }; + const handleClose = () => { + setOpen(false); + }; + const handleClose2 = () => { + setOpen2(false); + }; + + /* istanbul ignore next */ + const removeTraineeMod = () => { + const newState = !removeTraineeModel; + setRemoveTraineeModel(newState); + }; + const restoreTraineeMod = () => { + const newState = !restoreTraineeModel; + setRestoreTraineeModel(newState); + }; + const removeModel = () => { + const newState = !registerTraineeModel; + setRegisterTraineeModel(newState); + }; + + const dropModel = async (rowData: any) => { + const filteredUser = traineeData.filter( + (item: any) => item.email == rowData, + ); + if (filteredUser.length > 0) { + const user = filteredUser[0]; + if ( + user.profile && + user.profile.user && + user.profile.user.status && + user.profile.user.status.status + ) { + if (user.profile.user.status.status !== 'drop') { + let newState = !dropTraineeModel; + setDropTraineeModel(newState); + } else { + toast.success('Trainee is already dropped'); + } + } + } + }; + + /* istanbul ignore next */ + const removeEditModel = () => { + const newState = !editTraineeModel; + setEditTraineeModel(newState); + }; + const [selectedRow, setSelectedRow] = useState(null); + const [isDropdownOpen, setDropdownOpen] = useState(false); + + const toggleOptions = (row: string) => { + setSelectedRow(selectedRow === row ? null : row); + setDropdownOpen(true); + }; + + const inviteModel = () => { + const newState = !inviteTraineeModel; + setInviteTraineeModel(newState); + }; + /* istanbul ignore next */ + const handleToggle = () => { + setToggle(!toggle); + }; + + const customStyles = { + option: (provided: any, state: any) => ({ + ...provided, + borderBottom: '1px dotted pink', + color: state.isSelected ? 'red' : '#9e85f5', + }), + valueLabel: (styles: any) => ({ + ...styles, + text: 'white', + }), + control: (styles: any) => ({ + ...styles, + height: 20, + width: 370, + backgroundColor: '#374151', + borderColor: 'rgb(20 143 182)', + text: 'white', + }), + singleValue: (provided: any, state: any) => { + const opacity = state.isDisabled ? 0.5 : 1; + const transition = 'opacity 300ms'; + /* istanbul ignore next */ + return { ...provided, opacity, transition }; + }, + }; + + const columns = [ + { Header: t('name'), accessor: 'name' }, + { Header: t('email'), accessor: 'email' }, + + { Header: t('cohort'), accessor: 'cohort' }, + { Header: t('program'), accessor: 'program' }, + { + Header: t('Status'), + accessor: 'status', + + Cell: ({ row }: any) => { + return ( +
0 ? ' flex' : ' hidden') + } + > + +
+ ); + }, + }, + + { + Header: t('action'), + accessor: '', + Cell: ({ row }: any) => ( +
+
+ toggleOptions(row.original.email)} + /> + {selectedRow === row.original.email && ( +
+ <> +
+
+
{ + setSelectedOptionUpdate({ + value: row.original.cohort, + label: row.original.cohort, + }); + setSelectedTeamOptionUpdate({ + value: row.original.team, + label: row.original.team, + }); + removeEditModel(); + setEditEmail(row.original.email); + setEditCohort(row.original.cohort); + setEditTeam(row.original.team); + toggleOptions(row.original.email); + }} + > + +
+ Edit{' '} + <> +
+ Change cohort and team + +
+
+
+
+
{ + removeTraineeMod(); + setDeleteEmail(row.original.email); + setDeleteFromCohort(row.original.team); + toggleOptions(row.original.email); + }} + > + +
+ Remove + <> +
+ Remove trainee + +
+
+
+
+ {row.original?.Status?.status !== 'drop' ? ( +
{ + dropModel(row.original.email); + setdropTraineeID(row.original.userId); + setReason(row.original.reason); + toggleOptions(row.original.email); + }} + > + +
+ Drop + {row.original.status} + <> +
+ Drop trainee + +
+
+ ) : ( +
{ + restoreTraineeMod(); + setdropTraineeID(row.original.userId); + setReason(row.original.reason); + toggleOptions(row.original.email); + }} + > + +
+ Restore{' '} + <> +
+ Restore Dropped Trainee + +
+
+ )} +
+
+
{ + handleClickOpen(row.original.email); + toggleOptions(row.original.email); + }} + > + +
+ View +
+ View detailed information +
+
+
+ +
+ )} +
+
+ ), + }, + ]; + 8; + + const datum: any = []; + const [getUsers] = useLazyQuery(GET_USERS_QUERY, { + variables: { + orgToken: organizationToken, + }, + }); + const { loading, data, refetch } = useQuery(GET_TRAINEES_QUERY, { + variables: { + orgToken: organizationToken, + }, + fetchPolicy: 'network-only', + onError: (error) => { + toast.error(error.message); + }, + }); + + useEffect(() => { + if (data && data.getTrainees) { + refetch(); + setAllTrainees(data.getTrainees); + } + }, [data, registerTraineeModel, removeTraineeModel, toggle]); + + const [getCohortsQuery] = useLazyQuery(GET_COHORTS_QUERY, { + variables: { + orgToken: organizationToken, + }, + }); + const [getTeamQuery] = useLazyQuery(GET_TEAM_QUERY, { + variables: { + orgToken: organizationToken, + cohort: cohortName, + }, + }); + + function getTeam() { + getTeamQuery({ + fetchPolicy: 'network-only', + onCompleted: (data) => { + setTeams(data.getAllTeamInCohort); + }, + onError: (error) => { + toast.error(error.message); + }, + }); + } + + /* istanbul ignore if */ + + if (traineeData && traineeData.length > 0) { + traineeData?.map((data: any, index: number) => { + datum[index] = {}; + datum[index].name = data.profile ? data.profile.name : 'undefined'; + datum[index].email = data.email; + datum[index].rating = data.ratings.length ? data.ratings : 'not rated.'; + datum[index].team = data.team?.name; + datum[index].cohort = data.team?.cohort?.name; + datum[index].program = data.team?.cohort?.program?.name; + datum[index].userId = data.profile?.user?.id; + datum[index].Status = data.profile?.user?.status; + }); + } + + const [addMemberToTeam] = useMutation(ADD_MEMBER_TO_TEAM, { + variables: { + teamName: Object.values(selectedTeamOption)[1], + email: Object.values(email)[1], + orgToken: organizationToken, + }, + /* istanbul ignore next */ + onCompleted: (data) => { + setTimeout(() => { + setButtonLoading(false); + toast.success(data.addMemberToTeam); + removeModel(); + }, 500); + }, + /* istanbul ignore next */ + onError: (err) => { + setTimeout(() => { + setButtonLoading(false); + toast.error(err.message); + }, 1000); + }, + }); + + const [editMemberMutation] = useMutation(EDIT_MEMBER_MUTATION, { + variables: { + removedFromTeamName: editTeam, + addedToTeamName: selectedTeamOptionUpdate.value, + email: editEmail, + orgToken: organizationToken, + }, + onCompleted: (data) => { + handleToggle(); + + setTimeout(() => { + setButtonLoading(false); + toast.success(data.editMember); + removeEditModel(); + }, 500); + }, + onError: (err) => { + setTimeout(() => { + setButtonLoading(false); + toast.error(err.message); + }, 1000); + }, + }); + + const [dropMemberFromCohort] = useMutation(DROP_TRAINEE, { + variables: { + traineeId: dropTraineeID, + reason: reason, + date: currentDate, + }, + onCompleted: (data) => { + setTimeout(() => { + setButtonLoading(false); + if (data.dropTrainee) { + // Check the response structure + refetch(); + toast.success('Trainee dropped successfully'); + setDropTraineeModel(false); + } else { + toast.error('Failed to drop trainee'); + } + }, 1000); + }, + onError: (err) => { + setTimeout(() => { + setButtonLoading(false); + console.error('Mutation error:', err); // Log the error + toast.error(err.message); + }, 500); + }, + }); + + const [unDropTrainee] = useMutation(UNDROP_TRAINEE, { + variables: { + traineeId: dropTraineeID, + }, + onCompleted: (data) => { + setTimeout(() => { + setButtonLoading(false); + if (data.undropTrainee) { + // Check the response structure + refetch(); + toast.success('Trainee Undropped successfully'); + setDropTraineeModel(false); + restoreTraineeMod(); + } else { + toast.error('Failed to undrop trainee'); + } + }, 1000); + }, + onError: (err) => { + setTimeout(() => { + setButtonLoading(false); + console.error('Mutation error:', err); // Log the error + toast.error(err.message); + }, 500); + }, + }); + const [removeMemberFromCohort] = useMutation( + REMOVE_MEMBER_FROM_COHORT_MUTATION, + { + variables: { + teamName: deleteFromCohort, + orgToken: organizationToken, + email: deleteEmail, + }, + onCompleted: (data) => { + setTimeout(() => { + setButtonLoading(false); + toast.success(data.removeMemberFromCohort); + removeTraineeMod(); + }, 1000); + }, + onError: (err) => { + setTimeout(() => { + setButtonLoading(false); + toast.error(err.message); + }, 500); + }, + }, + ); + + const HandleInvite = () => { + // pass + setButtonLoading(true); + inviteUser(); + }; + const [inviteUser] = useMutation(INVITE_USER_MUTATION, { + variables: { + email: inviteEmail, + orgToken: organizationToken, + type: 'user', + }, + onCompleted: (data) => { + setTimeout(() => { + setButtonLoading(false); + toast.success(data.inviteUser); + inviteModel(); + }, 1000); + }, + onError: (err) => { + setTimeout(() => { + setButtonLoading(false); + toast.error(err.message); + }, 1000); + }, + }); + useEffect(() => { + getUsers({ + fetchPolicy: 'network-only', + onCompleted: (data) => { + setAllUserEmail(data.getUsers); + }, + onError: (error) => { + toast.error(error.message); + }, + }); + getCohortsQuery({ + fetchPolicy: 'network-only', + onCompleted: (data) => { + setCohorts(data.getCohorts); + }, + onError: (error) => { + toast.error(error.message); + }, + }); + }, [registerTraineeModel, removeTraineeModel, toggle]); + /* istanbul ignore if */ + if (allUserEmail.length > 0) { + allUserEmail.map((trainee: any, index: any) => { + traineeOptions[index] = {}; + traineeOptions[index].value = trainee.email; + traineeOptions[index].label = trainee.email; + }); + } + /* istanbul ignore if */ + if (cohorts.length > 0) { + cohorts.map((cohort: any, index: any) => { + options[index] = {}; + options[index].value = cohort.name; + options[index].label = cohort.name; + }); + } + if (teams.length > 0) { + teams.map((team: any, index: any) => { + teamsOptions[index] = {}; + teamsOptions[index].value = team.name; + teamsOptions[index].label = team.name; + }); + } + if (teams.length > 0) { + teams.map((team: any, index: any) => { + teamOptions[index] = {}; + teamOptions[index].value = team?.name; + teamOptions[index].label = team?.name; + }); + } + + return ( + <> + {/* =========================== Start:: InviteTraineeModel =============================== */} +
+ + + {/* */} +
+
+ Logo +
+ +

+ {traineeDetails && traineeDetails.profile + ? traineeDetails.profile.name + : 'Unavailable'} +

+ +
+ {' '} +

+ EMAIL{' '} +

+

+ + {' '} + {traineeDetails && traineeDetails.profile + ? traineeDetails.email + : 'Unavailable'} + +

+
+
+ {' '} +

+ START DATE +

+

+ {traineeDetails && traineeDetails.team + ? traineeDetails.team.cohort.startDate.split('T')[0] + : 'Unavailable'} +

+
+
+ {' '} +

+ PROGRAM{' '} +

+

+ + {' '} + {traineeDetails && traineeDetails.team + ? traineeDetails.team.cohort.program.name + : 'Unavailable'} + +

+
+ +
+ {' '} +

+ PHASE{' '} +

+

+ + {traineeDetails && traineeDetails.team + ? traineeDetails.team.cohort.phase.name + : 'Unavailable'} + +

+
+ + {/* show cohort */} +
+ {' '} +

+ COHORT{' '} +

+

+ + {' '} + {traineeDetails && traineeDetails.team + ? traineeDetails.team.cohort.name + : 'Unavailable'} + +

+
+ {/* show team */} +
+ {' '} +

+ TEAM{' '} +

+

+ + {' '} + {traineeDetails && traineeDetails.team + ? traineeDetails.team.name + : 'Unavailable'} + +

+
+ {/* show team */} +
+ {' '} +

+ RATINGS{' '} +

+

+ + {' '} + {traineeDetails && traineeDetails.ratings + ? traineeDetails.ratings[0] + ? traineeDetails.ratings[0] + : 'not yet rated' + : 'unavailable.'} + +

+
+ + {/* show manager */} +
+ {' '} +

+ MANAGER{' '} +

+

+ + {' '} + {traineeDetails && traineeDetails.team + ? traineeDetails.team.cohort.program.manager.profile.name + : 'Unavailable'} + +

+
+ + {/* show coordinator */} +
+ {' '} +

+ COORDINATOR{' '} +

+

+ + {' '} + {traineeDetails && traineeDetails.cohort + ? traineeDetails.cohort.coordinator.profile.name + : 'Unavailable'} + +

+
+ + {/* Show resume URL for admins and managers */} + {user && + (user.role === 'admin' || user.role === 'coordinator') && ( +
+

+ RESUME +

+

+ {traineeDetails?.profile?.resume ? ( + + View Resume + + ) : ( + 'Unavailable' + )} +

+
+ )} + +
+ {isLoaded ? ( +
+ Loading gitHub statistics... + +
+
+ ) : ( +
+
+ + {gitHubStatistics?.totalCommits} total commits + +
+
+
+ {traineeDetails?.profile && + traineeDetails?.profile?.githubUsername ? ( + + ) : ( + <> + )} +
+
+
+ )} +
+ + +
+ {/* */} + +
+
+ {/* =========================== Start:: InviteTraineeModel =============================== */} + +
+
+
+

+ {t('Send Invitation')} +

+
+
+
+
{ + e.preventDefault(); + }} + className="px-8 py-3 " + > +
+

+ {t('Fill in the email to invite a user to DevPulse.')} +

+
+ +
+
+ { + setInviteEmail(e.target.value); + }} + onSubmit={() => inviteModel()} + type="email" + name="email" + className="w-full px-5 py-2 font-sans text-xs text-black border rounded outline-none dark:bg-dark-tertiary border-primary" + placeholder={t('email')} + /> +
+
+ +
+ + + +
+
+
+
+
+ {/* =========================== End:: InviteTraineeModel =============================== */} + + {/* =========================== Start:: EditTraineeModel =============================== */} + +
+
+
+

+ {t('Edit Trainee')} +

+
+
+
+
+
+

+ {t( + 'Choose a different cohort for the trainee from the dropdown below.', + )} +

+
+ +
+
+ { + setSelectedOptionUpdate(e); + setSelectedTeamOptionUpdate({ + value: '', + label: 'Select team', + }); + setCohortName(e.value); + getTeam(); + }, + }} + options={options} + /> +
+
+
+
+ { + setSelectedTeamOptionUpdate(e); + }, + }} + options={teamsOptions.filter( + (option: any) => option.value !== editTeam, + )} + /> +
+
+ +
+ + +
+
+
+
+
+ {/* =========================== End:: EditTraineeModel =============================== */} + + {/* =========================== Start:: RemoveTraineeModel =============================== */} + +
+
+
+

+ {t('Remove Trainee')} +

+
+
+
+
+
+

+ {t( + 'Are you sure you want to remove trainee from this cohort?', + )} +

+
+ +
+ + +
+
+
+
+
+ {/* =========================== End:: RemoveTraineeModel =============================== */} + + {/* =========================== start:: deleteTraineeModel =============================== */} +
+
+
+

+ {t('Drop Trainee')} +

+
+
+
+
+ {/* ... (rest of your form) */} + + {/* Reason Field */} +
+ + +
+ + {/* Date Field */} +
+ + +
+ +
+ + + +
+
+
+
+
+ + {/* =========================== End:: deleteTraineeModel =============================== */} + + {/* =========================== Start:: AddTraineeModel =============================== */} + +
+
+
+

+ {t('Add Trainee')} +

+
+
+
+
+
+
+