Commit d8ebe16e authored by Нелли Ибрагимова's avatar Нелли Ибрагимова

Merge branch 'development' of…

Merge branch 'development' of ssh://git.attractor-school.com:30022/apollo64/crm-team-one into task-27-fixing_bags_page_my_tasks
parents 291c66b9 d1b8f15f
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
"@types/cors": "^2.8.12", "@types/cors": "^2.8.12",
"@types/express": "^4.17.14", "@types/express": "^4.17.14",
"bcrypt": "^5.1.0", "bcrypt": "^5.1.0",
"class-transformer": "^0.5.1",
"class-validator": "^0.13.2", "class-validator": "^0.13.2",
"cors": "^2.8.5", "cors": "^2.8.5",
"express": "^4.18.2", "express": "^4.18.2",
...@@ -2491,6 +2492,11 @@ ...@@ -2491,6 +2492,11 @@
"node": ">=10" "node": ">=10"
} }
}, },
"node_modules/class-transformer": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz",
"integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw=="
},
"node_modules/class-validator": { "node_modules/class-validator": {
"version": "0.13.2", "version": "0.13.2",
"resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.13.2.tgz", "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.13.2.tgz",
...@@ -7724,6 +7730,11 @@ ...@@ -7724,6 +7730,11 @@
"resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
"integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==" "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="
}, },
"class-transformer": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz",
"integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw=="
},
"class-validator": { "class-validator": {
"version": "0.13.2", "version": "0.13.2",
"resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.13.2.tgz", "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.13.2.tgz",
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
"@types/cors": "^2.8.12", "@types/cors": "^2.8.12",
"@types/express": "^4.17.14", "@types/express": "^4.17.14",
"bcrypt": "^5.1.0", "bcrypt": "^5.1.0",
"class-transformer": "^0.5.1",
"class-validator": "^0.13.2", "class-validator": "^0.13.2",
"cors": "^2.8.5", "cors": "^2.8.5",
"express": "^4.18.2", "express": "^4.18.2",
......
...@@ -12,6 +12,7 @@ import { ...@@ -12,6 +12,7 @@ import {
import {Project} from './Project'; import {Project} from './Project';
type taskFinishType = "open" | "done" |"failed"; type taskFinishType = "open" | "done" |"failed";
type priorityType = "A" | "B" |"C";
interface ITask{ interface ITask{
id: string; id: string;
...@@ -21,6 +22,7 @@ import { ...@@ -21,6 +22,7 @@ import {
dateTimeStart:Date| null; dateTimeStart:Date| null;
dateTimeDue:Date| null; dateTimeDue:Date| null;
accomplish: taskFinishType; accomplish: taskFinishType;
priority: priorityType;
author: User; author: User;
project:Project|null; project:Project|null;
executors:User[] executors:User[]
...@@ -40,6 +42,7 @@ import { ...@@ -40,6 +42,7 @@ import {
dateTimeStart!: Date | null; dateTimeStart!: Date | null;
@Column({ name: 'dateTimeDue', type: Date,nullable: true }) @Column({ name: 'dateTimeDue', type: Date,nullable: true })
dateTimeDue!: Date | null; dateTimeDue!: Date | null;
@Column({ @Column({
type: "enum", type: "enum",
enum: ["opened", "done" , "failed"], enum: ["opened", "done" , "failed"],
...@@ -47,6 +50,15 @@ import { ...@@ -47,6 +50,15 @@ import {
}) })
accomplish!: taskFinishType accomplish!: taskFinishType
@Column({
type: "enum",
enum: ["A", "B" , "C"],
default: "C"
})
priority!: priorityType
@ManyToOne(() => User, (user: { tasks: Task[]; }) => user.tasks,{eager : true}) @ManyToOne(() => User, (user: { tasks: Task[]; }) => user.tasks,{eager : true})
author!: User; author!: User;
...@@ -54,10 +66,10 @@ import { ...@@ -54,10 +66,10 @@ import {
@ManyToMany(() => User,{eager : true}) @ManyToMany(() => User,{eager : true})
@JoinTable() @JoinTable()
executors!: User[]; executors!: User[];
@ManyToOne(()=>Project,(project:{tasks: Task[]}) => project.tasks) @ManyToOne(()=>Project,(project:{tasks: Task[]}) => project.tasks)
project!: Project | null; project!: Project | null;
} }
...@@ -7,11 +7,11 @@ import { ...@@ -7,11 +7,11 @@ import {
BaseEntity, BaseEntity,
ManyToMany, ManyToMany,
OneToMany, OneToMany,
JoinTable JoinTable,
} from 'typeorm'; } from 'typeorm';
import {IsEmail import {IsEmail
} from "class-validator"; } from "class-validator";
import { Exclude, instanceToPlain } from "class-transformer";
import bcrypt from 'bcrypt'; import bcrypt from 'bcrypt';
import {nanoid} from 'nanoid'; import {nanoid} from 'nanoid';
import {Task} from './Task'; import {Task} from './Task';
...@@ -20,17 +20,17 @@ import {Project} from './Project'; ...@@ -20,17 +20,17 @@ import {Project} from './Project';
const SALT_WORK_FACTOR= 10; const SALT_WORK_FACTOR= 10;
type userRoleType = "worker" | "director"; export enum UserRole {USER="user" ,DIRECTOR= "director",SUPERUSER="superuser"}
interface IUser { interface IUser {
id:string; id:string;
role: UserRole;
name: string; name: string;
surname: string; surname: string;
email: string; email: string;
displayName: string; displayName: string;
password:string; password:string;
token: string; token: string;
role: userRoleType;
createdAt: Date; createdAt: Date;
createdTasks:Task[]; createdTasks:Task[];
workerInProjects:Project[]; workerInProjects:Project[];
...@@ -41,39 +41,40 @@ interface IUser { ...@@ -41,39 +41,40 @@ interface IUser {
@Entity({ name: 'User' }) @Entity({ name: 'User' })
export class User extends BaseEntity implements IUser { export class User extends BaseEntity implements IUser {
@PrimaryGeneratedColumn('uuid') @PrimaryGeneratedColumn("uuid")
id!: string id!: string;
@Column({ name: 'name', type: 'varchar', length:20,nullable: false }) @Column({ name: 'name', type: 'varchar', length:20,nullable: false })
name!: string name!: string;
@Column({ name: 'surname', type: 'varchar', length:30,nullable: false }) @Column({ name: 'surname', type: 'varchar', length:30,nullable: false })
surname!: string surname!: string;
@Column({ name: 'displayName', type: 'varchar', length:30,nullable: false }) @Column({ name: 'displayName', type: 'varchar', length:30,nullable: false })
displayName!: string displayName!: string;
@Column({ name: 'email', type: 'varchar',length:20, unique: true, nullable: false }) @Column({ name: 'email', type: 'varchar',length:20, unique: true, nullable: false })
@IsEmail() @IsEmail()
email!: string email!: string;
@Column({ name: 'phone', type: 'varchar',length:10, unique: true, nullable: true}) @Column({ name: 'phone', type: 'varchar',length:10, unique: true, nullable: true})
phone?: string phone?: string;
@Column({ name: 'token', type: 'varchar',length:100, unique: true, nullable: false }) @Column({ name: 'token', type: 'varchar',length:100, unique: true, nullable: false })
token!: string token!: string;
@CreateDateColumn({ name: 'created_at', type: Date, default: new Date() }) @CreateDateColumn({ name: 'created_at', type: Date, default: new Date() })
createdAt!: Date; createdAt!: Date;
@Column({ @Column({
type: "enum", type: "enum",
enum: ["worker", "director"], enum: UserRole,
default: "worker" default: UserRole.USER
}) })
role!: userRoleType role!: UserRole
@Column({ type: 'varchar', nullable: false, select:false }) @Column({ type: 'varchar', nullable: false, select:true })
password!: string @Exclude({ toPlainOnly: true })
password!: string;
@OneToMany(() => Task, (task: { user: User }) => task.user) @OneToMany(() => Task, (task: { user: User }) => task.user)
...@@ -106,20 +107,16 @@ export class User extends BaseEntity implements IUser { ...@@ -106,20 +107,16 @@ export class User extends BaseEntity implements IUser {
public async checkPassword( public async checkPassword(
candidatePassword: string, candidatePassword: string,
):Promise<boolean> { ):Promise<boolean> {
console.log("Checking password", candidatePassword,'this.password', this.password)
return await bcrypt.compare(candidatePassword, this.password); return await bcrypt.compare(candidatePassword, this.password);
} }
toJSON() {
return instanceToPlain(this);
} }
}
......
...@@ -17,7 +17,7 @@ export default router; ...@@ -17,7 +17,7 @@ export default router;
router.post('/', async(req:Request, res:Response):Promise<Response>=>{ router.post('/', async(req:Request, res:Response):Promise<Response>=>{
const token = req.get('Authorization'); const token = req.get('Authorization');
const newTask = new Task(); const newTask = new Task();
const {title,description,project,executors,dateTimeDue,dateTimeStart} = req.body; const {title,description,project,executors,dateTimeDue,dateTimeStart,accomplish,priority} = req.body;
const user = await dataSource const user = await dataSource
.createQueryBuilder() .createQueryBuilder()
.select("user") .select("user")
...@@ -32,11 +32,13 @@ router.post('/', async(req:Request, res:Response):Promise<Response>=>{ ...@@ -32,11 +32,13 @@ router.post('/', async(req:Request, res:Response):Promise<Response>=>{
newTask.dateTimeDue = dateTimeDue; newTask.dateTimeDue = dateTimeDue;
newTask.dateTimeStart = dateTimeStart; newTask.dateTimeStart = dateTimeStart;
newTask.author= user; newTask.author= user;
newTask.accomplish = accomplish;
newTask.priority = priority;
await newTask.save(); await newTask.save();
return res.send({newTask}) return res.send({newTask})
}) })
router.get('/userId/:userId', async (req: Request, res: Response)=>{ router.get('/userId/:userId', async (req: Request, res: Response):Promise<Response>=>{
const userId = req.params.userId; const userId = req.params.userId;
const tasks = await dataSource const tasks = await dataSource
.getRepository(Task) .getRepository(Task)
...@@ -47,8 +49,7 @@ router.get('/userId/:userId', async (req: Request, res: Response)=>{ ...@@ -47,8 +49,7 @@ router.get('/userId/:userId', async (req: Request, res: Response)=>{
return res.send({tasks}) return res.send({tasks})
}) })
router.get('/my', async (req: Request, res: Response):Promise<Response>=>{
router.get('/my', async (req: Request, res: Response)=>{
const token = req.get('Authorization'); const token = req.get('Authorization');
const user = await dataSource const user = await dataSource
.createQueryBuilder() .createQueryBuilder()
...@@ -64,4 +65,56 @@ router.get('/my', async (req: Request, res: Response)=>{ ...@@ -64,4 +65,56 @@ router.get('/my', async (req: Request, res: Response)=>{
.where('user.id = :userId', {userId :user.id}) .where('user.id = :userId', {userId :user.id})
.getMany() .getMany()
return res.send({tasks}) return res.send({tasks})
}) })
\ No newline at end of file
router.delete('/:taskId',async (req: Request, res: Response):Promise<Response>=>{
// const token = req.get('Authorization');
// const user = await dataSource
// .createQueryBuilder()
// .select("user")
// .from(User, "user")
// .where("user.token = :token", { token: token })
// .getOne()
// if(!user) return res.status(404).send({Message:'user not found'})
const taskId = req.params.taskId;
await myDataSource
.createQueryBuilder()
.delete()
.from(Task)
.where("id = :id", { id: taskId })
.execute()
return res.send({message: 'Task deleted successfully'})
})
router.put('/',async(req:Request, res:Response)=> {
const token = req.get('Authorization');
const user = await dataSource
.createQueryBuilder()
.select("user")
.from(User, "user")
.where("user.token = :token", { token: token })
.getOne()
if (!user) return res.status(404).send({Message:'user not found'})
const {id,title,description,project,executors,dateTimeDue,dateTimeStart,accomplish,priority} = req.body;
await dataSource
.createQueryBuilder()
.update(Task)
.set({
title: title,
description: description,
project: project,
executors: executors,
dateTimeDue: dateTimeDue,
dateTimeStart: dateTimeStart,
author:user,
accomplish: accomplish,
priority: priority
})
.where("id = :id", { id: id })
.execute()
res.send({message:'update task successfully'})
// res.send({task})
})
...@@ -17,7 +17,7 @@ return res.send({users}) ...@@ -17,7 +17,7 @@ return res.send({users})
router.post('/', async (req : Request, res : Response):Promise<object> => { router.post('/', async (req : Request, res : Response):Promise<object> => {
const {name,surname,password,email} = req.body; const {name,surname,password,email, role} = req.body;
const displayName = surname+' '+name[0]+'.' const displayName = surname+' '+name[0]+'.'
const user = new User(); const user = new User();
user.name = name; user.name = name;
...@@ -25,6 +25,7 @@ router.post('/', async (req : Request, res : Response):Promise<object> => { ...@@ -25,6 +25,7 @@ router.post('/', async (req : Request, res : Response):Promise<object> => {
user.password = password; user.password = password;
user.displayName= displayName; user.displayName= displayName;
user.email = email; user.email = email;
user.role = role;
user.generateToken() user.generateToken()
await user.save(); await user.save();
const userToFront:User|null = await dataSource.manager.findOneBy(User, { const userToFront:User|null = await dataSource.manager.findOneBy(User, {
...@@ -41,9 +42,9 @@ router.post('/sessions/', async (req : Request, res : Response):Promise<object> ...@@ -41,9 +42,9 @@ router.post('/sessions/', async (req : Request, res : Response):Promise<object>
.select("user") .select("user")
.from(User, "user") .from(User, "user")
.where("user.email = :email", { email: email }) .where("user.email = :email", { email: email })
.addSelect('password')
.getOne() .getOne()
if(!user) return res.status(404).send({Message:'user not found'}) if(!user) return res.status(404).send({Message:'user not found'})
const isMatch:boolean = await user.checkPassword(password); const isMatch:boolean = await user.checkPassword(password);
if (!isMatch) return res.status(400).send({ if (!isMatch) return res.status(400).send({
error: "Wrong Password" error: "Wrong Password"
...@@ -67,7 +68,6 @@ router.delete('/sessions', async(req: Request, res: Response):Promise<void | obj ...@@ -67,7 +68,6 @@ router.delete('/sessions', async(req: Request, res: Response):Promise<void | obj
token: token token: token
}) })
if(!user) return res.send({successMsg}); if(!user) return res.send({successMsg});
console.log('token: ' + token)
user.token = nanoid(); user.token = nanoid();
await user.save(); await user.save();
......
import { Grid } from "@mui/material";
const CalendarRow = ({children}) => {
return <>
<Grid
container
align='center'
sx={{borderBottom: '1px solid black', borderRight: '1px solid black', borderLeft: '1px solid black'}}
>
{children}
</Grid>
</>
};
export default CalendarRow;
import { Grid } from "@mui/material";
const CalendarSmallCell = ({children, xs}) => {
return <>
<Grid align='center' item xs={xs} sx={{borderRight: '1px solid black'}}>
{children}
</Grid>
</>
};
export default CalendarSmallCell;
\ No newline at end of file
import { Grid } from "@mui/material";
const CalendarStandartCell = ({children, xs, onClick}) => {
return <>
<Grid
item xs={xs}
sx={{borderRight: '1px solid black'}}
onClick={onClick}>
{children}
</Grid>
</>
};
export default CalendarStandartCell;
\ No newline at end of file
import { Grid, TextField } from "@mui/material";
import React, { useEffect, useState } from "react";
const CalendarTask = ({year, month, tasks, day, hours, setCurrentTask, onChange, hourFormat}) => {
const getTaskInDayCell = (tasks, day, hours) => {
const hour = parseInt(hours.split(':')[0])
let hourDiffEnd
let hourDiffStart
if (hourFormat) {
hourDiffEnd = hour + 1
} else {
hourDiffEnd = hour + 2
}
if (hourFormat) {
hourDiffStart = hour - 1
} else {
hourDiffStart = hour - 2
}
const tasksCell = tasks.filter(task=> {
if (year === task.infoForCell.startYear) {
if (month + 1 === task.infoForCell.startMonth) {
if (day.dayNumber === task.infoForCell.startDay) {
if (((task.infoForCell.endHour <= hour || task.infoForCell.startHour <= hour) && (task.infoForCell.endHour > hour))
|| (task.infoForCell.startHour >= hour && task.infoForCell.endHour < hourDiffEnd)
|| (task.infoForCell.endMinute <= 59 && task.infoForCell.endHour === hour)) {
return task
}
}
}
}
})
return tasksCell
}
const tasksCell = getTaskInDayCell(tasks, day, hours)
return (<>
{tasksCell.length ? tasksCell.map((task, i)=>
{
return (
<Grid key={task.id} sx={{backgroundColor: 'lightgreen'}}>
<TextField
id={task.title}
variant="standard"
value={task.title}
name='title'
onClick={(e)=>{e.stopPropagation(); setCurrentTask(task)}}
onChange={onChange}>
</TextField>
</Grid>)}
) : null }
</>)
};
export default CalendarTask;
\ No newline at end of file
import { Grid, TextField } from "@mui/material"; import { FormControlLabel, Switch } from "@mui/material";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import CalendarRow from "./CalendarRow/CalendarRow";
import CalendarSmallCell from "./CalendarSmallCell/CalendarSmallCell";
import CalendarStandartCell from "./CalendarStandartCell.js/CalendarStandartCell";
import CalendarTask from "./CalendarTask/CalendarTask";
const exampleTasks=[ function MonthCalendarBody({month, year, tasks, createTaskInCellHandler, onChangeCellTaskTitle, setCurrentTask, hourFormat, setHourFormat}) {
{
user:"first",
title:"задача1",
description:"описание задачи11111",
priority:"A",
author:"Ivan",
executor:"Arman",
dateTimeStart:"26.12.2022 20:00:00",
dateTimeDue:"27.10.2022 14:20:00",
id:1,
dateCreated:"26.10.2022"
}, {
user:"first",
title:"задача2",
description:"описание задачи11111",
priority:"A",
author:"Ivan",
executor:"Arman",
dateTimeStart:"1.12.2022 9:00:00",
dateTimeDue:"27.10.2022 15:20:00",
id:1,
dateCreated:"26.10.2022"
},{
user:"first",
title:"first",
description:"описание задачи11111",
priority:"A",
author:"Ivan",
executor:"Arman",
dateTimeStart:"5.11.2022 16:00:00",
dateTimeDue:"5.11.2022 17:00:00",
id:1,
dateCreated:"26.10.2022"
},{
user:"first",
title:"second",
description:"описание задачи11111",
priority:"A",
author:"Ivan",
executor:"Arman",
dateTimeStart:"5.11.2022 16:00:00",
dateTimeDue:"5.11.2022 17:00:00",
id:1,
dateCreated:"26.10.2022"
}
]
function MonthCalendarBody({month, year}) {
const [hoursInDay, setHoursInDay] = useState(['8:00', '10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00', '6:00']) const [hoursInDay, setHoursInDay] = useState(['8:00', '10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00'])
const [daysInMonth, setDaysInMonth] = useState([]) const [daysInMonth, setDaysInMonth] = useState([])
const [tasksForCell, setTasksForCell] = useState([]) const [cellSizes, setCellSizes] = useState({})
useEffect(()=>{
const cells = hoursInDay.length
const xs = 10.8/cells
setCellSizes(()=>{
return {smallCell: 0.6, standarCell: xs}
})
}, [])
useEffect(()=>{ useEffect(()=>{
setNewMonthDays(month, year) if (hourFormat) {
setNewTasksWithInfoForCell(exampleTasks, month, year) const arr = ['8:00', '9:00', '10:00', '11:00', '12:00', '13:00', '14:00', '15:00', '16:00', '17:00', '18:00', '19:00', '20:00','21:00','22:00']
}, [month, year]) const cells = arr.length
const xs = 10.8/cells
setCellSizes(()=>{
return {smallCell: 0.6, standarCell: xs}
})
setHoursInDay(()=>arr)
} else {
const arr = ['8:00', '10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00']
const cells = arr.length
const xs = 10.8/cells
setCellSizes(()=>{
return {smallCell: 0.6, standarCell: xs}
})
setHoursInDay(()=>arr)
}
}, [hourFormat])
useEffect(()=>{
setNewMonthDays()
}, [month])
const getDaysInMonth = () => { const getDaysInMonth = () => {
return new Date(year, month + 1, 0).getDate(); return new Date(year, month + 1, 0).getDate();
} }
const getDayOfWeekString = (day) => { const getDayOfWeekString = (day) => {
return ["ВС","ПН","ВТ","СР","ЧТ","ПТ","СБ"][day]; return ["ВС","ПН","ВТ","СР","ЧТ","ПТ","СБ"][day];
} }
const getDayOfWeekNumber = (month, year, day) => { const getDayOfWeekNumber = (day) => {
return new Date(year, month, day).getDay() return new Date(year, month, day).getDay()
} }
const setNewTasksWithInfoForCell = (tasks, month, year) => { const setNewMonthDays = () => {
const newArr = tasks.map((task)=>{
const dateStart = task.dateTimeStart.split(' ')[0]
const timeStart = task.dateTimeStart.split(' ')[1]
const timeEnd = task.dateTimeDue.split(' ')[1]
const dayStart = parseInt(dateStart.split('.')[0])
const dayOfWeekStartNumber = getDayOfWeekNumber(month, year, dayStart)
const dayOfWeekStartString = getDayOfWeekString(dayOfWeekStartNumber)
const monthStartNumber = parseInt(dateStart.split('.')[1])
const yearStartNumber = parseInt(dateStart.split('.')[2])
const timeStartHour = parseInt(timeStart.split(':')[0])
const timeEndHour = parseInt(timeEnd.split(':')[0])
return {...task,
startDay: dayStart,
startDayOfWeek: dayOfWeekStartString,
startHour: timeStartHour,
startMonth: monthStartNumber,
startYear: yearStartNumber,
endHour: timeEndHour,
}
})
setTasksForCell(newArr)
}
const createTaskInCellHandler = (month, year, dayOfWeek, dayNumber, dayHour) => {
const newTasks = [...tasksForCell]
const newTask = {
id: Date.now(),
user:"first",
title:"Новая",
description:"описание задачи11111",
priority:"A",
author:"Ivan",
executor:"Arman",
dateTimeStart:`${dayNumber}.${month+1}.${year} ${parseInt(dayHour.split(':')[0])}:00:00`,
dateTimeDue:`${dayNumber}.${month+1}.${year} ${parseInt(dayHour.split(':')[0]) + 1}:00:00`,
}
newTasks.push(newTask)
exampleTasks.push(newTask)
setNewTasksWithInfoForCell(newTasks, month, year)
}
const getTaskInDayCell = (tasks, day, hours, month, year) => {
const task = tasks.find(task=> {
if (year === task.startYear) {
if (month + 1 === task.startMonth) {
if (day.dayNumber === task.startDay && task.startDayOfWeek === day.dayOfWeek ) {
if ((task.endHour <= parseInt(hours.split(':')[0]) || task.startHour <= parseInt(hours.split(':')[0])) && (task.endHour >= parseInt(hours.split(':')[0]))) {
return task
}
}
}
}
})
return task
}
const setNewMonthDays = (month, year) => {
const newDaysInMonth = [] const newDaysInMonth = []
for (let i = 1; i <= getDaysInMonth(month, year); i++) { for (let i = 1; i <= getDaysInMonth(); i++) {
const dayOfWeekNumber = getDayOfWeekNumber(month, year, i) const dayOfWeekNumber = getDayOfWeekNumber(i)
newDaysInMonth.push({dayNumber: i, dayOfWeek: getDayOfWeekString(dayOfWeekNumber)}) newDaysInMonth.push({dayNumber: i, dayOfWeek: getDayOfWeekString(dayOfWeekNumber)})
} }
setDaysInMonth(newDaysInMonth) setDaysInMonth(prevState=>newDaysInMonth)
}
const onChangeCellTaskTitle = (e, task) => {
const value = e.target.value;
const name = e.target.name;
const { id } = task;
const newTasks = tasksForCell.map(task => {
if (task.id === id) {
return { ...task, [name]: value };
}
return task;
});
setTasksForCell(newTasks);
exampleTasks = [...newTasks]
} }
return ( return (
<> <>
<Grid <CalendarRow
container >
align='center' <CalendarSmallCell xs={1.2}>
sx={{borderBottom: '1px solid black', borderRight: '1px solid black', borderLeft: '1px solid black'}} <FormControlLabel
> control={<Switch color="primary" checked={hourFormat} onChange={()=>{setHourFormat(()=>!hourFormat)}}/>}
<Grid align='center' item xs={0.5} sx={{borderRight: '1px solid black'}}> label="1 час"
{' '} labelPlacement="end"
</Grid> />
<Grid align='center' item xs={0.5} sx={{borderRight: '1px solid black'}}> </CalendarSmallCell>
{' '}
</Grid>
{hoursInDay.map((hours, i)=>{ {hoursInDay.map((hours, i)=>{
return ( return (
<Grid key={i} item xs={1.2222} sx={{borderRight: '1px solid black'}}> <CalendarStandartCell key={i} xs={cellSizes.standarCell}>
{hours} {hours}
</Grid> </CalendarStandartCell>
) )
})} })}
</Grid> </CalendarRow>
{daysInMonth.map((day, i)=>{ {daysInMonth.map((day, i)=>{
return ( return (
<Grid <CalendarRow
key={i} key={i}
container
align='center'
sx={{borderBottom: '1px solid black', borderRight: '1px solid black', borderLeft: '1px solid black'}}
> >
<Grid align='center' item xs={0.5} sx={{borderRight: '1px solid black'}}> <CalendarSmallCell xs={cellSizes.smallCell}>{day.dayNumber}</CalendarSmallCell>
{day.dayNumber} <CalendarSmallCell xs={cellSizes.smallCell}>{day.dayOfWeek}</CalendarSmallCell>
</Grid>
<Grid align='center' item xs={0.5} sx={{borderRight: '1px solid black'}}>
{day.dayOfWeek}
</Grid>
{hoursInDay.map((hours, i)=>{ {hoursInDay.map((hours, i)=>{
const task = getTaskInDayCell(tasksForCell, day, hours, month, year)
return ( return (
<Grid <CalendarStandartCell
key={i} key={i}
item xs={1.2222} item xs={cellSizes.standarCell}
sx={{borderRight: '1px solid black'}} onClick={()=>{createTaskInCellHandler(day.dayNumber, hours)}}
onClick={()=>{createTaskInCellHandler(month, year, day.dayOfWeek, day.dayNumber, hours)}}> >
{ task ? <CalendarTask
<Grid key={i} sx={{backgroundColor: 'lightgreen'}}> setCurrentTask={setCurrentTask}
<TextField onChange={(e)=>{onChangeCellTaskTitle(e)}}
id={task.title} year={year}
variant="standard" month={month}
value={task.title} tasks={tasks}
name='title' day={day}
onChange={(e)=>{onChangeCellTaskTitle(e, task)}}></TextField> hours={hours}
</Grid> : null} hourFormat={hourFormat}
</Grid> />
</CalendarStandartCell>
) )
})} })}
</Grid> </CalendarRow>
) )
})} })}
</> </>
......
import { Container } from '@mui/material'; import { Container } from '@mui/material';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import MonthCalendarBody from '../../components/MonthCalendarBody/MonthCalendarBody'; import MonthCalendarBody from '../../components/MonthCalendarBody/MonthCalendarBody';
import MonthCalendarHeader from '../../components/MonthCalendarHeader/MonthCalendarHeader'; import MonthCalendarHeader from '../../components/MonthCalendarHeader/MonthCalendarHeader';
import { addTask, fetchTasks} from '../../store/actions/tasksActions';
function MonthCalendar() { function MonthCalendar() {
const dispatch = useDispatch();
const { tasks } = useSelector(state => state.tasks);
const [hourFormat, setHourFormat] = useState(false);
const [month, setMonth] = useState('') const [month, setMonth] = useState('')
const [year, setYear] = useState('') const [year, setYear] = useState('')
const [worker, setWorker] = useState(''); const [worker, setWorker] = useState('');
const [calendarType, setCalendarType] = useState('Месяц'); const [calendarType, setCalendarType] = useState('Месяц');
const [currentTask, setCurrentTask] = useState({})
useEffect(()=>{ useEffect(()=>{
setMonth(new Date().getMonth()) setMonth(new Date().getMonth())
setYear(new Date().getFullYear()) setYear(new Date().getFullYear())
},[]) dispatch(fetchTasks())
}, [dispatch])
const onChangeWorkerHandler = (event) => { const onChangeWorkerHandler = (event) => {
setWorker(event.target.value); setWorker(event.target.value);
}; };
...@@ -46,6 +54,40 @@ function MonthCalendar() { ...@@ -46,6 +54,40 @@ function MonthCalendar() {
}) })
} }
function dateToISOLikeButLocal(date) {
const offsetMs = date.getTimezoneOffset() * 60 * 1000;
const msLocal = date.getTime() - offsetMs;
const dateLocal = new Date(msLocal);
const iso = dateLocal.toISOString();
return iso;
}
const createTaskInCellHandler = (dayNumber, dayHour) => {
const hour = parseInt(dayHour.split(':')[0])
let hourDue
if (hourFormat) {
hourDue = hour + 0
} else {
hourDue = hour + 1
}
const newTask = {
title:"Задача",
description:"описание",
dateTimeStart: dateToISOLikeButLocal(new Date(year, month, dayNumber, hour, 0)),
dateTimeDue: dateToISOLikeButLocal(new Date(year, month, dayNumber, hourDue, 59)),
}
console.log(newTask)
dispatch(addTask(newTask))
setCurrentTask((newTask))
}
const onChangeCellTaskTitle = (e) => {
e.stopPropagation()
const value = e.target.value;
const name = e.target.name;
setCurrentTask({ ...currentTask, [name]: value })
}
return ( return (
<> <>
<Container> <Container>
...@@ -63,6 +105,12 @@ function MonthCalendar() { ...@@ -63,6 +105,12 @@ function MonthCalendar() {
<MonthCalendarBody <MonthCalendarBody
month={month} month={month}
year={year} year={year}
tasks={tasks}
createTaskInCellHandler={createTaskInCellHandler}
onChangeCellTaskTitle={onChangeCellTaskTitle}
setCurrentTask={setCurrentTask}
hourFormat={hourFormat}
setHourFormat={setHourFormat}
/> />
</Container> </Container>
</> </>
......
...@@ -5,6 +5,7 @@ import App from './App'; ...@@ -5,6 +5,7 @@ import App from './App';
import { configureStore } from '@reduxjs/toolkit'; import { configureStore } from '@reduxjs/toolkit';
import { Provider } from 'react-redux'; import { Provider } from 'react-redux';
import usersReducer from './store/reducers/usersReducer'; import usersReducer from './store/reducers/usersReducer';
import tasksReducer from './store/reducers/tasksReducer';
import axios from 'axios'; import axios from 'axios';
const localStorageMiddleware = ({getState}) => (next) => (action) => { const localStorageMiddleware = ({getState}) => (next) => (action) => {
...@@ -31,6 +32,7 @@ axios.interceptors.request.use(config=>{ ...@@ -31,6 +32,7 @@ axios.interceptors.request.use(config=>{
const store = configureStore({ const store = configureStore({
reducer: { reducer: {
users: usersReducer, users: usersReducer,
tasks: tasksReducer
}, },
preloadedState: loadFromLocalStorage(), preloadedState: loadFromLocalStorage(),
middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(localStorageMiddleware) middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(localStorageMiddleware)
......
export const FETCH_TASKS_REQUEST = "FETCH_TASKS_REQUEST";
export const FETCH_TASKS_SUCCESS = "FETCH_TASKS_SUCCESS";
export const FETCH_TASKS_FAILURE = "FETCH_TASKS_FAILURE";
export const ADD_NEW_TASK_REQUEST = "ADD_NEW_TASK_REQUEST";
export const ADD_NEW_TASK_SUCCESS = "ADD_NEW_TASK_SUCCESS";
export const ADD_NEW_TASK_FAILURE = "ADD_NEW_TASK_FAILURE";
\ No newline at end of file
import { ADD_NEW_TASK_FAILURE, ADD_NEW_TASK_REQUEST, ADD_NEW_TASK_SUCCESS, FETCH_TASKS_FAILURE, FETCH_TASKS_REQUEST, FETCH_TASKS_SUCCESS} from "../actionTypes/tasksTypes";
import axios from '../../axiosPlanner'
const fetchTasksRequest = () => {
return {type: FETCH_TASKS_REQUEST}
};
const fetchTasksSuccess = (tasks) => {
return {type: FETCH_TASKS_SUCCESS, tasks}
};
const fetchTasksFailure = (error) => {
return {type: FETCH_TASKS_FAILURE, error}
};
export const fetchTasks = () => {
return async (dispatch) => {
dispatch(fetchTasksRequest());
try {
const response = await axios.get("/tasks");
dispatch(fetchTasksSuccess(response.data.tasks))
} catch (error) {
dispatch(fetchTasksFailure(error.response.data));
}
}
}
const addTaskRequest = () => {
return {type: ADD_NEW_TASK_REQUEST}
};
const addTaskSuccess = () => {
return {type: ADD_NEW_TASK_SUCCESS}
};
const addTaskFailure = (error) => {
return {type: ADD_NEW_TASK_FAILURE, error}
};
export const addTask = (task) => {
return async (dispatch, getState) => {
dispatch(addTaskRequest());
const token = getState().users?.user?.token;
try {
await axios.post("/tasks", task, {
headers: {
'Authorization': 'aBhHYW8kXUUzjXlxOwGmg'
}
});
dispatch(addTaskSuccess())
dispatch(fetchTasks())
} catch (error) {
dispatch(addTaskFailure(error.response.data));
}
}
}
\ No newline at end of file
import { FETCH_TASKS_FAILURE, FETCH_TASKS_REQUEST, FETCH_TASKS_SUCCESS} from "../actionTypes/tasksTypes";
const initialState = {
tasks: [],
loading: false,
error: null
};
const tasksReduсer = (state = initialState, action) => {
switch(action.type) {
case FETCH_TASKS_REQUEST:
return {...state, loading: true};
case FETCH_TASKS_SUCCESS:
const newArr = []
action.tasks.forEach((task)=>{
if (task.dateTimeStart && task.dateTimeDue) {
const dateStart = task.dateTimeStart.split('T')[0]
const timeStart = task.dateTimeStart.split('T')[1]
const timeEnd = task.dateTimeDue.split('T')[1]
const dayStart = parseInt(dateStart.split('-')[2])
const monthStartNumber = parseInt(dateStart.split('-')[1])
const yearStartNumber = parseInt(dateStart.split('-')[0])
const timeStartHour = parseInt(timeStart.split(':')[0])
const timeEndHour = parseInt(timeEnd.split(':')[0])
const timeStartMinute = parseInt(timeStart.split(':')[1])
const timeEndMinute = parseInt(timeEnd.split(':')[1])
newArr.push({...task, infoForCell: {
startDay: dayStart,
startHour: timeStartHour,
startMonth: monthStartNumber,
startYear: yearStartNumber,
startMinute: timeStartMinute,
endHour: timeEndHour,
endMinute: timeEndMinute,
}
} )
}
})
return {...state, loading: false, tasks: newArr};
case FETCH_TASKS_FAILURE:
return {...state, loading: false, error: action.error};
default:
return state;
}
};
export default tasksReduсer;
\ No newline at end of file
...@@ -5,14 +5,14 @@ const initialState = { ...@@ -5,14 +5,14 @@ const initialState = {
name: 'Ivan', name: 'Ivan',
surname: 'Petrov', surname: 'Petrov',
email: 'test@gmail.com', email: 'test@gmail.com',
role: 'user' role: 'superuser'
}, },
registerError: null, registerError: null,
loginError: null, loginError: null,
loading: false loading: false
}; };
const usersReduser = (state = initialState, action) => { const usersReducer = (state = initialState, action) => {
switch(action.type) { switch(action.type) {
case REGISTER_USER_REQUEST: case REGISTER_USER_REQUEST:
return {...state, loading: true}; return {...state, loading: true};
...@@ -31,4 +31,4 @@ const usersReduser = (state = initialState, action) => { ...@@ -31,4 +31,4 @@ const usersReduser = (state = initialState, action) => {
} }
}; };
export default usersReduser; export default usersReducer;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment