Skip to content

Commit

Permalink
(fix): add coordinator dashboard page
Browse files Browse the repository at this point in the history
  • Loading branch information
Tuyisenge2 committed Nov 4, 2024
1 parent 2e47213 commit ed52623
Show file tree
Hide file tree
Showing 5 changed files with 1,836 additions and 2 deletions.
2 changes: 1 addition & 1 deletion src/components/DataTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ function DataTable({ data, columns, title, loading, className }: TableData) {

return (
<div
className={`relative font-serif bg-indigo-100 dark:bg-dark-bg shadow-lg h-fit px-5 py-8 rounded-md w-full lg:w-auto mx-auto mb-10 ${className}`}
className={`relative font-serif bg-indigo-100 dark:bg-dark-bg shadow-lg h-fit px-5 py-8 rounded-md w-[100%] overflow-scroll "lg:ml-60 mx-auto"} mb-10`}
>
<div className="flex flex-col md:flex-row items-center justify-between pb-6 space-y-4 md:space-y-0">
<div>
Expand Down
236 changes: 236 additions & 0 deletions src/pages/CoordinatorDashboard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
/* eslint-disable jsx-a11y/no-redundant-roles */

import React, { useContext, useEffect, useState } 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 {
user: {
id: string;
email: string;
profile: {
avatar: string;
firstName: string;
};
};
}

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 (
<div className="flex flex-col items-center w-[80%] mx-auto mdl:w-[100%] mdl:justify-between gap-5 xmd:flex-row xmd:flex-wrap bg-light-bg dark:bg-dark-frame-bg py-4 font-serif">
<InvitationCardSkeleton />
<InvitationCardSkeleton />
<InvitationCardSkeleton />
</div>
);
}
if (error) {
return <p>Error loading data</p>;
}

const sortedRatings = [...(data?.fetchAllRatings || [])]
.sort((a, b) => b.average - a.average)
.filter(
(rating, index, self) =>
index === self.findIndex((r) => r.user.id === rating.user.id),
);
const topThree = sortedRatings.slice(0, 3);

const lastThree = [];
const seenIds = new Set();

// eslint-disable-next-line no-plusplus
for (let i = sortedRatings.length - 1; i >= 0 && lastThree.length < 3; i--) {
// eslint-disable-line no-plusplus
const rating = sortedRatings[i];
if (!seenIds.has(rating.user.id)) {
seenIds.add(rating.user.id);
lastThree.push(rating);
}
}

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 (
<div className="flex flex-col grow bg-light-bg dark:bg-dark-frame-bg">
<div className="flex flex-row">
<div className="flex flex-col items-center w-[80%] mx-auto mdl:w-[100%] mdl:justify-between gap-5 xmd:flex-row xmd:flex-wrap bg-light-bg dark:bg-dark-frame-bg py-4 font-serif">
<div className="w-[20rem] p-4 bg-indigo-100 border border-gray-200 rounded-lg shadow sm:p-8 dark:bg-gray-800 dark:border-gray-700">
<div className="flex items-center justify-between mb-4 h-8">
<h5 className="text-xl font-bold leading-none text-gray-900 dark:text-white">
Top Performing Cohorts
</h5>
</div>
<div className="flow-root">
<ul
role="list"
className="divide-y h-[12.5rem] divide-gray-200 dark:divide-gray-700"
>
{topCohorts.map((cohort) => (
<li
key={cohort.cohortName}
className="py-3 sm:py-4 border-t border-t-black dark:border-t-gray-200"
>
<div className="flex items-center">
<div className="flex-shrink-0">
<div className="w-8 h-8 rounded-full bg-white text-black flex items-center justify-center">
{cohort.cohortName.charAt(0).toUpperCase()}
</div>
</div>
<div className="flex-1 min-w-0 ms-4">
<p className="text-sm font-medium text-gray-900 truncate dark:text-white">
{cohort.cohortName}
</p>
<p className="text-sm text-gray-500 truncate dark:text-gray-400">
Average Rating: {cohort.averageRating.toFixed(2)}
</p>
</div>
</div>
</li>
))}
</ul>
</div>
</div>

<div className="w-[20rem] p-4 bg-indigo-100 border border-gray-200 rounded-lg shadow sm:p-8 dark:bg-gray-800 dark:border-gray-700">
<div className="flex items-center justify-between mb-4 h-8">
<h5 className="text-xl font-bold leading-none text-gray-900 dark:text-white">
Top Performing Trainees
</h5>
</div>
<div className="flow-root">
<ul
role="list"
className="divide-y h-[12.5rem] divide-gray-200 dark:divide-gray-700"
>
{topThree.map((rating) => (
<li
key={rating.user.id}
className="py-3 sm:py-4 border-t border-t-black dark:border-t-gray-200"
>
<div className="flex items-center">
<div className="flex-shrink-0">
<div className="w-8 h-8 rounded-full bg-white text-black flex items-center justify-center">
<p className="text-lg">
{rating.user.profile?.firstName
.charAt(0)
.toUpperCase()}
</p>
</div>
</div>
<div className="flex-1 min-w-0 ms-4">
<p className="text-sm font-medium text-gray-900 truncate dark:text-white">
{`${rating.user.profile?.firstName || ''} ${
rating.user.profile?.lastName || ''
}`}
</p>
<p className="text-sm text-gray-500 truncate dark:text-gray-400">
sprint: {rating.sprint}
</p>
</div>
</div>
</li>
))}
</ul>
</div>
</div>

<div className="w-[20rem] p-4 bg-indigo-100 border border-gray-200 rounded-lg shadow sm:p-8 dark:bg-gray-800 dark:border-gray-700">
<div className="flex items-center justify-between mb-4 h-8">
<h5 className="text-xl font-bold leading-none text-gray-900 dark:text-white">
Last Performing Trainees
</h5>
</div>
<div className="flow-root">
<ul
role="list"
className="divide-y h-[12.5rem] divide-gray-200 dark:divide-gray-700"
>
{lastThree.map((rating) => (
<li
key={rating.user.id}
className="py-3 sm:py-4 border-t border-t-black dark:border-t-gray-200"
>
<div className="flex items-center">
<div className="flex-shrink-0">
<div className="w-8 h-8 rounded-full bg-white text-black flex items-center justify-center">
<p className="text-lg">
{rating.user.profile?.firstName
.charAt(0)
.toUpperCase()}
</p>
</div>
</div>
<div className="flex-1 min-w-0 ms-4">
<p className="text-sm font-medium text-gray-900 truncate dark:text-white">
{`${rating.user.profile?.firstName || ''} ${
rating.user.profile?.lastName || ''
}`}
</p>
<p className="text-sm text-gray-500 truncate dark:text-gray-400">
sprint: {rating.sprint}
</p>
</div>
</div>
</li>
))}
</ul>
</div>
</div>
</div>
</div>
<div className=" fex-row justify-ceter w-[100%] pb8">
<CoordinatorTraineeDashboard />
</div>
</div>
);
}

export default CoordinatorDashboard;
3 changes: 2 additions & 1 deletion src/pages/Dashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand All @@ -21,7 +22,7 @@ export function Dashboard() {
<TraineeDashboard />
</CheckRole>
<CheckRole roles={['coordinator']}>
<AdminDashboard />
<CoordinatorDashboard />
</CheckRole>
<CheckRole roles={['manager']}>
<ManagerCard />
Expand Down
Loading

0 comments on commit ed52623

Please sign in to comment.