Merge branch 'development' of…

Merge branch 'development' of ssh://git.attractor-school.com:30022/apollo64/crm-team-one into task-123-fix/invalid_Date
parents 08d099e0 5bca45a0
......@@ -22,7 +22,7 @@ router.post("/make-copy",auth,authAuthorOrExecutorOfTask, async(req:Request, res
/** change date time of copy of task in calendar view */
router.put("/change-copy/:dateTimeTaskId",auth, authAuthorOrExecutorOfTask, async(req:Request, res: Response):Promise<Response>=>{
const {dateTimeTaskId} = req.params
const {executorStatus,authorStatus, task, dateTimeStart, dateTimeDue, description, title, priority} = req.body
const {executorStatus,authorStatus, task, dateTimeStart, dateTimeDue, description, title, priority, project} = req.body
if(authorStatus){
task.title = title;
task.description = description;
......@@ -73,6 +73,7 @@ router.put("/change-copy/:dateTimeTaskId",auth, authAuthorOrExecutorOfTask, asyn
task.title = title;
task.description = description;
task.priority = priority;
task.project = project
await task.save()
return res.send({task})
})
......
import { Button, TextField } from "@mui/material";
import { memo } from "react";
import { priorities } from "../../../constants";
import CustomSelect from '../../UI/СustomSelect/СustomSelect'
import { isValidate } from "./Helpers";
function CalendarModalTaskContent({ title, onChangeCurrentTaskHandler, description, priority, sendNewTaskHandler, deleteTaskHandler, startHour, endHour, id }) {
return (<>
<TextField
id="task-description-title"
value={title}
label="Название"
variant="outlined"
sx={{ marginBottom: '30px' }}
name='title'
onChange={(e) => { onChangeCurrentTaskHandler(e) }}
/>
<TextField
id="task-description"
multiline
rows={4}
value={description}
label="Описание"
variant="outlined"
sx={{ marginBottom: '30px' }}
name='description'
onChange={(e) => { onChangeCurrentTaskHandler(e) }}
/>
<CustomSelect
defaultValue={null}
value={priority}
name={'priority'}
variant={'outlined'}
onChange={(e) => { onChangeCurrentTaskHandler(e) }}
label={'Приоритет'}
id={'priority-type'}
items={priorities}
/>
<div style={{ display: 'flex', gap: '20px', margin: '20px 0' }}>
<TextField
id="task-startHour"
value={startHour}
label="От"
variant="outlined"
name='startHour'
onChange={(e) => { onChangeCurrentTaskHandler(e) }}
/>
<TextField
id="task-endHour"
value={endHour}
label="До"
variant="outlined"
name='endHour'
onChange={(e) => { onChangeCurrentTaskHandler(e) }}
/>
</div>
<div style={{ display: 'flex', gap: '20px', margin: '10px 0' }}>
<Button id='test_button_save_task' onClick={sendNewTaskHandler} disabled={!isValidate(title, startHour, endHour)}>Сохранить</Button>
<Button onClick={deleteTaskHandler} disabled={!id}>Удалить</Button>
</div>
</>);
}
export default memo(CalendarModalTaskContent);
\ No newline at end of file
import { Grid } from "@mui/material";
import { memo, useMemo } from "react";
import { memo, useEffect, useMemo, useRef, useState } from "react";
import { getHoursInDayNumbers, getAvailableTasks, getLinesInDay, getSortedTasks } from "../../../../../helpers/CalendarHelpers";
import CalendarStandartCell from "../../../CalendarStandartCell/CalendarStandartCell";
import CalendarStandartCell from "../../../UI/CalendarStandartCell/CalendarStandartCell";
import CalendarTask from "../CalendarTask/CalendarTask";
import EmptyBox from "./EmptyBox/EmptyBox";
import { getBoxesInLine } from "./Helpers";
import { getTasksWithInfoForPosition } from "./Helpers";
const CalendarRowDay = ({ xs, hoursInDay, createTaskInCellHandler, currentTask, handleOpen, modal, setCurrentTask, year, month, tasks, day, hourFormat, setCurrentLine, currentLine, dragTaskHandler, createCopyTask, setCopyTask, copyTask }) => {
const CalendarRowDay = ({ xs, hoursInDay, createTaskInCellHandler, currentTask, handleOpen, modal, setCurrentTask, year, month, tasks, day, hourFormat, dragTaskHandler, createCopyTask, setCopyTask, copyTask }) => {
const [rowDaySize, setRowDaySize] = useState({ width: 0, height: 0 })
const dayRowRef = useRef('')
useEffect(() => {
setRowDaySize(prev => { return { height: dayRowRef.current.offsetHeight, width: dayRowRef.current.offsetWidth } })
}, [hourFormat])
const hours = useMemo(() => {
return getHoursInDayNumbers(hoursInDay)
......@@ -31,7 +36,35 @@ const CalendarRowDay = ({ xs, hoursInDay, createTaskInCellHandler, currentTask,
xs={10.8}
align='center'
sx={{ position: 'relative' }}
ref={dayRowRef}
>
{linesInDay?.map((line, i) => {
const tasks = getTasksWithInfoForPosition(line, hoursInDay, sortedTasks, i, rowDaySize.width)
return (<>
{tasks.map((task) => {
const step = rowDaySize.width / hoursInDay.length
return (
<CalendarTask
key={task.task.id}
width={task.width}
left={task.left}
task={task.task}
top={task.top}
handleOpen={handleOpen}
setCurrentTask={setCurrentTask}
modal={modal}
month={month}
setCopyTask={setCopyTask}
dragTaskHandler={dragTaskHandler}
hourFormat={hourFormat}
step={step}
>
</CalendarTask>
)
})}
</>)
})}
{hoursInDay.map((hour, i) => {
return (
<CalendarStandartCell
......@@ -45,79 +78,16 @@ const CalendarRowDay = ({ xs, hoursInDay, createTaskInCellHandler, currentTask,
currentTask={currentTask}
handleOpen={handleOpen}
modal={modal}
>
</CalendarStandartCell>
)
})}
<Grid sx={{ position: 'absolute', top: '0' }} container item xs={12}>
{linesInDay?.map((line, i) => {
const boxes = getBoxesInLine(line, hoursInDay, sortedTasks)
return (
<Grid key={i} container sx={{ height: '35px', backgroundColor: 'rgb(0,0,0,0)', marginBottom: '5px' }}>
{boxes.map((box, index) => {
if (box.task) {
return (<Grid
item xs={box.xs}
key={box.task.id}
sx={{ height: '35px', marginBottom: '5px' }}
>
<CalendarTask
dragTaskHandler={dragTaskHandler}
setCurrentLine={() => { setCurrentLine(day.dayNumber) }}
currentTask={currentTask}
currentLine={currentLine}
hour={parseInt(hours[index])}
line={day.dayNumber}
task={box.task}
setCurrentTask={setCurrentTask}
handleOpen={handleOpen}
setCopyTask={setCopyTask}
/>
</Grid>)
} else {
return (<EmptyBox
key={index}
modal={modal}
dayNumber={day.dayNumber}
hourNumber={box.hour}
handleOpen={handleOpen}
dragTaskHandler={dragTaskHandler}
createCopyTask={createCopyTask}
copyTask={copyTask}
createTaskInCellHandler={createTaskInCellHandler}
xs={box.xs}
>
</EmptyBox>)
}
})}
</Grid>)
})}
</Grid>
<Grid container sx={{ height: '35px', backgroundColor: 'rgb(0,0,0,0)', marginBottom: '5px', position: 'absolute', bottom: '0' }}>
{hoursInDay.map((hour, i) => {
const hourNumber = parseInt(hour)
return (<EmptyBox
key={i}
modal={modal}
dayNumber={day.dayNumber}
hourNumber={hourNumber}
handleOpen={handleOpen}
dragTaskHandler={dragTaskHandler}
createCopyTask={createCopyTask}
copyTask={copyTask}
createTaskInCellHandler={createTaskInCellHandler}
xs={xs}
month={month}
>
</EmptyBox>)
</CalendarStandartCell>
)
})}
</Grid>
</Grid>
</>
};
export default memo(CalendarRowDay, (prevProps, nextProps) => {
if (!prevProps.modal) return false
if (nextProps.modal) return true
});
export default memo(CalendarRowDay);
import { Grid } from "@mui/material";
import React, { memo, useEffect, useState } from "react";
import DefaultTask from "../../../../DefaultTask/DefaultTask";
const EmptyBox = ({ hourNumber, handleOpen, dayNumber, xs, dragTaskHandler, modal, createTaskInCellHandler, copyTask, createCopyTask }) => {
const [isThisCell, setIsThisCell] = useState(false)
useEffect(() => {
if (!modal) {
setIsThisCell(false);
}
}, [modal])
const onClickHandler = (e, dayNumber, hour) => {
if (copyTask) {
createCopyTask(dayNumber, hour)
} else {
createTaskInCellHandler(dayNumber, hour);
setIsThisCell(true);
handleOpen(e)
}
}
const dragOverHandler = (e) => {
e.preventDefault();
}
const dropHandler = (e) => {
e.stopPropagation()
e.preventDefault();
dragTaskHandler(dayNumber, hourNumber)
}
return (<Grid
onDragOver={(e) => { dragOverHandler(e) }}
onDrop={(e) => { dropHandler(e) }}
onClick={(e) => { onClickHandler(e, dayNumber, hourNumber) }}
className='test_empty_box'
item xs={xs} sx={{
height: '40px',
backgroundColor: 'rgb(0,0,0,0)',
zIndex: '6',
cursor: copyTask ? 'pointer' : 'default'
}}>
{isThisCell ?
<DefaultTask /> : ' '}
</Grid>)
};
export default memo(EmptyBox, (prevProps, nextProps) => {
if (!prevProps.modal) return false
if (nextProps.modal) return true
});
\ No newline at end of file
export const getBoxesInLine = (line, hoursInDay, sortedTasks) => {
export const getTasksWithInfoForPosition = (line, hoursInDay, sortedTasks, index, rowDayWidth) => {
const widthStep = rowDayWidth / hoursInDay.length
if (line) {
let xs = 12/hoursInDay.length
const boxes = []
const tasks = []
for (let i = 0; i < line.length; i++) {
if (!isNaN(line[i])) {
// if (boxes[boxes.length -1]?.task === null) {
// boxes[boxes.length -1].xs += xs
// } else {
boxes.push({xs: xs, task: null, hour: line[i]})
// }
} else {
const task = sortedTasks[line[i].split('-')[1]]
const taskIsThere = boxes.find((taskFind)=>{
const taskIsThere = tasks.find((taskFind) => {
if (taskFind?.task?.id === task.id) return taskFind
return false
})
if (taskIsThere) {
taskIsThere.xs +=xs
if (!taskIsThere) {
tasks.push({
width: widthStep,
top: index * 40,
left: i * widthStep,
task: sortedTasks[line[i].split('-')[1]]
})
} else {
boxes.push({
xs: xs,
task: sortedTasks[line[i].split('-')[1]]})
taskIsThere.width += widthStep
}
}
}
return boxes
return tasks
}
}
\ No newline at end of file
import { Grid } from "@mui/material";
import React, { memo, useEffect, useState } from "react";
import ContentCopyIcon from '@mui/icons-material/ContentCopy';
import React, { memo, useCallback, useMemo } from "react";
import { getColorTaskByPriority } from "../../../../../helpers/CalendarHelpers";
import CopyIcon from "../../../UI/CopyIcon/CopyIcon";
const CalendarTask = ({ setCurrentTask, handleOpen, task, line, setCurrentLine, setCopyTask }) => {
const CalendarTask = ({ setCurrentTask, handleOpen, task, setCopyTask, width, left, top, dragTaskHandler, hourFormat, step }) => {
const [color, setColor] = useState('')
useEffect(() => {
if (task.priority) {
if (task.priority === 'A') setColor('rgb(32, 138, 250)')
if (task.priority === 'B') setColor('lightgreen')
if (task.priority === 'C') setColor('yellow')
} else {
setColor('rgb(171, 157, 157);')
const color = useMemo(() => {
return getColorTaskByPriority(task.priority)
}, [task.priority])
const styles = useMemo(()=>{
return {
boxSizing: 'border-box',
backgroundColor: color,
height: `35px`,
width: `${width - 10}px`,
position: 'absolute',
display: 'flex',
left: left + 5,
top: top,
margin: '5px 5px 0 0',
padding: '5px',
textAlign: 'left',
overflow: 'hidden',
textOverflow: 'ellipsis',
borderRadius: '10px',
alignItems: 'center',
zIndex: '5',
'&:hover': {
cursor: 'pointer',
boxShadow: 'inset 0 0 100px 100px rgba(255, 255, 255, 0.3)'
},
}
}, [task])
}, [width, left, top, color])
const onClickTaskHandler = (e, task) => {
const onClickTaskHandler = useCallback((e, task) => {
e.stopPropagation();
setCurrentTask((prevState) => {
return {
......@@ -27,35 +46,58 @@ const CalendarTask = ({ setCurrentTask, handleOpen, task, line, setCurrentLine,
}
});
handleOpen(e)
}
},[handleOpen, setCurrentTask])
const dragLeaveHandler = (e) => {
const dragLeaveHandler = useCallback((e) => {
e.target.style.boxShadow = 'none'
}
const dragStartHandler = (e, line, task) => {
setCurrentLine()
},[])
const dragStartHandler = useCallback((e, task) => {
setCurrentTask(task);
}
const dragEndHandler = (e) => {
},[setCurrentTask])
const dragEndHandler = useCallback((e) => {
e.target.style.boxShadow = 'none'
},[])
const onClickCopyIconHandler = useCallback((e) => {
e.stopPropagation();
setCopyTask(task)
},[task, setCopyTask])
const dragOverHandler = useCallback((e) => {
e.preventDefault();
},[])
const dropHandler = useCallback((e, task) => {
e.preventDefault();
let hour
if (hourFormat) {
hour = task.infoForCell.startHour + (Math.ceil(e.nativeEvent.offsetX / step) - 1)
} else {
hour = task.infoForCell.startHour + (Math.ceil(e.nativeEvent.offsetX / step) - 1 + Math.ceil(e.nativeEvent.offsetX / step) - 1)
}
dragTaskHandler(task.infoForCell.startDay, hour)
},[dragTaskHandler, hourFormat, step])
return (<>
<Grid
draggable={true}
onDragLeave={(e) => { dragLeaveHandler(e) }}
onDragStart={(e) => { dragStartHandler(e, line, task) }}
onDragStart={(e) => { dragStartHandler(e, task) }}
onDragEnd={(e) => { dragEndHandler(e) }}
sx={{ position: 'relative', height: '30px', backgroundColor: color, borderRadius: '10px', margin: '5px 10px', display: 'flex', alignItems: 'center', zIndex: '5', justifyContent: 'space-between', padding: '0 15px' }}
onDrop={(e) => { dropHandler(e, task) }}
onDragOver={(e) => { dragOverHandler(e) }}
sx={styles}
onClick={(e) => { onClickTaskHandler(e, task) }}
>
<span style={{ maxWidth: '60%', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
{task.title}
</span>
<ContentCopyIcon sx={{ width: '20px', cursor: 'pointer' }} onClick={(e) => { e.stopPropagation(); setCopyTask(task) }}>
</ContentCopyIcon>
<CopyIcon
onClick={(e) => { onClickCopyIconHandler(e)}}
/>
</Grid>
</>)
};
......
import { Box, FormControlLabel, Switch } from "@mui/material";
import { useCallback, useState } from "react";
import CalendarRow from "../../CalendarRow/CalendarRow";
import CalendarSmallCell from "../../CalendarSmallCell/CalendarSmallCell";
import CalendarStandartCell from "../../CalendarStandartCell/CalendarStandartCell";
import ModalTask from "../../ModalTask/ModalTask"
import MonthCalendarModalContent from "../../CalendarModalTaskContent/CalendarModalTaskContent";
import CalendarRow from "../../UI/CalendarRow/CalendarRow";
import CalendarSmallCell from "../../UI/CalendarSmallCell/CalendarSmallCell";
import CalendarStandartCell from "../../UI/CalendarStandartCell/CalendarStandartCell";
import ModalTask from "../../UI/ModalTask/ModalTask"
import MonthCalendarModalContent from "../../UI/CalendarModalTaskContent/CalendarModalTaskContent";
import CalendarRowDay from "./CalendarRowDay/CalendarRowDay";
import { useSelector } from "react-redux";
function MonthCalendarBody({ month, year, tasks, createTaskInCellHandler, currentTask, setCurrentTask, hourFormat, setHourFormat, onChangeCurrentTaskHandler, sendNewTaskHandler, deleteTaskHandler, cellSizes, hoursInDay, daysInMonth, dragTaskHandler, createCopyTask, setCopyTask, copyTask }) {
function MonthCalendarBody({ month, year, tasks, createTaskInCellHandler, currentTask, setCurrentTask, hourFormat, setHourFormat, onChangeCurrentTaskHandler, sendNewTaskHandler, deleteTaskHandler, cellSizes, hoursInDay, daysInMonth, dragTaskHandler, createCopyTask, setCopyTask, copyTask}) {
const [currentLine, setCurrentLine] = useState('')
const [modal, setModal] = useState({ open: false, y: 0, x: 0, });
const handleOpen = useCallback((e) => {
setModal({
......@@ -64,8 +64,6 @@ function MonthCalendarBody({ month, year, tasks, createTaskInCellHandler, curren
hoursInDay={hoursInDay}
currentTask={currentTask}
handleOpen={handleOpen}
currentLine={currentLine}
setCurrentLine={setCurrentLine}
modal={modal.open}
setCurrentTask={setCurrentTask}
year={year}
......@@ -89,6 +87,7 @@ function MonthCalendarBody({ month, year, tasks, createTaskInCellHandler, curren
title={currentTask.title}
description={currentTask.description}
priority={currentTask.priority}
project={currentTask.project}
id={currentTask.id}
startHour={currentTask.infoForCell?.startHour}
endHour={currentTask.infoForCell?.endHour}
......
import { AppBar, Button, Toolbar, Typography } from '@mui/material';
import { Box } from '@mui/system';
import ButtonSwapCalendar from '../../UI/ButtonSwapCalendar/ButtonSwapCalendar';
import CalendarUserDisplayName from '../../UI/CalendarUserDisplayName/CalendarUserDisplayName';
import MonthAndYearInfo from './MonthAndYearInfo/MonthAndYearInfo';
function MonthCalendarHeader({ currentMonthString, decrementMonth, incrementMonth, year, handleOpen, currentCalendarDisplayName, user, userId}) {
......@@ -11,9 +13,11 @@ function MonthCalendarHeader({ currentMonthString, decrementMonth, incrementMont
<Toolbar>
<Box>
<Typography variant="h5" sx={{ margin: "20px 0 20px 0" }}>
Календарь: {currentCalendarDisplayName}
</Typography>
<CalendarUserDisplayName
currentCalendarDisplayName={currentCalendarDisplayName}
/>
<MonthAndYearInfo
currentMonthString={currentMonthString}
decrementMonth={decrementMonth}
......@@ -21,14 +25,12 @@ function MonthCalendarHeader({ currentMonthString, decrementMonth, incrementMont
year={year}
/>
</Box>
<Button
onClick={() => { handleOpen() }}
color="inherit"
size="large"
sx={{ marginLeft: 'auto' }}
>
{user.id === userId ? 'Выбрать сотрудника' : 'Вернуться назад'}
</Button>
<ButtonSwapCalendar
user={user}
userId={userId}
handleOpen={handleOpen}
/>
</Toolbar>
</AppBar>
</Box>
......
import {Button} from '@mui/material';
function ButtonSwapCalendar({ handleOpen, user, userId }) {
return (
<>
<Button
onClick={() => { handleOpen() }}
color="inherit"
size="large"
sx={{ marginLeft: 'auto', marginBottom: 'auto', marginTop: '20px' }}
>
{user.id === userId ? 'Выбрать сотрудника' : 'Вернуться назад'}
</Button>
</>
);
}
export default ButtonSwapCalendar;
\ No newline at end of file
import { Button, TextField } from "@mui/material";
import { memo } from "react";
import { useSelector } from "react-redux";
import { priorities } from "../../../../constants";
import CustomSelect from '../../../UI/СustomSelect/СustomSelect'
import { isValidate } from "./Helpers";
function CalendarModalTaskContent({ title, onChangeCurrentTaskHandler, description, priority, project, sendNewTaskHandler, deleteTaskHandler, startHour, endHour, id }) {
const { allUserProjectsForModalTask } = useSelector(state => state.projects)
return (
<>
<TextField
id="task-description-title"
value={title}
label="Название"
variant="outlined"
sx={{ marginBottom: '30px' }}
name='title'
onChange={(e) => { onChangeCurrentTaskHandler(e) }}
/>
<TextField
id="task-description"
multiline
rows={4}
value={description}
label="Описание"
variant="outlined"
sx={{ marginBottom: '30px' }}
name='description'
onChange={(e) => { onChangeCurrentTaskHandler(e) }}
/>
<div style={{ display: 'flex', gap: '20px', margin: '20px 0' }}>
<CustomSelect
defaultValue={null}
value={priority}
name={'priority'}
variant={'outlined'}
onChange={(e) => { onChangeCurrentTaskHandler(e) }}
label={'Приоритет'}
id={'priority-type'}
items={priorities}
/>
<CustomSelect
value={project}
name={'project'}
variant={'outlined'}
onChange={(e) => { onChangeCurrentTaskHandler(e) }}
label={'Проект'}
id={'project'}
items={allUserProjectsForModalTask}
/>
</div>
<div style={{ display: 'flex', gap: '20px', margin: '20px 0' }}>
<TextField
id="task-startHour"
value={startHour}
label="От"
variant="outlined"
name='startHour'
onChange={(e) => { onChangeCurrentTaskHandler(e) }}
/>
<TextField
id="task-endHour"
value={endHour}
label="До"
variant="outlined"
name='endHour'
onChange={(e) => { onChangeCurrentTaskHandler(e) }}
/>
</div>
<div style={{ display: 'flex', justifyContent: 'space-between', margin: '10px 0' }}>
<Button id='test_button_save_task' onClick={sendNewTaskHandler} disabled={!isValidate(title, project, startHour, endHour)}>Сохранить</Button>
<Button onClick={deleteTaskHandler} disabled={!id}>Удалить</Button>
</div>
</>);
}
export default memo(CalendarModalTaskContent);
\ No newline at end of file
export const isValidate = (title, startHour, endHour) => {
if (title) {
export const isValidate = (title, project, startHour, endHour) => {
if (title && project) {
const startHourInt = parseInt(startHour)
const endHourInt = parseInt(endHour)
if (startHourInt >= 8 && startHourInt <= 24) {
......
import { Autocomplete, Button, TextField } from "@mui/material";
import { Button } from "@mui/material";
import { memo } from "react";
import CustomAutocomplete from "../../UI/CustomAutocomplete/CustomAutocomplete";
import CustomAutocomplete from '../../../UI/CustomAutocomplete/CustomAutocomplete'
function CalendarModalWorkerContent({ allUserProjects, onChangeProjectHandler, onChangeWorkerHandler, workerInfo, workers, handleClose, onChangeCalendarUser }) {
......
......@@ -3,7 +3,7 @@ import { memo } from "react";
const CalendarSmallCell = ({ children, xs, week }) => {
return <>
<Grid align='center' item xs={xs} sx={{ borderRight: week ? null : '1px solid black', height: week ? '40px' : null, borderBottom: week ? '1px solid black' : null, }}>
<Grid align='center' item xs={xs} sx={{ borderRight: week ? null : '1px solid black', height: week ? '45px' : null, borderBottom: week ? '1px solid black' : null, }}>
{children}
</Grid>
</>
......
......@@ -2,17 +2,19 @@ import { Grid } from "@mui/material";
import { memo, useEffect, useState } from "react";
import DefaultTask from "../DefaultTask/DefaultTask";
const CalendarStandartCell = ({ children, xs, hours, dayNumber, createTaskInCellHandler, handleOpen, modal, dragTaskHandler, linesInDay, week, copyTask, createCopyTask, month}) => {
const heightCell = 40
const CalendarStandartCell = ({ children, xs, hours, dayNumber, createTaskInCellHandler, handleOpen, modal, dragTaskHandler, linesInDay, week, copyTask, createCopyTask, month, year }) => {
const [isThisCell, setIsThisCell] = useState(false)
const [top, setTop] = useState(0)
const cellClass = {
position: 'relative',
height: linesInDay?.length ? `${40 * linesInDay.length + 35}px` : `${40}px`,
height: linesInDay?.length ? `${heightCell * linesInDay.length + 5}px` : `${45}px`,
borderRight: '1px solid black',
borderBottom: week ? '1px solid black' : null,
'&:hover': {
cursor: children ? null : '#d6d2d2',
background: children ? null : '#d6d2d2'
},
}
useEffect(() => {
......@@ -23,30 +25,36 @@ const CalendarStandartCell = ({ children, xs, hours, dayNumber, createTaskInCell
const dragOverHandler = (e) => {
e.preventDefault();
e.target.style.background = children ? null : '#d6d2d2'
}
const dragLeaveHandler = (e) => {
e.preventDefault();
e.target.style.background = null
}
const dropHandler = (e) => {
e.stopPropagation()
e.preventDefault();
dragTaskHandler(dayNumber, parseInt(hours.split(':')[0]))
e.target.style.background = null
dragTaskHandler(dayNumber, parseInt(hours.split(':')[0]), month, year)
}
const onClickHandler = (e) => {
if (linesInDay?.length) {
createTaskInCellHandler(dayNumber, hours);
setIsThisCell(true);
handleOpen(e)
if (!week) {
if (e.nativeEvent.offsetY <= 5) {
setTop(40 * Math.ceil((e.nativeEvent.offsetY) / 40 - 1))
} else {
setTop(40 * Math.ceil((e.nativeEvent.offsetY - 5) / 40 - 1))
}
}
if (week) {
if (copyTask) {
createCopyTask(dayNumber, parseInt(hours.split(':')[0]), month)
createCopyTask(dayNumber, parseInt(hours.split(':')[0]), month, year)
} else {
createTaskInCellHandler(dayNumber, hours, month);
createTaskInCellHandler(dayNumber, hours, month, year);
setIsThisCell(true);
handleOpen(e)
}
}
}
return <>
<Grid
......@@ -54,11 +62,12 @@ const CalendarStandartCell = ({ children, xs, hours, dayNumber, createTaskInCell
sx={cellClass}
onClick={(e) => { onClickHandler(e) }}
onDragOver={(e) => { dragOverHandler(e) }}
onDragLeave={(e) => { dragLeaveHandler(e) }}
onDrop={(e) => { dropHandler(e) }}
>
{children}
{isThisCell ?
<DefaultTask week={week} /> : null}
<DefaultTask week={week} top={top} /> : null}
</Grid>
</>
......
import { Typography } from '@mui/material';
function CalendarUserDisplayName({currentCalendarDisplayName}) {
return (
<>
<Typography variant="h5" sx={{ marginTop: "20px" }}>
Календарь: {currentCalendarDisplayName}
</Typography>
</>
);
}
export default CalendarUserDisplayName;
\ No newline at end of file
import React, { memo} from "react";
import ContentCopyIcon from '@mui/icons-material/ContentCopy';
const styles = { width: '20px', cursor: 'pointer', marginLeft: 'auto' }
const CopyIcon = ({onClick}) => {
return (
<ContentCopyIcon sx={styles} onClick={onClick}>
</ContentCopyIcon>)
};
export default memo(CopyIcon);
\ No newline at end of file
import { Box } from "@mui/material";
import { memo } from "react";
const MonthDefaultTaskStyles = {
position: 'relative',
height: '30px',
backgroundColor: 'lightgreen',
whiteSpace: 'nowrap',
overflow: 'hidden',
textOverflow: 'ellipsis',
borderRadius: '10px',
margin: '5px 10px',
display: 'flex',
justifyContent: 'flex-start',
alignItems: 'center',
paddingLeft: '5px',
zIndex: '5'
}
const WeekDefaultTaskStyles = {
boxSizing: 'border-box',
padding: '0 5px',
......@@ -31,7 +17,25 @@ const WeekDefaultTaskStyles = {
}
const DefaultTask = ({ week }) => {
const DefaultTask = ({ week, top }) => {
const MonthDefaultTaskStyles = {
boxSizing: 'border-box',
position: 'relative',
height: '35px',
backgroundColor: 'lightgreen',
whiteSpace: 'nowrap',
overflow: 'hidden',
textOverflow: 'ellipsis',
borderRadius: '10px',
margin: '5px 3px 0 6px',
padding: '5px',
top: top,
display: 'flex',
justifyContent: 'flex-start',
alignItems: 'center',
zIndex: '5'
}
return (<>
<Box
......
......@@ -26,16 +26,16 @@ export default function ModalTask({ modal, handleClose, children, week }) {
const getYCordinatesToModal = useCallback(() => {
if (week) {
if (windowDimenion.winHeight > modal.yClickСordinates + 450) {
if (windowDimenion.winHeight > modal.yClickСordinates + 470) {
return modal.yClickСordinates - modal.yDivClick
} else {
return modal.yClickСordinates - 450
return modal.yClickСordinates - 480
}
} else {
if (windowDimenion.winHeight > modal.yClickСordinates + 450) {
if (windowDimenion.winHeight > modal.yClickСordinates + 470) {
return modal.yClickСordinates - modal.yDiv - modal.yDivClick
} else {
return modal.yClickСordinates - modal.yDiv - modal.yDivClick - ((modal.yClickСordinates + 450) - windowDimenion.winHeight) - 30
return modal.yClickСordinates - modal.yDiv - modal.yDivClick - ((modal.yClickСordinates + 470) - windowDimenion.winHeight) - 30
}
}
}, [windowDimenion.winHeight, modal])
......@@ -55,7 +55,7 @@ export default function ModalTask({ modal, handleClose, children, week }) {
top: getYCordinatesToModal(),
left: getXCordinatesToModal(),
width: 270,
height: 450,
height: 470,
bgcolor: 'background.paper',
border: '2px solid #000',
boxShadow: 24,
......
import { useMemo } from "react";
import { getHoursInDayNumbers, getAvailableTasks, getLinesInDay, getSortedTasks } from "../../../../../helpers/CalendarHelpers";
import CalendarStandartCell from "../../../CalendarStandartCell/CalendarStandartCell";
import CalendarStandartCell from "../../../UI/CalendarStandartCell/CalendarStandartCell";
import { useEffect, useRef, useState } from "react";
import { Grid } from "@mui/material";
import CalendarWeekTask from "./CalendarWeekTask/CalendarWeekTask";
......@@ -11,7 +11,6 @@ import { getTasksWithInfoForPosition, getWidthLeftZIndex } from "./Helpers";
function CalendarColumnDayWeek({ hoursInDay, tasks, month, year, day, hourFormat, handleOpen, setCurrentTask, copyTask, setCopyTask, createCopyTask, createTaskInCellHandler, modal, dragTaskHandler }) {
const [columnDaySize, setColumnDaySize] = useState({ width: 0, height: 0 })
const [diffForDragAndDrop, setDiffForDragAndDrop] = useState(1)
const dayColumnRef = useRef('')
useEffect(() => {
......@@ -81,6 +80,7 @@ function CalendarColumnDayWeek({ hoursInDay, tasks, month, year, day, hourFormat
copyTask={copyTask}
createCopyTask={createCopyTask}
month={month}
year={year}
dragTaskHandler={dragTaskHandler}
>
</CalendarStandartCell>
......
import { Box } from "@mui/material"
import { useEffect, useState, memo, useCallback, useMemo } from "react"
import { getColorTaskByPriority } from "../../../../../../helpers/CalendarHelpers"
import ContentCopyIcon from '@mui/icons-material/ContentCopy';
import CopyIcon from "../../../../UI/CopyIcon/CopyIcon";
function CalendarWeekTask({ height, width, left, top, task, zIndex, handleOpen, setCurrentTask, modal, setCopyTask, month, dragTaskHandler, step, hourFormat}) {
......@@ -81,13 +81,18 @@ function CalendarWeekTask({ height, width, left, top, task, zIndex, handleOpen,
} else {
hour = task.infoForCell.startHour + (Math.ceil(e.nativeEvent.offsetY/step)-1 + Math.ceil(e.nativeEvent.offsetY/step)-1)
}
dragTaskHandler(task.infoForCell.startDay, hour)
dragTaskHandler(task.infoForCell.startDay, hour, task.infoForCell.startMonth - 1, task.infoForCell.startYear)
}
const dragLeaveHandler = (e) => {
e.preventDefault();
}
const onClickCopyIconHandler = useCallback((e) => {
e.stopPropagation();
setCopyTask(task)
},[task, setCopyTask])
return (
<Box
draggable={true}
......@@ -102,8 +107,9 @@ function CalendarWeekTask({ height, width, left, top, task, zIndex, handleOpen,
<span style={{ textOverflow: 'ellipsis', padding: '5px 0 0 5px' }}>
{task.title}
</span>
<ContentCopyIcon sx={{ marginLeft: 'auto', marginTop: '5px' }} onClick={(e) => { e.stopPropagation(); setCopyTask(task) }}>
</ContentCopyIcon>
<CopyIcon
onClick={(e) => { onClickCopyIconHandler(e)}}
/>
</Box>);
}
......
......@@ -6,17 +6,18 @@ export const getCurrentWeekDayString = (dayNumber) => {
}
}
export const getMonthToDayColumn = (week, weekDay, month) => {
export const getMonthAndYearToDayColumn = (week, weekDay, month, year) => {
if (week[0] > week[6]) {
if (weekDay < week[0]) {
if (month === 11) {
return 0
}
return month + 1
return {month: month, year: year}
} else {
return month
if (month === 0) {
return {month: 11, year: year - 1}
}
return {month: month - 1, year: year}
}
} else {
return month
return {month: month, year: year}
}
}
import { Grid } from "@mui/material";
import { Box } from "@mui/system";
import { useCallback, useState } from "react";
import ModalTask from "../../ModalTask/ModalTask";
import MonthCalendarModalContent from "../../CalendarModalTaskContent/CalendarModalTaskContent";
import CalendarRow from "../../CalendarRow/CalendarRow";
import CalendarSmallCell from "../../CalendarSmallCell/CalendarSmallCell";
import CalendarStandartCell from "../../CalendarStandartCell/CalendarStandartCell";
import HourFormatSwitch from "../../HourFormatSwitch/HourFormatSwitch";
import ModalTask from "../../UI/ModalTask/ModalTask";
import CalendarModalTaskContent from "../../UI/CalendarModalTaskContent/CalendarModalTaskContent";
import CalendarRow from "../../UI/CalendarRow/CalendarRow";
import CalendarSmallCell from "../../UI/CalendarSmallCell/CalendarSmallCell";
import CalendarStandartCell from "../../UI/CalendarStandartCell/CalendarStandartCell";
import HourFormatSwitch from "../../UI/HourFormatSwitch/HourFormatSwitch";
import CalendarColumnDayWeek from "./CalendarColumnDayWeek/CalendarColumnDayWeek";
import { getCurrentWeekDayString, getMonthToDayColumn } from "./Helpers";
import { getCurrentWeekDayString, getMonthAndYearToDayColumn } from "./Helpers";
function WeekCalendarBody({ week, hoursInDay, hourFormat, setHourFormat, date, tasks, currentTask, setCurrentTask, onChangeCurrentTaskHandler, deleteTaskHandler, sendNewTaskHandler, createTaskInCellHandler, copyTask, setCopyTask, createCopyTask, dragTaskHandler }) {
const [modal, setModal] = useState({ open: false, y: 0, x: 0, });
......@@ -66,13 +66,14 @@ function WeekCalendarBody({ week, hoursInDay, hourFormat, setHourFormat, date, t
<Grid item xs={11.005}>
<CalendarRow week={true}>
{week?.map((weekDay, i) => {
const {month, year} = getMonthAndYearToDayColumn(week, weekDay, date.month, date.year)
return (
<CalendarColumnDayWeek
key={i}
hoursInDay={hoursInDay}
tasks={tasks}
month={getMonthToDayColumn(week, weekDay, date.month)}
year={date.year}
month={month}
year={year}
day={weekDay}
hourFormat={hourFormat}
setCurrentTask={setCurrentTask}
......@@ -98,13 +99,14 @@ function WeekCalendarBody({ week, hoursInDay, hourFormat, setHourFormat, date, t
handleClose={() => { handleClose() }}
week={true}
>
<MonthCalendarModalContent
<CalendarModalTaskContent
title={currentTask.title}
description={currentTask.description}
priority={currentTask.priority}
id={currentTask.id}
startHour={currentTask.infoForCell?.startHour}
endHour={currentTask.infoForCell?.endHour}
project={currentTask.project}
onChangeCurrentTaskHandler={(e) => { onChangeCurrentTaskHandler(e) }}
sendNewTaskHandler={() => { sendNewTaskHandler(); handleClose() }}
deleteTaskHandler={() => { deleteTaskHandler(currentTask.id); handleClose() }}
......
import { AppBar, Toolbar } from '@mui/material';
import { Box } from '@mui/system';
import { memo } from 'react';
import ButtonSwapCalendar from '../../UI/ButtonSwapCalendar/ButtonSwapCalendar';
import CalendarUserDisplayName from '../../UI/CalendarUserDisplayName/CalendarUserDisplayName';
import WeekCalendarHeaderInfo from './WeekCalendarHeaderInfo/WeekCalendarHeaderInfo';
import WeekGoal from './WeekGoal/WeekGoal';
import WeekPriorities from './WeekPriorities/WeekPriorities';
function WeekCalendarHeader({ decrementWeek, incrementWeek, weekInfo }) {
function WeekCalendarHeader({ decrementWeek, incrementWeek, weekInfo, weekGoal, onChangeWeekGoalHandler, weekPriorities, onChangeWeekPrioritiesHandler, handleOpen, currentCalendarDisplayName, user, userId }) {
return (
<>
<Box sx={{ flexGrow: 1 }}>
<AppBar position="static">
<Toolbar>
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 1 }}>
<CalendarUserDisplayName
currentCalendarDisplayName={currentCalendarDisplayName}
/>
<WeekGoal
weekGoal={weekGoal}
onChangeWeekGoalHandler={onChangeWeekGoalHandler}
/>
<WeekPriorities
weekPriorities={weekPriorities}
onChangeWeekPrioritiesHandler={onChangeWeekPrioritiesHandler}
/>
<WeekCalendarHeaderInfo
decrementWeek={decrementWeek}
incrementWeek={incrementWeek}
weekInfo={weekInfo}
weekGoal={weekGoal}
onChangeWeekGoalHandler={onChangeWeekGoalHandler}
/>
</Box>
<ButtonSwapCalendar
user={user}
userId={userId}
handleOpen={handleOpen}
/>
</Toolbar>
</AppBar>
</Box>
......
......@@ -2,16 +2,15 @@ import ArrowDecrementButton from '../../../../UI/ArrowDecrementButton/ArrowDecre
import ArrowIncrementButton from '../../../../UI/ArrowIncrementButton/ArrowIncrementButton';
import { Box } from '@mui/system';
import { Typography } from '@mui/material';
import { memo } from 'react';
import { memo, } from 'react';
function WeekCalendarHeaderInfo({ decrementWeek, incrementWeek, weekInfo }) {
function WeekCalendarHeaderInfo({ decrementWeek, incrementWeek, weekInfo}) {
return (
<>
<Box sx={{ width: '40%', marginBottom: '15px' }}>
<h2>Цель недели: Наладить режим сна</h2>
<Box sx={{ width: '80%', marginBottom: '15px' }}>
<Box sx={{ display: 'flex', alignItems: 'center' }}>
<ArrowDecrementButton
onClick={() => { decrementWeek() }}
......
import { Box } from '@mui/system';
import { TextField, Typography } from '@mui/material';
import { memo, useCallback, useState } from 'react';
function WeekGoal({ weekGoal, onChangeWeekGoalHandler }) {
const [goalEditCheck, setGoalEditCheck] = useState(false)
const onClickGoalHandler = useCallback(() => {
setGoalEditCheck(true)
}, [])
return (
<>
<Box sx={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
{goalEditCheck ?
<>
<Typography variant='h5' sx={{ marginTop: '20px' }}>
Цель недели:
</Typography>
<TextField
id="week-gaol"
value={weekGoal}
variant="standard"
sx={{ input: { color: 'white', fontSize: '22px', fontWeight: '400', paddingTop: '25px' } }}
InputProps={{
disableUnderline: true,
}}
name='weekGoal'
autoFocus
onBlur={() => { setGoalEditCheck(false) }}
onChange={(e) => { onChangeWeekGoalHandler(e) }}
/>
</>
: <Typography variant='h5' onClick={() => { onClickGoalHandler() }} sx={{ marginTop: '20px' }}>Цель недели: {weekGoal}</Typography>
}
</Box>
</>
);
}
export default memo(WeekGoal);
\ No newline at end of file
import { Box } from '@mui/system';
import { Typography } from '@mui/material';
import { memo } from 'react';
import WeekPriority from './WeekPriority/WeekPriority';
function WeekPriorities({ weekPriorities, onChangeWeekPrioritiesHandler }) {
return (
<>
<Box>
<Typography variant='h5' sx={{ display: 'flex', flexDirection: 'column' }}>
Приоритеты:
{Object.values(weekPriorities).map((priority, i)=>{
return (
<WeekPriority
key={i}
onChangeWeekPrioritiesHandler={(e)=>{onChangeWeekPrioritiesHandler(e)}}
priorityName={Object.keys(weekPriorities)[i]}
priority={priority}
number={i+1}
/>
)
})}
</Typography>
</Box>
</>
);
}
export default memo(WeekPriorities);
\ No newline at end of file
import { Box } from '@mui/system';
import { TextField, Typography } from '@mui/material';
import { memo, useCallback, useState } from 'react';
function WeekPriority({ number, priority, onChangeWeekPrioritiesHandler, priorityName }) {
const [priorityEditCheck, setPriorityEditCheck] = useState(false)
const onClickPriorityHandler = useCallback(() => {
setPriorityEditCheck(true)
}, [])
return (
<>
<Box sx={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
{priorityEditCheck ?
<>
<Typography variant='string'>
{number}.
</Typography>
<TextField
id={priorityName}
value={priority}
variant="standard"
sx={{ input: { color: 'white', fontSize: '22px', fontWeight: '400'} }}
InputProps={{
disableUnderline: true,
}}
name={priorityName}
autoFocus
onBlur={() => { setPriorityEditCheck(false) }}
onChange={(e) => { onChangeWeekPrioritiesHandler(e) }}
/>
</>
: <Typography variant='string' onClick={() => { onClickPriorityHandler() }}>{number}. {priority}</Typography>
}
</Box>
</>
);
}
export default memo(WeekPriority);
\ No newline at end of file
import { Button } from "@mui/material";
import { NavLink } from "react-router-dom";
import { superuserMenuButtons } from "../../../constants";
import ProfileBlock from "../ProfileBlock/ProfileBlock";
const AdminMenu = () => {
return <>
{superuserMenuButtons.map((button, i) => {
return (
<Button
key={i}
component={NavLink}
to={button.path}
color="inherit"
size="large"
>
{button.text}
</Button>
)
})}
<ProfileBlock />
</>
};
export default AdminMenu;
\ No newline at end of file
......@@ -4,6 +4,7 @@ import { useDispatch, useSelector } from "react-redux";
import {NavLink, useNavigate} from "react-router-dom";
import { fetchUsersAllFields, logoutUser } from "../../../store/actions/usersActions";
import SwitchUserModal from "../../SwitchUserModal/SwitchUserModal";
import HasAccess from "../../UI/HasAccess/HasAccess";
const ProfileBlock = () => {
const dispatch = useDispatch();
......@@ -33,6 +34,11 @@ const ProfileBlock = () => {
handleClose()
handleOpenSwitchUser()
}
const navigateToRegisterUser =()=>{
navigate('/sign-up')
handleClose()
}
return <>
......@@ -51,6 +57,9 @@ const ProfileBlock = () => {
>
<MenuItem component={NavLink} to="/profile/test" color="inherit" onClick={handleClose}>Профиль</MenuItem>
<MenuItem onClick={()=>{switchUser()}}>Поменять юзера</MenuItem>
<HasAccess roles={['superuser']}>
<MenuItem onClick={()=>{navigateToRegisterUser()}}>Создать сотрудника</MenuItem>
</HasAccess>
<MenuItem onClick={()=>{logout()}}>Выйти</MenuItem>
</Menu>
<SwitchUserModal
......
import { Grid } from "@mui/material";
const CalendarRow = ({children, week}) => {
return <>
<Grid
container
align='center'
sx={{borderBottom: week ? null : '1px solid black', borderRight: '1px solid black', borderLeft: '1px solid black'}}
>
{children}
</Grid>
</>
};
export default CalendarRow;
import { Grid } from "@mui/material";
import { memo, useMemo} from "react";
import CalendarStandartCell from "../CalendarStandartCell.js/CalendarStandartCell";
import CalendarTask from "../CalendarTask/CalendarTask";
import EmptyBox from "./EmptyBox/EmptyBox";
import { getAvailableTasks, getBoxesInLine, getLinesInDay, getSortedTasks } from "./Helpers";
const CalendarRowDay = ({xs, hoursInDay, createTaskInCellHandler, currentTask, handleOpen, modal, setCurrentTask, year, month, tasks, day, hourFormat, setCurrentLine, currentLine, dragTaskHandler, createCopyTask, setCopyTask, copyTask}) => {
const hours = useMemo(()=>{
return hoursInDay.map((hour)=>parseInt(hour.split(':')[0]))},
[hoursInDay])
const availableTasks = useMemo(() => {
return getAvailableTasks(tasks, year, month, day.dayNumber)
}, [tasks, month, year, day.dayNumber])
const sortedTasks = useMemo(() => {
return getSortedTasks(availableTasks)
}, [availableTasks])
const linesInDay = useMemo(() => {
return getLinesInDay(availableTasks, sortedTasks, hoursInDay, hours, hourFormat)
}, [availableTasks, hourFormat, hours, hoursInDay, sortedTasks])
return <>
<Grid
container
item
xs={10.8}
align='center'
sx={{position: 'relative'}}
>
{hoursInDay.map((hour, i)=>{
return (
<CalendarStandartCell
linesInDay={linesInDay}
key={i}
item xs={xs}
createTaskInCellHandler={createTaskInCellHandler}
hours={hour}
dragTaskHandler={dragTaskHandler}
dayNumber={day.dayNumber}
currentTask={currentTask}
handleOpen={handleOpen}
modal={modal}
>
</CalendarStandartCell>
)
})}
<Grid sx={{position: 'absolute', top: '0'}} container item xs={12}>
{linesInDay?.map((line, i)=>{
const boxes = getBoxesInLine(line, hoursInDay, sortedTasks)
return(
<Grid key={i} container sx={{height: '35px', backgroundColor: 'rgb(0,0,0,0)', marginBottom: '5px'}}>
{boxes.map((box, index)=>{
if (box.task) {
return (<Grid
item xs={box.xs}
key={box.task.id}
sx={{height: '35px', marginBottom: '5px'}}
>
<CalendarTask
dragTaskHandler={dragTaskHandler}
setCurrentLine={()=>{setCurrentLine(day.dayNumber)}}
currentTask={currentTask}
currentLine={currentLine}
hour={parseInt(hours[index])}
line={day.dayNumber}
task={box.task}
setCurrentTask={setCurrentTask}
handleOpen={handleOpen}
setCopyTask={setCopyTask}
/>
</Grid>)
} else {
return (<EmptyBox
key={index}
modal={modal}
dayNumber={day.dayNumber}
hourNumber={box.hour}
handleOpen={handleOpen}
dragTaskHandler={dragTaskHandler}
createCopyTask={createCopyTask}
copyTask={copyTask}
createTaskInCellHandler={createTaskInCellHandler}
xs={box.xs}
>
</EmptyBox>)
}
})}
</Grid>)
})}
</Grid>
<Grid container sx={{height: '35px', backgroundColor: 'rgb(0,0,0,0)', marginBottom: '5px', position: 'absolute', bottom: '0'}}>
{hoursInDay.map((hour, i)=>{
const hourNumber = parseInt(hour)
return(<EmptyBox
key={i}
modal={modal}
dayNumber={day.dayNumber}
hourNumber={hourNumber}
handleOpen={handleOpen}
dragTaskHandler={dragTaskHandler}
createCopyTask={createCopyTask}
copyTask={copyTask}
createTaskInCellHandler={createTaskInCellHandler}
xs={xs}
>
</EmptyBox>)
})}
</Grid>
</Grid>
</>
};
export default memo(CalendarRowDay, (prevProps, nextProps)=>{
if(!prevProps.modal) return false
if(nextProps.modal) return true
});
import { Grid} from "@mui/material";
import React, { memo, useEffect, useState} from "react";
import DefaultTask from "../../DefaultTask/DefaultTask";
const EmptyBox = ({hourNumber, handleOpen, dayNumber, xs, dragTaskHandler, modal, createTaskInCellHandler, copyTask, createCopyTask}) => {
const [isThisCell, setIsThisCell] = useState(false)
useEffect(()=>{
if(!modal) {
setIsThisCell(false);
}
}, [modal])
const onClickHandler = (e, dayNumber, hour) => {
if (copyTask) {
createCopyTask(dayNumber, hour)
} else {
createTaskInCellHandler(dayNumber, hour);
setIsThisCell(true);
handleOpen(e)
}
}
const dragOverHandler = (e) => {
e.preventDefault();
}
const dropHandler = (e) => {
e.stopPropagation()
e.preventDefault();
dragTaskHandler(dayNumber, hourNumber)
}
return(<Grid
onDragOver={(e)=>{dragOverHandler(e)}}
onDrop={(e)=>{dropHandler(e)}}
onClick={(e)=>{onClickHandler(e, dayNumber, hourNumber)}}
className='test_empty_box'
item xs={xs} sx={{
height: '40px',
backgroundColor: 'rgb(0,0,0,0)',
zIndex: '6',
cursor: copyTask ? 'pointer' : 'default'
}}>
{isThisCell ?
<DefaultTask/> : ' '}
</Grid>)
};
export default memo(EmptyBox, (prevProps, nextProps)=>{
if(!prevProps.modal) return false
if(nextProps.modal) return true
});
\ No newline at end of file
const taskIsAvailableInCell = (task, hour, hourDiffEnd, hourDiff, hourFormat) => {
if (((task.infoForCell.endHour <= hour || task.infoForCell.startHour <= hour) && (task.infoForCell.endHour > hour))
|| (!hourFormat && task.infoForCell.startHour >= hour && task.infoForCell.endHour < hour + hourDiff)
|| (!hourFormat && task.infoForCell.startHour === hour + hourDiffEnd && task.infoForCell.endHour > hour)
|| (task.infoForCell.endMinute <= 59 && task.infoForCell.endHour === hour)) {
return true
} else {
return false
}
}
const lastPlaceInLineForTask = (task, hour, hourDiffEnd, hourFormat) => {
if ((task.infoForCell.endMinute === 59 && task.infoForCell.endHour === hour + hourDiffEnd) || (!hourFormat && task.infoForCell.endMinute === 59 && task.infoForCell.endHour === hour)) {
return true
} else {
return false
}
}
export const getLinesInDay = (availableTasks, sortedTasks, hoursInDay, hours, hourFormat) => {
let hourDiff
let hourDiffEnd
const lines = []
if (hourFormat) {
hourDiff = 1
hourDiffEnd = 0
} else {
hourDiff = 2
hourDiffEnd = 1
}
if (availableTasks.length) {
lines.push(hoursInDay.map((hour)=>parseInt(hour.split(':')[0])))
for (let k = 0; k < sortedTasks.length; k++) {
let skipLine = false
for (let j = 0; j < lines.length; j++) {
const line = lines[j]
const task = sortedTasks[k]
if (skipLine) {
skipLine = false
break;
}
for (let i = 0; i < line.length; i++) {
const hour = hours[i]
let havePlace = true
if (taskIsAvailableInCell(task, hour, hourDiffEnd, hourDiff, hourFormat)) {
if (!isNaN(line[i])) {
for (let a = 0; a < hours.length; a++) {
const hour = hours[a]
if (lastPlaceInLineForTask(task, hour, hourDiffEnd, hourFormat)) {
if (isNaN(line[a])) {
havePlace = false
break;
}
}
}
if (!havePlace) {
if (j + 1 === lines.length) {
lines.push(hoursInDay.map((hour)=>parseInt(hour.split(':')[0])))
}
havePlace = true
break;
}
line[i] += `-${k}`
if (lastPlaceInLineForTask(task, hour, hourDiffEnd, hourFormat)) {
skipLine = true
break;
}
} else {
if (j + 1 === lines.length) {
lines.push(hoursInDay.map((hour)=>parseInt(hour.split(':')[0])))
}
break;
}
}
}
}
}
}
return lines
}
export const getSortedTasks = (availableTasks) => {
if (availableTasks.length) {
const newSortedArr = [...availableTasks].sort(function(a,b){
const durattionFirstDate = a.infoForCell.endHour - a.infoForCell.startHour
const durattionSecondDate = b.infoForCell.endHour - b.infoForCell.startHour
return durattionSecondDate - durattionFirstDate;
})
return newSortedArr
}
}
export const getAvailableTasks = (tasks, year, month, dayNumber) => {
const tasksInDay = tasks.filter((task)=> {
if (year === task.infoForCell.startYear) {
if (month + 1 === task.infoForCell.startMonth) {
if (dayNumber === task.infoForCell.startDay) {
return task
} else {return false}
} else {return false}
} else {return false}
})
return tasksInDay
}
export const getBoxesInLine = (line, hoursInDay, sortedTasks) => {
if (line) {
let xs = 12/hoursInDay.length
const boxes = []
for (let i = 0; i < line.length; i++) {
if (!isNaN(line[i])) {
// if (boxes[boxes.length -1]?.task === null) {
// boxes[boxes.length -1].xs += xs
// } else {
boxes.push({xs: xs, task: null, hour: line[i]})
// }
} else {
const task = sortedTasks[line[i].split('-')[1]]
const taskIsThere = boxes.find((taskFind)=>{
if (taskFind?.task?.id === task.id) return taskFind
return false
})
if (taskIsThere) {
taskIsThere.xs +=xs
} else {
boxes.push({
xs: xs,
task: sortedTasks[line[i].split('-')[1]]})
}
}
}
return boxes
}
}
\ No newline at end of file
import { Grid } from "@mui/material";
import { memo } from "react";
const CalendarSmallCell = ({children, xs, week}) => {
return <>
<Grid align='center' item xs={xs} sx={{borderRight: week ? null : '1px solid black', height: week ? '40px' : null, borderBottom: week ? '1px solid black' : null,}}>
{children}
</Grid>
</>
};
export default memo(CalendarSmallCell);
\ No newline at end of file
import { Grid} from "@mui/material";
import { memo, useEffect, useState } from "react";
import DefaultTask from "../DefaultTask/DefaultTask";
const CalendarStandartCell = ({children, xs, hours, dayNumber, createTaskInCellHandler, handleOpen, modal, dragTaskHandler, linesInDay, week}) => {
const [isThisCell, setIsThisCell] = useState(false)
const cellClass = {
position: 'relative',
height: linesInDay?.length ? `${40*linesInDay.length+35}px` : `${40}px`,
borderRight: '1px solid black',
borderBottom: week ?'1px solid black' : null,
}
useEffect(()=>{
if(!modal) {
setIsThisCell(false);
}
}, [modal])
const dragOverHandler = (e) => {
e.preventDefault();
}
const dropHandler = (e) => {
e.stopPropagation()
e.preventDefault();
dragTaskHandler(dayNumber, parseInt(hours.split(':')[0]))
}
const onClickHandler = (e) => {
if (linesInDay?.length) {
createTaskInCellHandler(dayNumber, hours);
setIsThisCell(true);
handleOpen(e)
}
}
return <>
<Grid
item xs={xs}
sx={cellClass}
onClick={(e)=>{onClickHandler(e)}}
onDragOver={(e)=>{dragOverHandler(e)}}
onDrop={(e)=>{dropHandler(e)}}
>
{children}
{isThisCell ?
<DefaultTask/> : null}
</Grid>
</>
};
export default memo(CalendarStandartCell, (prevProps, nextProps)=>{
if(!prevProps.modal) return false
if(nextProps.modal) return true
});
\ No newline at end of file
import { Grid} from "@mui/material";
import React, { memo, useEffect, useState} from "react";
import ContentCopyIcon from '@mui/icons-material/ContentCopy';
const CalendarTask = ({setCurrentTask, handleOpen, task, line, setCurrentLine, setCopyTask}) => {
const [color, setColor] = useState('')
useEffect(() => {
if (task.priority) {
if (task.priority === 'A') setColor('rgb(32, 138, 250)')
if (task.priority === 'B') setColor('lightgreen')
if (task.priority === 'C') setColor('yellow')
} else {
setColor('rgb(171, 157, 157);')
}
}, [task])
const onClickTaskHandler = (e, task) => {
e.stopPropagation();
setCurrentTask((prevState)=>{
return {
...task,
infoForCell: {
...task.infoForCell,
endHour: task.infoForCell.endHour + 1
}
}
});
handleOpen(e)
}
const dragLeaveHandler = (e) => {
e.target.style.boxShadow = 'none'
}
const dragStartHandler = (e, line, task) => {
setCurrentLine()
setCurrentTask(task);
}
const dragEndHandler = (e) => {
e.target.style.boxShadow = 'none'
}
return (<>
<Grid
draggable={true}
onDragLeave={(e)=>{dragLeaveHandler(e)}}
onDragStart={(e)=>{dragStartHandler(e, line, task)}}
onDragEnd={(e)=>{dragEndHandler(e)}}
sx={{ position: 'relative', height: '30px', backgroundColor: color, borderRadius: '10px', margin: '5px 10px', display: 'flex', alignItems: 'center', zIndex: '5', justifyContent: 'space-between', padding: '0 15px'}}
onClick={(e)=>{onClickTaskHandler(e, task)}}
>
<span style={{maxWidth: '60%', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis'}}>
{task.title}
</span>
<ContentCopyIcon sx={{width: '20px', cursor: 'pointer'}} onClick={(e)=>{e.stopPropagation(); setCopyTask(task)}}>
</ContentCopyIcon>
</Grid>
</>)
};
export default memo(CalendarTask);
\ No newline at end of file
import { Box } from "@mui/material";
import { memo } from "react";
const DefaultTaskStyles = {
position: 'relative',
height: '30px',
backgroundColor: 'lightgreen',
whiteSpace: 'nowrap',
overflow: 'hidden',
textOverflow: 'ellipsis',
borderRadius: '10px',
margin: '5px 10px',
display: 'flex',
justifyContent: 'flex-start',
alignItems: 'center',
paddingLeft: '5px',
zIndex: '5'
}
const DefaultTask = ({}) => {
return (<>
<Box
sx={DefaultTaskStyles}
>
<span>
Задача
</span>
</Box>
</>)
};
export default memo(DefaultTask);
\ No newline at end of file
import { Box, FormControlLabel, Switch} from "@mui/material";
import { useState } from "react";
import CalendarRow from "./CalendarRow/CalendarRow";
import CalendarSmallCell from "./CalendarSmallCell/CalendarSmallCell";
import CalendarStandartCell from "./CalendarStandartCell.js/CalendarStandartCell";
import ModalTask from "../../UI/ModalTask/ModalTask";
import MonthCalendarModalContent from "../MonthCalendarModalContent/MonthCalendarModalContent";
import CalendarRowDay from "./CalendarRowDay/CalendarRowDay";
function MonthCalendarBody({month, year, tasks, createTaskInCellHandler, currentTask, setCurrentTask, hourFormat, setHourFormat, onChangeCurrentTaskHandler, sendNewTaskHandler, deleteTaskHandler, cellSizes, hoursInDay, daysInMonth, dragTaskHandler, createCopyTask, setCopyTask, copyTask}) {
const [currentLine, setCurrentLine] = useState('')
const [modal, setModal] = useState({open:false, y: 0, x: 0,});
const handleOpen = (e) => {
setModal( {
open: true,
yClickСordinates: e.clientY,
xClickСordinates: e.clientX,
yDivClick: e.nativeEvent.offsetY,
xDivClick: e.nativeEvent.offsetX,
yDiv: e.target.offsetHeight,
xDiv: e.target.offsetWidth,
})
};
const handleClose = () => {
setModal({...modal, open: false})
setCurrentTask({})
};
return (
<Box style={{marginBottom: '30px'}}>
<div style={{position: 'sticky', top: '0px', zIndex: '10', backgroundColor: 'lightgrey'}}>
<CalendarRow
>
<CalendarSmallCell xs={1.2}>
<FormControlLabel
control={<Switch color="primary" checked={hourFormat} onChange={()=>{setHourFormat(()=>!hourFormat)}}/>}
label="1 час"
labelPlacement="end"
/>
</CalendarSmallCell>
{hoursInDay?.map((hours, i)=>{
return (
<CalendarStandartCell key={i} xs={cellSizes.standarCell}>
{hours}
</CalendarStandartCell>
)
})}
</CalendarRow>
</div>
{daysInMonth?.map((day, i)=>{
return (
<CalendarRow
key={i}
>
<CalendarSmallCell xs={cellSizes.smallCell}>{day.dayNumber}</CalendarSmallCell>
<CalendarSmallCell xs={cellSizes.smallCell}>{day.dayOfWeek}</CalendarSmallCell>
<CalendarRowDay
dragTaskHandler={dragTaskHandler}
xs={cellSizes.dayCell}
createTaskInCellHandler={createTaskInCellHandler}
hoursInDay={hoursInDay}
currentTask={currentTask}
handleOpen={handleOpen}
currentLine={currentLine}
setCurrentLine={setCurrentLine}
modal={modal.open}
setCurrentTask={setCurrentTask}
year={year}
month={month}
tasks={tasks}
day={day}
hourFormat={hourFormat}
createCopyTask={createCopyTask}
copyTask={copyTask}
setCopyTask={setCopyTask}
>
</CalendarRowDay>
</CalendarRow>
)
})}
<ModalTask
modal={modal}
handleClose={()=>{handleClose()}}
>
<MonthCalendarModalContent
title={currentTask.title}
description={currentTask.description}
priority={currentTask.priority}
startHour={currentTask.infoForCell?.startHour}
endHour={currentTask.infoForCell?.endHour}
onChangeCurrentTaskHandler={(e)=>{ onChangeCurrentTaskHandler(e)}}
sendNewTaskHandler={()=>{sendNewTaskHandler(); handleClose()}}
deleteTaskHandler={()=>{deleteTaskHandler(currentTask.id); handleClose()}}
/>
</ModalTask>
</Box>
);
}
export default MonthCalendarBody;
\ No newline at end of file
import { Box, Typography } from '@mui/material';
import { memo } from 'react';
import ArrowDecrementButton from '../../../UI/ArrowDecrementButton/ArrowDecrementButton';
import ArrowIncrementButton from '../../../UI/ArrowIncrementButton/ArrowIncrementButton';
function MonthAndYearInfo({currentMonthString, year, incrementMonth, decrementMonth}) {
return (
<>
<Box
sx={{
flexGrow: 1,
display: 'flex',
alignItems: 'center',
gap: '10px'
}}
id='test_month_info'
>
<ArrowDecrementButton
onClick={decrementMonth}
/>
<Box sx={{ flexBasis: '150px' }}>
<Typography
variant="h6"
sx={{
display: 'flex',
justifyContent: 'center',
}}
>
{currentMonthString}
</Typography>
<Typography align='center'>{year}</Typography>
</Box>
<ArrowIncrementButton
onClick={incrementMonth}
/>
</Box>
</> );
}
export default memo(MonthAndYearInfo);
\ No newline at end of file
import { AppBar, Toolbar} from '@mui/material';
import { Box } from '@mui/system';
import MonthAndYearInfo from './MonthAndYearInfo/MonthAndYearInfo';
import СustomSelect from '../../UI/СustomSelect/СustomSelect'
const workers = [{value: '', text: '--выберите сотрудника--'}, {value: 'Василий', text: 'Василий'}, {value: 'Никита', text: 'Никита'}]
const types = [{value: 'Месяц', text: 'Месяц'}, {value: 'Неделя', text: 'Неделя'}]
function MonthCalendarHeader({ currentMonthString, decrementMonth, incrementMonth, calendarType, onChangeWorkerHandler, onChangeCalendarTypeHandler, worker, year}) {
return (
<>
<Box sx={{ flexGrow: 1 }}>
<AppBar position="static">
<Toolbar>
<MonthAndYearInfo
currentMonthString={currentMonthString}
decrementMonth={decrementMonth}
incrementMonth={incrementMonth}
year={year}
/>
<СustomSelect
value={worker}
onChange={(e)=>{onChangeWorkerHandler(e)}}
label={'Сотрудник'}
id={'worker'}
items={workers}
/>
<div style={{marginLeft: '20px'}}>
<СustomSelect
value={calendarType}
onChange={(e)=>{onChangeCalendarTypeHandler(e)}}
label={'Календарь'}
id={'calendar-type'}
items={types}
/>
</div>
</Toolbar>
</AppBar>
</Box>
</>
);
}
export default MonthCalendarHeader;
\ No newline at end of file
import { Button, TextField } from "@mui/material";
import { memo } from "react";
import CustomSelect from '../../UI/СustomSelect/СustomSelect'
const priorities = [{value: null, text: '--Приоритет--'}, {value: 'A', text: 'A'}, {value: 'B', text: 'B'}, {value: 'C', text: 'C'}]
function MonthCalendarModalContent({title, onChangeCurrentTaskHandler, description, priority, sendNewTaskHandler, deleteTaskHandler, startHour, endHour}) {
return (<>
<TextField
id="task-description-title"
value={title}
label="Название"
variant="outlined"
sx={{marginBottom: '30px'}}
name='title'
onChange={(e)=>{onChangeCurrentTaskHandler(e)}}
/>
<TextField
id="task-description"
multiline
rows={4}
value={description}
label="Описание"
variant="outlined"
sx={{marginBottom: '30px'}}
name='description'
onChange={(e)=>{onChangeCurrentTaskHandler(e)}}
/>
<CustomSelect
defaultValue={null}
value={priority}
name={'priority'}
variant={'outlined'}
onChange={(e)=>{onChangeCurrentTaskHandler(e)}}
label={'Приоритет'}
id={'priority-type'}
items={priorities}
/>
<div style={{display: 'flex', gap: '20px', margin: '20px 0'}}>
<TextField
id="task-startHour"
value={startHour}
label="От"
variant="outlined"
name='startHour'
onChange={(e)=>{onChangeCurrentTaskHandler(e)}}
/>
<TextField
id="task-endHour"
value={endHour}
label="До"
variant="outlined"
name='endHour'
onChange={(e)=>{onChangeCurrentTaskHandler(e)}}
/>
</div>
<div style={{display: 'flex', gap: '20px', margin: '10px 0'}}>
<Button id='test_button_save_task'onClick={sendNewTaskHandler}>Сохранить</Button>
<Button onClick={deleteTaskHandler}>Удалить</Button>
</div>
</>);
}
export default memo(MonthCalendarModalContent);
\ No newline at end of file
......@@ -4,7 +4,6 @@ import { useSelector } from "react-redux";
import HasAccess from "../HasAccess/HasAccess";
import AnonymousMenu from "../../Menus/AnonymousMenu/AnonymousMenu";
import WorkerMenu from "../../Menus/WorkerMenu/WorkerMenu";
import AdminMenu from "../../Menus/AdminMenu/AdminMenu";
const AppToolbar = () => {
const user = useSelector(state => state.users.user);
......@@ -23,12 +22,9 @@ const AppToolbar = () => {
<HasAccess allowed={!user}>
<AnonymousMenu />
</HasAccess>
<HasAccess roles={['user']}>
<HasAccess allowed={user}>
<WorkerMenu />
</HasAccess>
<HasAccess roles={['superuser']}>
<AdminMenu />
</HasAccess>
</Toolbar>
</AppBar>
</Box>
......
......@@ -5,7 +5,7 @@ function СustomSelect({ value, onChange, label, variant = 'standard', items, id
return (
<>
<FormControl variant={variant} sx={{ m: 0, minWidth: 120 }}>
<FormControl variant={variant} sx={{ m: 0, minWidth: 125 }}>
<InputLabel id={`${id}-select-label`}>{label}</InputLabel>
<Select
labelId={`${id}-select-label`}
......
......@@ -3,20 +3,11 @@ export const uploadsUrl = `${apiUrl}/uploads`;
export const workerMenuButtons = [
{ text: 'Проекты', path: '/projects' },
{ text: 'Мои задачи', path: '/my-tasks' },
{ text: 'Неделя', path: '/week' },
{ text: 'Месяц', path: '/month' },
{ text: 'Задачи Сотрудников', path: '/workers-tasks' },
{ text: 'Мои задачи', path: '/my-tasks' }
]
export const superuserMenuButtons = [
{ text: 'Проекты', path: '/projects' },
{ text: 'Неделя', path: '/week' },
{ text: 'Месяц', path: '/month' },
{ text: 'Мои задачи', path: '/my-tasks' },
{ text: 'Задачи Сотрудников', path: '/workers-tasks' },
{ text: 'Создать Сотрудника', path: '/sign-up' }
]
export const anonymoysMenuButtons = [
......
import { useEffect, useCallback, useState, useMemo } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import CalendarModalWorkerContent from '../../components/Calendars/CalendarModalWorkerContent/CalendarModalWorkerContent';
import CalendarModalWorkerContent from '../../components/Calendars/UI/CalendarModalWorkerContent/CalendarModalWorkerContent';
import MonthCalendarBody from '../../components/Calendars/MonthCalendar/MonthCalendarBody/MonthCalendarBody';
import MonthCalendarHeader from '../../components/Calendars/MonthCalendar/MonthCalendarHeader/MonthCalendarHeader';
import DefaultModal from '../../components/UI/DefaultModal/DefaultModal';
......@@ -38,10 +38,12 @@ function MonthCalendar() {
setUserId(userCalendarId)
dispatch(fetchCalendarTasks(userCalendarId))
dispatch(fetchCurrentCalendarDisplayName(userCalendarId))
dispatch(fetchAllUserProjects())
} else {
setUserId(user.id)
dispatch(fetchCalendarTasks(user.id))
dispatch(fetchCurrentCalendarDisplayName(user.id))
dispatch(fetchAllUserProjects())
}
}, [userCalendarId, dispatch, user.id])
......@@ -145,10 +147,11 @@ function MonthCalendar() {
startHour: hour,
endHour: hourDue,
startDay: dayNumber
}
},
project: allUserProjects[0].id
}
setCurrentTask((newTask))
}, [dateNow.month, dateNow.year, hourFormat])
}, [dateNow.month, dateNow.year, hourFormat, allUserProjects])
const dragTaskHandler = useCallback(async (dayNumber, hour) => {
const hourDiff = currentTask.infoForCell.endHour - currentTask.infoForCell.startHour
......@@ -238,7 +241,7 @@ function MonthCalendar() {
await dispatch(fetchAllUserProjects())
setModal(true)
} else {
dispatch(setUserCalendarId(null))
setUserCalendarId(null)
}
}, [dispatch, user.id, userId])
......@@ -294,6 +297,7 @@ function MonthCalendar() {
createCopyTask={createCopyTask}
copyTask={copyTask}
setCopyTask={setCopyTask}
allUserProjects={allUserProjects}
/>
</>
......
import {DELETE_MEMBER_FAILURE, DELETE_MEMBER_REQUEST, DELETE_MEMBER_SUCCESS, DELETE_PROJECT_FAILURE, DELETE_PROJECT_REQUEST, DELETE_PROJECT_SUCCESS, FETCH_ALL_USER_PROJECTS_SUCCESS, FETCH_PROJECTS_ERROR, FETCH_PROJECTS_REQUEST, FETCH_PROJECTS_SUCCESS, FETCH_PROJECT_SUCCESS } from "../actionTypes/projectsActionTypes";
import { DELETE_MEMBER_FAILURE, DELETE_MEMBER_REQUEST, DELETE_MEMBER_SUCCESS, DELETE_PROJECT_FAILURE, DELETE_PROJECT_REQUEST, DELETE_PROJECT_SUCCESS, FETCH_ALL_USER_PROJECTS_SUCCESS, FETCH_PROJECTS_ERROR, FETCH_PROJECTS_REQUEST, FETCH_PROJECTS_SUCCESS, FETCH_PROJECT_SUCCESS } from "../actionTypes/projectsActionTypes";
const initialState = {
allUserProjectsForModalTask: [],
allUserProjects: [],
projects: [],
project: "",
loading: false,
error: null
};
};
const projectsReducer = (state = initialState, action) => {
const projectsReducer = (state = initialState, action) => {
switch (action.type) {
case FETCH_PROJECTS_REQUEST:
return {...state, loading: true};
return { ...state, loading: true };
case FETCH_PROJECTS_SUCCESS:
return {...state, loading: false, projects: action.projects};
return { ...state, loading: false, projects: action.projects };
case FETCH_PROJECTS_ERROR:
return {...state, loading: false, error: action.error};
return { ...state, loading: false, error: action.error };
case FETCH_PROJECT_SUCCESS:
return {...state, loading: false, project: action.project}
return { ...state, loading: false, project: action.project }
case DELETE_MEMBER_SUCCESS:
return {...state, loading: false};
return { ...state, loading: false };
case DELETE_MEMBER_REQUEST:
return {...state, loading: true};
return { ...state, loading: true };
case DELETE_MEMBER_FAILURE:
return {...state, loading: false, error: action.error};
return { ...state, loading: false, error: action.error };
case DELETE_PROJECT_SUCCESS:
return {...state, loading: false};
return { ...state, loading: false };
case DELETE_PROJECT_REQUEST:
return {...state, loading: true};
return { ...state, loading: true };
case DELETE_PROJECT_FAILURE:
return {...state, loading: false, error: action.error};
return { ...state, loading: false, error: action.error };
case FETCH_ALL_USER_PROJECTS_SUCCESS:
return {...state, loading: false, allUserProjects: action.projects}
const newArr = action.projects.map((project)=>{
return {value: project.id, text: project.title}
})
return { ...state, loading: false, allUserProjects: action.projects, allUserProjectsForModalTask: newArr}
default:
return state;
}
};
};
export default projectsReducer;
\ No newline at end of file
export default projectsReducer;
\ No newline at end of file
......@@ -38,6 +38,7 @@ const tasksReduсer = (state = initialState, action) => {
for (let copy of task.dateTimeTasks) {
newTasksWithoutInfoForCell.push({
...copy,
project: task?.project?.id,
mainTaskId: task.id,
executor: task.executor,
author: task.author,
......
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