Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

resolved various bugs #11

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 88 additions & 1 deletion backend/routes/api/leaderboard/controller.ts
Original file line number Diff line number Diff line change
@@ -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()
Expand All @@ -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();
3 changes: 2 additions & 1 deletion backend/routes/api/leaderboard/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
37 changes: 36 additions & 1 deletion backend/routes/api/user-task/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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({
Expand Down
1 change: 1 addition & 0 deletions backend/routes/api/user-task/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
11 changes: 10 additions & 1 deletion backend/utils/sanitizer.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { User } from 'entity';
import { User, UserTask } from 'entity';
import { use } from 'passport';

export const generateSanitizeduser = (data: User[]) => {
Expand All @@ -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;
};
61 changes: 61 additions & 0 deletions frontend/components/LeaderBoard/MonthlyLeaderboard.tsx
Original file line number Diff line number Diff line change
@@ -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<Leaderboard[]>([]);
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 (
<div className="card br-10 p-0 bg-white">
<div className="p-30">
<div className="heading-6 bold mb-30">
Monthly Leaderboard : {month} - {year}
</div>
{loading ? (
<div>Loading...</div>
) : (
<div className="">
<table className="w-100">
<thead className="font-4 mb-30">
<tr className="med-grey">
<th className="pb-4 t-align-l">RANK</th>
<th className="pb-4 t-align-c">NAME</th>
<th className="pb-4">STAR</th>
</tr>
</thead>
<tbody>
{leaderboard.map((row, i) => (
<LeaderboardRow row={row} i={i + 1} key={i} />
))}
</tbody>
</table>
</div>
)}
</div>
</div>
);
};

export default LeaderBoard;
10 changes: 5 additions & 5 deletions frontend/components/LeaderBoard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<Leaderboard[]>([]);
const [pagination, setPagination] = React.useState<Pagination>(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);

Expand All @@ -34,8 +36,6 @@ export const LeaderBoard = () => {
React.useEffect(() => {
(async () => {
const leaderboardData = await fetchLeaderboard();
// setLeaderboard(leaderboardData.data);
// setPagination(leaderboardData.meta.pagination);
})();
}, [activePage]);

Expand All @@ -57,7 +57,7 @@ export const LeaderBoard = () => {
</thead>
<tbody>
{leaderboard.map((row, i) => (
<LeaderboardRow row={row} i={i + 1} key={i} />
<LeaderboardRow row={row} i={i + 1 + 10 * (pagination.currentPage - 1)} key={i} />
))}
</tbody>
</table>
Expand Down
6 changes: 5 additions & 1 deletion frontend/components/TaskCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,11 @@ export const TaskCard: React.FC<any> = ({ task }) => {
src="https://cb-thumbnails.s3.ap-south-1.amazonaws.com/wakanda-star.svg"
style={{ height: '30px' }}
/>
<div className="heading-5 wakanda-grey bold">{task.points}</div>
<div className="heading-5 wakanda-grey bold">
{status === 'draft'
? task.points
: `${task.userTask[0].assignedPoints}/${task.points}`}
</div>
</div>
</div>
</div>
Expand Down
36 changes: 33 additions & 3 deletions frontend/components/admin/AdminSubmissionModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,22 @@ import Button from '../common/Button';

export const SubmissionModal: React.FC<any> = (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) {
Expand All @@ -22,17 +33,36 @@ export const SubmissionModal: React.FC<any> = (props) => {
<Modal show={props.show} setShow={props.setShow}>
<SubmissionEditor submission={submission} disabled />

<div className="p-30">
<div className="row">
<div className="col">
{/* <label className="font-4">Describe what you did in the task</label> */}
<input
// style={"outline:none"}
min={'0'}
max={task.points}
disabled={status !== 'review'}
type="number"
placeholder="Assign the points"
className="input-number w-100 mt-10 bg-light-grey br-5 p-10"
onChange={(e) => setPoints(Number(e.target.value))}
></input>
{points > task.points ? `Max score for the task is ${task.points}` : ''}
</div>
</div>
</div>

<div className="row mt-5 px-5 py-4">
<div className="col d-flex justify-content-around">
<Button
disabled={status !== 'review'}
disabled={buttonStatus()}
className="button-primary button-primary--accepted"
action={() => handleSubmission('accepted')}
activeText="Saving"
text="Accept"
/>
<Button
disabled={status !== 'review'}
disabled={buttonStatus()}
className="button-primary button-primary--rejected"
action={() => handleSubmission('rejected')}
activeText="Submitting"
Expand Down
2 changes: 1 addition & 1 deletion frontend/components/common/Pagination.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export const Pagination = (props: { meta; onChange }) => {
key={number}
className={
number === currentPage
? 'pagination-number pagination-number--current'
? 'pagination-number pagination-number--current bg-blue'
: 'pagination-number'
}
onClick={() => handleOnClick(number)}
Expand Down
Loading