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

Merge branch 'development' of…

Merge branch 'development' of ssh://git.attractor-school.com:30022/apollo64/crm-team-one into task-80-my-task-new-task
parents b20ea305 39724752
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
"@types/bcrypt": "^5.0.0", "@types/bcrypt": "^5.0.0",
"@types/cors": "^2.8.12", "@types/cors": "^2.8.12",
"@types/express": "^4.17.14", "@types/express": "^4.17.14",
"@types/nodemailer": "^6.4.6",
"bcrypt": "^5.1.0", "bcrypt": "^5.1.0",
"class-transformer": "^0.5.1", "class-transformer": "^0.5.1",
"class-validator": "^0.13.2", "class-validator": "^0.13.2",
...@@ -20,6 +21,7 @@ ...@@ -20,6 +21,7 @@
"mongoose": "^6.7.0", "mongoose": "^6.7.0",
"multer": "^1.4.5-lts.1", "multer": "^1.4.5-lts.1",
"nanoid": "^3.3.4", "nanoid": "^3.3.4",
"nodemailer": "^6.8.0",
"path": "^0.12.7", "path": "^0.12.7",
"pg": "^8.8.0", "pg": "^8.8.0",
"reflect-metadata": "^0.1.13", "reflect-metadata": "^0.1.13",
...@@ -1712,6 +1714,14 @@ ...@@ -1712,6 +1714,14 @@
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.8.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.8.tgz",
"integrity": "sha512-uGwPWlE0Hj972KkHtCDVwZ8O39GmyjfMane1Z3GUBGGnkZ2USDq7SxLpVIiIHpweY9DS0QTDH0Nw7RNBsAAZ5A==" "integrity": "sha512-uGwPWlE0Hj972KkHtCDVwZ8O39GmyjfMane1Z3GUBGGnkZ2USDq7SxLpVIiIHpweY9DS0QTDH0Nw7RNBsAAZ5A=="
}, },
"node_modules/@types/nodemailer": {
"version": "6.4.6",
"resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-6.4.6.tgz",
"integrity": "sha512-pD6fL5GQtUKvD2WnPmg5bC2e8kWCAPDwMPmHe/ohQbW+Dy0EcHgZ2oCSuPlWNqk74LS5BVMig1SymQbFMPPK3w==",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/qs": { "node_modules/@types/qs": {
"version": "6.9.7", "version": "6.9.7",
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz",
...@@ -4488,6 +4498,14 @@ ...@@ -4488,6 +4498,14 @@
"webidl-conversions": "^3.0.0" "webidl-conversions": "^3.0.0"
} }
}, },
"node_modules/nodemailer": {
"version": "6.8.0",
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.8.0.tgz",
"integrity": "sha512-EjYvSmHzekz6VNkNd12aUqAco+bOkRe3Of5jVhltqKhEsjw/y0PYPJfp83+s9Wzh1dspYAkUW/YNQ350NATbSQ==",
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/nodemon": { "node_modules/nodemon": {
"version": "2.0.20", "version": "2.0.20",
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.20.tgz", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.20.tgz",
...@@ -7663,6 +7681,14 @@ ...@@ -7663,6 +7681,14 @@
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.8.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.8.tgz",
"integrity": "sha512-uGwPWlE0Hj972KkHtCDVwZ8O39GmyjfMane1Z3GUBGGnkZ2USDq7SxLpVIiIHpweY9DS0QTDH0Nw7RNBsAAZ5A==" "integrity": "sha512-uGwPWlE0Hj972KkHtCDVwZ8O39GmyjfMane1Z3GUBGGnkZ2USDq7SxLpVIiIHpweY9DS0QTDH0Nw7RNBsAAZ5A=="
}, },
"@types/nodemailer": {
"version": "6.4.6",
"resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-6.4.6.tgz",
"integrity": "sha512-pD6fL5GQtUKvD2WnPmg5bC2e8kWCAPDwMPmHe/ohQbW+Dy0EcHgZ2oCSuPlWNqk74LS5BVMig1SymQbFMPPK3w==",
"requires": {
"@types/node": "*"
}
},
"@types/qs": { "@types/qs": {
"version": "6.9.7", "version": "6.9.7",
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz",
...@@ -9721,6 +9747,11 @@ ...@@ -9721,6 +9747,11 @@
} }
} }
}, },
"nodemailer": {
"version": "6.8.0",
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.8.0.tgz",
"integrity": "sha512-EjYvSmHzekz6VNkNd12aUqAco+bOkRe3Of5jVhltqKhEsjw/y0PYPJfp83+s9Wzh1dspYAkUW/YNQ350NATbSQ=="
},
"nodemon": { "nodemon": {
"version": "2.0.20", "version": "2.0.20",
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.20.tgz", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.20.tgz",
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
"@types/bcrypt": "^5.0.0", "@types/bcrypt": "^5.0.0",
"@types/cors": "^2.8.12", "@types/cors": "^2.8.12",
"@types/express": "^4.17.14", "@types/express": "^4.17.14",
"@types/nodemailer": "^6.4.6",
"bcrypt": "^5.1.0", "bcrypt": "^5.1.0",
"class-transformer": "^0.5.1", "class-transformer": "^0.5.1",
"class-validator": "^0.13.2", "class-validator": "^0.13.2",
...@@ -37,6 +38,7 @@ ...@@ -37,6 +38,7 @@
"mongoose": "^6.7.0", "mongoose": "^6.7.0",
"multer": "^1.4.5-lts.1", "multer": "^1.4.5-lts.1",
"nanoid": "^3.3.4", "nanoid": "^3.3.4",
"nodemailer": "^6.8.0",
"path": "^0.12.7", "path": "^0.12.7",
"pg": "^8.8.0", "pg": "^8.8.0",
"reflect-metadata": "^0.1.13", "reflect-metadata": "^0.1.13",
......
...@@ -4,6 +4,7 @@ import {Task} from './models/Task'; ...@@ -4,6 +4,7 @@ import {Task} from './models/Task';
import { Project } from "./models/Project"; import { Project } from "./models/Project";
import { Member } from "./models/Member"; import { Member } from "./models/Member";
import { DateTimeTask } from "./models/DateTimeTask"; import { DateTimeTask } from "./models/DateTimeTask";
import { PasswordRecovery } from "./models/PasswordRecovery";
export const myDataSource = new DataSource({ export const myDataSource = new DataSource({
type: "postgres", type: "postgres",
...@@ -12,7 +13,7 @@ export const myDataSource = new DataSource({ ...@@ -12,7 +13,7 @@ export const myDataSource = new DataSource({
username: "pluser", username: "pluser",
password: "pluser", password: "pluser",
database: "planner", database: "planner",
entities: [User,Task,Project,Member,DateTimeTask], entities: [User,Task,Project,Member,DateTimeTask,PasswordRecovery],
logging: true, logging: true,
synchronize: true, // in build switch to false synchronize: true, // in build switch to false
migrationsRun: false migrationsRun: false
......
...@@ -2,6 +2,8 @@ import express, { NextFunction, Request, Response, Router } from "express"; ...@@ -2,6 +2,8 @@ import express, { NextFunction, Request, Response, Router } from "express";
import { myDataSource } from "./app-data-source"; import { myDataSource } from "./app-data-source";
import { Task } from "./models/Task"; import { Task } from "./models/Task";
import { User } from "./models/User"; import { User } from "./models/User";
import nodemailer from 'nodemailer';
const dataSource = myDataSource; const dataSource = myDataSource;
...@@ -24,33 +26,39 @@ export const auth = async(req: Request,res: Response, next:NextFunction):Promise ...@@ -24,33 +26,39 @@ export const auth = async(req: Request,res: Response, next:NextFunction):Promise
export const authAuthorOrExecutorOfTask = async(req: Request,res: Response, next:NextFunction):Promise<void | express.Response<Response>>=>{ export const authAuthorOrExecutorOfTask = async(req: Request,res: Response, next:NextFunction):Promise<void | express.Response<Response>>=>{
const token = req.get('Authorization'); const token = req.get('Authorization');
const {taskId} = req.body const {taskId} = req.body
if(!token) return res.status(401).send({Message:'token not exists'}) if(!token) return res.status(401).send({Message:'token not exists'})
req.body={...req.body,executorStatus:false} req.body={...req.body,executorStatus:false}
req.body={...req.body,authorStatus:false} req.body={...req.body,authorStatus:false}
const executor = await dataSource const task = await dataSource
.createQueryBuilder() .getRepository(Task)
.select("user") .findOne({
.from(User, "user") relations:{
.leftJoinAndSelect("user.tasks", "task") executor:true,
.where("user.token = :token", { token: token }) author:true,
.getOne(); },
console.log('executor', executor) where:[
if (executor) { {
req.body={...req.body,executorStatus:true} id:taskId,
} executor:{
const author = await dataSource token:token
.createQueryBuilder() }
.select("user") },
.from(User, "user") {
.leftJoinAndSelect("user.createdTasks", "task") id:taskId,
.where("user.token = :token", { token: token }) author:{
.getOne(); token:token
console.log('author', author) }
if (author) { },
]})
if (!task) return res.status(404).send({message:'task with possible user involved is not found'})
if (task?.author?.token === token ) {
req.body={...req.body,authorStatus:true} req.body={...req.body,authorStatus:true}
} else if(task?.executor?.token === token) {
req.body={...req.body,executorStatus:true}
} else {
} }
if(!author && !executor)return res.status(401).send({Message:'user is not authorized'})
next() next()
}; };
...@@ -69,4 +77,21 @@ export const taskFinderById = async (taskId:string):Promise<null | Task>=>{ ...@@ -69,4 +77,21 @@ export const taskFinderById = async (taskId:string):Promise<null | Task>=>{
} }
}) })
return task return task
} }
\ No newline at end of file
export let transporter = nodemailer.createTransport({
service:'Yandex',
// host: "smtp.yandex.ru",
// port: 465,
// secure: true, // true for 465, false for other ports
auth: {
user: "planner45@yandex.ru", // generated ethereal user
pass: "newPlannerProject123" // generated ethereal password
}
})
export const FRONTEND_URL = 'localhost:3000'
\ No newline at end of file
import {
Column,
Entity,
PrimaryGeneratedColumn,
BaseEntity,
OneToOne,
CreateDateColumn,
JoinColumn,
} from 'typeorm';
import { User } from './User';
interface IPasswordRecovery{
createdAt:Date;
token: string;
user: User;
enabled:boolean;
}
@Entity({name: 'PasswordRecovery'})
export class PasswordRecovery extends BaseEntity implements IPasswordRecovery{
@PrimaryGeneratedColumn('uuid')
id!: string;
@CreateDateColumn({ name: 'created_at', type: Date, default: new Date() })
createdAt!: Date;
@Column({ name: 'token', type: 'varchar',length:100, unique: true, nullable:true })
token!: string;
@OneToOne(()=>User,{nullable: false, eager:true})
@JoinColumn()
user!:User;
@Column({ name: 'enabled', type:'boolean', default:true})
enabled!: boolean;
}
\ No newline at end of file
...@@ -7,7 +7,8 @@ import { ...@@ -7,7 +7,8 @@ import {
ManyToOne, ManyToOne,
OneToOne, OneToOne,
JoinTable, JoinTable,
OneToMany OneToMany,
JoinColumn
} from 'typeorm'; } from 'typeorm';
import {User} from './User'; import {User} from './User';
import {Project} from './Project'; import {Project} from './Project';
...@@ -28,9 +29,9 @@ import { DateTimeTask } from './DateTimeTask'; ...@@ -28,9 +29,9 @@ import { DateTimeTask } from './DateTimeTask';
priority: priorityType | null; priority: priorityType | null;
archive:boolean, archive:boolean,
author: User; author: User;
executor:User;
project:Project|null; project:Project|null;
dateTimeTasks:DateTimeTask[]|null; dateTimeTasks:DateTimeTask[]|null;
executor:User;
} }
@Entity({ name: 'Task' }) @Entity({ name: 'Task' })
...@@ -49,7 +50,7 @@ import { DateTimeTask } from './DateTimeTask'; ...@@ -49,7 +50,7 @@ import { DateTimeTask } from './DateTimeTask';
dateTimeDeadLine!: Date; dateTimeDeadLine!: Date;
@Column({ name: 'dateTimeFactDeadLine', type: Date,nullable: true }) @Column({ name: 'dateTimeFactDeadLine', type: Date,nullable: true })
dateTimeFactDeadLine!: Date; dateTimeFactDeadLine!: Date;
@Column({ name: 'archive', type: 'varchar', length:50,nullable: false, default:false }) @Column({ name: 'archive', type: 'boolean',nullable: false, default:false })
archive!: boolean archive!: boolean
@Column({ @Column({
...@@ -73,8 +74,7 @@ import { DateTimeTask } from './DateTimeTask'; ...@@ -73,8 +74,7 @@ import { DateTimeTask } from './DateTimeTask';
@ManyToOne(() => User, (user: { tasks: Task[]; }) => user.tasks,{eager : true}) @ManyToOne(() => User, (user: { tasks: Task[]; }) => user.tasks,{eager : true})
author!: User; author!: User;
@ManyToOne(() =>User, (user: { tasks: Task[]}) => user.tasks,{eager : true,nullable: true, onUpdate:'CASCADE'}) @ManyToOne(() =>User, (user: { tasks: Task[]}) => user.tasks,{nullable: true,cascade: true, onUpdate:'CASCADE', eager : true,})
@JoinTable()
executor!: User; executor!: User;
@ManyToOne(()=>Project,(project:{tasks: Task[]}) => project.tasks,{eager : true,nullable: true,onUpdate:'CASCADE'}) @ManyToOne(()=>Project,(project:{tasks: Task[]}) => project.tasks,{eager : true,nullable: true,onUpdate:'CASCADE'})
......
...@@ -5,9 +5,7 @@ import { ...@@ -5,9 +5,7 @@ import {
CreateDateColumn, CreateDateColumn,
BeforeInsert, BeforeInsert,
BaseEntity, BaseEntity,
ManyToMany,
OneToMany, OneToMany,
JoinTable,
OneToOne, OneToOne,
} from 'typeorm'; } from 'typeorm';
import {IsEmail import {IsEmail
...@@ -17,8 +15,9 @@ import bcrypt from 'bcrypt'; ...@@ -17,8 +15,9 @@ import bcrypt from 'bcrypt';
import {nanoid} from 'nanoid'; import {nanoid} from 'nanoid';
import {Task} from './Task'; import {Task} from './Task';
import {Member} from './Member'; import {Member} from './Member';
import { PasswordRecovery } from './PasswordRecovery';
const SALT_WORK_FACTOR= 10; export const SALT_WORK_FACTOR= 10;
export enum UserRole {USER="user" ,DIRECTOR= "director",SUPERUSER="superuser"} export enum UserRole {USER="user" ,DIRECTOR= "director",SUPERUSER="superuser"}
...@@ -38,7 +37,6 @@ interface IUser { ...@@ -38,7 +37,6 @@ 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")
...@@ -76,20 +74,15 @@ export class User extends BaseEntity implements IUser { ...@@ -76,20 +74,15 @@ export class User extends BaseEntity implements IUser {
@Exclude({ toPlainOnly: true }) @Exclude({ toPlainOnly: true })
password!: string; password!: string;
@OneToMany(() => Task, (task: { user: User }) => task.user) @OneToMany(() => Task, (task: { user: User }) => task.user)
createdTasks!: Task[]; createdTasks!: Task[];
@OneToMany(() => Task, (task: { user: User }) =>task.user) @OneToMany(() => Task, (task: { user: User }) =>task.user)
tasks!: Task[]; tasks!: Task[];
@OneToMany(() => Member, (member: { user: User }) => member.user) @OneToMany(() => Member, (member: { user: User }) => member.user)
members!: Member[]; members!: Member[];
// @ManyToMany(() => Project,(project: { user: User }) => project.user)
// @JoinTable()
// workerInProjects!: Project[];
@BeforeInsert() @BeforeInsert()
......
...@@ -28,38 +28,51 @@ const taskFinderById = async (taskId:string):Promise<null | Task>=>{ ...@@ -28,38 +28,51 @@ const taskFinderById = async (taskId:string):Promise<null | Task>=>{
} }
/** make copy of task in calendar view */ /** make copy of task in calendar view */
router.post("/make-copy",authAuthorOrExecutorOfTask, async(req:Request, res:Response):Promise<Response>=>{ router.post("/make-copy", async(req:Request, res:Response):Promise<Response>=>{
const {executorStatus,taskId,start, due} = req.body const {taskId, dateTimeDue, dateTimeStart} = req.body
if (executorStatus){ const newDateTimeTask = new DateTimeTask();
const newDateTimeTask = new DateTimeTask(); newDateTimeTask.dateTimeStart = dateTimeStart
newDateTimeTask.dateTimeStart = start newDateTimeTask.dateTimeDue = dateTimeDue
newDateTimeTask.dateTimeDue = due newDateTimeTask.task = taskId
newDateTimeTask.task = taskId await newDateTimeTask.save()
await newDateTimeTask.save() const task = taskFinderById(taskId)
const task = taskFinderById(taskId) return res.send({task})
return res.send({task})
}
return res.send({message :"Something wrong in make-copy router"})
} ) } )
/** change date time of copy of task in calendar view */ /** change date time of copy of task in calendar view */
router.put("change-copy", authAuthorOrExecutorOfTask, async(req:Request, res: Response):Promise<Response>=>{ router.put("/change-copy", authAuthorOrExecutorOfTask, async(req:Request, res: Response):Promise<Response>=>{
const {executorStatus,dateTimeTaskId,taskId, start, due} = req.body const {dateTimeTaskId, taskId, dateTimeStart, dateTimeDue, description, title, priority} = req.body
if (executorStatus){ const dateTimeTask = await dataSource
const dateTimeTask = await dataSource .createQueryBuilder()
.createQueryBuilder() .select('dateTimeTask')
.select('dateTikeTask') .from(DateTimeTask,'dateTimeTask')
.from(DateTimeTask,'dateTimeTask') .where("dateTimeTask.id = :dateTimeTaskId",{dateTimeTaskId})
.where("dateTimeTask.id = :dateTimeTaskId",{dateTimeTaskId}) .getOne()
.getOne() if(!dateTimeTask) return res.send({message:"such dateTimeTask does not exists"})
if(!dateTimeTask) return res.send({message:"such dateTimeTask does not exists"}) dateTimeTask.dateTimeStart=dateTimeStart
dateTimeTask.dateTimeStart=start dateTimeTask.dateTimeDue=dateTimeDue
dateTimeTask.dateTimeDue=due await dateTimeTask.save()
await dateTimeTask.save() const task = await taskFinderById(taskId)
const task = taskFinderById(taskId) if (!task) return res.status(404).send({Message:'task not found'})
return res.send({task}) task.title = title;
} task.description = description;
return res.send({message :"Something wrong in make-copy router"}) task.priority = priority;
await task.save()
return res.send({task})
}) })
/**delete copyTask by dateTimeTaskId */
router.delete('/:id', authAuthorOrExecutorOfTask, async(req:Request, res:Response):Promise<Response>=>{
const {id} = req.params
await myDataSource
.createQueryBuilder()
.delete()
.from(DateTimeTask)
.where("id = :id", { id })
.execute()
return res.send({message:"delete succesfully"})
}
)
export default router; export default router;
import express,{Router, Request, Response} from 'express';
import {User} from '../models/User';
import {myDataSource} from '../app-data-source';
import { nanoid } from 'nanoid';
import { PasswordRecovery } from '../models/PasswordRecovery';
import { transporter } from '../helpers';
import {FRONTEND_URL} from "../helpers";
import {SALT_WORK_FACTOR} from "../models/User";
import bcrypt from 'bcrypt';
const router:Router = express.Router();
const dataSource = myDataSource;
/**Make requiest to init recovery process */
router.post ('/', async (req:Request, res:Response):Promise<void |Response>=>{
const {email} = req.body
const user = await dataSource
.getRepository(User)
.findOne({
where:{
email:email
}
})
if (!user) return res.status(404).send({message:'user not found'})
const token = nanoid();
try{
const passwordRecovery = new PasswordRecovery()
passwordRecovery.user= user;
passwordRecovery.token=token;
await passwordRecovery.save()
const url = `${FRONTEND_URL}/reset-password/${token}`;
await transporter.sendMail({
from:"planner45@yandex.com",
to: `${email}`,
subject:"Запрос на восстановление пароля",
text:`Вы отправили запрос на восстановление пароля,
перейдите по ссылке плз:{url}`,
html:`Вы отправили запрос на восстановление пароля,
перейдите по ссылке плз: <br><a> href="${url}">${url}</a>`});
return res.send({message:'Email successffuly send'})
} catch (e){
console.log(e)
res.status(502).send({message:'mail got stuck in ', e })
}
})
/**reset token in password recovery */
router.get('/', async(req: Request, res: Response):Promise<Response|void>=>{
const token = req.query.token;
if(!token) return res.status(401).send({Message:'token not exists'})
const passwordRecovery = await dataSource
.createQueryBuilder()
.from(PasswordRecovery,'passwordRecovery')
.select('passwordRecovery')
.innerJoinAndSelect('passwordRecovery.user', 'user')
.where(' passwordRecovery.token=:token',{token})
.getOne()
if(!passwordRecovery || !passwordRecovery.enabled) return res.status(404).send({message:"Token is not valid"})
res.send(passwordRecovery)
passwordRecovery.enabled=false;
try{
await passwordRecovery.save();
} catch(e){
console.log(e)
}
})
/**change password */
router.patch('/:id/change-password', async (req: Request, res: Response):Promise<Response|void>=>{
const user = await dataSource
.getRepository(User)
.findOneBy({id:req.params.id})
if(!user) return res.status(404).send({Message:'user not found'})
const salt = await bcrypt.genSalt(SALT_WORK_FACTOR);
let newPassword:string = await bcrypt.hash(req.body.password, salt);
user.password = newPassword
try{
await user.save()
res.send({message:"Password saved"})
} catch (e){
res.status(502).send({message:"error in saving new psasword"})
}
})
export default router;
\ No newline at end of file
...@@ -25,7 +25,7 @@ router.get('/', async(req:Request, res:Response):Promise<Response> => { ...@@ -25,7 +25,7 @@ router.get('/', async(req:Request, res:Response):Promise<Response> => {
/**create new task */ /**create new task */
router.post('/', auth, async(req:Request, res:Response):Promise<Response>=>{ router.post('/', auth, async(req:Request, res:Response):Promise<Response>=>{
const {user,title,description,project,executor, dateTimeDeadLine,priority} = req.body; const {user,title,description,project,executor,dateTimeStart,dateTimeDue, dateTimeDeadLine,priority} = req.body;
const newTask = new Task(); const newTask = new Task();
newTask.title = title; newTask.title = title;
newTask.description = description; newTask.description = description;
...@@ -35,6 +35,11 @@ router.post('/', auth, async(req:Request, res:Response):Promise<Response>=>{ ...@@ -35,6 +35,11 @@ router.post('/', auth, async(req:Request, res:Response):Promise<Response>=>{
newTask.executor= executor; newTask.executor= executor;
newTask.priority = priority; newTask.priority = priority;
await newTask.save(); await newTask.save();
const newDateTimeTask = new DateTimeTask();
newDateTimeTask.dateTimeStart = dateTimeStart
newDateTimeTask.dateTimeDue = dateTimeDue
newDateTimeTask.task = newTask
await newDateTimeTask.save()
return res.send({newTask}); return res.send({newTask});
}) })
...@@ -153,7 +158,7 @@ router.delete('/:taskId',async (req: Request, res: Response):Promise<Response>=> ...@@ -153,7 +158,7 @@ router.delete('/:taskId',async (req: Request, res: Response):Promise<Response>=>
/**change of task by task id */ /**change of task by task id */
router.put('/',authAuthorOrExecutorOfTask,async(req:Request, res:Response)=> { router.put('/',authAuthorOrExecutorOfTask,async(req:Request, res:Response)=> {
const {authorStatus,executorStatus,taskId,title,description,note, archive,project,dateTimeTaskId,start,due,executor,accomplish,dateTimeDeadLine, dateTimeFactDeadLine,priority} = req.body; const {authorStatus,executorStatus,taskId,title,description,note, archive,project,dateTimeTaskId,dateTimeStart,dateTimeDue,executor,accomplish,dateTimeDeadLine, dateTimeFactDeadLine,priority} = req.body;
const task = await taskFinderById(taskId) const task = await taskFinderById(taskId)
if (!task) return res.status(404).send({Message:'task not found'}) if (!task) return res.status(404).send({Message:'task not found'})
let dateTimeTask = null; let dateTimeTask = null;
...@@ -168,6 +173,12 @@ router.put('/',authAuthorOrExecutorOfTask,async(req:Request, res:Response)=> { ...@@ -168,6 +173,12 @@ router.put('/',authAuthorOrExecutorOfTask,async(req:Request, res:Response)=> {
dateTimeTask = dateTimeTaskData dateTimeTask = dateTimeTaskData
} }
if (dateTimeTask!==null) {
dateTimeTask.dateTimeStart = dateTimeStart
dateTimeTask.dateTimeDue = dateTimeDue
await dateTimeTask.save()
}
if (authorStatus){ if (authorStatus){
task.title = title task.title = title
task.description= description task.description= description
...@@ -177,13 +188,9 @@ router.put('/',authAuthorOrExecutorOfTask,async(req:Request, res:Response)=> { ...@@ -177,13 +188,9 @@ router.put('/',authAuthorOrExecutorOfTask,async(req:Request, res:Response)=> {
task.executor=executor task.executor=executor
task.priority= priority task.priority= priority
} }
if(executorStatus && dateTimeTask!==null){ if(executorStatus){
dateTimeTask.dateTimeStart = start
dateTimeTask.dateTimeDue = due
await dateTimeTask.save()
task.note = note task.note = note
task.dateTimeFactDeadLine= dateTimeFactDeadLine task.dateTimeFactDeadLine= dateTimeFactDeadLine
} }
task.accomplish= accomplish task.accomplish= accomplish
await task.save() await task.save()
......
...@@ -5,6 +5,7 @@ import tasks from './routers/tasks'; ...@@ -5,6 +5,7 @@ import tasks from './routers/tasks';
import projects from './routers/projects'; import projects from './routers/projects';
import {myDataSource} from './app-data-source'; import {myDataSource} from './app-data-source';
import copyTasks from './routers/copyTasks'; import copyTasks from './routers/copyTasks';
import passwordRecovery from './routers/passwordRecovery';
myDataSource myDataSource
...@@ -25,6 +26,7 @@ app.use('/users',users) ...@@ -25,6 +26,7 @@ app.use('/users',users)
app.use('/tasks',tasks) app.use('/tasks',tasks)
app.use('/copy-tasks',copyTasks) app.use('/copy-tasks',copyTasks)
app.use('/projects',projects) app.use('/projects',projects)
app.use('/password-recovery',passwordRecovery)
const run = async() => { const run = async() => {
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -8,7 +8,7 @@ const CalendarStandartCell = ({children, xs, hours, dayNumber, createTaskInCell ...@@ -8,7 +8,7 @@ const CalendarStandartCell = ({children, xs, hours, dayNumber, createTaskInCell
const [isThisCell, setIsThisCell] = useState(false) const [isThisCell, setIsThisCell] = useState(false)
const cellClass = { const cellClass = {
position: 'relative', position: 'relative',
height: linesInDay?.length ? `${40*linesInDay.length+35}px` : `${35+35}px`, height: linesInDay?.length ? `${40*linesInDay.length+35}px` : `${35}px`,
borderRight: '1px solid black', borderRight: '1px solid black',
} }
useEffect(()=>{ useEffect(()=>{
......
import { Card, CardActions, CardContent, Grid, IconButton } from "@mui/material";
import { Link } from "react-router-dom";
import ArrowForwardIcon from "@mui/icons-material/ArrowForward";
import { useDispatch, useSelector } from "react-redux";
const ProjectMembersItem = ({ displayName, id }) => {
const dispatch = useDispatch();
const { projects, project } = useSelector(state => state.projects);
return <>
<Grid item xs={12} sm={12} md={6} lg={4}>
<Card>
<CardContent>
<strong>
<br></br>
{displayName}
</strong>
<strong>
<br></br>
роль: {project?.project?.members[0]?.roleProject}
</strong>
<strong>
<br></br>
<button>delete</button>
</strong>
</CardContent>
</Card>
</Grid>
</>
};
export default ProjectMembersItem;
import {Grid} from "@mui/material";
import ProjectMembersItem from "../ProjectMembersItem/ProjectMembersItem";
const ProjectMembersList = ({users}) => {
console.log(users)
return (
<Grid item container direction="row" spacing={1}>
{users?.map(user => {
return <ProjectMembersItem
displayName={user.displayName}
id={user.id}
key={user.id}
/>
})}
</Grid>
);
};
export default ProjectMembersList;
\ No newline at end of file
...@@ -4,16 +4,27 @@ import { useSelector, useDispatch } from "react-redux"; ...@@ -4,16 +4,27 @@ import { useSelector, useDispatch } from "react-redux";
import { useEffect } from "react"; import { useEffect } from "react";
import { fetchProject } from "../../store/actions/projectsActions"; import { fetchProject } from "../../store/actions/projectsActions";
import ProjectTasksBody from "../../components/ProjectTasks/ProjectTasksBody"; import ProjectTasksBody from "../../components/ProjectTasks/ProjectTasksBody";
import { fetchUsers } from "../../store/actions/usersActions";
import ProjectMembersList from "../../components/ProjectMembersList/ProjectMembersList";
const FullProject = () => { const FullProject = () => {
const { projects, project } = useSelector(state => state.projects); const { projects, project } = useSelector(state => state.projects);
const users = useSelector(state => state.users.users);
const dispatch = useDispatch(); const dispatch = useDispatch();
const params = useParams() const params = useParams()
const tasks = project.tasks; const tasks = project.tasks;
console.log(projects); console.log(projects);
console.log(tasks); console.log(tasks);
useEffect(() => {
dispatch(fetchUsers())
}, [dispatch]);
console.log(users)
useEffect(() => { useEffect(() => {
dispatch(fetchProject(params.id)) dispatch(fetchProject(params.id))
}, [params.id, dispatch]); }, [params.id, dispatch]);
...@@ -34,7 +45,17 @@ const FullProject = () => { ...@@ -34,7 +45,17 @@ const FullProject = () => {
</strong> </strong>
<strong> <strong>
<br></br> <br></br>
{/* Админ проекта: {project?.project?.members} */} Автор проекта: {project?.project?.members[0]?.user.displayName}
</strong>
<strong>
<br></br>
Роль в проекте: {project?.project?.members[0]?.roleProject}
</strong>
<strong>
<br></br>
Участники проекта:
<ProjectMembersList users={users} project={project}/>
</strong> </strong>
<strong> <strong>
<br></br> <br></br>
......
...@@ -3,11 +3,12 @@ import { useDispatch, useSelector } from 'react-redux'; ...@@ -3,11 +3,12 @@ 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 { dateToISOLikeButLocal, getCurrentMonthString, getDaysInMonth } from '../../helpers/CalendarHelpers'; import { dateToISOLikeButLocal, getCurrentMonthString, getDaysInMonth } from '../../helpers/CalendarHelpers';
import { addCalendarTask, deleteCalendarTask, editCalendarTask, fetchCalendarTasks} from '../../store/actions/tasksActions'; import { addCalendarTask, addCopyCalendarTask, deleteCalendarTask, editCalendarTask, fetchCalendarTasks} from '../../store/actions/tasksActions';
function MonthCalendar() { function MonthCalendar() {
const dispatch = useDispatch(); const dispatch = useDispatch();
const { calendarTasks } = useSelector(state => state.tasks); const { calendarTasks } = useSelector(state => state.tasks);
const user = useSelector(state => state.users?.user);
const [hourFormat, setHourFormat] = useState(false); const [hourFormat, setHourFormat] = useState(false);
const [dateNow, setDateNow] = useState({month: '', year: ''}) const [dateNow, setDateNow] = useState({month: '', year: ''})
...@@ -65,7 +66,6 @@ function MonthCalendar() { ...@@ -65,7 +66,6 @@ function MonthCalendar() {
return {...prevState, month: prevState.month + 1} return {...prevState, month: prevState.month + 1}
}) })
}, []) }, [])
console.log(currentTask)
const decrementMonth = useCallback(() => { const decrementMonth = useCallback(() => {
setDateNow((prevState)=>{ setDateNow((prevState)=>{
if (prevState.month - 1 === -1) { if (prevState.month - 1 === -1) {
...@@ -135,13 +135,15 @@ function MonthCalendar() { ...@@ -135,13 +135,15 @@ function MonthCalendar() {
due = dateToISOLikeButLocal(new Date(dateNow.year, dateNow.month, dayNumber, hour + hourDiff, 59)) due = dateToISOLikeButLocal(new Date(dateNow.year, dateNow.month, dayNumber, hour + hourDiff, 59))
} }
const start = dateToISOLikeButLocal(new Date(dateNow.year, dateNow.month, dayNumber, hour, 0)) const start = dateToISOLikeButLocal(new Date(dateNow.year, dateNow.month, dayNumber, hour, 0))
const newObj = { const newTask = {
...currentTask, ...currentTask,
dateTimeTaskId: currentTask.id,
dateTimeStart: start, dateTimeStart: start,
dateTimeDue: due dateTimeDue: due
} }
delete newObj.infoForCell delete newTask.id
await dispatch(editCalendarTask(newObj)) delete newTask.infoForCell
await dispatch(editCalendarTask(newTask))
setCurrentTask({}) setCurrentTask({})
} }
...@@ -151,15 +153,26 @@ function MonthCalendar() { ...@@ -151,15 +153,26 @@ function MonthCalendar() {
const day = currentTask.infoForCell.startDay const day = currentTask.infoForCell.startDay
const due = dateToISOLikeButLocal(new Date(dateNow.year, dateNow.month, day, timeEndHour - 1, 59)) const due = dateToISOLikeButLocal(new Date(dateNow.year, dateNow.month, day, timeEndHour - 1, 59))
const start = dateToISOLikeButLocal(new Date(dateNow.year, dateNow.month, day, timeStartHour, 0)) const start = dateToISOLikeButLocal(new Date(dateNow.year, dateNow.month, day, timeStartHour, 0))
const newTask = {
...currentTask,
dateTimeStart: start,
dateTimeDue: due
}
delete newTask.infoForCell
if (currentTask.id) { if (currentTask.id) {
const newTask = {
...currentTask,
dateTimeStart: start,
dateTimeDue: due,
dateTimeTaskId: currentTask.id,
taskId: currentTask.mainTaskId
}
delete newTask.infoForCell
delete newTask.id
await dispatch(editCalendarTask(newTask)) await dispatch(editCalendarTask(newTask))
} else { } else {
const newTask = {
...currentTask,
dateTimeStart: start,
dateTimeDue: due,
executor: user,
}
delete newTask.infoForCell
delete newTask.id
await dispatch(addCalendarTask(newTask)) await dispatch(addCalendarTask(newTask))
} }
} }
...@@ -178,10 +191,11 @@ function MonthCalendar() { ...@@ -178,10 +191,11 @@ function MonthCalendar() {
...copyTask, ...copyTask,
dateTimeStart: start, dateTimeStart: start,
dateTimeDue: due, dateTimeDue: due,
taskId: copyTask.mainTaskId
} }
delete newTask.infoForCell delete newTask.infoForCell
delete newTask.id delete newTask.id
await dispatch(addCalendarTask(newTask)) await dispatch(addCopyCalendarTask(newTask))
setCopyTask(null) setCopyTask(null)
} }
......
...@@ -9,12 +9,11 @@ const NewProject = () => { ...@@ -9,12 +9,11 @@ const NewProject = () => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const projects = useSelector(state => state.projects.projects); const projects = useSelector(state => state.projects.projects);
const navigate = useNavigate(); const navigate = useNavigate();
let lastProject = projects.projects[projects.projects.length - 1];
const onSubmit = async (projectData) => { const onSubmit = async (projectData) => {
await dispatch(createProject(projectData, navigate)); await dispatch(createProject(projectData, navigate));
console.log(projectData) console.log(projectData)
console.log(lastProject)
}; };
useEffect(()=> { useEffect(()=> {
......
...@@ -11,8 +11,10 @@ import NewProject from "../NewProject/NewProject"; ...@@ -11,8 +11,10 @@ import NewProject from "../NewProject/NewProject";
const Projects = () => { const Projects = () => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const { projects, loading } = useSelector(state => state.projects.projects); const { projects, loading } = useSelector(state => state.projects.projects);
const {users} = useSelector(state => state.users);
console.log(projects) console.log(projects)
console.log(loading) console.log(users)
useEffect(() => { useEffect(() => {
dispatch(fetchProjects()) dispatch(fetchProjects())
}, [dispatch]); }, [dispatch]);
......
export const getDaysInMonth = (dateNow) => { export const getDaysInMonth = (dateNow) => {
const newDaysInMonth = [] if (dateNow.month <= 11 && dateNow.month >= 0) {
const daysInMonthNumber = new Date(dateNow.year, dateNow.month + 1, 0).getDate() const newDaysInMonth = []
for (let i = 1; i <= daysInMonthNumber; i++) { const daysInMonthNumber = new Date(dateNow.year, dateNow.month + 1, 0).getDate()
const dayOfWeekNumber = new Date(dateNow.year, dateNow.month, i).getDay() for (let i = 1; i <= daysInMonthNumber; i++) {
const getDayOfWeekString = ["ВС","ПН","ВТ","СР","ЧТ","ПТ","СБ"][dayOfWeekNumber] const dayOfWeekNumber = new Date(dateNow.year, dateNow.month, i).getDay()
newDaysInMonth.push({dayNumber: i, dayOfWeek: getDayOfWeekString}) const getDayOfWeekString = ["ВС","ПН","ВТ","СР","ЧТ","ПТ","СБ"][dayOfWeekNumber]
newDaysInMonth.push({dayNumber: i, dayOfWeek: getDayOfWeekString})
}
return newDaysInMonth
} else {
return null
} }
return newDaysInMonth
} }
export const getCurrentMonthString = (dateNow) => { export const getCurrentMonthString = (dateNow) => {
return ["Январь","Февраль","Март","Апрель","Май","Июнь","Июль","Август","Сентябрь","Октябрь","Ноябрь", "Декабрь"][dateNow.month]; if (dateNow.month <= 11 && dateNow.month >= 0) {
return ["Январь","Февраль","Март","Апрель","Май","Июнь","Июль","Август","Сентябрь","Октябрь","Ноябрь", "Декабрь"][dateNow.month];
} else {
return null
}
} }
export const dateToISOLikeButLocal = (date) => { export const dateToISOLikeButLocal = (date) => {
const offsetMs = date.getTimezoneOffset() * 60 * 1000; if (date instanceof Date && !isNaN(date)) {
const msLocal = date.getTime() - offsetMs; const offsetMs = date.getTimezoneOffset() * 60 * 1000;
const dateLocal = new Date(msLocal); const msLocal = date.getTime() - offsetMs;
const iso = dateLocal.toISOString(); const dateLocal = new Date(msLocal);
return iso; const iso = dateLocal.toISOString();
return iso;
} else {
return null
}
} }
\ No newline at end of file
...@@ -6,4 +6,8 @@ export const LOGIN_USER_SUCCESS = "LOGIN_USER_SUCCESS"; ...@@ -6,4 +6,8 @@ export const LOGIN_USER_SUCCESS = "LOGIN_USER_SUCCESS";
export const LOGIN_USER_FAILURE = "LOGIN_USER_FAILURE"; export const LOGIN_USER_FAILURE = "LOGIN_USER_FAILURE";
export const LOGOUT_USER_SUCCESS = "LOGOUT_USER_SUCCESS"; export const LOGOUT_USER_SUCCESS = "LOGOUT_USER_SUCCESS";
export const LOGOUT_USER_FAILURE = "LOGOUT_USER_FAILURE"; export const LOGOUT_USER_FAILURE = "LOGOUT_USER_FAILURE";
\ No newline at end of file
export const FETCH_USERS_REQUEST = "FETCH_USERS_REQUEST";
export const FETCH_USERS_SUCCESS = "FETCH_USERS_SUCCESS";
export const FETCH_USERS_FAILURE = "FETCH_USERS_FAILURE";
\ No newline at end of file
...@@ -71,10 +71,23 @@ const addTaskFailure = (error) => { ...@@ -71,10 +71,23 @@ const addTaskFailure = (error) => {
}; };
export const addCalendarTask = (task) => { export const addCalendarTask = (task) => {
return async (dispatch, getState) => { return async (dispatch) => {
dispatch(addTaskRequest()); dispatch(addTaskRequest());
try { try {
await axios.post("/tasks", task); const response = await axios.post("/tasks", task);
dispatch(addTaskSuccess())
dispatch(fetchCalendarTasks())
} catch (error) {
dispatch(addTaskFailure(error.response.data));
}
}
}
export const addCopyCalendarTask = (task) => {
return async (dispatch) => {
dispatch(addTaskRequest());
try {
const response = await axios.post("/copy-tasks/make-copy", task);
dispatch(addTaskSuccess()) dispatch(addTaskSuccess())
dispatch(fetchCalendarTasks()) dispatch(fetchCalendarTasks())
} catch (error) { } catch (error) {
...@@ -84,7 +97,7 @@ export const addCalendarTask = (task) => { ...@@ -84,7 +97,7 @@ export const addCalendarTask = (task) => {
} }
export const addTask = (task) => { export const addTask = (task) => {
return async (dispatch, getState) => { return async (dispatch) => {
dispatch(addTaskRequest()); dispatch(addTaskRequest());
try { try {
await axios.post("/tasks", task); await axios.post("/tasks", task);
...@@ -109,7 +122,7 @@ const editTaskFailure = (error) => { ...@@ -109,7 +122,7 @@ const editTaskFailure = (error) => {
}; };
export const editTask = (task) => { export const editTask = (task) => {
return async (dispatch, getState) => { return async (dispatch) => {
dispatch(editTaskRequest()); dispatch(editTaskRequest());
try { try {
await axios.put("/tasks", task); await axios.put("/tasks", task);
...@@ -122,10 +135,10 @@ export const editTask = (task) => { ...@@ -122,10 +135,10 @@ export const editTask = (task) => {
} }
export const editCalendarTask = (task) => { export const editCalendarTask = (task) => {
return async (dispatch, getState) => { return async (dispatch) => {
dispatch(editTaskRequest()); dispatch(editTaskRequest());
try { try {
await axios.put("/tasks", task); await axios.put("/copy-tasks/change-copy", task);
dispatch(editTaskSuccess()) dispatch(editTaskSuccess())
dispatch(fetchCalendarTasks()) dispatch(fetchCalendarTasks())
} catch (error) { } catch (error) {
...@@ -147,7 +160,7 @@ const deleteTaskFailure = (error) => { ...@@ -147,7 +160,7 @@ const deleteTaskFailure = (error) => {
}; };
export const deleteTask = (taskId) => { export const deleteTask = (taskId) => {
return async (dispatch, getState) => { return async (dispatch) => {
dispatch(deleteTaskRequest()); dispatch(deleteTaskRequest());
try { try {
await axios.delete(`/tasks/${taskId}`); await axios.delete(`/tasks/${taskId}`);
...@@ -160,10 +173,10 @@ export const deleteTask = (taskId) => { ...@@ -160,10 +173,10 @@ export const deleteTask = (taskId) => {
} }
export const deleteCalendarTask = (taskId) => { export const deleteCalendarTask = (taskId) => {
return async (dispatch, getState) => { return async (dispatch) => {
dispatch(deleteTaskRequest()); dispatch(deleteTaskRequest());
try { try {
await axios.delete(`/tasks/${taskId}`); await axios.delete(`/copy-tasks/${taskId}`);
dispatch(deleteTaskSuccess()) dispatch(deleteTaskSuccess())
dispatch(fetchCalendarTasks()) dispatch(fetchCalendarTasks())
} catch (error) { } catch (error) {
......
import axios from "../../axiosPlanner"; import axios from "../../axiosPlanner";
import { LOGIN_USER_FAILURE, LOGIN_USER_SUCCESS, LOGOUT_USER_FAILURE, LOGOUT_USER_SUCCESS, REGISTER_USER_FAILURE, REGISTER_USER_REQUEST, REGISTER_USER_SUCCESS } from "../actionTypes/userActionTypes" import { FETCH_USERS_FAILURE, FETCH_USERS_REQUEST, FETCH_USERS_SUCCESS, LOGIN_USER_FAILURE, LOGIN_USER_SUCCESS, LOGOUT_USER_FAILURE, LOGOUT_USER_SUCCESS, REGISTER_USER_FAILURE, REGISTER_USER_REQUEST, REGISTER_USER_SUCCESS } from "../actionTypes/userActionTypes"
import { showNotification } from "./commonActions"; import { showNotification } from "./commonActions";
const registerUserRequest = () => { const registerUserRequest = () => {
...@@ -14,6 +14,16 @@ const registerUserFailure = (error) => { ...@@ -14,6 +14,16 @@ const registerUserFailure = (error) => {
return {type: REGISTER_USER_FAILURE, error} return {type: REGISTER_USER_FAILURE, error}
}; };
const fetchUsersRequest = () => {
return {type: FETCH_USERS_REQUEST}
};
const fetchUsersSuccess = (users) => {
return {type: FETCH_USERS_SUCCESS, users}
};
const fetchUsersFailure = () => {
return {type: FETCH_USERS_FAILURE}
};
export const registerUser = (userData, navigate) => { export const registerUser = (userData, navigate) => {
return async (dispatch) => { return async (dispatch) => {
dispatch(registerUserRequest()); dispatch(registerUserRequest());
...@@ -90,4 +100,17 @@ export const logoutUser = (navigate) => { ...@@ -90,4 +100,17 @@ export const logoutUser = (navigate) => {
dispatch(showNotification("Не удалось выйти", "error")); dispatch(showNotification("Не удалось выйти", "error"));
} }
} }
} }
\ No newline at end of file
export const fetchUsers = () => {
return async dispatch => {
dispatch(fetchUsersRequest());
try {
const response = await axios.get("/users");
dispatch(fetchUsersSuccess(response.data.users));
console.log(response.data.users)
} catch (e) {
dispatch(fetchUsersFailure(e));
}
}
};
\ No newline at end of file
...@@ -29,37 +29,51 @@ const tasksReduсer = (state = initialState, action) => { ...@@ -29,37 +29,51 @@ const tasksReduсer = (state = initialState, action) => {
case FETCH_CALENDAR_TASKS_REQUEST: case FETCH_CALENDAR_TASKS_REQUEST:
return {...state, loading: true}; return {...state, loading: true};
case FETCH_CALENDAR_TASKS_SUCCESS: case FETCH_CALENDAR_TASKS_SUCCESS:
const newArr = [] const newTasksWithoutInfoForCell = []
action.tasks.forEach((task)=>{ const newTasksWithInfoForCell = []
if (task.dateTimeStart && task.dateTimeDue) { for (let task of action.tasks) {
if (new Date(task.dateTimeDue).getTime() - new Date(task.dateTimeStart).getTime() < (24 * 3600000) && for (let copy of task.dateTimeTasks) {
new Date(task.dateTimeDue).getTime() - new Date(task.dateTimeStart).getTime() > 0) { newTasksWithoutInfoForCell.push({
const dateStart = task.dateTimeStart.split('T')[0] ...copy,
const timeStart = task.dateTimeStart.split('T')[1] mainTaskId: task.id,
const timeEnd = task.dateTimeDue.split('T')[1] executor: task.executor,
const dayStart = parseInt(dateStart.split('-')[2]) author: task.author,
const monthStartNumber = parseInt(dateStart.split('-')[1]) priority: task.priority,
const yearStartNumber = parseInt(dateStart.split('-')[0]) title: task.title,
const timeStartHour = parseInt(timeStart.split(':')[0]) description: task.description
const timeEndHour = parseInt(timeEnd.split(':')[0])
const timeStartMinute = parseInt(timeStart.split(':')[1])
const timeEndMinute = parseInt(timeEnd.split(':')[1])
const newObj = {...task,
infoForCell: {
startDay: dayStart,
startHour: timeStartHour,
startMonth: monthStartNumber,
startYear: yearStartNumber,
startMinute: timeStartMinute,
endHour: timeEndHour,
endMinute: timeEndMinute,
}
}
newArr.push(newObj)
}
}
}) })
return {...state, loading: false, calendarTasks: newArr}; }
}
newTasksWithoutInfoForCell.forEach((task)=>{
if (task.dateTimeStart && task.dateTimeDue) {
if (new Date(task.dateTimeDue).getTime() - new Date(task.dateTimeStart).getTime() < (24 * 3600000) &&
new Date(task.dateTimeDue).getTime() - new Date(task.dateTimeStart).getTime() > 0) {
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])
const newObj = {...task,
infoForCell: {
startDay: dayStart,
startHour: timeStartHour,
startMonth: monthStartNumber,
startYear: yearStartNumber,
startMinute: timeStartMinute,
endHour: timeEndHour,
endMinute: timeEndMinute,
}
}
newTasksWithInfoForCell.push(newObj)
}
}
})
return {...state, loading: false, calendarTasks: newTasksWithInfoForCell};
case FETCH_ALL_TASKS_SUCCESS: case FETCH_ALL_TASKS_SUCCESS:
return {...state, loading: false, tasks: action.tasks}; return {...state, loading: false, tasks: action.tasks};
case FETCH_CALENDAR_TASKS_FAILURE: case FETCH_CALENDAR_TASKS_FAILURE:
......
import { REGISTER_USER_REQUEST, REGISTER_USER_SUCCESS, REGISTER_USER_FAILURE, LOGIN_USER_SUCCESS, LOGIN_USER_FAILURE, LOGOUT_USER_SUCCESS } from "../actionTypes/userActionTypes"; import { REGISTER_USER_REQUEST, REGISTER_USER_SUCCESS, REGISTER_USER_FAILURE, LOGIN_USER_SUCCESS, LOGIN_USER_FAILURE, LOGOUT_USER_SUCCESS, FETCH_USERS_SUCCESS } from "../actionTypes/userActionTypes";
const initialState = { const initialState = {
user: null, user: null,
users: [],
registerError: null, registerError: null,
loginError: null, loginError: null,
loading: false loading: false
...@@ -24,6 +25,8 @@ const usersReducer = (state = initialState, action) => { ...@@ -24,6 +25,8 @@ const usersReducer = (state = initialState, action) => {
return {...state, loginError: action.error}; return {...state, loginError: action.error};
case LOGOUT_USER_SUCCESS: case LOGOUT_USER_SUCCESS:
return {...state, user: null}; return {...state, user: null};
case FETCH_USERS_SUCCESS:
return {...state, loading: false, users: action.users};
default: default:
return state; return state;
} }
......
import {getDaysInMonth, getCurrentMonthString, dateToISOLikeButLocal} from '../helpers/CalendarHelpers';
import {getAvailableTasks, getSortedTasks} from '../components/MonthCalendarBody/CalendarRowDay/Helpers'
describe('Получение дней в феврале 2022', () => {
test('Всего дней', () => {
expect(getDaysInMonth({year:2022, month:1}).length).toBe(28);
})
test('Первый день', () => {
expect(getDaysInMonth({year:2022, month:1})[0]).toEqual({dayNumber: 1, dayOfWeek: 'ВТ'});
})
test('Последний день', () => {
expect(getDaysInMonth({year:2022, month:1})[27]).toEqual({dayNumber: 28, dayOfWeek: 'ПН'});
})
test('Неккоретное значение выше нормы', () => {
expect(getDaysInMonth({year:2022, month:12})).toBe(null);
})
test('Неккоретное значение ниже нормы', () => {
expect(getDaysInMonth({year:2022, month:-1})).toBe(null);
})
})
describe('Получение дней в ноябре 2022', () => {
test('Всего дней', () => {
expect(getDaysInMonth({year:2022, month:10}).length).toBe(30);
})
test('Первый день', () => {
expect(getDaysInMonth({year:2022, month:10})[0]).toEqual({dayNumber: 1, dayOfWeek: 'ВТ'});
})
test('Последний день', () => {
expect(getDaysInMonth({year:2022, month:10})[29]).toEqual({dayNumber: 30, dayOfWeek: 'СР'});
})
})
describe('Получение месяца', () => {
test('Первый месяц', () => {
expect(getCurrentMonthString({month:0})).toBe("Январь");
})
test('Последний месяц', () => {
expect(getCurrentMonthString({month:11})).toBe("Декабрь");
})
test('Неккоретное значение выше нормы', () => {
expect(getCurrentMonthString({month:12})).toBe(null);
})
test('Неккоретное значение ниже нормы', () => {
expect(getCurrentMonthString({month:-1})).toBe(null);
})
})
describe('Получение ISO даты', () => {
test('Валидная дата', () => {
expect(dateToISOLikeButLocal(new Date(2021, 11, 28, 5, 59))).toBe("2021-12-28T05:59:00.000Z");
})
test('Не валидная дата', () => {
expect(dateToISOLikeButLocal(new Date(2021, 'sd', 28, 5, 59))).toBe(null);
})
})
describe('Получение допустимых задач для клетки', () => {
test('Валидные задачи', () => {
expect(getAvailableTasks([{infoForCell: {startYear: 2022, startMonth: 12, startDay: 12}}, {infoForCell: {startYear: 2022, startMonth: 12, startDay: 12}}], 2022, 11, 12).length).toBe(2);
})
test('Не валидные задачи', () => {
expect(getAvailableTasks([{infoForCell: {startYear: 2021, startMonth: 11, startDay: 12}}, {infoForCell: {startYear: 2022, startMonth: 12, startDay: 14}}], 2022, 11, 12).length).toBe(0);
})
test('Не все прошедшие проверку задачи', () => {
expect(getAvailableTasks([{infoForCell: {startYear: 2021, startMonth: 11, startDay: 12}}, {infoForCell: {startYear: 2022, startMonth: 12, startDay: 12}}], 2022, 11, 12).length).toBe(1);
})
})
\ No newline at end of file
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