Merge branch 'development' of…

Merge branch 'development' of ssh://git.attractor-school.com:30022/apollo64/crm-team-one into task-110-enhance/CRUD_author_tasks
parents 09cd2acf 752c4a67
...@@ -121,6 +121,7 @@ router.get('/user/:userId', async (req : Request, res : Response): Promise<Respo ...@@ -121,6 +121,7 @@ router.get('/user/:userId', async (req : Request, res : Response): Promise<Respo
router.post('/add-user/', authAdminProject, async (req: Request, res: Response):Promise<Response>=>{ router.post('/add-user/', authAdminProject, async (req: Request, res: Response):Promise<Response>=>{
const {userId, projectId, roleProject} = req.body; const {userId, projectId, roleProject} = req.body;
console.log("req body" + req.body)
const newMember:Member = new Member(); const newMember:Member = new Member();
try{ try{
newMember.user= userId; newMember.user= userId;
......
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
...@@ -12,13 +12,18 @@ const CustomTableCell = ({ ...@@ -12,13 +12,18 @@ const CustomTableCell = ({
onModalOpen, onModalOpen,
placeholder, placeholder,
user, user,
width,
}) => { }) => {
const styles = placeholder ? { width: "100%" } : { width: "auto" }; const styles = { width: width, padding: "1px 16px 1px 1px" };
const inputStyles = placeholder
? { width: "100%", padding: "1px" }
: { padding: "1px" };
const divStyle = { const divStyle = {
display: "flex", display: "flex",
justifyContent: "space-between", justifyContent: "space-between",
flexDirection: "column", flexDirection: "column",
fontSize: "12px", fontSize: "12px",
}; };
const duration = moment.duration( const duration = moment.duration(
...@@ -34,7 +39,7 @@ const CustomTableCell = ({ ...@@ -34,7 +39,7 @@ const CustomTableCell = ({
<TableCell <TableCell
onClick={(e) => (onModalOpen ? onModalOpen(e, task) : null)} onClick={(e) => (onModalOpen ? onModalOpen(e, task) : null)}
align="left" align="left"
// style={styles} style={styles}
> >
{(task.isEditMode && {(task.isEditMode &&
onChange && onChange &&
...@@ -46,7 +51,7 @@ const CustomTableCell = ({ ...@@ -46,7 +51,7 @@ const CustomTableCell = ({
value={value} value={value}
name={name} name={name}
onChange={(e) => onChange(e, task)} onChange={(e) => onChange(e, task)}
style={styles} style={inputStyles}
/> />
) : name !== "dateTimeStart" ? ( ) : name !== "dateTimeStart" ? (
<span>{value}</span> <span>{value}</span>
......
...@@ -21,10 +21,7 @@ import BasicSelect from "../UI/Select/Select"; ...@@ -21,10 +21,7 @@ import BasicSelect from "../UI/Select/Select";
import { addTask } from "../../store/actions/tasksActions"; import { addTask } from "../../store/actions/tasksActions";
import TaskModal from "./TaskModal/TaskModal"; import TaskModal from "./TaskModal/TaskModal";
export default function NewTaskForm({ export default function NewTaskForm({ projects, setAddTaskForm }) {
projects,
setAddTaskForm,
}) {
const dispatch = useDispatch(); const dispatch = useDispatch();
const user = useSelector((state) => state.users.user); const user = useSelector((state) => state.users.user);
const currentDateTime = new Date(); const currentDateTime = new Date();
...@@ -103,8 +100,9 @@ export default function NewTaskForm({ ...@@ -103,8 +100,9 @@ export default function NewTaskForm({
{header.map((headCell) => ( {header.map((headCell) => (
<TableCell <TableCell
key={headCell.id} key={headCell.id}
align="center" align="left"
padding={headCell.disablePadding ? "none" : "normal"} padding={headCell.disablePadding ? "none" : "normal"}
style={{ paddingLeft: "0" }}
> >
{headCell.label} {headCell.label}
</TableCell> </TableCell>
...@@ -113,9 +111,9 @@ export default function NewTaskForm({ ...@@ -113,9 +111,9 @@ export default function NewTaskForm({
</TableHead> </TableHead>
<TableBody> <TableBody>
<TableRow hover key={task.id}> <TableRow hover key={task.id} style={{ paddingLeft: "40px" }}>
<TableCell component="th" scope="row" padding="none"></TableCell> <TableCell style={{ width: "40px", padding: "0" }}></TableCell>
<TableCell> <TableCell style={{ width: "8%", paddingLeft: "0" }}>
<BasicSelect <BasicSelect
items={[ items={[
{ value: "A", title: "A" }, { value: "A", title: "A" },
...@@ -134,8 +132,10 @@ export default function NewTaskForm({ ...@@ -134,8 +132,10 @@ export default function NewTaskForm({
task, task,
name: "createdAt", name: "createdAt",
value: moment(task.createdAt).format("DD-MM-YYYY hh:mm A"), value: moment(task.createdAt).format("DD-MM-YYYY hh:mm A"),
width: "15%",
}} }}
/> />
<CustomTableCell <CustomTableCell
{...{ {...{
task, task,
...@@ -143,11 +143,12 @@ export default function NewTaskForm({ ...@@ -143,11 +143,12 @@ export default function NewTaskForm({
value: task.title, value: task.title,
onModalOpen, onModalOpen,
user: user, user: user,
placeholder: "Кликните для ввода информации по задаче" placeholder: "Кликните для ввода информации по задаче",
width: "auto",
}} }}
/> />
<TableCell> <TableCell style={{ width: "15%", paddingLeft: "0" }}>
<BasicSelect <BasicSelect
items={projects.map((e) => ({ items={projects.map((e) => ({
value: e?.id, value: e?.id,
...@@ -168,7 +169,7 @@ export default function NewTaskForm({ ...@@ -168,7 +169,7 @@ export default function NewTaskForm({
/> />
</TableCell> */} </TableCell> */}
<TableCell> <TableCell style={{ width: "20%", paddingLeft: "0" }}>
<MaterialUIPickers <MaterialUIPickers
task={task} task={task}
name="dateTimeDeadLine" name="dateTimeDeadLine"
...@@ -176,7 +177,7 @@ export default function NewTaskForm({ ...@@ -176,7 +177,7 @@ export default function NewTaskForm({
/> />
</TableCell> </TableCell>
<TableCell> <TableCell style={{ width: "5%" }}>
<Tooltip title="Добавить"> <Tooltip title="Добавить">
<IconButton size="large" onClick={handleAddTask}> <IconButton size="large" onClick={handleAddTask}>
<AddBox fontSize="large" /> <AddBox fontSize="large" />
...@@ -184,16 +185,15 @@ export default function NewTaskForm({ ...@@ -184,16 +185,15 @@ export default function NewTaskForm({
</Tooltip> </Tooltip>
</TableCell> </TableCell>
</TableRow> </TableRow>
</TableBody> </TableBody>
</Table> </Table>
<TaskModal <TaskModal
task={task} task={task}
open={modal} open={modal}
handleClose={handleClose} handleClose={handleClose}
onChange={onChange} onChange={onChange}
user={user} user={user}
/> />
</TableContainer> </TableContainer>
<Divider /> <Divider />
</> </>
......
export const getCurrentWeekDayString = (dayNumber) => {
if (dayNumber <= 6 && dayNumber >= 0) {
return ["ПН","ВТ","СР","ЧТ","ПТ","СБ","ВС"][dayNumber];
} else {
return null
}
}
\ No newline at end of file
import { FormControlLabel, Grid, Switch } from "@mui/material";
import { Box } from "@mui/system";
import CalendarRow from "../../MonthCalendar/MonthCalendarBody/CalendarRow/CalendarRow";
import CalendarSmallCell from "../../MonthCalendar/MonthCalendarBody/CalendarSmallCell/CalendarSmallCell";
import CalendarStandartCell from "../../MonthCalendar/MonthCalendarBody/CalendarStandartCell.js/CalendarStandartCell";
import { getCurrentWeekDayString } from "./Helpers";
function WeekCalendarBody({week, hoursInDay, hourFormat, setHourFormat}) {
return (
<>
<Box style={{marginBottom: '30px'}}>
<Box style={{position: 'sticky', top: '0px', zIndex: '10', backgroundColor: 'lightgrey'}}>
<CalendarRow
>
<CalendarSmallCell xs={1}>
<FormControlLabel
control={<Switch color="primary" checked={hourFormat} onChange={()=>{setHourFormat(()=>!hourFormat)}}/>}
label="1 час"
labelPlacement="end"
/>
</CalendarSmallCell>
{week?.map((weekDay, i)=>{
return (
<CalendarStandartCell key={i} xs={11/week.length}>
<span style={{display: 'block', fontWeight: "600"}}>{weekDay}</span>
<span style={{marginBottom: '10px'}}>{getCurrentWeekDayString(i)}</span>
</CalendarStandartCell>
)
})}
</CalendarRow>
</Box>
<Grid container>
<CalendarRow week={true}>
<Grid item xs={0.995} flexDirection='column'>
{hoursInDay?.map((hour, i)=>{
return (
<CalendarSmallCell key={i} week={true}>
{hour}
</CalendarSmallCell>)
})}
</Grid>
<Grid item xs={11.005}>
<CalendarRow week={true}>
{week?.map((weekDay, i)=>{
return (
<Grid item key={i} xs={12/week.length}>
{hoursInDay?.map((hour, i)=>{
return (
<CalendarStandartCell key={i} week={true}>
</CalendarStandartCell>)
})}
</Grid>)
})}
</CalendarRow>
</Grid>
</CalendarRow>
</Grid>
</Box>
</>
);
}
export default WeekCalendarBody;
\ No newline at end of file
import { AppBar, Toolbar} from '@mui/material';
import { Box } from '@mui/system';
import WeekCalendarHeaderInfo from './WeekCalendarHeaderInfo/WeekCalendarHeaderInfo';
function WeekCalendarHeader({decrementWeek, incrementWeek, weekInfo}) {
return (
<>
<Box sx={{ flexGrow: 1 }}>
<AppBar position="static">
<Toolbar>
<WeekCalendarHeaderInfo
decrementWeek={decrementWeek}
incrementWeek={incrementWeek}
weekInfo={weekInfo}
/>
</Toolbar>
</AppBar>
</Box>
</>
);
}
export default WeekCalendarHeader;
\ No newline at end of file
import ArrowDecrementButton from '../../../UI/ArrowDecrementButton/ArrowDecrementButton';
import ArrowIncrementButton from '../../../UI/ArrowIncrementButton/ArrowIncrementButton';
import { Box } from '@mui/system';
import {Typography} from '@mui/material';
function WeekCalendarHeaderInfo({decrementWeek, incrementWeek, weekInfo}) {
return (
<>
<Box sx={{width: '40%', marginBottom: '15px'}}>
<h2>Цель недели: Наладить режим сна</h2>
<Box sx={{display: 'flex', alignItems: 'center'}}>
<ArrowDecrementButton
onClick={()=>{decrementWeek()}}
/>
<Typography
variant="h6"
sx={{
flexBasis: '250px',
display: 'flex',
justifyContent: 'center',
}}
>
{weekInfo}
</Typography>
<ArrowIncrementButton
onClick={()=>{incrementWeek()}}
/>
</Box>
</Box>
</>
);
}
export default WeekCalendarHeaderInfo;
\ No newline at end of file
...@@ -19,7 +19,6 @@ import TableRowTask from "../../components/MyTasksCompoments/TableRowTask/TableR ...@@ -19,7 +19,6 @@ import TableRowTask from "../../components/MyTasksCompoments/TableRowTask/TableR
export default function EnhancedTable() { export default function EnhancedTable() {
const dispatch = useDispatch(); const dispatch = useDispatch();
const tasks = useSelector((state) => state.tasks.tasks); const tasks = useSelector((state) => state.tasks.tasks);
...@@ -29,31 +28,33 @@ export default function EnhancedTable() { ...@@ -29,31 +28,33 @@ export default function EnhancedTable() {
const [order, setOrder] = useState("asc"); const [order, setOrder] = useState("asc");
const [orderBy, setOrderBy] = useState("id"); const [orderBy, setOrderBy] = useState("id");
const [page, setPage] = useState(0); const [page, setPage] = useState(0);
const [rowsPerPage, setRowsPerPage] =useState(5); const [rowsPerPage, setRowsPerPage] = useState(5);
const [modal, setModal] = useState({ const [modal, setModal] = useState({
open: false, open: false,
task: null, task: null,
}); });
const [projects,setProjects]=useState(['1','2']) const [projects, setProjects] = useState(["1", "2"]);
useEffect(() => { useEffect(() => {
dispatch(fetchAllTasks()); dispatch(fetchAllTasks());
filterProjectsNamesFromTasks() filterProjectsNamesFromTasks();
}, [dispatch]);
useEffect(() => {
if (tasks && tasks?.length > 0) { if (tasks && tasks?.length > 0) {
setRecievedTasks(tasks); setRecievedTasks(tasks);
} }
}, [dispatch, tasks?.length]); }, [dispatch, tasks?.length]);
useEffect(() => { useEffect(() => {
dispatch(fetchAllTasks()); dispatch(fetchAllTasks());
}, [addTaskForm, setAddTaskForm]); }, [addTaskForm, setAddTaskForm]);
const handleRequestSort = ( property) => { const handleRequestSort = ( property) => {
const isAsc = orderBy === property && order === "asc"; const isAsc = orderBy === property && order === "asc";
setOrder(isAsc ? "desc" : "asc"); setOrder(isAsc ? "desc" : "asc");
setOrderBy(property); setOrderBy(property);
}; };
...@@ -72,7 +73,6 @@ useEffect(() => { ...@@ -72,7 +73,6 @@ useEffect(() => {
const name = e.target.name; const name = e.target.name;
const { id } = task; const { id } = task;
const newTasks = recievedTasks.map((task) => { const newTasks = recievedTasks.map((task) => {
console.log(task)
if (task.id === id) { if (task.id === id) {
return { ...task, [name]: value }; return { ...task, [name]: value };
} }
...@@ -108,7 +108,7 @@ useEffect(() => { ...@@ -108,7 +108,7 @@ useEffect(() => {
}); });
setRecievedTasks(newTasks); setRecievedTasks(newTasks);
}; };
const onProjectChange = (e, task) => { const onProjectChange = (e, task) => {
const value = e.target.value; const value = e.target.value;
const project = uniqueProjects.find((e) => e.id === value); const project = uniqueProjects.find((e) => e.id === value);
...@@ -120,12 +120,11 @@ useEffect(() => { ...@@ -120,12 +120,11 @@ useEffect(() => {
updated.projectName = project.title; updated.projectName = project.title;
return updated; return updated;
} }
return task; return task;
}); });
setRecievedTasks(newTasks); setRecievedTasks(newTasks);
}; };
const onToggleEditMode = (id) => { const onToggleEditMode = (id) => {
const newTasks = recievedTasks.map((task) => { const newTasks = recievedTasks.map((task) => {
if (task.id === id) { if (task.id === id) {
...@@ -154,9 +153,9 @@ useEffect(() => { ...@@ -154,9 +153,9 @@ useEffect(() => {
setRecievedTasks(newTasks); setRecievedTasks(newTasks);
}; };
const handleEditTask= (task)=>{ const handleEditTask = (task) => {
dispatch(editTask(task)) dispatch(editTask(task));
} };
const deleteHandle = (id) => { const deleteHandle = (id) => {
dispatch(deleteTask(id)); dispatch(deleteTask(id));
...@@ -186,37 +185,36 @@ useEffect(() => { ...@@ -186,37 +185,36 @@ useEffect(() => {
const [projectName, setProjectName] = React.useState([]); const [projectName, setProjectName] = React.useState([]);
const [filterProjectTumbler, setFilterProjectTumbler] = React.useState(false); const [filterProjectTumbler, setFilterProjectTumbler] = React.useState(false);
const onClose = (projectName) => {
const onClose=(projectName)=>{ let tasksFilteredByProject = tasks;
let tasksFilteredByProject = tasks if (projectName.length > 0) {
if (projectName.length>0) { tasksFilteredByProject = tasks.filter((task) =>
tasksFilteredByProject = tasks.filter(task=>projectName.includes(task.project?.title)) projectName.includes(task.project?.title)
);
} }
setRecievedTasks(tasksFilteredByProject) setRecievedTasks(tasksFilteredByProject);
setFilterProjectTumbler(true) setFilterProjectTumbler(true);
} };
const rawProjects= tasks?.map(task=>task.project) const rawProjects = tasks?.map((task) => task.project);
const filterProjectsNamesFromTasks = ()=>{ const filterProjectsNamesFromTasks = () => {
if (tasks && tasks?.length > 0) { if (tasks && tasks?.length > 0) {
let rawSetProjectNames = [];
let rawSetProjectNames = [] for (let project of rawProjects) {
for (let project of rawProjects){ if (project === null) {
if (project===null){ } else {
} else{ rawSetProjectNames.push(project.title);
rawSetProjectNames.push(project.title)
} }
} }
let uniqueTitlesProjects = [...new Set(rawSetProjectNames)]; let uniqueTitlesProjects = [...new Set(rawSetProjectNames)];
setProjects(uniqueTitlesProjects) setProjects(uniqueTitlesProjects);
} }
} };
const uniqueProjects = rawProjects?.reduce((results, value, index) => { const uniqueProjects = rawProjects?.reduce((results, value, index) => {
const exist = results.find((v) => { const exist = results.find((v) => {
return v !== null && v.id === value?.id return v !== null && v.id === value?.id;
}); });
if (!exist && value !== null) { if (!exist && value !== null) {
results.push(value); results.push(value);
} }
...@@ -243,14 +241,13 @@ console.log('tasks', tasks) ...@@ -243,14 +241,13 @@ console.log('tasks', tasks)
setProjectName={setProjectName} setProjectName={setProjectName}
/> />
{addTaskForm ? ( {addTaskForm ? (
<NewTaskForm <NewTaskForm
projects={uniqueProjects} projects={uniqueProjects}
setAddTaskForm={()=>setAddTaskForm(false)} setAddTaskForm={() => setAddTaskForm(false)}
/> />
) : null} ) : null}
<TableContainer> <TableContainer>
<Table sx={{ minWidth: 600 }} aria-labelledby="tableTitle"> <Table sx={{ minWidth: 600 }} aria-labelledby="tableTitle">
<EnhancedTableHead <EnhancedTableHead
...@@ -260,7 +257,6 @@ console.log('tasks', tasks) ...@@ -260,7 +257,6 @@ console.log('tasks', tasks)
rowCount={tasks.length} rowCount={tasks.length}
/> />
<TableBody> <TableBody>
{stableSort(recievedTasks, getComparator(order, orderBy)) {stableSort(recievedTasks, getComparator(order, orderBy))
.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage) .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
.map((task, index) => { .map((task, index) => {
...@@ -310,7 +306,6 @@ console.log('tasks', tasks) ...@@ -310,7 +306,6 @@ console.log('tasks', tasks)
} }
} }
function descendingComparator(a, b, orderBy) { function descendingComparator(a, b, orderBy) {
if (b[orderBy] < a[orderBy]) { if (b[orderBy] < a[orderBy]) {
return -1; return -1;
......
...@@ -13,36 +13,42 @@ const headCells = [ ...@@ -13,36 +13,42 @@ const headCells = [
numeric: true, numeric: true,
disablePadding: true, disablePadding: true,
label: "", label: "",
canSort: true,
}, },
{ {
id: "priority", id: "priority",
numeric: false, numeric: false,
disablePadding: true, disablePadding: true,
label: "Приоритет", label: "Приоритет",
canSort: true,
}, },
{ {
id: "createdAt", id: "createdAt",
numeric: true, numeric: true,
disablePadding: false, disablePadding: false,
label: "Дата создания", label: "Дата создания",
canSort: true,
}, },
{ {
id: "title", id: "title",
numeric: true, numeric: true,
disablePadding: false, disablePadding: false,
label: "Заголовок", label: "Заголовок",
canSort: true,
}, },
{ {
id: "projectName", id: "projectName",
numeric: true, numeric: true,
disablePadding: false, disablePadding: false,
label: "Проект", label: "Проект",
canSort: true,
}, },
{ {
id: "authorDisplayName", id: "authorDisplayName",
numeric: true, numeric: true,
disablePadding: false, disablePadding: false,
label: "Автор", label: "Автор",
canSort: true,
}, },
{ {
...@@ -50,38 +56,44 @@ const headCells = [ ...@@ -50,38 +56,44 @@ const headCells = [
numeric: true, numeric: true,
disablePadding: false, disablePadding: false,
label: "Дата и время выполнения", label: "Дата и время выполнения",
canSort: false,
}, },
{ {
id: "dateTimeDue", id: "dateTimeDeadLine",
numeric: true, numeric: true,
disablePadding: false, disablePadding: false,
label: "Дедлайн", label: "Дедлайн",
canSort: true,
}, },
{ {
id: "accomplish", id: "accomplish",
numeric: true, numeric: true,
disablePadding: false, disablePadding: false,
label: "Статус", label: "Статус",
canSort: true,
}, },
{ {
id: "change", id: "change",
numeric: false, numeric: false,
disablePadding: false, disablePadding: false,
label: "", label: "",
canSort: false,
}, },
{ {
id: "delete", id: "delete",
numeric: false, numeric: false,
disablePadding: false, disablePadding: false,
label: "", label: "",
canSort: false,
}, },
]; ];
export default function EnhancedTableHead({ order, orderBy, rowCount, onRequestSort }) { export default function EnhancedTableHead({
order,
const createSortHandler = (property) => (event) => { orderBy,
onRequestSort(event, property); rowCount,
}; onRequestSort,
}) {
return ( return (
<TableHead> <TableHead>
...@@ -89,22 +101,31 @@ export default function EnhancedTableHead({ order, orderBy, rowCount, onRequestS ...@@ -89,22 +101,31 @@ export default function EnhancedTableHead({ order, orderBy, rowCount, onRequestS
{headCells.map((headCell) => ( {headCells.map((headCell) => (
<TableCell <TableCell
key={headCell.id} key={headCell.id}
align={"center"} align={"left"}
padding={headCell.disablePadding ? "none" : "normal"} padding={headCell.disablePadding ? "none" : "normal"}
sortDirection={orderBy === headCell.id ? order : false} sortDirection={
headCell.canSort && orderBy === headCell.id ? order : false
}
style={{ paddingLeft: "0" }}
> >
<TableSortLabel {headCell.canSort ? (
active={orderBy === headCell.id} <TableSortLabel
direction={orderBy === headCell.id ? order : "asc"} active={orderBy === headCell.id}
onClick={createSortHandler(headCell.id)} direction={orderBy === headCell.id ? order : "asc"}
> onClick={() => onRequestSort(headCell.id)}
{headCell.label} >
{orderBy === headCell.id ? ( {headCell.label}
<Box component="span" sx={visuallyHidden}> {orderBy === headCell.id ? (
{order === "desc" ? "sorted descending" : "sorted ascending"} <Box component="span" sx={visuallyHidden}>
</Box> {order === "desc"
) : null} ? "sorted descending"
</TableSortLabel> : "sorted ascending"}
</Box>
) : null}
</TableSortLabel>
) : (
<span>{headCell.label}</span>
)}
</TableCell> </TableCell>
))} ))}
</TableRow> </TableRow>
......
import axios from "../../axiosPlanner"; import axios from "../../axiosPlanner";
import { CREATE_MEMBER_SUCCESS, CREATE_PROJECT_SUCCESS, DELETE_MEMBER_FAILURE, DELETE_MEMBER_REQUEST, DELETE_MEMBER_SUCCESS, FETCH_ALL_USER_PROJECTS_SUCCESS, FETCH_MEMBERS_ERROR, FETCH_MEMBERS_REQUEST, FETCH_MEMBERS_SUCCESS, FETCH_PROJECTS_ERROR, FETCH_PROJECTS_REQUEST, FETCH_PROJECTS_SUCCESS, FETCH_PROJECT_SUCCESS } from "../actionTypes/projectsActionTypes"; import { CREATE_MEMBER_SUCCESS, CREATE_PROJECT_SUCCESS, DELETE_MEMBER_FAILURE, DELETE_MEMBER_REQUEST, DELETE_MEMBER_SUCCESS, FETCH_ALL_USER_PROJECTS_SUCCESS, FETCH_MEMBERS_ERROR, FETCH_MEMBERS_REQUEST, FETCH_MEMBERS_SUCCESS, FETCH_PROJECTS_ERROR, FETCH_PROJECTS_REQUEST, FETCH_PROJECTS_SUCCESS, FETCH_PROJECT_SUCCESS } from "../actionTypes/projectsActionTypes";
import { showNotification } from "./commonActions"; import { showNotification } from "./commonActions";
......
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