Commit 87084c37 authored by Ermolaev Timur's avatar Ermolaev Timur

Merge branch 'task-56-feature/drag_and_drop_tasks' into 'development'

Task 56 feature/drag and drop tasks

See merge request !35
parents 5bbfca5e 559fc3b6
import { Grid } from "@mui/material"; import { Grid } from "@mui/material";
import { memo, useMemo } from "react"; import { memo, useEffect, useMemo, useState } from "react";
import CalendarStandartCell from "../CalendarStandartCell.js/CalendarStandartCell"; import CalendarStandartCell from "../CalendarStandartCell.js/CalendarStandartCell";
import CalendarTask from "../CalendarTask/CalendarTask"; import CalendarTask from "../CalendarTask/CalendarTask";
import EmptyBox from "./EmptyBox/EmptyBox";
const CalendarRowDay = ({xs, hoursInDay, createTaskInCellHandler, currentTask, handleOpen, modal, setCurrentTask, year, month, tasks, day, hourFormat}) => { const CalendarRowDay = ({xs, hoursInDay, createTaskInCellHandler, currentTask, handleOpen, modal, setCurrentTask, year, month, tasks, day, hourFormat, setCurrentLine, currentLine, dragTaskHandler}) => {
const hours = useMemo(()=>{ const hours = useMemo(()=>{
return hoursInDay.map((hour)=>parseInt(hour.split(':')[0]))}, return hoursInDay.map((hour)=>parseInt(hour.split(':')[0]))},
...@@ -25,8 +26,8 @@ const CalendarRowDay = ({xs, hoursInDay, createTaskInCellHandler, currentTask, h ...@@ -25,8 +26,8 @@ const CalendarRowDay = ({xs, hoursInDay, createTaskInCellHandler, currentTask, h
const sortedTasks = useMemo(() => { const sortedTasks = useMemo(() => {
if (availableTasks.length) { if (availableTasks.length) {
const newSortedArr = [...availableTasks].sort(function(a,b){ const newSortedArr = [...availableTasks].sort(function(a,b){
const durattionFirstDate = new Date(a.dateTimeDue).getTime() - new Date(a.dateTimeStart).getTime() const durattionFirstDate = a.infoForCell.endHour - a.infoForCell.startHour
const durattionSecondDate = new Date(b.dateTimeDue).getTime() - new Date(b.dateTimeStart).getTime() const durattionSecondDate = b.infoForCell.endHour - b.infoForCell.startHour
return durattionSecondDate - durattionFirstDate; return durattionSecondDate - durattionFirstDate;
}) })
return newSortedArr return newSortedArr
...@@ -44,6 +45,7 @@ const CalendarRowDay = ({xs, hoursInDay, createTaskInCellHandler, currentTask, h ...@@ -44,6 +45,7 @@ const CalendarRowDay = ({xs, hoursInDay, createTaskInCellHandler, currentTask, h
hourDiff = 2 hourDiff = 2
hourDiffEnd = 1 hourDiffEnd = 1
} }
if (availableTasks.length) { if (availableTasks.length) {
lines.push(hoursInDay.map((hour)=>parseInt(hour.split(':')[0]))) lines.push(hoursInDay.map((hour)=>parseInt(hour.split(':')[0])))
for (let k = 0; k < sortedTasks.length; k++) { for (let k = 0; k < sortedTasks.length; k++) {
...@@ -73,11 +75,15 @@ const CalendarRowDay = ({xs, hoursInDay, createTaskInCellHandler, currentTask, h ...@@ -73,11 +75,15 @@ const CalendarRowDay = ({xs, hoursInDay, createTaskInCellHandler, currentTask, h
} }
} }
if (!havePlace) { if (!havePlace) {
if (j + 1 === lines.length) {
lines.push(hoursInDay.map((hour)=>parseInt(hour.split(':')[0])))
}
havePlace = true havePlace = true
break; break;
} }
line[i] += `-${k}` line[i] += `-${k}`
if ((task.infoForCell.endMinute === 59 && task.infoForCell.endHour === hour + hourDiffEnd) || (!hourFormat && task.infoForCell.endMinute === 59 && task.infoForCell.endHour === hour)) { if ((task.infoForCell.endMinute === 59 && task.infoForCell.endHour === hour + hourDiffEnd)
|| (!hourFormat && task.infoForCell.endMinute === 59 && task.infoForCell.endHour === hour)) {
skipLine = true skipLine = true
break; break;
} }
...@@ -101,11 +107,11 @@ const CalendarRowDay = ({xs, hoursInDay, createTaskInCellHandler, currentTask, h ...@@ -101,11 +107,11 @@ const CalendarRowDay = ({xs, hoursInDay, createTaskInCellHandler, currentTask, h
const boxes = [] const boxes = []
for (let i = 0; i < line.length; i++) { for (let i = 0; i < line.length; i++) {
if (!isNaN(line[i])) { if (!isNaN(line[i])) {
if (boxes[boxes.length -1]?.task === null) { // if (boxes[boxes.length -1]?.task === null) {
boxes[boxes.length -1].xs += xs // boxes[boxes.length -1].xs += xs
} else { // } else {
boxes.push({xs: xs, task: null}) boxes.push({xs: xs, task: null, hour: line[i]})
} // }
} else { } else {
const task = sortedTasks[line[i].split('-')[1]] const task = sortedTasks[line[i].split('-')[1]]
const taskIsThere = boxes.find((taskFind)=>{ const taskIsThere = boxes.find((taskFind)=>{
...@@ -114,7 +120,9 @@ const CalendarRowDay = ({xs, hoursInDay, createTaskInCellHandler, currentTask, h ...@@ -114,7 +120,9 @@ const CalendarRowDay = ({xs, hoursInDay, createTaskInCellHandler, currentTask, h
if (taskIsThere) { if (taskIsThere) {
taskIsThere.xs +=xs taskIsThere.xs +=xs
} else { } else {
boxes.push({xs: xs, task: sortedTasks[line[i].split('-')[1]]}) boxes.push({
xs: xs,
task: sortedTasks[line[i].split('-')[1]]})
} }
} }
} }
...@@ -129,17 +137,20 @@ const CalendarRowDay = ({xs, hoursInDay, createTaskInCellHandler, currentTask, h ...@@ -129,17 +137,20 @@ const CalendarRowDay = ({xs, hoursInDay, createTaskInCellHandler, currentTask, h
xs={10.8} xs={10.8}
align='center' align='center'
> >
{hoursInDay.map((hour, i)=>{ {hoursInDay.map((hour, i)=>{
return ( return (
<CalendarStandartCell <CalendarStandartCell
key={i} linesInDay={linesInDay}
item xs={xs} key={i}
createTaskInCellHandler={createTaskInCellHandler} item xs={xs}
hours={hour} createTaskInCellHandler={createTaskInCellHandler}
dayNumber={day.dayNumber} hours={hour}
currentTask={currentTask} dragTaskHandler={dragTaskHandler}
handleOpen={handleOpen} dayNumber={day.dayNumber}
modal={modal} currentTask={currentTask}
handleOpen={handleOpen}
modal={modal}
> >
</CalendarStandartCell> </CalendarStandartCell>
) )
...@@ -148,26 +159,62 @@ const CalendarRowDay = ({xs, hoursInDay, createTaskInCellHandler, currentTask, h ...@@ -148,26 +159,62 @@ const CalendarRowDay = ({xs, hoursInDay, createTaskInCellHandler, currentTask, h
{linesInDay?.map((line, i)=>{ {linesInDay?.map((line, i)=>{
const boxes = getBoxesInLine(line) const boxes = getBoxesInLine(line)
return( return(
<Grid key={i} container sx={{height: '35px', backgroundColor: 'rgb(0,0,0,0)', marginTop: i === 0 ? '-35px' : 0, marginBottom: '5px'}}> <Grid key={i} container sx={{height: '35px', backgroundColor: 'rgb(0,0,0,0)', marginBottom: '5px'}}>
{boxes.map((box)=>{ {boxes.map((box, index)=>{
if (box.task) { if (box.task) {
return (<Grid item xs={box.xs} sx={{height: '35px', marginBottom: '5px'}}> return (<Grid
key={i}
item xs={box.xs}
sx={{height: '35px', marginBottom: '5px'}}
>
<CalendarTask <CalendarTask
dragTaskHandler={dragTaskHandler}
setCurrentLine={()=>{setCurrentLine(day.dayNumber)}}
currentTask={currentTask}
currentLine={currentLine}
hour={parseInt(hours[index])}
line={day.dayNumber}
task={box.task} task={box.task}
setCurrentTask={setCurrentTask} setCurrentTask={setCurrentTask}
handleOpen={handleOpen} handleOpen={handleOpen}
/> />
</Grid>) </Grid>)
} else { } else {
return (<Grid item xs={box.xs} sx={{height: '35px', backgroundColor: 'rgb(0,0,0,0)'}}> return (<EmptyBox
key={i}
</Grid>) modal={modal}
dayNumber={day.dayNumber}
hourNumber={box.hour}
handleOpen={handleOpen}
dragTaskHandler={dragTaskHandler}
createTaskInCellHandler={createTaskInCellHandler}
xs={box.xs}
>
</EmptyBox>)
} }
})} })}
</Grid>) </Grid>)
})} })}
<Grid container sx={{height: '35px', backgroundColor: 'rgb(0,0,0,0)', marginBottom: '5px'}}>
{hoursInDay.map((hour, i)=>{
const hourNumber = parseInt(hour)
return(<EmptyBox
key={i}
modal={modal}
dayNumber={day.dayNumber}
hourNumber={hourNumber}
handleOpen={handleOpen}
dragTaskHandler={dragTaskHandler}
createTaskInCellHandler={createTaskInCellHandler}
xs={xs}
>
</EmptyBox>)
})}
</Grid>
</Grid> </Grid>
</> </>
}; };
export default memo(CalendarRowDay); export default memo(CalendarRowDay);
\ No newline at end of file
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}) => {
const [isThisCell, setIsThisCell] = useState(false)
useEffect(()=>{
if(!modal) {
setIsThisCell(false);
}
}, [modal])
const onClickHandler = (e, dayNumber, hour) => {
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)}}
item xs={xs} sx={{height: '35px', backgroundColor: 'rgb(0,0,0,0)'}}>
{isThisCell ?
<DefaultTask/> : null}
</Grid>)
};
export default memo(EmptyBox, (prevProps, nextProps)=>{
if(!prevProps.modal) return false
if(nextProps.modal) return true
});
\ No newline at end of file
import { Grid} from "@mui/material"; import { Grid} from "@mui/material";
import { memo, useEffect, useState } from "react"; import { memo, useEffect, useState } from "react";
const CalendarStandartCell = ({children, xs, hours, dayNumber, createTaskInCellHandler, handleOpen, modal, divRef }) => { const CalendarStandartCell = ({children, xs, hours, dayNumber, createTaskInCellHandler, handleOpen, modal, divRef, dragTaskHandler, linesInDay}) => {
const [isThisCell, setIsThisCell] = useState(false) const [isThisCell, setIsThisCell] = useState(false)
useEffect(()=>{ useEffect(()=>{
if(!modal) { if(!modal) {
...@@ -9,11 +9,23 @@ const CalendarStandartCell = ({children, xs, hours, dayNumber, createTaskInCell ...@@ -9,11 +9,23 @@ const CalendarStandartCell = ({children, xs, hours, dayNumber, createTaskInCell
} }
}, [modal]) }, [modal])
const dragOverHandler = (e) => {
e.preventDefault();
}
const dropHandler = (e) => {
e.stopPropagation()
e.preventDefault();
dragTaskHandler(dayNumber, parseInt(hours.split(':')[0]))
}
return <> return <>
<Grid <Grid
item xs={xs} item xs={xs}
sx={{position: 'relative', height: '35px'}} sx={{position: 'relative', height: linesInDay?.length ? `${35*linesInDay}px` : '35px'}}
onClick={(e)=>{createTaskInCellHandler(dayNumber, hours); setIsThisCell(true); handleOpen(e)}} onClick={(e)=>{createTaskInCellHandler(dayNumber, hours); setIsThisCell(true); handleOpen(e)}}
onDragOver={(e)=>{dragOverHandler(e)}}
onDrop={(e)=>{dropHandler(e)}}
> >
{children} {children}
{isThisCell ? {isThisCell ?
......
import { Grid} from "@mui/material"; import { Grid} from "@mui/material";
import React, { memo} from "react"; import React, { memo, useEffect, useState} from "react";
const CalendarTask = ({setCurrentTask, handleOpen, task}) => { const CalendarTask = ({setCurrentTask, handleOpen, task, line, setCurrentLine, currentLine, currentTask, dragTaskHandler, hour}) => {
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) => { const onClickTaskHandler = (e, task) => {
...@@ -12,10 +23,26 @@ const CalendarTask = ({setCurrentTask, handleOpen, task}) => { ...@@ -12,10 +23,26 @@ const CalendarTask = ({setCurrentTask, handleOpen, task}) => {
handleOpen(e) handleOpen(e)
} }
return (<> 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 <Grid
sx={{ 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'}} draggable={true}
onClick={(e)=>{onClickTaskHandler(e, task)}}
onDragLeave={(e)=>{dragLeaveHandler(e)}}
onDragStart={(e)=>{dragStartHandler(e, line, task)}}
onDragEnd={(e)=>{dragEndHandler(e)}}
sx={{ position: 'relative', height: '30px', backgroundColor: color, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', borderRadius: '10px', margin: '5px 10px', display: 'flex', justifyContent: 'flex-start', alignItems: 'center', paddingLeft: '5px', zIndex: '5'}}
onClick={(e)=>{onClickTaskHandler(e, task)}}
> >
<span> <span>
{task.title} {task.title}
......
import { Box } from "@mui/material";
import { memo } from "react";
const DefaultTask = ({}) => {
return (<>
<Box
sx={{ 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'}}
>
<span>
Задача
</span>
</Box>
</>)
};
export default memo(DefaultTask);
\ No newline at end of file
import { FormControlLabel, Switch} from "@mui/material"; import { FormControlLabel, Switch} from "@mui/material";
import { useEffect, useRef, useState } from "react"; import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import CalendarRow from "./CalendarRow/CalendarRow"; import CalendarRow from "./CalendarRow/CalendarRow";
import CalendarSmallCell from "./CalendarSmallCell/CalendarSmallCell"; import CalendarSmallCell from "./CalendarSmallCell/CalendarSmallCell";
import CalendarStandartCell from "./CalendarStandartCell.js/CalendarStandartCell"; import CalendarStandartCell from "./CalendarStandartCell.js/CalendarStandartCell";
...@@ -7,33 +7,39 @@ import ModalTask from "../UI/ModalTask/ModalTask"; ...@@ -7,33 +7,39 @@ import ModalTask from "../UI/ModalTask/ModalTask";
import MonthCalendarModalContent from "../MonthCalendarModalContent/MonthCalendarModalContent"; import MonthCalendarModalContent from "../MonthCalendarModalContent/MonthCalendarModalContent";
import CalendarRowDay from "./CalendarRowDay/CalendarRowDay"; import CalendarRowDay from "./CalendarRowDay/CalendarRowDay";
function MonthCalendarBody({month, year, tasks, createTaskInCellHandler, currentTask, setCurrentTask, hourFormat, setHourFormat, onChangeCurrentTaskHandler, sendNewTaskHandler, deleteTaskHandler, cellSizes, hoursInDay, daysInMonth}) {
function MonthCalendarBody({month, year, tasks, createTaskInCellHandler, currentTask, setCurrentTask, hourFormat, setHourFormat, onChangeCurrentTaskHandler, sendNewTaskHandler, deleteTaskHandler, cellSizes, hoursInDay, daysInMonth, dragTaskHandler}) {
const [currentLine, setCurrentLine] = useState('')
const [modal, setModal] = useState({open:false, y: 0, x: 0,}); const [modal, setModal] = useState({open:false, y: 0, x: 0,});
const handleOpen = (e) => { const handleOpen = (e) => {
setModal( { setModal( {
open: true, open: true,
yPage: e.pageY, yPage: e.clientY,
xPage: e.pageX, xPage: e.clientX,
yDivClick: e.nativeEvent.offsetY, yDivClick: e.nativeEvent.offsetY,
xDivClick: e.nativeEvent.offsetX, xDivClick: e.nativeEvent.offsetX,
yDiv: e.target.offsetHeight, yDiv: e.target.offsetHeight,
xDiv: e.target.offsetWidth, xDiv: e.target.offsetWidth,
}) })
}; };
const handleClose = () => { const handleClose = () => {
setModal({...modal, open: false}) setModal({...modal, open: false})
setCurrentTask({}) setCurrentTask({})
}; };
const divRef = useRef(null) const divRef = useRef(null)
const [divHeight, setDivHeight] = useState('') const [divHeight, setDivHeight] = useState('')
useEffect(() => { useEffect(() => {
if (divRef) { if (divRef) {
setDivHeight(()=>{ setDivHeight(()=>{
return divRef.current?.offsetHeight return divRef.current?.offsetHeight
}) })
} }
}, [divRef.current?.offsetHeight, hourFormat, month, tasks]); }, [divRef.current?.offsetHeight, hourFormat, month, tasks]);
return ( return (
<div ref={divRef} style={{marginBottom: '30px'}}> <div ref={divRef} style={{marginBottom: '30px'}}>
...@@ -54,30 +60,34 @@ function MonthCalendarBody({month, year, tasks, createTaskInCellHandler, current ...@@ -54,30 +60,34 @@ function MonthCalendarBody({month, year, tasks, createTaskInCellHandler, current
) )
})} })}
</CalendarRow> </CalendarRow>
{daysInMonth?.map((day, i)=>{ {daysInMonth?.map((day, i)=>{
return ( return (
<CalendarRow <CalendarRow
key={i} key={i}
> >
<CalendarSmallCell xs={cellSizes.smallCell}>{day.dayNumber}</CalendarSmallCell> <CalendarSmallCell xs={cellSizes.smallCell}>{day.dayNumber}</CalendarSmallCell>
<CalendarSmallCell xs={cellSizes.smallCell}>{day.dayOfWeek}</CalendarSmallCell> <CalendarSmallCell xs={cellSizes.smallCell}>{day.dayOfWeek}</CalendarSmallCell>
<CalendarRowDay <CalendarRowDay
xs={cellSizes.dayCell} dragTaskHandler={dragTaskHandler}
createTaskInCellHandler={createTaskInCellHandler} xs={cellSizes.dayCell}
hoursInDay={hoursInDay} createTaskInCellHandler={createTaskInCellHandler}
currentTask={currentTask} hoursInDay={hoursInDay}
handleOpen={handleOpen} currentTask={currentTask}
modal={modal.open} handleOpen={handleOpen}
setCurrentTask={setCurrentTask} currentLine={currentLine}
year={year} setCurrentLine={setCurrentLine}
month={month} modal={modal.open}
tasks={tasks} setCurrentTask={setCurrentTask}
day={day} year={year}
hourFormat={hourFormat} month={month}
/> tasks={tasks}
</CalendarRow> day={day}
) hourFormat={hourFormat}
})} >
</CalendarRowDay>
</CalendarRow>
)
})}
<ModalTask <ModalTask
modal={modal} modal={modal}
handleClose={()=>{handleClose()}} handleClose={()=>{handleClose()}}
......
...@@ -101,8 +101,14 @@ function MonthCalendar() { ...@@ -101,8 +101,14 @@ function MonthCalendar() {
const iso = dateLocal.toISOString(); const iso = dateLocal.toISOString();
return iso; return iso;
} }
const createTaskInCellHandler = (dayNumber, dayHour) => { const createTaskInCellHandler = (dayNumber, dayHour) => {
const hour = parseInt(dayHour.split(':')[0]) let hour
if (!isNaN(dayHour)) {
hour = dayHour
} else {
hour = parseInt(dayHour.split(':')[0])
}
let hourDue let hourDue
if (hourFormat) { if (hourFormat) {
hourDue = hour + 0 hourDue = hour + 0
...@@ -118,11 +124,26 @@ function MonthCalendar() { ...@@ -118,11 +124,26 @@ function MonthCalendar() {
} }
setCurrentTask((newTask)) setCurrentTask((newTask))
} }
const dragTaskHandler = async (dayNumber, hour) => {
const timeEnd = currentTask.dateTimeDue.split('T')[1]
const timeEndHour = parseInt(timeEnd.split(':')[0])
const timeStart = currentTask.dateTimeStart.split('T')[1]
const timeStartHour = parseInt(timeStart.split(':')[0])
const hourDiff = timeEndHour - timeStartHour
const due = dateToISOLikeButLocal(new Date(dateNow.year, dateNow.month, dayNumber, hour + hourDiff, 59))
const start = dateToISOLikeButLocal(new Date(dateNow.year, dateNow.month, dayNumber, hour, 0))
await dispatch(editTask({
...currentTask,
dateTimeStart: start,
dateTimeDue: due
}))
setCurrentTask({})
}
const sendNewTaskHandler = async () => { const sendNewTaskHandler = async () => {
if (currentTask.id) { if (currentTask.id) {
delete currentTask.infoForCell delete currentTask.infoForCell
console.log(currentTask)
setCurrentTask(() => { setCurrentTask(() => {
return{ return{
...currentTask, ...currentTask,
...@@ -171,6 +192,7 @@ function MonthCalendar() { ...@@ -171,6 +192,7 @@ function MonthCalendar() {
cellSizes={cellSizes} cellSizes={cellSizes}
hoursInDay={hoursInDay} hoursInDay={hoursInDay}
daysInMonth={daysInMonth} daysInMonth={daysInMonth}
dragTaskHandler={dragTaskHandler}
/> />
</> </>
......
...@@ -98,11 +98,8 @@ const editTaskFailure = (error) => { ...@@ -98,11 +98,8 @@ const editTaskFailure = (error) => {
export const editTask = (task) => { export const editTask = (task) => {
return async (dispatch, getState) => { return async (dispatch, getState) => {
dispatch(editTaskRequest()); dispatch(editTaskRequest());
// const token = getState().users?.user?.token;
try { try {
console.log('task' , task) await axios.put("/tasks", task);
const r=await axios.put("/tasks/", task);
console.log(r)
dispatch(editTaskSuccess()) dispatch(editTaskSuccess())
dispatch(fetchAllTasks()) dispatch(fetchAllTasks())
dispatch(fetchCalendarTasks()) dispatch(fetchCalendarTasks())
......
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