Commit e2fdc5e2 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 458bbbc0 fa05180f
This diff is collapsed.
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
"license": "ISC", "license": "ISC",
"devDependencies": { "devDependencies": {
"@faker-js/faker": "^7.6.0", "@faker-js/faker": "^7.6.0",
"@types/multer": "^1.4.7",
"@types/node": "^18.11.8", "@types/node": "^18.11.8",
"@typescript-eslint/eslint-plugin": "^5.41.0", "@typescript-eslint/eslint-plugin": "^5.41.0",
"@typescript-eslint/parser": "^5.41.0", "@typescript-eslint/parser": "^5.41.0",
...@@ -34,7 +35,9 @@ ...@@ -34,7 +35,9 @@
"cors": "^2.8.5", "cors": "^2.8.5",
"express": "^4.18.2", "express": "^4.18.2",
"mongoose": "^6.7.0", "mongoose": "^6.7.0",
"multer": "^1.4.5-lts.1",
"nanoid": "^3.3.4", "nanoid": "^3.3.4",
"path": "^0.12.7",
"pg": "^8.8.0", "pg": "^8.8.0",
"reflect-metadata": "^0.1.13", "reflect-metadata": "^0.1.13",
"typeorm": "^0.3.10" "typeorm": "^0.3.10"
......
*
!.gitignore
\ No newline at end of file
import path = require('path');
const rootPath = __dirname;
export const config = {
rootPath,
uploadPath: path.join(rootPath, "public", "uploads"),
db: {
url: "mongodb://localhost/",
name: "planner"
}
};
...@@ -2,10 +2,29 @@ import express,{Router, Request, Response} from 'express'; ...@@ -2,10 +2,29 @@ import express,{Router, Request, Response} from 'express';
import {User} from '../models/User'; import {User} from '../models/User';
import {myDataSource} from '../app-data-source'; import {myDataSource} from '../app-data-source';
import { nanoid } from 'nanoid'; import { nanoid } from 'nanoid';
import multer from 'multer';
import path from 'path';
import {config} from "../config"
const router:Router = express.Router(); const router:Router = express.Router();
const dataSource = myDataSource; const dataSource = myDataSource;
type DestinationCallback = (error: Error | null, destination: string) => void
type FileNameCallback = (error: Error | null, filename: string) => void
const storage = multer.diskStorage({
destination: (req:Request, file: Express.Multer.File, cb:DestinationCallback) => {
cb(null, config.uploadPath);
},
filename: (req:Request, file: Express.Multer.File, cb:FileNameCallback) => {
cb(null, nanoid() + path.extname(file.originalname));
}
})
const upload = multer({ storage })
router.get('/', async (req : Request, res : Response):Promise<object> => { router.get('/', async (req : Request, res : Response):Promise<object> => {
const users = await dataSource const users = await dataSource
.getRepository(User) .getRepository(User)
...@@ -15,9 +34,10 @@ return res.send({users}) ...@@ -15,9 +34,10 @@ return res.send({users})
}) })
router.post('/', async (req : Request, res : Response):Promise<object> => { router.post('/', upload.single("avatar"), async (req : Request, res : Response):Promise<object> => {
console.log(req.body)
const {name,surname,password,email, role} = req.body; const {name,surname,password,email, role} = req.body;
console.log(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;
...@@ -27,16 +47,20 @@ router.post('/', async (req : Request, res : Response):Promise<object> => { ...@@ -27,16 +47,20 @@ router.post('/', async (req : Request, res : Response):Promise<object> => {
user.email = email; user.email = email;
user.role = role; user.role = role;
user.generateToken() user.generateToken()
console.log("user " + user)
await user.save(); await user.save();
console.log("saved")
const userToFront:User|null = await dataSource.manager.findOneBy(User, { const userToFront:User|null = await dataSource.manager.findOneBy(User, {
email: user.email email: user.email
}) })
console.log("userToFront " + userToFront)
return res.send({userToFront}) return res.send({userToFront})
}) })
router.post('/sessions/', async (req : Request, res : Response):Promise<object> => { router.post('/sessions/', async (req : Request, res : Response):Promise<object> => {
const {email, password} = req.body; const {email, password} = req.body;
console.log("email" + email, "password" + password )
const user = await dataSource const user = await dataSource
.createQueryBuilder() .createQueryBuilder()
.select("user") .select("user")
...@@ -46,6 +70,7 @@ router.post('/sessions/', async (req : Request, res : Response):Promise<object> ...@@ -46,6 +70,7 @@ router.post('/sessions/', async (req : Request, res : Response):Promise<object>
.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);
console.log("123")
if (!isMatch) return res.status(400).send({ if (!isMatch) return res.status(400).send({
error: "Wrong Password" error: "Wrong Password"
}) })
......
...@@ -6,6 +6,7 @@ import MyTasks from './containers/MyTasks/MyTasks'; ...@@ -6,6 +6,7 @@ import MyTasks from './containers/MyTasks/MyTasks';
import Login from './containers/Login/Login'; import Login from './containers/Login/Login';
import Register from './containers/Register/Register'; import Register from './containers/Register/Register';
import MonthCalendar from './containers/MonthCalendar/MonthCalendar'; import MonthCalendar from './containers/MonthCalendar/MonthCalendar';
import ForgottenPassword from "./containers/ForgottenPassword/ForgottenPassword";
const ProtectedRoute = ({isAllowed, roles, redirectUrl, children}) => { const ProtectedRoute = ({isAllowed, roles, redirectUrl, children}) => {
const user = useSelector(state => state.users?.user); const user = useSelector(state => state.users?.user);
...@@ -95,6 +96,7 @@ const App = () => { ...@@ -95,6 +96,7 @@ const App = () => {
}/> }/>
<Route path={"/sign-in"} element={<Login/>}/> <Route path={"/sign-in"} element={<Login/>}/>
<Route path={"/forgottenpassword"} element={<ForgottenPassword/>}/>
<Route path='*' element={<h1>404</h1>}/> <Route path='*' element={<h1>404</h1>}/>
</Route> </Route>
</Routes> </Routes>
......
import {Button} from "@mui/material"; import {Button, Menu, MenuItem} from "@mui/material";
import {NavLink} from "react-router-dom"; import { useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import {NavLink, useNavigate} from "react-router-dom";
import { logoutUser } from "../../../store/actions/usersActions";
const AdminMenu = () => { const AdminMenu = () => {
const dispatch = useDispatch();
const navigate = useNavigate()
const [anchorEl, setAnchorEl] = useState(null);
const open = Boolean(anchorEl);
const user = useSelector(state => state.users.user)
console.log(user)
const handleClick = (event) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
const logout = () => {
dispatch(logoutUser(navigate));
handleClose()
}
return <> return <>
<Button <Button
component={NavLink} component={NavLink}
...@@ -44,13 +64,20 @@ const AdminMenu = () => { ...@@ -44,13 +64,20 @@ const AdminMenu = () => {
Создать сотрудника Создать сотрудника
</Button> </Button>
<Button <Button
component={NavLink}
to="/profile/test"
color="inherit" color="inherit"
size="large" onClick={handleClick}
> >
Профиль Hello, {user?.displayName}
</Button> </Button>
<Menu
anchorEl={anchorEl}
open={open}
onClose={handleClose}
>
<MenuItem component={NavLink} to="/profile/test" color="inherit" onClick={handleClose}>Profile</MenuItem>
<MenuItem onClick={logout}>Logout</MenuItem>
</Menu>
</> </>
}; };
......
import {Button} from "@mui/material"; import {Button, Menu, MenuItem} from "@mui/material";
import {NavLink} from "react-router-dom"; import { useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import {NavLink, useNavigate} from "react-router-dom";
import { logoutUser } from "../../../store/actions/usersActions";
const WorkerMenu = ({user}) => { const WorkerMenu = () => {
const dispatch = useDispatch();
const navigate = useNavigate()
const [anchorEl, setAnchorEl] = useState(null);
const open = Boolean(anchorEl);
const user = useSelector(state => state.users.user)
console.log(user)
const handleClick = (event) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
const logout = () => {
dispatch(logoutUser(navigate));
handleClose()
}
return <> return <>
<Button <Button
component={NavLink} component={NavLink}
...@@ -28,13 +48,20 @@ const WorkerMenu = ({user}) => { ...@@ -28,13 +48,20 @@ const WorkerMenu = ({user}) => {
Мои задачи Мои задачи
</Button> </Button>
<Button <Button
component={NavLink}
to="/profile/test"
color="inherit" color="inherit"
size="large" onClick={handleClick}
> >
Профиль Hello, {user?.displayName}
</Button> </Button>
<Menu
anchorEl={anchorEl}
open={open}
onClose={handleClose}
>
<MenuItem component={NavLink} to="/profile/test" color="inherit" onClick={handleClose}>Profile</MenuItem>
<MenuItem onClick={logout}>Logout</MenuItem>
</Menu>
</> </>
}; };
......
import { Grid } from "@mui/material"; import { Grid } from "@mui/material";
import { memo } from "react";
const CalendarRow = ({children}) => { const CalendarRow = ({children}) => {
return <> return <>
...@@ -12,6 +13,6 @@ const CalendarRow = ({children}) => { ...@@ -12,6 +13,6 @@ const CalendarRow = ({children}) => {
</> </>
}; };
export default CalendarRow; export default memo(CalendarRow);
import { Grid } from "@mui/material"; import { Grid } from "@mui/material";
import { memo } from "react";
const CalendarSmallCell = ({children, xs}) => { const CalendarSmallCell = ({children, xs}) => {
return <> return <>
...@@ -8,4 +9,4 @@ const CalendarSmallCell = ({children, xs}) => { ...@@ -8,4 +9,4 @@ const CalendarSmallCell = ({children, xs}) => {
</> </>
}; };
export default CalendarSmallCell; export default memo(CalendarSmallCell);
\ No newline at end of file \ No newline at end of file
import { Grid, TextField, Typography } from "@mui/material"; import { Grid, TextField, Typography } from "@mui/material";
import { useEffect, useState } from "react"; import { memo, useEffect, useState } from "react";
const CalendarStandartCell = ({children, xs, currentTask, hours, dayNumber, createTaskInCellHandler, handleOpen, modal}) => { const CalendarStandartCell = ({children, xs, hours, dayNumber, createTaskInCellHandler, handleOpen, modal}) => {
const [isThisCell, setIsThisCell] = useState(false) const [isThisCell, setIsThisCell] = useState(false)
useEffect(()=>{ useEffect(()=>{
if(!modal) { if(!modal) {
...@@ -19,11 +19,14 @@ const CalendarStandartCell = ({children, xs, currentTask, hours, dayNumber, cre ...@@ -19,11 +19,14 @@ const CalendarStandartCell = ({children, xs, currentTask, hours, dayNumber, cre
sx={{backgroundColor: 'lightgreen', padding: '10px', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis'}} sx={{backgroundColor: 'lightgreen', padding: '10px', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis'}}
> >
<span> <span>
{currentTask.title} Задача
</span> </span>
</Grid> : null} </Grid> : null}
</Grid> </Grid>
</> </>
}; };
export default CalendarStandartCell; export default memo(CalendarStandartCell, (prevProps, nextProps)=>{
\ No newline at end of file if(!prevProps.modal) return false
if(nextProps.modal) return true
});
\ No newline at end of file
import { Grid, TextField, Typography } from "@mui/material"; import { Grid, TextField, Typography } from "@mui/material";
import React, { useEffect, useState } from "react"; import React, { memo, useState, useEffect} from "react";
const CalendarTask = ({year, month, tasks, day, hours, setCurrentTask, hourFormat, handleOpen, currentTask}) => { const CalendarTask = ({year, month, tasks, day, hours, setCurrentTask, hourFormat, handleOpen, currentTask}) => {
const [thisCellCurrentTask, setThisCellCurrentTask] = useState({}) const [thisCellCurrentTask, setThisCellCurrentTask] = useState({})
...@@ -27,20 +27,13 @@ const CalendarTask = ({year, month, tasks, day, hours, setCurrentTask, hourForma ...@@ -27,20 +27,13 @@ const CalendarTask = ({year, month, tasks, day, hours, setCurrentTask, hourForma
return tasksCell return tasksCell
} }
const tasksCell = getTaskInDayCell(tasks, day, hours) const tasksCell = getTaskInDayCell(tasks, day, hours)
useEffect(()=>{ useEffect(()=>{
if (!currentTask.title) { if (!currentTask.title) {
setThisCellCurrentTask({}) setThisCellCurrentTask({})
} }
}, [currentTask]) }, [currentTask])
const renderText = (i, task) => {
if (thisCellCurrentTask && i === thisCellCurrentTask.i) {
return (<>{currentTask.title}</>)
} else {
return (<>{task.title}</>)
}
}
return (<> return (<>
{tasksCell.length ? tasksCell.map((task, i)=> {tasksCell.length ? tasksCell.map((task, i)=>
...@@ -49,9 +42,9 @@ const CalendarTask = ({year, month, tasks, day, hours, setCurrentTask, hourForma ...@@ -49,9 +42,9 @@ const CalendarTask = ({year, month, tasks, day, hours, setCurrentTask, hourForma
<Grid <Grid
key={task.id} key={task.id}
sx={{backgroundColor: 'lightgreen', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', padding: '10px', borderBottom: '1px solid rgb(29, 161, 51);;'}} sx={{backgroundColor: 'lightgreen', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', padding: '10px', borderBottom: '1px solid rgb(29, 161, 51);;'}}
onClick={(e)=>{e.stopPropagation(); setCurrentTask(task); handleOpen(e); setThisCellCurrentTask({...task, i: i})}} onClick={(e)=>{e.stopPropagation(); setCurrentTask(task); handleOpen(e)}}
> >
{renderText(i, task)} {task.title}
</Grid> </Grid>
)} )}
) )
...@@ -59,4 +52,4 @@ const CalendarTask = ({year, month, tasks, day, hours, setCurrentTask, hourForma ...@@ -59,4 +52,4 @@ const CalendarTask = ({year, month, tasks, day, hours, setCurrentTask, hourForma
</>) </>)
}; };
export default CalendarTask; export default memo(CalendarTask);
\ No newline at end of file \ No newline at end of file
import { FormControlLabel, Switch} from "@mui/material"; import { FormControlLabel, Switch} from "@mui/material";
import { useEffect, useState } from "react"; import { memo, useEffect, useState } from "react";
import CalendarRow from "./CalendarRow/CalendarRow"; import CalendarRow from "./CalendarRow/CalendarRow";
import CalendarSmallCell from "./CalendarSmallCell/CalendarSmallCell"; import CalendarSmallCell from "./CalendarSmallCell/CalendarSmallCell";
import CalendarStandartCell from "./CalendarStandartCell.js/CalendarStandartCell"; import CalendarStandartCell from "./CalendarStandartCell.js/CalendarStandartCell";
...@@ -7,11 +7,8 @@ import CalendarTask from "./CalendarTask/CalendarTask"; ...@@ -7,11 +7,8 @@ import CalendarTask from "./CalendarTask/CalendarTask";
import ModalTask from "../UI/ModalTask/ModalTask"; import ModalTask from "../UI/ModalTask/ModalTask";
import MonthCalendarModalContent from "../MonthCalendarModalContent/MonthCalendarModalContent"; import MonthCalendarModalContent from "../MonthCalendarModalContent/MonthCalendarModalContent";
function MonthCalendarBody({month, year, tasks, createTaskInCellHandler, currentTask, setCurrentTask, hourFormat, setHourFormat, onChangeCurrentTaskHandler, sendNewTaskHandler, deleteTaskHandler}) { function MonthCalendarBody({month, year, tasks, createTaskInCellHandler, currentTask, setCurrentTask, hourFormat, setHourFormat, onChangeCurrentTaskHandler, sendNewTaskHandler, deleteTaskHandler, cellSizes, hoursInDay, daysInMonth}) {
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 [cellSizes, setCellSizes] = useState({})
const [modal, setModal] = useState({open:false, y: 0, x: 0,}); const [modal, setModal] = useState({open:false, y: 0, x: 0,});
const handleOpen = (e) => { const handleOpen = (e) => {
setModal( { setModal( {
...@@ -30,58 +27,6 @@ function MonthCalendarBody({month, year, tasks, createTaskInCellHandler, current ...@@ -30,58 +27,6 @@ function MonthCalendarBody({month, year, tasks, createTaskInCellHandler, current
}; };
useEffect(()=>{
const cells = hoursInDay.length
const xs = 10.8/cells
setCellSizes(()=>{
return {smallCell: 0.6, standarCell: xs}
})
}, [])
useEffect(()=>{
if (hourFormat) {
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']
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 = () => {
return new Date(year, month + 1, 0).getDate();
}
const getDayOfWeekString = (day) => {
return ["ВС","ПН","ВТ","СР","ЧТ","ПТ","СБ"][day];
}
const getDayOfWeekNumber = (day) => {
return new Date(year, month, day).getDay()
}
const setNewMonthDays = () => {
const newDaysInMonth = []
for (let i = 1; i <= getDaysInMonth(); i++) {
const dayOfWeekNumber = getDayOfWeekNumber(i)
newDaysInMonth.push({dayNumber: i, dayOfWeek: getDayOfWeekString(dayOfWeekNumber)})
}
setDaysInMonth(prevState=>newDaysInMonth)
}
return ( return (
<> <>
...@@ -94,7 +39,7 @@ function MonthCalendarBody({month, year, tasks, createTaskInCellHandler, current ...@@ -94,7 +39,7 @@ function MonthCalendarBody({month, year, tasks, createTaskInCellHandler, current
labelPlacement="end" labelPlacement="end"
/> />
</CalendarSmallCell> </CalendarSmallCell>
{hoursInDay.map((hours, i)=>{ {hoursInDay?.map((hours, i)=>{
return ( return (
<CalendarStandartCell key={i} xs={cellSizes.standarCell}> <CalendarStandartCell key={i} xs={cellSizes.standarCell}>
{hours} {hours}
...@@ -102,7 +47,7 @@ function MonthCalendarBody({month, year, tasks, createTaskInCellHandler, current ...@@ -102,7 +47,7 @@ function MonthCalendarBody({month, year, tasks, createTaskInCellHandler, current
) )
})} })}
</CalendarRow> </CalendarRow>
{daysInMonth.map((day, i)=>{ {daysInMonth?.map((day, i)=>{
return ( return (
<CalendarRow <CalendarRow
key={i} key={i}
......
import { Box, Typography } from '@mui/material';
import { memo } from 'react';
import MonthDecrementButton from './MonthDecrementButton/MonthDecrementButton';
import MonthIncrementButton from './MonthIncrementButton/MonthIncrementButton';
function MonthAndYearInfo({getCurrentMonthString, year, incrementMonth, decrementMonth}) {
return (
<>
<Box
sx={{
flexGrow: 1,
display: 'flex',
alignItems: 'center',
gap: '10px'
}}
>
<MonthDecrementButton
decrementMonth={decrementMonth}
/>
<Box sx={{ flexBasis: '150px' }}>
<Typography
variant="h6"
sx={{
display: 'flex',
justifyContent: 'center',
}}
>
{getCurrentMonthString}
</Typography>
<Typography align='center'>{year}</Typography>
</Box>
<MonthIncrementButton
incrementMonth={incrementMonth}
/>
</Box>
</> );
}
export default memo(MonthAndYearInfo);
\ No newline at end of file
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
import { memo } from 'react';
const arrowClass = {
borderRadius: '50%',
cursor: 'pointer',
transition: '0.5s',
"&:hover": {
background: 'rgb(48, 154, 252, 0.65)',
transition: '0.5s',
transform: 'scale(1.2)'
}
}
function MonthDecrementButton({decrementMonth}) {
return (
<>
<ArrowBackIcon
sx={arrowClass}
onClick={decrementMonth}
/>
</> );
}
export default memo(MonthDecrementButton);
\ No newline at end of file
import ArrowForwardIcon from '@mui/icons-material/ArrowForward';
import { memo } from 'react';
const arrowClass = {
borderRadius: '50%',
cursor: 'pointer',
transition: '0.5s',
"&:hover": {
background: 'rgb(48, 154, 252, 0.65)',
transition: '0.5s',
transform: 'scale(1.2)'
}
}
function MonthIncrementButton({incrementMonth}) {
return (
<>
<ArrowForwardIcon
sx={arrowClass}
onClick={incrementMonth}
/>
</> );
}
export default memo(MonthIncrementButton);
\ No newline at end of file
import { AppBar, FormControl, InputLabel, MenuItem, Select, Toolbar, Typography } from '@mui/material'; import { AppBar, Toolbar} from '@mui/material';
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
import ArrowForwardIcon from '@mui/icons-material/ArrowForward';
import { Box } from '@mui/system'; import { Box } from '@mui/system';
import MonthAndYearInfo from './MonthAndYearInfo/MonthAndYearInfo';
import СustomSelect from '../UI/СustomSelect/СustomSelect'
const arrowClass = { const workers = [{value: '', text: '--выберите сотрудника'}, {value: 'Василий', text: 'Василий'}, {value: 'Никита', text: 'Никита'}]
borderRadius: '50%', const types = [{value: 'Месяц', text: 'Месяц'}, {value: 'Неделя', text: 'Неделя'}]
cursor: 'pointer',
transition: '0.5s',
"&:hover": {
background: 'rgb(48, 154, 252, 0.65)',
transition: '0.5s',
transform: 'scale(1.2)'
}
}
function MonthCalendarHeader({month, getCurrentMonthString, decrementMonth, incrementMonth, calendarType, onChangeWorkerHandler, onChangeCalendarTypeHandler, worker, year}) { function MonthCalendarHeader({ getCurrentMonthString, decrementMonth, incrementMonth, calendarType, onChangeWorkerHandler, onChangeCalendarTypeHandler, worker, year}) {
return ( return (
<> <>
<Box sx={{ flexGrow: 1 }}> <Box sx={{ flexGrow: 1 }}>
<AppBar position="static"> <AppBar position="static">
<Toolbar> <Toolbar>
<Box
sx={{ <MonthAndYearInfo
flexGrow: 1, getCurrentMonthString={getCurrentMonthString}
display: 'flex', decrementMonth={decrementMonth}
alignItems: 'center', incrementMonth={incrementMonth}
gap: '10px' year={year}
}} />
> <СustomSelect
<ArrowBackIcon value={worker}
onClick={()=>{decrementMonth()}} onChange={(e)=>{onChangeWorkerHandler(e)}}
sx={arrowClass} label={'Сотрудник'}
/> id={'worker'}
<Box sx={{ flexBasis: '150px' }}> items={workers}
<Typography />
variant="h6"
sx={{
display: 'flex',
justifyContent: 'center',
}}
>
{getCurrentMonthString(month)}
</Typography>
<Typography align='center'>{year}</Typography>
</Box>
<ArrowForwardIcon
sx={arrowClass}
onClick={()=>{incrementMonth()}}
/>
</Box>
<FormControl variant="standard" sx={{ m: 1, minWidth: 120 }}>
<InputLabel id="worker-select-label">Сотрудник</InputLabel>
<Select
labelId="worker-select-label"
id="worker-select"
value={worker}
onChange={(e)=>{onChangeWorkerHandler(e)}}
label="Worker"
>
<MenuItem value="">
<em>-- Выберите сотрудника --</em>
</MenuItem>
<MenuItem value={"Василий"}>Василий</MenuItem>
<MenuItem value={"Никита"}>Никита</MenuItem>
<MenuItem value={"Артем"}>Артем</MenuItem>
</Select>
</FormControl>
<FormControl variant="standard" sx={{ m: 1, minWidth: 120 }}>
<InputLabel id="calendar-type-label">Календарь</InputLabel>
<Select
labelId="calendar-type-label"
id="calendar-type"
value={calendarType}
onChange={(e)=>{onChangeCalendarTypeHandler(e)}}
label="Type"
>
<MenuItem value={"Месяц"}>Месяц</MenuItem>
<MenuItem value={"Неделя"}>Неделя</MenuItem>
</Select>
</FormControl>
<СustomSelect
value={calendarType}
onChange={(e)=>{onChangeCalendarTypeHandler(e)}}
label={'Календарь'}
id={'calendar-type'}
items={types}
/>
</Toolbar> </Toolbar>
</AppBar> </AppBar>
</Box> </Box>
......
import { FormControl, InputLabel, MenuItem, Select} from '@mui/material';
import { memo } from 'react';
function СustomSelect({value, onChange, label, variant='standard', items, id}) {
return (
<>
<FormControl variant={variant} sx={{ m: 1, minWidth: 120 }}>
<InputLabel id={id + '-select' + '-label'}>{label}</InputLabel>
<Select
labelId={id + '-select'+ '-label'}
id={id + '-select'}
value={value}
onChange={onChange}
label={label}
>
{items.map((item, i)=>{
return (
<MenuItem
key={i}
value={item?.value}
>{item?.text}</MenuItem>
)
})}
</Select>
</FormControl>
</> );
}
export default memo(СustomSelect, (prevProps, nextProps)=>{
if(prevProps.value !== nextProps.value) {
return false
} else {
return true
}
});
\ No newline at end of file
import { Button, Grid} from "@mui/material";
import { NavLink } from "react-router-dom";
import FormElement from "../UI/Form/FormElement/FormElement";
const ResetPasswordForm = ({ state, onChange, onSubmit, getFieldError, buttonText }) => {
return <form onSubmit={onSubmit}>
<Grid container spacing={2}>
<FormElement
onChange={onChange}
name="email"
label="Enter your email address"
state={state}
error={getFieldError?.("email")}
/>
</Grid>
<Button
sx={{ mt: "15px" }}
type="submit"
fullWidth
variant="contained"
color="primary"
>
{buttonText}
</Button>
</form>
}
export default ResetPasswordForm;
\ No newline at end of file
import { Button, Grid} from "@mui/material"; import { Button, Grid} from "@mui/material";
// import { NavLink } from "react-router-dom"; import { NavLink } from "react-router-dom";
import FormElement from "../UI/Form/FormElement/FormElement"; import FormElement from "../UI/Form/FormElement/FormElement";
const UserForm = ({ state, onChange, onSubmit, getFieldError, buttonText, resetPassword }) => { const UserForm = ({ state, onChange, onSubmit, getFieldError, buttonText, resetPassword }) => {
...@@ -30,17 +30,17 @@ const UserForm = ({ state, onChange, onSubmit, getFieldError, buttonText, resetP ...@@ -30,17 +30,17 @@ const UserForm = ({ state, onChange, onSubmit, getFieldError, buttonText, resetP
> >
{buttonText} {buttonText}
</Button> </Button>
{/* <Button <Button
component={NavLink} component={NavLink}
to={"/forgottenpassword"} to={"/forgottenpassword"}
sx={{ mt: "15px" }} sx={{ mt: "15px", color: "red" }}
type="submit" type="submit"
fullWidth fullWidth
variant="contained" variant="contained"
color="primary" color="inherit"
> >
{resetPassword} {resetPassword}
</Button> */} </Button>
</form> </form>
} }
......
...@@ -25,13 +25,13 @@ const UserRegistrationForm = ({ state, onChange, onSubmit, getFieldError, button ...@@ -25,13 +25,13 @@ const UserRegistrationForm = ({ state, onChange, onSubmit, getFieldError, button
state={state} state={state}
error={getFieldError?.("email")} error={getFieldError?.("email")}
/> />
<FormElement {/* <FormElement
onChange={onChange} onChange={onChange}
name="number" name="number"
label="Number" label="Number"
state={state} state={state}
error={getFieldError?.("number")} error={getFieldError?.("number")}
/> /> */}
<FormElement <FormElement
onChange={onChange} onChange={onChange}
name="password" name="password"
...@@ -40,12 +40,14 @@ const UserRegistrationForm = ({ state, onChange, onSubmit, getFieldError, button ...@@ -40,12 +40,14 @@ const UserRegistrationForm = ({ state, onChange, onSubmit, getFieldError, button
state={state} state={state}
error={getFieldError?.("password")} error={getFieldError?.("password")}
/> />
{/* <FormElement <FormElement
onChange={onChange} onChange={onChange}
name="displayName" name="confirmPassword"
label="DisplayName" label="Confirm password"
type="password"
state={state} state={state}
/> */} error={getFieldError?.("password")}
/>
{/* <FormElement {/* <FormElement
onChange={fileChangeHandler} onChange={fileChangeHandler}
name="avatar" name="avatar"
......
// import { useState } from "react"; import { useState } from "react";
// import { useDispatch, useSelector } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
// import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
// import Loader from "../../components/UI/Loader/Loader"; import Loader from "../../components/UI/Loader/Loader";
// import UserForm from "../../components/UserForm/UserForm"; import { loginUser } from "../../store/actions/usersActions";
// import { loginUser } from "../../store/actions/usersActions"; import PersonIcon from '@mui/icons-material/Person';
// import PersonIcon from '@mui/icons-material/Person'; import styled from "@emotion/styled";
// import styled from "@emotion/styled"; import { Alert, Avatar, Container, Typography } from "@mui/material";
// import { Alert, Avatar, Container, Typography } from "@mui/material"; import ResetPasswordForm from "../../components/UserForm/ResetPasswordForm";
// const StyledContainer = styled(Container)` const StyledContainer = styled(Container)`
// padding-top: 30px; padding-top: 30px;
// padding-bottom: 30px; padding-bottom: 30px;
// box-shadow: 0 18px 30px 0 rgba(0, 0, 0, 0.6); box-shadow: 0 18px 30px 0 rgba(0, 0, 0, 0.6);
// border-radius: 6px; border-radius: 6px;
// `; `;
// const StyledTitle = styled(Typography)` const StyledTitle = styled(Typography)`
// text-align: center; text-align: center;
// font-size: 30px; font-size: 30px;
// margin-bottom: 30px; margin-bottom: 30px;
// `; `;
// const ForgottenPassword = () => { const ForgottenPassword = () => {
// const [state, setState] = useState({ const [state, setState] = useState({
// email: '', email: '',
// redirectUrl: 'http://localhost:3000/passwordreset' redirectUrl: 'http://localhost:3000/passwordreset'
// }); });
// const dispatch = useDispatch(); const dispatch = useDispatch();
// const { loginError, loading } = useSelector(state => state.users); const { loginError, loading } = useSelector(state => state.users);
// console.log(loginError) console.log(loginError)
// const navigate = useNavigate("/") const navigate = useNavigate("/")
// const inputChangeHandler = (e) => { const inputChangeHandler = (e) => {
// const { name, value } = e.target; const { name, value } = e.target;
// setState((prevState) => { setState((prevState) => {
// return { return {
// ...prevState, ...prevState,
// [name]: value [name]: value
// } }
// }); });
// }; };
// const submitHandler = async (e) => { const submitHandler = async (e) => {
// e.preventDefault(); e.preventDefault();
// await dispatch(loginUser(state, navigate)); await dispatch(loginUser(state, navigate));
// }; };
// return <> return <>
// <StyledContainer component={"section"} maxWidth={"xs"}> <StyledContainer component={"section"} maxWidth={"xs"}>
// {!!loginError && <Alert color="error">{loginError}</Alert>} {!!loginError && <Alert color="error">{loginError}</Alert>}
// <Avatar sx={{ m: "0 auto 30px" }}> <Avatar sx={{ m: "0 auto 30px" }}>
// <PersonIcon /> <PersonIcon />
// </Avatar> </Avatar>
// <StyledTitle variant={"h1"}> <StyledTitle variant={"h1"}>
// Password Reset Password Reset
// </StyledTitle> </StyledTitle>
// <UserForm <ResetPasswordForm
// onSubmit={submitHandler} onSubmit={submitHandler}
// state={state} state={state}
// onChange={inputChangeHandler} onChange={inputChangeHandler}
// buttonText={"Sign In"} buttonText={"Submit"}
// resetPassword={"Forgot your password?"} resetPassword={"Forgot your password?"}
// /> />
// </StyledContainer> </StyledContainer>
// <Loader loading={loading} /> <Loader loading={loading} />
// </> </>
// }; };
// export default ForgottenPassword; export default ForgottenPassword;
\ No newline at end of file \ No newline at end of file
...@@ -62,7 +62,7 @@ const Login = () => { ...@@ -62,7 +62,7 @@ const Login = () => {
state={state} state={state}
onChange={inputChangeHandler} onChange={inputChangeHandler}
buttonText={"Sign In"} buttonText={"Sign In"}
// resetPassword={"Forgot your password?"} resetPassword={"Forgot your password?"}
/> />
</StyledContainer> </StyledContainer>
<Loader loading={loading} /> <Loader loading={loading} />
......
import { useEffect, useState } from 'react'; import { useEffect, useCallback, useState, useMemo } from 'react';
import { useDispatch, useSelector } from 'react-redux'; 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';
...@@ -9,58 +9,84 @@ function MonthCalendar() { ...@@ -9,58 +9,84 @@ function MonthCalendar() {
const { calendarTasks } = useSelector(state => state.tasks); const { calendarTasks } = useSelector(state => state.tasks);
const [hourFormat, setHourFormat] = useState(false); const [hourFormat, setHourFormat] = useState(false);
const [month, setMonth] = useState('') const [dateNow, setDateNow] = useState({month: '', year: ''})
const [year, setYear] = useState('')
const [worker, setWorker] = useState(''); const [worker, setWorker] = useState('');
const [calendarType, setCalendarType] = useState('Месяц'); const [calendarType, setCalendarType] = useState('Месяц');
const [currentTask, setCurrentTask] = useState({title: '', description: '', priority: null, dateTimeStart: '', dateTimeDue:''}) const [currentTask, setCurrentTask] = useState({title: '', description: '', priority: ''})
const [cellSizes, setCellSizes] = useState({})
useEffect(()=>{ useEffect(()=>{
setMonth(new Date().getMonth()) setDateNow({
setYear(new Date().getFullYear()) month: new Date().getMonth(),
year: new Date().getFullYear(),
})
dispatch(fetchCalendarTasks()) dispatch(fetchCalendarTasks())
}, [dispatch]) }, [dispatch])
const onChangeWorkerHandler = (event) => {
const hoursInDay = useMemo(()=>{
if (hourFormat) {
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']
const cells = arr.length
const xs = 10.8/cells
setCellSizes(()=>{
return {smallCell: 0.6, standarCell: xs}
})
return 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}
})
return arr
}
}, [hourFormat])
const daysInMonth = useMemo(() => {
const newDaysInMonth = []
const daysInMonthNumber = new Date(dateNow.year, dateNow.month + 1, 0).getDate()
for (let i = 1; i <= daysInMonthNumber; i++) {
const dayOfWeekNumber = new Date(dateNow.year, dateNow.month, i).getDay()
const getDayOfWeekString = ["ВС","ПН","ВТ","СР","ЧТ","ПТ","СБ"][dayOfWeekNumber]
newDaysInMonth.push({dayNumber: i, dayOfWeek: getDayOfWeekString})
}
return newDaysInMonth
}, [dateNow.month, dateNow.year])
const onChangeWorkerHandler = useCallback((event) => {
setWorker(event.target.value); setWorker(event.target.value);
}; }, []);
const onChangeCalendarTypeHandler = (event) => { const onChangeCalendarTypeHandler = useCallback((event) => {
setCalendarType(event.target.value); setCalendarType(event.target.value);
}; }, []);
const getCurrentMonthString = (month) => { const getCurrentMonthString = useMemo(() => {
return ["Январь","Февраль","Март","Апрель","Май","Июнь","Июль","Август","Сентябрь","Октябрь","Ноябрь", "Декабрь"][month]; return ["Январь","Февраль","Март","Апрель","Май","Июнь","Июль","Август","Сентябрь","Октябрь","Ноябрь", "Декабрь"][dateNow.month];
} }, [dateNow.month])
const incrementMonth = () => { const incrementMonth = useCallback(() => {
setMonth((prevState)=>{ setDateNow((prevState)=>{
if (prevState + 1 === 12 ) { if (prevState.month + 1 === 12 ) {
setYear(prevState=>prevState+1) return { month: 0, year: prevState.year + 1}
return 0
} }
return prevState + 1 return {...prevState, month: prevState.month + 1}
}) })
} }, [])
const decrementMonth = () => { const decrementMonth = useCallback(() => {
setMonth((prevState)=>{ setDateNow((prevState)=>{
if (prevState - 1 === -1) { if (prevState.month - 1 === -1) {
setYear(prevState=>prevState-1) return { month: 11, year: prevState.year - 1}
return 11
} }
return prevState - 1 return {...prevState, month: prevState.month - 1}
}) })
} }, [])
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 onChangeCurrentTaskHandler = (e) => { const onChangeCurrentTaskHandler = useCallback((e) => {
const {name, value} = e.target; const {name, value} = e.target;
setCurrentTask((prevState) => { setCurrentTask((prevState) => {
return { return {
...@@ -68,8 +94,14 @@ function MonthCalendar() { ...@@ -68,8 +94,14 @@ function MonthCalendar() {
[name]: value [name]: value
} }
}); });
}; }, []);
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 createTaskInCellHandler = (dayNumber, dayHour) => {
const hour = parseInt(dayHour.split(':')[0]) const hour = parseInt(dayHour.split(':')[0])
let hourDue let hourDue
...@@ -82,14 +114,13 @@ function MonthCalendar() { ...@@ -82,14 +114,13 @@ function MonthCalendar() {
title:"Задача", title:"Задача",
description:"описание", description:"описание",
priority: null, priority: null,
dateTimeStart: dateToISOLikeButLocal(new Date(year, month, dayNumber, hour, 0)), dateTimeStart: dateToISOLikeButLocal(new Date(dateNow.year, dateNow.month, dayNumber, hour, 0)),
dateTimeDue: dateToISOLikeButLocal(new Date(year, month, dayNumber, hourDue, 59)), dateTimeDue: dateToISOLikeButLocal(new Date(dateNow.year, dateNow.month, dayNumber, hourDue, 59)),
} }
setCurrentTask((newTask)) setCurrentTask((newTask))
} }
const sendNewTaskHandler = async () => { const sendNewTaskHandler = async () => {
if (currentTask.id) { if (currentTask.id) {
setCurrentTask(() => { setCurrentTask(() => {
return{ return{
...@@ -104,6 +135,7 @@ function MonthCalendar() { ...@@ -104,6 +135,7 @@ function MonthCalendar() {
...currentTask, ...currentTask,
}} }}
) )
console.log(currentTask)
delete currentTask.infoForCell delete currentTask.infoForCell
await dispatch(addTask(currentTask)) await dispatch(addTask(currentTask))
} }
...@@ -116,8 +148,7 @@ function MonthCalendar() { ...@@ -116,8 +148,7 @@ function MonthCalendar() {
return ( return (
<> <>
<MonthCalendarHeader <MonthCalendarHeader
month={month} year={dateNow.year}
year={year}
getCurrentMonthString={getCurrentMonthString} getCurrentMonthString={getCurrentMonthString}
decrementMonth={decrementMonth} decrementMonth={decrementMonth}
incrementMonth={incrementMonth} incrementMonth={incrementMonth}
...@@ -127,8 +158,8 @@ function MonthCalendar() { ...@@ -127,8 +158,8 @@ function MonthCalendar() {
calendarType={calendarType} calendarType={calendarType}
/> />
<MonthCalendarBody <MonthCalendarBody
month={month} month={dateNow.month}
year={year} year={dateNow.year}
tasks={calendarTasks} tasks={calendarTasks}
createTaskInCellHandler={createTaskInCellHandler} createTaskInCellHandler={createTaskInCellHandler}
setCurrentTask={setCurrentTask} setCurrentTask={setCurrentTask}
...@@ -138,7 +169,11 @@ function MonthCalendar() { ...@@ -138,7 +169,11 @@ function MonthCalendar() {
onChangeCurrentTaskHandler={onChangeCurrentTaskHandler} onChangeCurrentTaskHandler={onChangeCurrentTaskHandler}
sendNewTaskHandler={sendNewTaskHandler} sendNewTaskHandler={sendNewTaskHandler}
deleteTaskHandler={deleteTaskHandler} deleteTaskHandler={deleteTaskHandler}
cellSizes={cellSizes}
hoursInDay={hoursInDay}
daysInMonth={daysInMonth}
/> />
</> </>
); );
} }
......
...@@ -3,7 +3,7 @@ import { useDispatch, useSelector } from "react-redux"; ...@@ -3,7 +3,7 @@ import { useDispatch, useSelector } from "react-redux";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import Loader from "../../components/UI/Loader/Loader"; import Loader from "../../components/UI/Loader/Loader";
import UserForm from "../../components/UserForm/UserRegistrationForm"; import UserForm from "../../components/UserForm/UserRegistrationForm";
import { loginUser, registerUser } from "../../store/actions/usersActions"; import { registerUser } from "../../store/actions/usersActions";
import styled from "@emotion/styled"; import styled from "@emotion/styled";
import { Avatar, Container, Typography } from "@mui/material"; import { Avatar, Container, Typography } from "@mui/material";
import LockIcon from "@mui/icons-material/Lock"; import LockIcon from "@mui/icons-material/Lock";
...@@ -26,8 +26,9 @@ const Register = () => { ...@@ -26,8 +26,9 @@ const Register = () => {
name: '', name: '',
surname: "", surname: "",
email: "", email: "",
number: "", // number: "",
password: '', password: '',
confirmPassword: "",
// avatar: "", // avatar: "",
}); });
...@@ -62,9 +63,14 @@ const Register = () => { ...@@ -62,9 +63,14 @@ const Register = () => {
const formData = new FormData(); const formData = new FormData();
Object.keys(state).forEach(key => { Object.keys(state).forEach(key => {
formData.append(key, state[key]); formData.append(key, state[key]);
console.log("key " + key + "state " + state[key])
}) })
await dispatch(registerUser(formData, navigate)); if (state["password"] === state["confirmPassword"]) {
await dispatch(loginUser(state, navigate)) await dispatch(registerUser(formData, navigate));
} else {
alert("Пароли не совпадают")
}
}; };
const getFieldError = (fieldname) => { const getFieldError = (fieldname) => {
......
...@@ -18,7 +18,9 @@ export const registerUser = (userData, navigate) => { ...@@ -18,7 +18,9 @@ export const registerUser = (userData, navigate) => {
return async (dispatch) => { return async (dispatch) => {
dispatch(registerUserRequest()); dispatch(registerUserRequest());
try { try {
console.log("register " + userData)
const response = await axios.post("/users", userData); const response = await axios.post("/users", userData);
console.log(response)
dispatch(registerUserSuccess()) dispatch(registerUserSuccess())
navigate("/") navigate("/")
} catch (error) { } catch (error) {
...@@ -49,7 +51,25 @@ const logoutUserFailure = (error) => { ...@@ -49,7 +51,25 @@ const logoutUserFailure = (error) => {
export const loginUser = (userData, navigate) => { export const loginUser = (userData, navigate) => {
return async (dispatch) => { return async (dispatch) => {
try { try {
console.log(userData)
const response = await axios.post("users/sessions", userData); const response = await axios.post("users/sessions", userData);
console.log(response)
dispatch(loginUserSuccess(response.data.user));
navigate("/")
} catch (e) {
dispatch(loginUserFailure(e?.response?.data?.err))
}
}
}
export const forgottenPassword = (userData, navigate) => {
return async (dispatch) => {
try {
console.log(userData)
const response = await axios.post("users/requestPasswordReset", userData);
// if (userData.email === response.data.email) {
// }
dispatch(loginUserSuccess(response.data)); dispatch(loginUserSuccess(response.data));
navigate("/") navigate("/")
} catch (e) { } catch (e) {
......
import { REGISTER_USER_REQUEST, REGISTER_USER_SUCCESS, REGISTER_USER_FAILURE, LOGIN_USER_SUCCESS, LOGIN_USER_FAILURE, LOGOUT_USER_SUCCESS } from "../actionTypes/actionTypes"; import { REGISTER_USER_REQUEST, REGISTER_USER_SUCCESS, REGISTER_USER_FAILURE, LOGIN_USER_SUCCESS, LOGIN_USER_FAILURE, LOGOUT_USER_SUCCESS } from "../actionTypes/actionTypes";
const initialState = { const initialState = {
user: { user: null,
name: 'Ivan',
surname: 'Petrov',
email: 'test@gmail.com',
role: 'superuser'
},
registerError: null, registerError: null,
loginError: null, loginError: null,
loading: false loading: false
...@@ -17,12 +12,15 @@ const usersReducer = (state = initialState, action) => { ...@@ -17,12 +12,15 @@ const usersReducer = (state = initialState, action) => {
case REGISTER_USER_REQUEST: case REGISTER_USER_REQUEST:
return {...state, loading: true}; return {...state, loading: true};
case REGISTER_USER_SUCCESS: case REGISTER_USER_SUCCESS:
console.log("register.user " + action)
return {...state, loading: false}; return {...state, loading: false};
case REGISTER_USER_FAILURE: case REGISTER_USER_FAILURE:
return {...state, loading: false, registerError: action.error}; return {...state, loading: false, registerError: action.error};
case LOGIN_USER_SUCCESS: case LOGIN_USER_SUCCESS:
console.log("action.user " + action)
return {...state, user: action.user}; return {...state, user: action.user};
case LOGIN_USER_FAILURE: case LOGIN_USER_FAILURE:
console.log("action.error" + action.error)
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};
......
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