Skip to content
This repository has been archived by the owner on Jan 2, 2022. It is now read-only.

Commit

Permalink
feat: schedule section
Browse files Browse the repository at this point in the history
WDY-369
  • Loading branch information
jcmnunes committed Jul 1, 2020
1 parent 8de6513 commit d4f413c
Show file tree
Hide file tree
Showing 32 changed files with 807 additions and 165 deletions.
22 changes: 22 additions & 0 deletions backend/src/controllers/schedule/getSchedule.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Response } from 'express';
import { AuthRequest } from '../types';
import { ScheduleModel } from '../../models/Schedule';

interface Request extends AuthRequest {}

/**
* Gets the user's schedule
*
* endpoint ➜ GET /api/schedule
*/
export const getSchedule = async (req: Request, res: Response) => {
const schedule = await ScheduleModel.findOne({
owner: req.userId,
}).populate('tasks.scope');

if (!schedule) {
return res.status(404).json({ error: 'Schedule not found' });
}

res.json(schedule);
};
1 change: 1 addition & 0 deletions backend/src/controllers/schedule/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { getSchedule } from './getSchedule';
29 changes: 23 additions & 6 deletions backend/src/controllers/tasks/createTask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { DayModel } from '../../models/Day';
import { TaskModel } from '../../models/Task';
import { AuthRequest } from '../types';
import { Response } from 'express';
import { ScheduleModel } from '../../models/Schedule';

interface Body {
dayId: string;
Expand Down Expand Up @@ -66,20 +67,36 @@ export const createTask = async (req: Request, res: Response) => {
belongsTo: userId,
});

if (!day) return res.status(404).json({ error: 'Day not found' });
const schedule = await ScheduleModel.findOne({
owner: req.userId,
});

const section = day.sections.id(sectionId);
if (!section) return res.status(404).json({ error: 'Section not found' });
if (!day) return res.status(404).json({ error: 'Day not found' });
if (!schedule) {
return res.status(404).json({ error: 'Schedule not found' });
}

const task = new TaskModel(newTask);
section.tasks.push(task);

await day.save();
if (sectionId === 'schedule') {
schedule.tasks.push(task);
await schedule.save();
} else {
const section = day.sections.id(sectionId);
if (!section) return res.status(404).json({ error: 'Section not found' });

section.tasks.push(task);
await day.save();
}

const savedDay = await DayModel.findOne({
_id: dayId,
belongsTo: userId,
}).populate('sections.tasks.scope');

res.json(savedDay);
const savedSchedule = await ScheduleModel.findOne({
owner: userId,
}).populate('tasks.scope');

res.json({ day: savedDay, schedule: savedSchedule });
};
19 changes: 19 additions & 0 deletions backend/src/controllers/tasks/deleteTask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import Joi from 'joi';
import { Response } from 'express';
import { DayModel } from '../../models/Day';
import { AuthRequest } from '../types';
import { ScheduleModel } from '../../models/Schedule';

type Params = {
id: string;
Expand Down Expand Up @@ -48,6 +49,24 @@ export const deleteTask = async (req: Request, res: Response) => {
});
if (!day) return res.status(404).json({ error: 'Day not found' });

if (sectionId === 'schedule') {
const schedule = await ScheduleModel.findOne({
owner: req.userId,
});

if (!schedule) {
return res.status(404).json({ error: 'Schedule not found' });
}

const task = schedule.tasks.id(taskId);
if (!task) return res.status(404).json({ error: 'Task not found' });

task.remove();
await schedule.save();

res.json(task);
}

const section = day.sections.id(sectionId);
if (!section) return res.status(404).json({ error: 'Section not found' });

Expand Down
118 changes: 95 additions & 23 deletions backend/src/controllers/tasks/moveTask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { AuthRequest } from '../types';
import { Task } from '../../models/Task';
import { Types } from 'mongoose';
import * as tasksService from '../../services/tasks.service';
import { ScheduleModel } from '../../models/Schedule';
import { Section } from '../../models/Section';

type Params = {
id: string;
Expand Down Expand Up @@ -61,33 +63,101 @@ export const moveTask = async (req: Request, res: Response) => {
userId,
} = req;

// If launching a task ➜ stop the currently active task (if any)
if (start) {
await tasksService.stopActiveTask({ userId });
}
// Move inside schedule
if (fromSectionId === 'schedule' && toSectionId === 'schedule') {
const schedule = await ScheduleModel.findOne({
owner: req.userId,
});
if (!schedule) {
return res.status(404).json({ error: 'Schedule not found' });
}

const day = await DayModel.findOne({
_id: dayId,
belongsTo: userId,
});
if (!day) return res.status(404).json({ error: 'Day not found' });
if (toIndex !== null) {
schedule.tasks = move(schedule.tasks, fromIndex, toIndex) as Types.DocumentArray<Task>;
}

const fromSection = day.sections.id(fromSectionId);
if (!fromSection) return res.status(404).json({ error: 'Source Section not found' });
await schedule.save();
return res.json({ message: '🥑' });
}

const toSection = day.sections.id(toSectionId);
if (!toSection) return res.status(404).json({ error: 'Destination Section not found' });
// Move without considering Schedule
if (fromSectionId !== 'schedule' && toSectionId !== 'schedule') {
const day = await DayModel.findOne({
_id: dayId,
belongsTo: userId,
});
if (!day) return res.status(404).json({ error: 'Day not found' });

const fromSection = day.sections.id(fromSectionId);
if (!fromSection) return res.status(404).json({ error: 'Source Section not found' });

const toSection = day.sections.id(toSectionId);
if (!toSection) return res.status(404).json({ error: 'Destination Section not found' });

const task = fromSection.tasks.id(taskId);
if (!task) return res.status(404).json({ error: 'No task found' });

if (fromSectionId === toSectionId) {
if (toIndex !== null) {
fromSection.tasks = move(fromSection.tasks, fromIndex, toIndex) as Types.DocumentArray<
Task
>;
}
} else {
// Moving a task to the plan resets the time to zero
if (toSection.isPlan) {
task.time = 0;
task.start = null;
task.completed = false;
}

// Launching a task
if (start) {
task.start = start;

tasksService.stopActiveTask({ userId });
}

fromSection.tasks = remove(fromSection.tasks, fromIndex) as Types.DocumentArray<Task>;

// If toIndex is not specified ➜ append the task
if (toIndex === null) {
toSection.tasks = [...toSection.tasks, task] as Types.DocumentArray<Task>;
} else {
toSection.tasks = insert(toSection.tasks, toIndex, task) as Types.DocumentArray<Task>;
}
}

const task = fromSection.tasks.id(taskId);
if (!task) return res.status(404).json({ error: 'No task found' });
await day.save();
res.json({ message: '🥑' });
}

if (fromSectionId === toSectionId) {
if (toIndex !== null) {
fromSection.tasks = move(fromSection.tasks, fromIndex, toIndex) as Types.DocumentArray<Task>;
if (fromSectionId === 'schedule' || toSectionId === 'schedule') {
const schedule = await ScheduleModel.findOne({
owner: req.userId,
});
if (!schedule) {
return res.status(404).json({ error: 'Schedule not found' });
}
} else {
// Moving a task to the plan resets the time to zero
if (toSection.isPlan) {

const day = await DayModel.findOne({
_id: dayId,
belongsTo: userId,
});
if (!day) return res.status(404).json({ error: 'Day not found' });

const fromSection = fromSectionId === 'schedule' ? schedule : day.sections.id(fromSectionId);
if (!fromSection) return res.status(404).json({ error: 'Source Section not found' });

const toSection = toSectionId === 'schedule' ? schedule : day.sections.id(toSectionId);
if (!toSection) return res.status(404).json({ error: 'Destination Section not found' });

const task =
fromSectionId === 'schedule' ? schedule.tasks.id(taskId) : fromSection.tasks.id(taskId);
if (!task) return res.status(404).json({ error: 'No task found' });

// Moving a task to the plan or schedule resets the time to zero
if ((toSection as Section).isPlan || toSectionId === 'schedule') {
task.time = 0;
task.start = null;
task.completed = false;
Expand All @@ -108,8 +178,10 @@ export const moveTask = async (req: Request, res: Response) => {
} else {
toSection.tasks = insert(toSection.tasks, toIndex, task) as Types.DocumentArray<Task>;
}

await day.save();
await schedule.save();
}

await day.save();
res.json({ message: '🥑' });
return res.json({ message: '🥑' });
};
33 changes: 26 additions & 7 deletions backend/src/controllers/tasks/updateTask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Task } from '../../models/Task';
import { AuthRequest } from '../types';
import { DayModel } from '../../models/Day';
import * as tasksService from '../../services/tasks.service';
import { ScheduleModel } from '../../models/Schedule';

type Params = {
id: string;
Expand Down Expand Up @@ -54,14 +55,32 @@ export const updateTask = async (req: Request, res: Response) => {
const day = await DayModel.findOne({ _id: dayId, belongsTo: userId });
if (!day) return res.status(404).json({ error: 'Day not found' });

const section = day.sections.id(sectionId);
if (!section) return res.status(404).json({ error: 'Section not found' });
if (sectionId === 'schedule') {
const schedule = await ScheduleModel.findOne({
owner: req.userId,
});

const task = section.tasks.id(taskId);
if (!task) return res.status(404).json({ error: 'Task not found' });
if (!schedule) {
return res.status(404).json({ error: 'Schedule not found' });
}

task.set(payload);
await day.save();
const task = schedule.tasks.id(taskId);
if (!task) return res.status(404).json({ error: 'Task not found' });

res.json(task);
task.set(payload);
await schedule.save();

res.json(task);
} else {
const section = day.sections.id(sectionId);
if (!section) return res.status(404).json({ error: 'Section not found' });

const task = section.tasks.id(taskId);
if (!task) return res.status(404).json({ error: 'Task not found' });

task.set(payload);
await day.save();

res.json(task);
}
};
2 changes: 2 additions & 0 deletions backend/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import days from './routes/days';
import tasks from './routes/tasks';
import scopes from './routes/scopes';
import report from './routes/report';
import schedule from './routes/schedule';

const mongooseOptions = {
useNewUrlParser: true,
Expand Down Expand Up @@ -68,6 +69,7 @@ app.use('/api/days', days);
app.use('/api/tasks', tasks);
app.use('/api/scopes', scopes);
app.use('/api/report', report);
app.use('/api/schedule', schedule);

if (!dev) {
app.use(express.static(process.env.STATIC_DIR!));
Expand Down
9 changes: 9 additions & 0 deletions backend/src/routes/schedule.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { getSchedule } from '../controllers/schedule';
import { catchErrors } from '../middlewares/catchErrors';
import requireLogin from '../middlewares/requireLogin';

const router = require('express').Router();

router.get('/', requireLogin, catchErrors(getSchedule));

export default router;
55 changes: 55 additions & 0 deletions frontend/src/features/day/AddToPlan/AddToPlan.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import React from 'react';
import { useParams } from 'react-router';
import { Button, IconButton, theme, Tooltip } from '@binarycapsule/ui-capsules';
import { TaskDto, useDay } from '../api/useDay';
import { useMoveTask } from '../api/useMoveTask';
import { useSchedule } from '../api/useSchedule';

const colors = [theme.neutral200, theme.neutral400, '#CFBCF2', '#653CAD'];

interface Props {
isButton?: boolean;
task: TaskDto;
}

export const AddToPlan: React.FC<Props> = ({ isButton, task }) => {
const { dayId } = useParams();
const { data: day } = useDay(dayId);
const [moveTask] = useMoveTask();
const { data: schedule } = useSchedule();

if (!schedule) return null;

const taskIndex = schedule.tasks.findIndex(({ id }) => id === task.id);

const moveToPlan = () => {
if (day) {
const toSectionId = day.sections.find(({ isPlan }) => isPlan)?.id;

if (!toSectionId) return;

moveTask({
taskId: task.id,
body: {
dayId,
fromIndex: taskIndex,
fromSectionId: 'schedule',
toSectionId,
toIndex: null,
},
});
}
};

return (
<Tooltip tooltip="Add task to Plan" delayShow={1000}>
{isButton ? (
<Button appearance="minimal" iconBefore="plus_c" onClick={moveToPlan}>
Add to Plan
</Button>
) : (
<IconButton colors={colors} icon="circle_add" onClick={moveToPlan} />
)}
</Tooltip>
);
};
Loading

0 comments on commit d4f413c

Please # to comment.