From c67a23409545f0b1220b749fecac6d71d7760261 Mon Sep 17 00:00:00 2001 From: Prakash6605 Date: Mon, 21 Jun 2021 21:04:39 +0530 Subject: [PATCH] resolved various bugs --- backend/routes/api/leaderboard/controller.ts | 89 ++++++++++++++++++- backend/routes/api/leaderboard/index.ts | 3 +- backend/routes/api/user-task/controller.ts | 37 +++++++- backend/routes/api/user-task/index.ts | 1 + backend/utils/sanitizer.ts | 11 ++- .../LeaderBoard/MonthlyLeaderboard.tsx | 61 +++++++++++++ frontend/components/LeaderBoard/index.tsx | 10 +-- frontend/components/TaskCard.tsx | 6 +- .../components/admin/AdminSubmissionModal.tsx | 36 +++++++- frontend/components/common/Pagination.tsx | 2 +- .../admin/task-view-pages/assigned-users.tsx | 17 ++++ .../admin/task-view-pages/leaderboard.tsx | 13 +++ frontend/pages/admin/task-view.tsx | 2 + frontend/pages/dashboard.tsx | 6 +- 14 files changed, 279 insertions(+), 15 deletions(-) create mode 100644 frontend/components/LeaderBoard/MonthlyLeaderboard.tsx create mode 100644 frontend/pages/admin/task-view-pages/leaderboard.tsx diff --git a/backend/routes/api/leaderboard/controller.ts b/backend/routes/api/leaderboard/controller.ts index 442b39f..d319b47 100644 --- a/backend/routes/api/leaderboard/controller.ts +++ b/backend/routes/api/leaderboard/controller.ts @@ -1,8 +1,10 @@ import { Request, Response } from 'express'; import Repositories from '../../../repositories/index'; import { generatePaginationObject } from '../../../utils/pagination'; -import { generateSanitizeduser } from '../../../utils/sanitizer'; +import { generateSanitizeduser, generateSanitizedUserFromUserTask } from '../../../utils/sanitizer'; import AsyncHandler from '../../../decorators/async-handler'; +import { getRepository, In, MoreThan } from 'typeorm'; +import { UserTask } from 'entity'; class LeaderboardController { @AsyncHandler() @@ -22,6 +24,91 @@ class LeaderboardController { }, }); } + + @AsyncHandler() + async filterLeaderboard(req: Request, res: Response) { + console.log(' hitting the api with task_id '); + const offset = Number(req.query.offset || 0); + const limit = Number(req.query.limit || 10); + const task_id = Number(req.params.id); + + const [data, count] = await Repositories.userTask.findAndCount({ + skip: offset, + take: limit, + where: { taskId: task_id }, + order: { assignedPoints: 'DESC' }, + relations: ['user'], + }); + + res.json({ + data: generateSanitizedUserFromUserTask(data), + meta: { + pagination: generatePaginationObject(count, offset, limit), + }, + }); + } + + @AsyncHandler() + async monthlyLeaderboard(req: Request, res: Response) { + const today = new Date(); + const dd = String(today.getDate()).padStart(2, '0'); + const mm = String(today.getMonth() + 1).padStart(2, '0'); // January is 0! + const yyyy = today.getFullYear(); + + const start_date = '01' + '-' + mm + '-' + yyyy; + + const [data, count] = await Repositories.task.findAndCount({ + where: { endDate: MoreThan(start_date) }, + }); + // filter the task ids for the month + const valid_task_id = data.map((result) => result.id); + + // find all the users that have max point for the valid_task_id + const res3 = await Repositories.userTask + .createQueryBuilder('ut') + .select('ut.userId') + .addSelect('SUM(ut.assignedPoints)', 'points') + .innerJoin('ut.user', 'usr') + .where('ut.taskId IN(:...task_ids)', { task_ids: valid_task_id }) + .groupBy('ut.userId') + .orderBy('points', 'DESC') + .limit(5) + .getRawMany(); + + const valid_users = res3.map((result) => result.ut_userId); + + const [data1, count1] = await Repositories.user.findAndCount({ + where: { id: In(valid_users) }, + }); + + // making the map of user_id and user credentials + const userIdMap = new Map(); + for (const i in data1) { + if (true) { + const id = data1[i].id; + if (!userIdMap.has(id)) { + userIdMap.set(id, { + name: data1[i].name, + username: data1[i].username, + photo: data1[i].photo, + }); + } + } + } + + // Making the array of monthly winners + const WinnerOfMonth = []; + for (const i in res3) { + if (true) { + const id = res3[i].ut_userId; + const obj = userIdMap.get(id); + obj.totalPoints = res3[i].points; + WinnerOfMonth.push(obj); + } + } + + res.json({ data: WinnerOfMonth, month: mm, year: yyyy }); + } } export default new LeaderboardController(); diff --git a/backend/routes/api/leaderboard/index.ts b/backend/routes/api/leaderboard/index.ts index 7a4ec51..a10a6c2 100644 --- a/backend/routes/api/leaderboard/index.ts +++ b/backend/routes/api/leaderboard/index.ts @@ -2,7 +2,8 @@ import { Router } from 'express'; import controller from './controller'; const router = Router(); - +router.get('/monthly', controller.monthlyLeaderboard); +router.get('/:id', controller.filterLeaderboard); router.get('/', controller.handleLeaderboard); export default router; diff --git a/backend/routes/api/user-task/controller.ts b/backend/routes/api/user-task/controller.ts index b9c9b3b..6ae6331 100644 --- a/backend/routes/api/user-task/controller.ts +++ b/backend/routes/api/user-task/controller.ts @@ -2,7 +2,7 @@ import { Request, Response } from 'express'; import Repositories from '../../../repositories/index'; import AsyncHandler from '../../../decorators/async-handler'; import { generatePaginationObject } from '../../../utils/pagination'; -import { In } from 'typeorm'; +import { In, Not } from 'typeorm'; class TaskController { @AsyncHandler() @@ -12,6 +12,41 @@ class TaskController { res.json({ data: userTask }); } + @AsyncHandler() + async handleBulkCreate(req: Request, res: Response) { + const { taskId } = req.body; + const users = await Repositories.user.find({ + where: { role: Not('admin') }, + }); // where role is not admin + + const usersWithSameTask = await Repositories.userTask.find({ + where: { taskId }, + }); + + const idsToRemove = usersWithSameTask.map((userTask) => userTask.userId); + const userIds = users.map((user) => user.id); + + for (const i in idsToRemove) { + if (true) { + const index = userIds.indexOf(idsToRemove[i]); + if (index !== -1) { + userIds.splice(index, 1); + } + } + } + + const builkInsert = userIds.map((id) => { + return { userId: id, taskId }; + }); + try { + const userTasks = await Repositories.userTask.save(builkInsert); + } catch (err) { + console.error(err); + } + + res.send({ msg: 'Successfully assigned the tasks to all users' }); + } + @AsyncHandler() async handleDelete(req: Request, res: Response) { await Repositories.userTask.delete({ diff --git a/backend/routes/api/user-task/index.ts b/backend/routes/api/user-task/index.ts index 241601d..3504391 100644 --- a/backend/routes/api/user-task/index.ts +++ b/backend/routes/api/user-task/index.ts @@ -6,6 +6,7 @@ import validator from './validator'; const router = Router(); router.post('/', validator.POST, controller.handleCreate); +router.post('/all', controller.handleBulkCreate); router.get('/', validator.GET, controller.handleGetTasks); router.delete('/', validator.DELETE, controller.handleDelete); diff --git a/backend/utils/sanitizer.ts b/backend/utils/sanitizer.ts index e0daacc..4ef11ec 100644 --- a/backend/utils/sanitizer.ts +++ b/backend/utils/sanitizer.ts @@ -1,4 +1,4 @@ -import { User } from 'entity'; +import { User, UserTask } from 'entity'; import { use } from 'passport'; export const generateSanitizeduser = (data: User[]) => { @@ -10,3 +10,12 @@ export const generateSanitizeduser = (data: User[]) => { })); return newData; }; + +export const generateSanitizedUserFromUserTask = (data: UserTask[]) => { + const newData = data.map((currentUser) => { + const { name, photo, username } = currentUser.user; + const totalPoints = currentUser.assignedPoints; + return { name, photo, username, totalPoints }; + }); + return newData; +}; diff --git a/frontend/components/LeaderBoard/MonthlyLeaderboard.tsx b/frontend/components/LeaderBoard/MonthlyLeaderboard.tsx new file mode 100644 index 0000000..ab5ade1 --- /dev/null +++ b/frontend/components/LeaderBoard/MonthlyLeaderboard.tsx @@ -0,0 +1,61 @@ +import React from 'react'; +import { Leaderboard } from '../../types/leaderboard'; +import api from '../../services/api'; +import LeaderboardRow from './LeaderboardRow'; + +export const LeaderBoard = (props) => { + const [loading, setLoading] = React.useState(true); + const [leaderboard, setLeaderboard] = React.useState([]); + const [month, setMonth] = React.useState(''); + const [year, setYear] = React.useState(''); + const m = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'July', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; + const { url } = props; + + const fetchLeaderboard = async () => { + setLoading(true); + const response = await api.get(url); + setLeaderboard(response.data.data); + setMonth(m[Number(response.data.month)]); + setYear(response.data.year); + setLoading(false); + return response; + }; + + React.useEffect(() => { + (async () => { + const leaderboardData = await fetchLeaderboard(); + })(); + }, []); + + return ( +
+
+
+ Monthly Leaderboard : {month} - {year} +
+ {loading ? ( +
Loading...
+ ) : ( +
+ + + + + + + + + + {leaderboard.map((row, i) => ( + + ))} + +
RANKNAMESTAR
+
+ )} +
+
+ ); +}; + +export default LeaderBoard; diff --git a/frontend/components/LeaderBoard/index.tsx b/frontend/components/LeaderBoard/index.tsx index ee09a4a..431634b 100644 --- a/frontend/components/LeaderBoard/index.tsx +++ b/frontend/components/LeaderBoard/index.tsx @@ -5,21 +5,23 @@ import api from '../../services/api'; import LeaderboardRow from './LeaderboardRow'; import PaginationPills from '../common/Pagination'; -export const LeaderBoard = () => { +export const LeaderBoard = (props) => { const [loading, setLoading] = React.useState(true); const [leaderboard, setLeaderboard] = React.useState([]); const [pagination, setPagination] = React.useState(null); const [activePage, setActivePage] = React.useState(1); + const { task_id, url } = props; const fetchLeaderboard = async () => { setLoading(true); const limit = 10; - const response = await api.get('leaderboard', { + const response = await api.get(url, { params: { offset: (activePage - 1) * limit, }, }); + setLeaderboard(response.data.data); setPagination(response.data.meta.pagination); @@ -34,8 +36,6 @@ export const LeaderBoard = () => { React.useEffect(() => { (async () => { const leaderboardData = await fetchLeaderboard(); - // setLeaderboard(leaderboardData.data); - // setPagination(leaderboardData.meta.pagination); })(); }, [activePage]); @@ -57,7 +57,7 @@ export const LeaderBoard = () => { {leaderboard.map((row, i) => ( - + ))} diff --git a/frontend/components/TaskCard.tsx b/frontend/components/TaskCard.tsx index bb4ffc4..906d87d 100644 --- a/frontend/components/TaskCard.tsx +++ b/frontend/components/TaskCard.tsx @@ -34,7 +34,11 @@ export const TaskCard: React.FC = ({ task }) => { src="https://cb-thumbnails.s3.ap-south-1.amazonaws.com/wakanda-star.svg" style={{ height: '30px' }} /> -
{task.points}
+
+ {status === 'draft' + ? task.points + : `${task.userTask[0].assignedPoints}/${task.points}`} +
diff --git a/frontend/components/admin/AdminSubmissionModal.tsx b/frontend/components/admin/AdminSubmissionModal.tsx index 9bcfbc7..aecf35f 100644 --- a/frontend/components/admin/AdminSubmissionModal.tsx +++ b/frontend/components/admin/AdminSubmissionModal.tsx @@ -6,11 +6,22 @@ import Button from '../common/Button'; export const SubmissionModal: React.FC = (props) => { const { id, task, submission, status } = props; + const [points, setPoints] = React.useState(0); + + function buttonStatus() { + if (status === 'review' && points <= task.points) { + return false; + } + return true; + } async function handleSubmission(value) { + if (value === 'rejected') { + setPoints(0); + } await client.post(`submission/${id}/status`, { status: value, - points: (task as any).points, + points, }); if (props.onAfterAdd) { @@ -22,17 +33,36 @@ export const SubmissionModal: React.FC = (props) => { +
+
+
+ {/* */} + setPoints(Number(e.target.value))} + > + {points > task.points ? `Max score for the task is ${task.points}` : ''} +
+
+
+
+ +
+ +
{userTasks.map((userTask, i) => ( diff --git a/frontend/pages/admin/task-view-pages/leaderboard.tsx b/frontend/pages/admin/task-view-pages/leaderboard.tsx new file mode 100644 index 0000000..52e3c3a --- /dev/null +++ b/frontend/pages/admin/task-view-pages/leaderboard.tsx @@ -0,0 +1,13 @@ +import React from 'react'; +import { useParams } from 'react-router-dom'; +import { LeaderBoard } from '../../../components/LeaderBoard'; + +export default () => { + const { id } = useParams(); + + return ( +
+ +
+ ); +}; diff --git a/frontend/pages/admin/task-view.tsx b/frontend/pages/admin/task-view.tsx index f0a0cf8..cfd8cc9 100644 --- a/frontend/pages/admin/task-view.tsx +++ b/frontend/pages/admin/task-view.tsx @@ -2,6 +2,7 @@ import React from 'react'; import EditTask from './task-view-pages/edit-tasks'; import Submissions from './task-view-pages/submissions'; import AssignedUsers from './task-view-pages/assigned-users'; +import Leaderboard from './task-view-pages/leaderboard'; import TabNav from '../../components/common/tab-nav'; export default () => { @@ -16,6 +17,7 @@ export default () => { { title: 'Edit', component: () => }, { title: 'Assigned', component: () => }, { title: 'Submissions', component: () => }, + { title: 'Leaderboard', component: () => }, ]} />
diff --git a/frontend/pages/dashboard.tsx b/frontend/pages/dashboard.tsx index fef762f..a128846 100644 --- a/frontend/pages/dashboard.tsx +++ b/frontend/pages/dashboard.tsx @@ -7,6 +7,7 @@ import { TaskCard } from '../components/TaskCard'; import { UserStats } from '../components/UserStats'; import { LeaderBoard } from '../components/LeaderBoard'; import InactiveTasks from '../components/InactiveTasks'; +import MonthlyLeaderboard from '../components/LeaderBoard/MonthlyLeaderboard'; const ArchivedTasksAccordian = (props) => { if (props.showContent) return
{props.children}
; @@ -60,7 +61,10 @@ const CAPortal: React.FC = () => {
- +
+ +
+