Skip to content

Commit

Permalink
[feature][0.0.17] Mouse tracking on shared projets
Browse files Browse the repository at this point in the history
+ users can see the mouse pointers of their collaborators in a shared project 
+ bug fixes
  • Loading branch information
Mhirii committed Aug 28, 2023
1 parent b7d5d10 commit fd02ba0
Show file tree
Hide file tree
Showing 12 changed files with 134 additions and 79 deletions.
4 changes: 2 additions & 2 deletions backend/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ import { GatewayModule } from './gateway/gateway.module';
@Module({
imports: [
MongooseModule.forRoot(
// 'mongodb+srv://Mhiri:[email protected]/task-manager?retryWrites=true&w=majority',
'mongodb://127.0.0.1:27017/task-manager',
'mongodb+srv://Mhiri:[email protected]/task-manager?retryWrites=true&w=majority',
// 'mongodb://127.0.0.1:27017/task-manager',
),
TasksModule,
ProjectsModule,
Expand Down
4 changes: 3 additions & 1 deletion backend/src/tasks/tasks.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,18 @@ import { TasksService } from './tasks.service';
import { Task, TaskSchema } from '../schemas/task.schema';
import { UserModule } from '../user/user.module';
import { Project, ProjectSchema } from 'src/schemas/project.schema';
import { UserService } from '../user/user.service';

@Module({
imports: [
MongooseModule.forFeature([
{ name: Project.name, schema: ProjectSchema },
{ name: Task.name, schema: TaskSchema },
]),
UserModule,
// UserModule,
],
controllers: [TasksController],
providers: [TasksService],
exports: [TasksService],
})
export class TasksModule {}
15 changes: 5 additions & 10 deletions backend/src/tasks/tasks.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { InjectModel } from '@nestjs/mongoose';
import { Task } from '../schemas/task.schema';
import { CreateTaskDto } from './dto/create-task.dto';
import { UpdateTaskDto } from './dto/updateTask.dto';
import { JwtService } from '@nestjs/jwt';
import { UserService } from '../user/user.service';
// import { JwtService } from '@nestjs/jwt';
// import { UserService } from '../user/user.service';
import { Project } from 'src/schemas/project.schema';

@Injectable()
Expand All @@ -15,13 +15,11 @@ export class TasksService {
private taskModel: Model<Task>,
@InjectModel(Project.name)
public projectModel: Model<Project>,
private userService: UserService,
) {}

async createTask(createTaskDto: CreateTaskDto): Promise<Task> {
const newTask = await new this.taskModel(createTaskDto);
// TODO: save the task id in user's array
const res = this.userService.addProgTaskToUser(newTask.owner, newTask._id);
// const res = this.userService.addProgTaskToUser(newTask.owner, newTask._id);
return newTask.save();
}

Expand All @@ -42,20 +40,17 @@ export class TasksService {
}

async editTask(taskID, updateTaskDto: UpdateTaskDto): Promise<Task> {
// TODO: if its a check operation then move from user array to another accordingly
return this.taskModel.findByIdAndUpdate(taskID, updateTaskDto, {
new: true,
});
}

async deleteTask(taskID): Promise<any> {
//return this.taskModel.findByIdAndRemove(taskID);
// TODO: remove from user's array
const task = await this.taskModel.findById(taskID);
if (!task) {
throw new NotFoundException(`task #${taskID} does not exist`);
}
const res = this.userService.removeProgTaskFromUser(task.owner, task._id);
// const res = this.userService.removeProgTaskFromUser(task.owner, task._id);
return this.taskModel.findByIdAndRemove(taskID);
}

Expand All @@ -65,7 +60,7 @@ export class TasksService {
if (!project) {
throw new NotFoundException(`project ${project_id} does not exits`);
}
const tasksList = project.tasks; // holds id of tasks [id1,id2,id3,...]
const tasksList = project.tasks;

const tasks = [];
for (const id of tasksList) {
Expand Down
44 changes: 43 additions & 1 deletion backend/src/user/user.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { Project } from '../schemas/project.schema';
import { ProjectsService } from '../projects/projects.service';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { CreateTaskDto } from '../tasks/dto/create-task.dto';

@Controller('user')
export class UserController {
Expand Down Expand Up @@ -67,14 +68,55 @@ export class UserController {
return this.userService.getTasksInProgress(username);
}

@Public()
@Post(':username/tasksInProgress')
async addProgTaskToUser(
@Param('username') username: string,
@Res() response,
@Body() createTaskDto: CreateTaskDto,
) {
try {
const newTask = await this.userService.addProgTaskToUser(
username,
createTaskDto,
);
return response.status(HttpStatus.CREATED).json({
message: 'Task has been created successfully',
newTask,
});
} catch (err) {
return response.status(HttpStatus.BAD_REQUEST).json({
statusCode: 400,
message: 'Error: Task not created!',
error: 'Bad Request',
});
}
}

@Public()
@Delete(':username/tasksInProgress/:taskId')
@HttpCode(204)
async deleteTasksInProgress(
@Param('username') username: string,
@Param('taskId') taskId: string,
@Res() response,
) {
return await this.userService.deleteTasksInProgress(username, taskId);
try {
const deletedTask = await this.userService.deleteTasksInProgress(
username,
taskId,
);
return response.status(HttpStatus.CREATED).json({
message: 'Task has been deleted successfully',
deletedTask,
});
} catch (err) {
return response.status(HttpStatus.BAD_REQUEST).json({
statusCode: 400,
message: 'Error: Task could not be deleted!',
error: 'Bad Request',
});
}
}

@Public()
Expand Down
8 changes: 7 additions & 1 deletion backend/src/user/user.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,18 @@ import { MongooseModule } from '@nestjs/mongoose';
import { User, UserSchema } from '../schemas/user.schema';
import { JwtModule } from '@nestjs/jwt';
import { ProjectsModule } from '../projects/projects.module';
import { TasksModule } from '../tasks/tasks.module';
import { Task, TaskSchema } from '../schemas/task.schema';

@Module({
imports: [
TasksModule,
ProjectsModule,
JwtModule.register({}),
MongooseModule.forFeature([{ name: User.name, schema: UserSchema }]),
MongooseModule.forFeature([
{ name: User.name, schema: UserSchema },
{ name: Task.name, schema: TaskSchema },
]),
],
controllers: [UserController],
providers: [UserService],
Expand Down
20 changes: 14 additions & 6 deletions backend/src/user/user.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,16 @@ import { Model } from 'mongoose';
// import { JwtService } from '@nestjs/jwt';
import { UpdateUserDto } from './dto/updateUser.dto';
import { ProjectsService } from '../projects/projects.service';
import { TasksService } from '../tasks/tasks.service';
import { Task } from '../schemas/task.schema';

@Injectable()
export class UserService {
constructor(
@InjectModel(User.name) private userModel: Model<User>,
// private readonly jwtService: JwtService,
@InjectModel(Task.name) private taskModel: Model<Task>,
private readonly projectService: ProjectsService,
private tasksService: TasksService,
) {}

async getUserById(id: string): Promise<User | null> {
Expand Down Expand Up @@ -57,17 +60,20 @@ export class UserService {
// }
// }

async addProgTaskToUser(username, newTaskId) {
return this.userModel.updateOne(
async addProgTaskToUser(username, createTaskDto) {
const newTask = await this.tasksService.createTask(createTaskDto);
const newTaskId = newTask._id.toString();
this.userModel.updateOne(
{ username: username },
{ $push: { tasksInProgress: newTaskId } },
);
return newTask;
}

async removeProgTaskFromUser(username, newTaskId) {
async removeProgTaskFromUser(username, taskId) {
return this.userModel.updateOne(
{ username: username },
{ $pull: { tasksInProgress: newTaskId } },
{ $pull: { tasksInProgress: taskId } },
);
}

Expand Down Expand Up @@ -119,11 +125,13 @@ export class UserService {
}

async deleteTasksInProgress(username: string, taskId: string) {
return this.userModel.findOneAndUpdate(
const deletedTask = await this.tasksService.deleteTask(taskId);
this.userModel.findOneAndUpdate(
{ username },
{ $pull: { tasksInProgress: taskId } },
{ new: true },
);
return deletedTask;
}

async getTasksDone(username: string) {
Expand Down
1 change: 1 addition & 0 deletions frontend/src/api/endPoints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export function allUsersUrl(){return baseUrl+`/user`}
export function usersId(userId: string){return baseUrl+`/user/${userId}`}
export function usersUsername(username: string){return baseUrl+`/user/username/${username}`}
export function usersTasksInProgress(username: string){return baseUrl+`/user/${username}/tasksInProgress`}
export function usersAddTasksInProgress(username: string, taskId:string){return baseUrl+`/user/${username}/tasksInProgress/${taskId}`}
export function usersDeleteTasksInProgress(username: string, taskId:string){return baseUrl+`/user/${username}/tasksInProgress/${taskId}`}
export function usersTasksDone(username: string){return baseUrl+`/user/${username}/tasksDone`}
export function usersDeleteTasksDone(username: string, taskId:string){return baseUrl+`/user/${username}/tasksDone/${taskId}`}
Expand Down
49 changes: 22 additions & 27 deletions frontend/src/components/Task/AddTask.tsx
Original file line number Diff line number Diff line change
@@ -1,71 +1,70 @@
import { Modal } from "../common/Modal.tsx";
import { useState } from "react";
import {Modal} from "../common/Modal.tsx";
import {useState} from "react";
import Button from "../common/Button.tsx";
import axios from "axios";
import { useDispatch, useSelector } from "react-redux";
import {useDispatch, useSelector} from "react-redux";
import PlusOutlined from "@ant-design/icons/PlusOutlined";
import {allTasksUrl} from "../../api/endPoints.ts";
import { usersTasksInProgress} from "../../api/endPoints.ts";

interface Props{
interface Props {
project_id?: string
}

export default function AddTask({project_id}:Props) {
export default function AddTask({project_id}: Props) {

const dispatch = useDispatch();

const username = useSelector((state:any) => state.auth.username);
const accessToken = useSelector((state:any) => state.auth.accessToken);
const TasksInProgress = useSelector((state:any) => state.user.tasksInProgress);
const username = useSelector((state: any) => state.auth.username);
const accessToken = useSelector((state: any) => state.auth.accessToken);



const [title, setTitle] = useState("");
const [desc, setDesc] = useState("");
const [due, setDue] = useState("");
const [isModalOpen, setModal] = useState(false);

const toggleModal = () => {
setModal((prevismodalopen) => !prevismodalopen);
};

const handleSubmit = (event: any) => {
event.preventDefault();
const creationDate = new Date().toISOString();
const updatedAt = new Date().toISOString();
const isDone = false;
const completedAt = null;
const config = {
headers: { Authorization: `Bearer ${accessToken}` },
headers: {Authorization: `Bearer ${accessToken}`},
};
// TasksInProgress.append(newTask)
console.log('tasks in prog:', TasksInProgress)
const data = (!project_id)?{
const data = (!project_id) ? {
title: title,
owner: username,
desc: desc,
due: due,
dateAdded: creationDate,
updatedAt:updatedAt,
updatedAt: updatedAt,
isDone: isDone,
completedAt: completedAt,
}:{
} : {
title: title,
owner: username,
desc: desc,
due: due,
dateAdded: creationDate,
updatedAt:updatedAt,
updatedAt: updatedAt,
isDone: isDone,
completedAt: completedAt,
project: project_id
}

axios
.post(
allTasksUrl(),
usersTasksInProgress(username),
data,
config
)
.then((response) => {
console.log(response)
dispatch({
type: "ADD_TASK_INPROGRESS",
payload: response.data.newTask,
Expand All @@ -74,13 +73,9 @@ export default function AddTask({project_id}:Props) {
type: "ADD_TASK",
payload: response.data.newTask,
});
// console.log(owner)
})
.catch(function (error) {
console.log(error);
});
};

// Modal
const modalHeader = (
<input
Expand Down Expand Up @@ -123,9 +118,9 @@ export default function AddTask({project_id}:Props) {
const modalFooter = (
<>
<div onClick={toggleModal}>
<Button label={"Cancel"} variant={"ghost"} type={"reset"} />
<Button label={"Cancel"} variant={"ghost"} type={"reset"}/>
</div>
<Button label={"Create"} variant={"confirm"} />
<Button label={"Create"} variant={"confirm"}/>
</>
);
return (
Expand Down
4 changes: 3 additions & 1 deletion frontend/src/components/projectPage/ProjectTasks.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import Task from "../../interfaces/TaskInterface.ts";
import {Droppable} from "react-beautiful-dnd";
import ProjectDropArea from "./ProjectDropArea.tsx";
import React from "react";

const ProjectDropArea = React.lazy(() => import('./ProjectDropArea.tsx'))

interface Props{
view: string;
Expand Down
Loading

1 comment on commit fd02ba0

@vercel
Copy link

@vercel vercel bot commented on fd02ba0 Aug 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deployment failed with the following error:

If `rewrites`, `redirects`, `headers`, `cleanUrls` or `trailingSlash` are used, then `routes` cannot be present.

Learn More: https://vercel.link/mix-routing-props

Please sign in to comment.