Merge branch 'development' of…

Merge branch 'development' of ssh://git.attractor-school.com:30022/apollo64/crm-team-one into task-136-fix/project_select_my_tasks
parents f45ef93f 1db10f3d
......@@ -108,10 +108,11 @@ router.delete('/:dateTimeTaskId',authAuthorOrExecutorOfDateTimeTask, async(req:R
}
}
if (dateTimeTasks.length ===1 ) {
if (dateTimeTasks.length === 1 ) {
if ( authorStatus) {
Task.remove(task)
return res.send({message:"task delete succesfully"})
task.dateTimeTasks = []
await task.save()
return res.send({message:"copyTask delete succesfully"})
} else{
return res.send({message:"not uathorized to delete task"})
}
......
......@@ -194,6 +194,7 @@ router.delete('/remove-user/:userId', authAdminProject,async (req: Request, res:
router.put('/change-project-role/:userId',authAdminProject, async (req: Request, res: Response):Promise<Response|void> =>{
const {userId}= req.params
const {projectId, newRoleProject} =req.body
const member = await dataSource
.createQueryBuilder()
.select("member")
......@@ -212,6 +213,7 @@ router.put('/change-project-role/:userId',authAdminProject, async (req: Request
return res.send({message:"failed to change role"})
}
return res.send({message:"User's new role ", newRoleProject})
})
export default router;
......@@ -9,7 +9,6 @@ import MonthCalendar from './containers/MonthCalendar/MonthCalendar';
import ForgottenPassword from "./containers/ForgottenPassword/ForgottenPassword";
import Projects from "./containers/Projects/Projects";
import FullProject from "./containers/FullProject/FullProject";
import NewProject from "./containers/NewProject/NewProject";
import WeekCalendar from "./containers/WeekCalendar/WeekCalendar";
import UsersTasks from "./containers/UsersTasks/UsersTasks";
......
import { Box, Button } from "@mui/material";
import { memo } from "react";
const style = {
position: 'fixed',
left: '50%',
bottom: 10,
width: '30%',
height: '70px',
backgroundColor: 'white',
border: '2px solid black',
borderRadius: '10px',
zIndex: '100',
transform: 'translateX(-50%)',
boxShadow: '0px 5px 54px 27px rgba(34, 60, 80, 0.2)',
display: 'flex',
alignItems: 'center',
justifyContent: 'space-around'
}
const CreateCopyTasksModeBlock = ({ copyMode, copyModeReturn, copyModeStay }) => {
return (<>
{copyMode ?
<Box sx={style}>
<Button onClick={copyModeStay} sx={{fontWeight: 800}}>
Остаться
</Button>
<Button onClick={copyModeReturn} sx={{fontWeight: 800}}>
Вернуться
</Button>
</Box>
: null}
</>
);
};
export default memo(CreateCopyTasksModeBlock);
......@@ -81,6 +81,7 @@ const CalendarRowDay = ({ xs, hoursInDay, createTaskInCellHandler, currentTask,
copyTask={copyTask}
createCopyTask={createCopyTask}
month={month}
year={year}
>
</CalendarStandartCell>
)
......
......@@ -6,7 +6,6 @@ import CalendarStandartCell from "../../UI/CalendarStandartCell/CalendarStandart
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}) {
......
import { AppBar, Button, Toolbar, Typography } from '@mui/material';
import { AppBar, Toolbar, } from '@mui/material';
import { Box } from '@mui/system';
import ButtonSwapCalendar from '../../UI/ButtonSwapCalendar/ButtonSwapCalendar';
import CalendarUserDisplayName from '../../UI/CalendarUserDisplayName/CalendarUserDisplayName';
......
import { Grid } from "@mui/material";
import { memo, useEffect, useState } from "react";
import { memo, useCallback, useEffect, useMemo, useState } from "react";
import DefaultTask from "../DefaultTask/DefaultTask";
const heightCell = 40
const CalendarStandartCell = ({ children, xs, hours, dayNumber, createTaskInCellHandler, handleOpen, modal, dragTaskHandler, linesInDay, week, copyTask, createCopyTask, month, year }) => {
const CalendarStandartCell = ({ children, xs, hours, dayNumber, createTaskInCellHandler, handleOpen, modal, dragTaskHandler, linesInDay, week, copyTask, createCopyTask, month, year, copyMode, copyModeTask }) => {
const [isThisCell, setIsThisCell] = useState(false)
const [top, setTop] = useState(0)
const cellClass = {
position: 'relative',
height: linesInDay?.length ? `${heightCell * linesInDay.length + 5}px` : `${45}px`,
borderRight: '1px solid black',
borderBottom: week ? '1px solid black' : null,
transition: week ? '0.3s' : null,
'&:hover': {
transition: '0.3s',
cursor: children ? null : '#d6d2d2',
background: children ? null : '#d6d2d2'
},
}
const isDeadLine = useMemo(()=>{
if (copyTask?.dateTimeDeadLine) {
if (new Date(copyTask?.dateTimeDeadLine).getTime() - new Date(year, month, dayNumber, parseInt(hours?.split(':')[0])).getTime() < 0 ) {
return true
}
} else {
if (copyModeTask?.dateTimeDeadLine) {
if (new Date(copyModeTask?.dateTimeDeadLine).getTime() - new Date(year, month, dayNumber, parseInt(hours?.split(':')[0])).getTime() < 0 ) {
return true
}
} else {
return false
}
}
},[copyTask, copyModeTask, year, month, dayNumber, hours])
console.log(copyTask)
const cellClass = useMemo(() => {
const backgroundColor = isDeadLine ? '#fa9b9be3' : 'null'
return ({
position: 'relative',
height: linesInDay?.length ? `${heightCell * linesInDay.length + 5}px` : `${45}px`,
borderRight: '1px solid black',
borderBottom: week ? '1px solid black' : null,
padding: week ? '2px' : null,
transition: week ? '0.3s' : null,
backgroundColor: backgroundColor,
'&:hover': {
transition: '0.3s',
cursor: children ? null : '#d6d2d2',
background: children ? null : '#d6d2d2'
}
})
}, [children, linesInDay?.length, week, isDeadLine])
useEffect(() => {
if (!modal) {
......@@ -25,23 +48,23 @@ const CalendarStandartCell = ({ children, xs, hours, dayNumber, createTaskInCell
}
}, [modal])
const dragOverHandler = (e) => {
const dragOverHandler = useCallback((e) => {
e.preventDefault();
e.target.style.background = children ? null : '#d6d2d2'
}
const dragLeaveHandler = (e) => {
}, [children])
const dragLeaveHandler = useCallback((e) => {
e.preventDefault();
e.target.style.background = null
}
}, [])
const dropHandler = (e) => {
const dropHandler = useCallback((e) => {
e.stopPropagation()
e.preventDefault();
e.target.style.background = null
dragTaskHandler(dayNumber, parseInt(hours.split(':')[0]), month, year)
}
}, [dayNumber, hours, month, year, dragTaskHandler])
const onClickHandler = (e) => {
const onClickHandler = useCallback((e) => {
if (!week) {
if (e.nativeEvent.offsetY <= 5) {
setTop(40 * Math.ceil((e.nativeEvent.offsetY) / 40 - 1))
......@@ -49,29 +72,58 @@ const CalendarStandartCell = ({ children, xs, hours, dayNumber, createTaskInCell
setTop(40 * Math.ceil((e.nativeEvent.offsetY - 5) / 40 - 1))
}
}
if (copyTask) {
if (copyTask || copyMode) {
createCopyTask(dayNumber, parseInt(hours.split(':')[0]), month, year)
} else {
createTaskInCellHandler(dayNumber, hours, month, year);
setIsThisCell(true);
handleOpen(e)
}
}
}, [week, copyTask, copyMode, dayNumber, hours, month, year, createTaskInCellHandler, createCopyTask, handleOpen])
return <>
<Grid
item xs={xs}
sx={cellClass}
onClick={(e) => { onClickHandler(e) }}
onDragOver={(e) => { dragOverHandler(e) }}
onDragLeave={(e) => { dragLeaveHandler(e) }}
onDrop={(e) => { dropHandler(e) }}
>
{children}
{isThisCell ?
<DefaultTask week={week} top={top} /> : null}
const returnCells = useMemo(() => {
if (copyTask || copyMode) {
if (isDeadLine) {
return (<Grid
item xs={xs}
sx={cellClass}
>
</Grid>)
} else {
return (<Grid
item xs={xs}
sx={cellClass}
onClick={(e) => { onClickHandler(e) }}
onDragOver={(e) => { dragOverHandler(e) }}
onDragLeave={(e) => { dragLeaveHandler(e) }}
onDrop={(e) => { dropHandler(e) }}
>
{children}
{isThisCell ?
<DefaultTask week={week} top={top} /> : null}
</Grid>)
}
}
return (<>
<Grid
item xs={xs}
sx={cellClass}
onClick={(e) => { onClickHandler(e) }}
onDragOver={(e) => { dragOverHandler(e) }}
onDragLeave={(e) => { dragLeaveHandler(e) }}
onDrop={(e) => { dropHandler(e) }}
>
{children}
{isThisCell ?
<DefaultTask week={week} top={top} /> : null}
</Grid>
</Grid>
</>)
}, [cellClass, children, copyMode, copyTask, dragOverHandler, dropHandler, isThisCell, onClickHandler, top, week, xs, dragLeaveHandler, isDeadLine])
return <>
{returnCells}
</>
};
......
import React, {useState} from 'react';
import DatePicker from "react-datepicker";
const DateTimePicker =({task,name,onChange}) => {
const [startDate, setStartDate] = useState(new Date());
return (
<>
<DatePicker
selected={startDate}
onChange={(date) => setStartDate(date)}
// locale="ru"
showTimeSelect
timeFormat="p"
timeIntervals={60}
dateFormat="Pp"
/>
</>
);
};
export default DateTimePicker;
import React, { memo} from "react";
import DeleteIcons from '@mui/icons-material/Delete';
const DeleteIcon = ({onClick}) => {
const styles = { width: '20px', cursor: 'pointer', marginLeft: 'auto', marginTop: '5px', marginRight: '5px'}
return (
<DeleteIcons sx={styles} onClick={onClick}>
</DeleteIcons>)
};
export default memo(DeleteIcon);
\ No newline at end of file
import Box from '@mui/material/Box';
import Modal from '@mui/material/Modal';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { useCallback, useEffect, useState } from 'react';
export default function ModalTask({ modal, handleClose, children, week }) {
......@@ -38,7 +38,7 @@ export default function ModalTask({ modal, handleClose, children, week }) {
return modal.yClickСordinates - modal.yDiv - modal.yDivClick - ((modal.yClickСordinates + 470) - windowDimenion.winHeight) - 30
}
}
}, [windowDimenion.winHeight, modal])
}, [windowDimenion.winHeight, modal, week])
const getXCordinatesToModal = useCallback(() => {
if (windowDimenion.winWidth > modal.xClickСordinates + 270 + modal.xDiv) {
......
......@@ -8,7 +8,7 @@ import { getTasksWithInfoForPosition, getWidthLeftZIndex } from "./Helpers";
function CalendarColumnDayWeek({ hoursInDay, tasks, month, year, day, hourFormat, handleOpen, setCurrentTask, copyTask, setCopyTask, createCopyTask, createTaskInCellHandler, modal, dragTaskHandler }) {
function CalendarColumnDayWeek({ hoursInDay, tasks, month, year, day, hourFormat, handleOpen, setCurrentTask, copyTask, setCopyTask, createCopyTask, createTaskInCellHandler, modal, dragTaskHandler, copyMode, deleteTaskHandler }) {
const [columnDaySize, setColumnDaySize] = useState({ width: 0, height: 0 })
......@@ -62,6 +62,8 @@ function CalendarColumnDayWeek({ hoursInDay, tasks, month, year, day, hourFormat
step={step}
tasksLength={tasksLength}
hourFormat={hourFormat}
copyModeTask={copyMode.task}
deleteTaskHandler={deleteTaskHandler}
>
</CalendarWeekTask>
)
......@@ -84,6 +86,8 @@ function CalendarColumnDayWeek({ hoursInDay, tasks, month, year, day, hourFormat
month={month}
year={year}
dragTaskHandler={dragTaskHandler}
copyMode={copyMode.working}
copyModeTask={copyMode.task}
>
</CalendarStandartCell>
)
......
......@@ -2,9 +2,10 @@ import { Box } from "@mui/material"
import { useEffect, useState, memo, useCallback, useMemo } from "react"
import { getColorTaskByPriority } from "../../../../../../helpers/CalendarHelpers"
import CopyIcon from "../../../../UI/CopyIcon/CopyIcon";
import DeleteIcon from "../../../../UI/DeleteIcon/DeleteIcon";
function CalendarWeekTask({ height, width, left, top, task, zIndex, handleOpen, setCurrentTask, modal, setCopyTask, month, dragTaskHandler, step, hourFormat, tasksLength }) {
function CalendarWeekTask({ height, width, left, top, task, zIndex, handleOpen, setCurrentTask, modal, setCopyTask, month, dragTaskHandler, step, hourFormat, tasksLength, copyModeTask, deleteTaskHandler }) {
const [zIndexStyle, setZIndexStyle] = useState(10)
const color = useMemo(() => {
return getColorTaskByPriority(task.priority)
......@@ -94,7 +95,40 @@ function CalendarWeekTask({ height, width, left, top, task, zIndex, handleOpen,
e.stopPropagation();
setCopyTask(task)
}, [task, setCopyTask])
console.log(tasksLength)
const returnTask = useMemo(() => {
if (copyModeTask?.id === task?.mainTaskId) {
return (<>
<span style={{ textOverflow: 'ellipsis', padding: '5px 0 0 5px' }}>
{task.title}
</span>
<DeleteIcon
onClick={(e) => { deleteTaskHandler(e, task.id) }}
/>
</>)
}
if (tasksLength > 2) {
return (<>
<CopyIcon
tasksLength={tasksLength}
onClick={(e) => { onClickCopyIconHandler(e) }}
/>
<span style={{ textOverflow: 'ellipsis', padding: '5px 0 0 5px' }}>
{task.title}
</span>
</>)
} else {
return (<>
<span style={{ textOverflow: 'ellipsis', padding: '5px 0 0 5px' }}>
{task.title}
</span>
<CopyIcon
onClick={(e) => { onClickCopyIconHandler(e) }}
/>
</>)
}
}, [tasksLength, task.title, onClickCopyIconHandler, copyModeTask?.id, deleteTaskHandler, task?.id, task?.mainTaskId])
return (
<Box
draggable={true}
......@@ -106,22 +140,7 @@ function CalendarWeekTask({ height, width, left, top, task, zIndex, handleOpen,
onClick={(e) => { onClickTaskHandler(e, task) }}
className='calendar_task_block'
sx={styles}>
{tasksLength > 2 ? <>
<CopyIcon
tasksLength={tasksLength}
onClick={(e) => { onClickCopyIconHandler(e) }}
/>
<span style={{ textOverflow: 'ellipsis', padding: '5px 0 0 5px' }}>
{task.title}
</span>
</>
: <>
<span style={{ textOverflow: 'ellipsis', padding: '5px 0 0 5px' }}>
{task.title}
</span>
<CopyIcon
onClick={(e) => { onClickCopyIconHandler(e) }}
/> </>}
{returnTask}
</Box>);
}
......
......@@ -10,7 +10,7 @@ import HourFormatSwitch from "../../UI/HourFormatSwitch/HourFormatSwitch";
import CalendarColumnDayWeek from "./CalendarColumnDayWeek/CalendarColumnDayWeek";
import { getCurrentWeekDayString, getMonthAndYearToDayColumn } from "./Helpers";
function WeekCalendarBody({ week, hoursInDay, hourFormat, setHourFormat, date, tasks, currentTask, setCurrentTask, onChangeCurrentTaskHandler, deleteTaskHandler, sendNewTaskHandler, createTaskInCellHandler, copyTask, setCopyTask, createCopyTask, dragTaskHandler }) {
function WeekCalendarBody({ week, hoursInDay, hourFormat, setHourFormat, date, tasks, currentTask, setCurrentTask, onChangeCurrentTaskHandler, deleteTaskHandler, sendNewTaskHandler, createTaskInCellHandler, copyTask, setCopyTask, createCopyTask, dragTaskHandler, copyMode }) {
const [modal, setModal] = useState({ open: false, y: 0, x: 0, });
const handleOpen = useCallback((e) => {
setModal({
......@@ -31,7 +31,7 @@ function WeekCalendarBody({ week, hoursInDay, hourFormat, setHourFormat, date, t
return (
<>
<Box style={{ marginBottom: '30px' }}>
<Box style={{ marginBottom: copyMode.working ? '100px' : '30px'}}>
<Box style={{ position: 'sticky', top: '0px', zIndex: '10', backgroundColor: 'lightgrey' }}>
<CalendarRow
>
......@@ -84,6 +84,8 @@ function WeekCalendarBody({ week, hoursInDay, hourFormat, setHourFormat, date, t
setCopyTask={setCopyTask}
createCopyTask={createCopyTask}
dragTaskHandler={dragTaskHandler}
copyMode={copyMode}
deleteTaskHandler={deleteTaskHandler}
/>
)
})}
......@@ -109,7 +111,7 @@ function WeekCalendarBody({ week, hoursInDay, hourFormat, setHourFormat, date, t
project={currentTask.project}
onChangeCurrentTaskHandler={(e) => { onChangeCurrentTaskHandler(e) }}
sendNewTaskHandler={() => { sendNewTaskHandler(); handleClose() }}
deleteTaskHandler={() => { deleteTaskHandler(currentTask.id); handleClose() }}
deleteTaskHandler={(e) => { deleteTaskHandler(e, currentTask.id); handleClose() }}
/>
</ModalTask>
</>
......
import { Box, Button, Grid, Modal } from "@mui/material";
import { useState } from "react";
import { useSelector, useDispatch } from "react-redux";
import { Typography } from "@mui/material";
import TextField from '@mui/material/TextField';
import Autocomplete from '@mui/material/Autocomplete';
import { useParams } from "react-router-dom";
import PersonAddIcon from '@mui/icons-material/PersonAdd';
import { useEffect } from "react";
import { fetchProject } from "../../store/actions/projectsActions";
const style = {
position: 'relative',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
width: 400,
bgcolor: 'background.paper',
border: '2px solid #000',
boxShadow: 24,
p: 4,
};
const MemberForm = ({ onSubmit, members }) => {
const users = useSelector(state => state.users.users)
const [role, setRole] = useState([{ role: "user" }, { role: "admin" }, { role: "watcher" }])
const params = useParams()
const dispatch = useDispatch();
const [open, setOpen] = useState(false);
const handleOpen = () => setOpen(true);
const handleClose = () => setOpen(false);
const [state, setState] = useState({
roleProject: "",
user: "",
projectId: ""
});
const submitFormHandler = (e) => {
e.preventDefault();
let members = { roleProject: state.roleProject, projectId: params.id, userId: state.user.id }
console.log(members);
onSubmit(members);
setOpen(false);
};
console.log(state);
useEffect(() => {
dispatch(fetchProject(params.id))
}, [params]);
const memberChangeHandler = (e, value) => {
setState(() => { return { ...state, user: value, projectId: params.id } });
console.log("memberChangeHandler" + value)
}
const roleChangeHandler = (e, value) => {
setState(() => { return { ...state, roleProject: value } });
console.log(value)
}
return (
<div >
<PersonAddIcon onClick={handleOpen} style={{ marginLeft: "30px", marginTop: "-3px", cursor: 'pointer' }} >Добавить участника</PersonAddIcon>
<Modal
open={open}
onClose={handleClose}
aria-labelledby="modal-modal-title"
aria-describedby="modal-modal-description"
>
<Box sx={style}>
<form onSubmit={submitFormHandler}>
<Grid container direction="column" spacing={2}>
<Typography variant="h5" style={{ margin: "5px", textAlign: "center" }} >Новый участник</Typography>
<Autocomplete
id="free-solo-demo"
freeSolo
options={users}
getOptionLabel={(item) => (members[0]?.user?.displayName !== item.displayName) ? (item.displayName || "") : ""}
onChange={memberChangeHandler}
name={"userId"}
value={state.user}
renderInput={(params) => <TextField
style={{ margin: "5px" }}
label={"Участник"}
state={state}
{...params} />}
/>
<Autocomplete
id="free-solo-demo"
freeSolo
options={role?.map((role) => role.role)}
value={state.roleProject}
onChange={roleChangeHandler}
renderInput={(params) => <TextField
style={{ margin: "5px" }}
name={"roleProject"}
label={"Роль в проекте"}
state={state}
{...params} />}
/>
<Grid item>
<Button
type="submit"
color="primary"
variant="contained"
>
Create
</Button>
</Grid>
</Grid>
</form>
</Box>
</Modal>
</div>
);
};
export default MemberForm;
\ No newline at end of file
......@@ -22,6 +22,9 @@ import BasicSelect from "../../UI/Select/Select";
import CalendarMonthIcon from '@mui/icons-material/CalendarMonth';
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
import KeyboardArrowUpIcon from '@mui/icons-material/KeyboardArrowUp';
import { useNavigate } from "react-router-dom";
import { useDispatch } from "react-redux";
import { activateCreateCopyTasksMode } from "../../../store/actions/tasksActions";
const weekDays = ["Вс","Пн","Вт","Ср","Чт","Пт","Сб" ];
......@@ -40,9 +43,10 @@ const TableRowTask= ({
onToggleEditMode,
onToggleEditModeDone,
})=>{
const [open, setOpen] = React.useState(false);
const navigate = useNavigate()
const dispatch = useDispatch()
const roudHourUp =(dateIso)=>{
let m = moment(dateIso);
let roundUp = m.minute() || m.second() || m.millisecond() ? m.add(1, 'hour').startOf('hour') : m.startOf('hour');
......@@ -59,7 +63,7 @@ const TableRowTask= ({
return weekDays[date.day()];
}
const calendarOpen=(taskId)=>{
console.log('task Id in Calendar Open' , taskId)
dispatch(activateCreateCopyTasksMode(task, navigate))
}
return (
......@@ -159,11 +163,11 @@ const TableRowTask= ({
user:user
}}
/>
{task.isEditMode && task.author.id===user.id ? (
{task.dateTimeTasks.length === 0 && task.author.id === user.id ? (
<TableCell>
<Tooltip title="Перейти в календарь">
<IconButton
onClick={() => { calendarOpen(task.id)}}
onClick={() => { calendarOpen(task)}}
>
<CalendarMonthIcon />
</IconButton>
......@@ -172,7 +176,7 @@ const TableRowTask= ({
</TableCell>
) : (
task.dateTimeTasks.length>1 ?
task.dateTimeTasks.length >= 1 ?
<TableCell>
<IconButton
aria-label="expand row"
......@@ -286,7 +290,7 @@ const TableRowTask= ({
</TableCell>):null}
</TableRow>
{task.dateTimeTasks.length>1?
{task.dateTimeTasks.length>=1?
<TableRow>
<TableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={11}>
<Collapse in={open} timeout="auto" unmountOnExit>
......
import { Button } from "@mui/material";
import { memo } from "react";
import { projectRoles } from "../../../constants";
import CustomAutocomplete from "../../UI/CustomAutocomplete/CustomAutocomplete";
import { isValidate } from "./helpers";
function NewMemberModalContent({ members, users, onChangeNewMemberHandler, onChangeRoleHandler, newMember, handleClose, createNewMemberHandler }) {
return (<>
<CustomAutocomplete
name={'newMember'}
label={'Новый участник'}
options={users}
onChange={onChangeNewMemberHandler}
value={newMember?.userId}
getOptionLabel={(item) => item.displayName || ""}
style={{ marginBottom: '15px' }}
/>
<CustomAutocomplete
name={'role'}
label={'Роль'}
options={projectRoles}
onChange={onChangeRoleHandler}
value={newMember?.roleProject}
getOptionLabel={(item) => item.text || ""}
style={{ marginBottom: '15px' }}
/>
<div style={{ display: 'flex', justifyContent: 'space-between', margin: '10px 0' }}>
<Button onClick={() => { createNewMemberHandler() }} disabled={!isValidate(members, newMember?.userId, newMember?.roleProject)}>Выбрать</Button>
<Button onClick={() => handleClose()}>Отмена</Button>
</div>
</>);
}
export default memo(NewMemberModalContent);
\ No newline at end of file
export const isValidate = (members, userId, role) => {
if (!userId || !role) return false
return !members.find((member) => member?.user?.id === userId)
}
\ No newline at end of file
import { Box, Typography } from "@mui/material";
import moment from "moment";
import { memo } from "react";
import PersonAddIcon from '@mui/icons-material/PersonAdd';
import ArrowIncrementButton from "../../UI/ArrowIncrementButton/ArrowIncrementButton";
const style = {
display: 'flex',
flexDirection: 'column',
}
const styleText = {
fontSize: '20px',
fontWeight: '600',
display: 'flex',
alignItems: 'center',
gap: '10px'
}
const ProjectInfo = ({ project, handleOpen, currentRoleInProject,onClickTasksHandler }) => {
return (
<Box sx={style} justifyContent={'space-between'}>
<Typography variant="h2">Проект - {project?.title} </Typography>
<Typography variant="body1" sx={styleText}>
Дата создания проекта: {moment(project?.createdAt).format('MM.DD.YYYY')}
</Typography>
<Typography variant="body1" sx={styleText}>
Цвет: {project?.color || 'Зеленый'}
</Typography>
<Typography variant="body1" sx={styleText}>
Автор проекта: {project?.members[0]?.user.displayName}
</Typography>
<Typography variant="body1" sx={styleText}>
Роль в проекте: {currentRoleInProject}
</Typography>
<Typography variant="body1" sx={styleText}>
Задачи: <ArrowIncrementButton onClick={()=>{onClickTasksHandler()}}/>
</Typography>
{currentRoleInProject === 'admin' ?
<Typography variant="body1" sx={styleText}>
Добавить участника: <PersonAddIcon style={{ cursor: 'pointer' }} onClick={() => { handleOpen() }} />
</Typography>
: null
}
</Box>
);
};
export default memo(ProjectInfo);
\ No newline at end of file
import { Card, CardContent, Grid, IconButton, Tooltip } from "@mui/material";
import { useParams } from "react-router-dom";
import { useDispatch } from "react-redux";
import DeleteIcon from "@mui/icons-material/Delete";
import { deleteMember } from "../../../store/actions/projectsActions";
const ProjectMembersItem = ({ displayName, roleProject, id, roleProjectOfAuthor, userId, members, authorOfProject }) => {
console.log(displayName)
const dispatch = useDispatch();
let params = useParams()
console.log(members)
console.log(userId)
const deleteHandle = (userId, projectId) => {
dispatch(deleteMember(userId, params.id))
};
return <>
<Grid item xs={12} sm={12} md={6} lg={4}>
<Card>
<CardContent>
<strong>
<br></br>
{displayName}
</strong>
<strong>
<br></br>
роль: {roleProject}
</strong>
<strong>
{(members.filter(e => e.user.displayName === authorOfProject).length > 0) ?
(<strong>
<Tooltip title="Удалить">
<IconButton
onClick={(id) => {
deleteHandle(userId);
}}
> {(displayName !== authorOfProject) ? <DeleteIcon style={{ marginTop: "-5px" }} /> : null}
</IconButton>
</Tooltip>
</strong>) : null}
</strong>
</CardContent>
</Card>
</Grid>
</>
};
export default ProjectMembersItem;
import {Grid} from "@mui/material";
import ProjectMembersItem from "../ProjectMembersItem/ProjectMembersItem";
const ProjectMembersList = ({members, roleProjectOfAuthor, authorOfProject}) => {
console.log("members ", members)
return (
<Grid item container direction="column" spacing={1}>
{members?.map(member => {
return <ProjectMembersItem
displayName={member?.user?.displayName}
roleProject={member?.roleProject}
id={member.id}
key={member.id}
roleProjectOfAuthor={roleProjectOfAuthor}
userId={member?.user?.id}
members={members}
authorOfProject={authorOfProject}
/>
})}
</Grid>
);
};
export default ProjectMembersList;
\ No newline at end of file
import * as React from "react";
import {
Box,
Table,
TableBody,
TableCell,
TableContainer,
TablePagination,
TableRow,
Paper
} from "@mui/material";
import { useState } from "react";
import TaskModal from "../../../components/MyTasksCompoments/TaskModal/TaskModal";
import moment from "moment";
import CustomTableCell from "../../../components/MyTasksCompoments/CustomTableCell";
import MaterialUIPickers from "../../../components/MyTasksCompoments/DateTimePicker/DateTimePicker";
import BasicSelect from "../../../components/UI/Select/Select";
import ProjectTasksHeader from "./ProjectTasksHeader";
export default function ProjectTasksBody({ tasks }) {
const [order, setOrder] = useState("asc");
const [orderBy, setOrderBy] = useState("id");
const [page, setPage] = useState(0);
const [rowsPerPage, setRowsPerPage] = useState(5);
const [modal, setModal] = useState({
open: false,
task: null,
});
console.log(tasks)
const handleRequestSort = (event, property) => {
const isAsc = orderBy === property && order === "asc";
setOrder(isAsc ? "desc" : "asc");
setOrderBy(property);
};
const handleChangePage = (event, newPage) => {
setPage(newPage);
};
const handleChangeRowsPerPage = (event) => {
setRowsPerPage(parseInt(event.target.value, 10));
setPage(0);
};
const onModalOpen = (event, task) => {
event.stopPropagation();
setModal({ ...modal, open: true, id: task.id });
};
const handleClose = () => {
setModal({ ...modal, open: false, id: null });
};
const rawProjects = tasks?.map(task => task.project)
if (
tasks &&
tasks?.length > 0
) {
return (
<Box sx={{ width: "fullwidth" }}>
<Paper sx={{ width: "100%", mb: 2 }}>
<TableContainer>
<Table sx={{ minWidth: 600 }} aria-labelledby="tableTitle">
<ProjectTasksHeader
order={order}
orderBy={orderBy}
onRequestSort={handleRequestSort}
rowCount={tasks.length}
/>
<TableBody>
{stableSort(tasks, getComparator(order, orderBy))
.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
.map((task, index) => {
return (
<TableRow hover key={task.id}>
<TableCell
component="th"
scope="row"
padding="none"
></TableCell>
{task.isEditMode ? (
<TableCell>
<BasicSelect
items={[
{ value: "A", title: "A" },
{ value: "B", title: "B" },
{ value: "C", title: "C" },
]}
task={task}
value={task.priority}
// onChange={onChange}
name="priority"
/>
</TableCell>
) : (
<CustomTableCell
{...{
task,
name: "priority",
value: task.priority,
}}
/>
)}
<CustomTableCell
{...{
task,
name: "createdAt",
value: moment(task.createdAt)
.utc()
.format("DD-MM-YYYY hh:mm A"),
}}
/>
<CustomTableCell
{...{
task,
name: "title",
value: task.title,
onModalOpen,
}}
/>
{task.isEditMode ? (
<TableCell>
<BasicSelect
items={rawProjects.map((e) => ({
value: e?.id,
title: e?.title,
}))}
task={task}
name="project"
value={task.project?.id}
/>
</TableCell>
) : (
<CustomTableCell
{...{
task,
name: "projectId",
value: task.project?.title,
}}
/>
)}
<CustomTableCell
{...{
task,
name: "author",
value: task.author.displayName,
}}
/>
<TableCell>
<MaterialUIPickers
task={task}
name="dateTimeStart"
/>
</TableCell>
<TableCell>
<MaterialUIPickers
task={task}
name="dateTimeDue"
/>
</TableCell>
{task.isEditMode ? (
<TableCell>
<BasicSelect
items={[
{ value: "opened", title: "opened" },
{ value: "done", title: "done" },
{ value: "failed", title: "failed" },
]}
task={task}
name="accomplish"
value={task.accomplish}
/>
</TableCell>
) : (
<CustomTableCell
{...{
task,
name: "accomplish",
value: task.accomplish,
}}
/>
)}
</TableRow>
);
})}
</TableBody>
</Table>
</TableContainer>
<TablePagination
rowsPerPageOptions={[5, 10, 25]}
component="div"
count={tasks.length}
rowsPerPage={rowsPerPage}
page={page}
onPageChange={handleChangePage}
onRowsPerPageChange={handleChangeRowsPerPage}
/>
</Paper>
<TaskModal
task={tasks.find((task) => task.id === modal.id)}
open={modal.open}
handleClose={handleClose}
/>
</Box>
);
}
}
function descendingComparator(a, b, orderBy) {
if (b[orderBy] < a[orderBy]) {
return -1;
}
if (b[orderBy] > a[orderBy]) {
return 1;
}
return 0;
}
function getComparator(order, orderBy) {
return order === "desc"
? (a, b) => descendingComparator(a, b, orderBy)
: (a, b) => -descendingComparator(a, b, orderBy);
}
function stableSort(array, comparator) {
const stabilizedThis = array?.map((el, index) => [el, index]);
stabilizedThis.sort((a, b) => {
const order = comparator(a[0], b[0]);
if (order !== 0) {
return order;
}
return a[1] - b[1];
});
return stabilizedThis.map((el) => el[0]);
}
import * as React from "react";
import PropTypes from "prop-types";
import Box from "@mui/material/Box";
import TableCell from "@mui/material/TableCell";
import TableHead from "@mui/material/TableHead";
import TableRow from "@mui/material/TableRow";
import TableSortLabel from "@mui/material/TableSortLabel";
import { visuallyHidden } from "@mui/utils";
const headCells = [
{
id: "id",
numeric: true,
disablePadding: true,
label: "",
},
{
id: "priority",
numeric: false,
disablePadding: true,
label: "Приоритет",
},
{
id: "createdAt",
numeric: true,
disablePadding: false,
label: "Дата создания",
},
{
id: "title",
numeric: true,
disablePadding: false,
label: "Заголовок",
},
{
id: "projectName",
numeric: true,
disablePadding: false,
label: "Проект",
},
{
id: "authorDisplayName",
numeric: true,
disablePadding: false,
label: "Автор",
},
{
id: "dateTimeStart",
numeric: true,
disablePadding: false,
label: "Дата начала",
},
{
id: "dateTimeDue",
numeric: true,
disablePadding: false,
label: "Дата завершения",
},
{
id: "accomplish",
numeric: true,
disablePadding: false,
label: "Статус",
}
];
export default function EnhancedTableHead({ order, orderBy, rowCount, onRequestSort }) {
const createSortHandler = (property) => (event) => {
onRequestSort(event, property);
};
return (
<TableHead>
<TableRow>
{headCells.map((headCell) => (
<TableCell
key={headCell.id}
align={"center"}
padding={headCell.disablePadding ? "none" : "normal"}
sortDirection={orderBy === headCell.id ? order : false}
>
<TableSortLabel
active={orderBy === headCell.id}
direction={orderBy === headCell.id ? order : "asc"}
onClick={createSortHandler(headCell.id)}
>
{headCell.label}
{orderBy === headCell.id ? (
<Box component="span" sx={visuallyHidden}>
{order === "desc" ? "sorted descending" : "sorted ascending"}
</Box>
) : null}
</TableSortLabel>
</TableCell>
))}
</TableRow>
</TableHead>
);
}
EnhancedTableHead.propTypes = {
onRequestSort: PropTypes.func.isRequired,
order: PropTypes.oneOf(["asc", "desc"]).isRequired,
orderBy: PropTypes.string.isRequired,
rowCount: PropTypes.number.isRequired,
};
import { Grid } from "@mui/material";
import DeleteIcon from "@mui/icons-material/Delete";
import { deleteMember } from "../../../store/actions/projectsActions";
import { memo } from "react";
const ProjectMembersItem = ({ user }) => {
const style = {
width: '90%',
border: '1px solid black',
borderRadius: '5px',
padding: '15px 15px',
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center'
}
return <>
<Grid sx={style}>
{user?.displayName}
<DeleteIcon
/>
</Grid>
</>
};
export default memo(ProjectMembersItem);
import { Typography } from "@mui/material";
import { memo } from "react";
const ColumnTitle = ({ text }) => {
return <>
<Typography variant="h4" textAlign={'center'} sx={{ height: '10%' }}>
{text}
</Typography>
</>
};
export default memo(ColumnTitle);
import { Box } from "@mui/material";
import { memo} from "react";
import ColumnTitle from "./ColumnTitle/ColumnTitle";
import UsersList from "./UsersList/UserList";
const styleColumn = {
border: '3px solid black',
borderRadius: '10px',
height: '60vh',
flexBasis: 60 / 3 + '%',
overflow: 'auto',
overflowX: 'hidden',
}
const ProjectUsersColumn = ({ role, members, deleteMemberHandler, currentRoleInProject, dragMemberToNewRole, setCurrentMember }) => {
return (
<Box
sx={styleColumn}
>
<ColumnTitle text={role.text} />
<UsersList
role={role}
members={members}
deleteMemberHandler={deleteMemberHandler}
currentRoleInProject={currentRoleInProject}
dragMemberToNewRole={dragMemberToNewRole}
setCurrentMember={setCurrentMember}
>
</UsersList>
</Box>
);
};
export default memo(ProjectUsersColumn);
\ No newline at end of file
import { Grid } from "@mui/material";
import DeleteIcon from "@mui/icons-material/Delete";
import { memo } from "react";
import { useSelector } from "react-redux";
const style = {
width: '90%',
border: '1px solid black',
borderRadius: '5px',
padding: '15px 15px',
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center'
}
const ProjectMembersItem = ({ user, deleteMemberHandler, currentRoleInProject, dragMemberToNewRole, setCurrentMember, role }) => {
const userId = useSelector(state => state.users.user.id);
const dragStartHandler = (e) => {
setCurrentMember(user)
}
const dragEndHandler = (e) => {
setCurrentMember(null)
}
const dragOverHandler = (e) => {
e.preventDefault();
}
const dropHandler = (e) => {
e.preventDefault();
dragMemberToNewRole(role)
}
const dragLeaveHandler = (e) => {
e.preventDefault();
}
return <>
<Grid sx={style}
draggable={user.id !== userId ? true : false}
onDragStart={(e) => { dragStartHandler(e) }}
onDragEnd={(e) => { dragEndHandler(e) }}
onDrop={(e) => { dropHandler(e) }}
onDragOver={(e) => { dragOverHandler(e) }}
onDragLeave={(e) => { dragLeaveHandler(e) }}
>
{user?.displayName}
{currentRoleInProject === 'admin' && user.id !== userId ?
<DeleteIcon
sx={{ cursor: 'pointer' }}
onClick={deleteMemberHandler}
/>
: null}
</Grid>
</>
};
export default memo(ProjectMembersItem);
import { Box } from "@mui/material";
import { memo, useCallback } from "react";
import UserItem from "./UserItem/UserItem";
const styleList = {
display: 'flex',
gap: '10px',
flexDirection: 'column',
alignItems: 'center',
height: '90%',
}
const UsersList = ({ role, members, deleteMemberHandler, currentRoleInProject, dragMemberToNewRole, setCurrentMember }) => {
const dropHandler = (e) => {
e.preventDefault();
e.target.style.background = null
setCurrentMember(null)
dragMemberToNewRole(role)
}
const dragOverHandler = useCallback((e) => {
e.preventDefault();
e.target.style.background = '#d6d2d2'
}, [])
const dragLeaveHandler = useCallback((e) => {
e.preventDefault();
e.target.style.background = null
}, [])
return (
<Box
sx={styleList}
onDrop={(e) => { dropHandler(e) }}
onDragOver={(e) => { dragOverHandler(e) }}
onDragLeave={(e) => { dragLeaveHandler(e) }}
>
{members.map((member) => {
if (member.roleProject === role.value) {
return (
<UserItem
key={member.id}
user={member?.user}
deleteMemberHandler={() => { deleteMemberHandler(member?.user?.id) }}
role={role.value}
currentRoleInProject={currentRoleInProject}
dragMemberToNewRole={dragMemberToNewRole}
setCurrentMember={setCurrentMember}
/>
)
} else {
return null
}
})}
</Box>
);
};
export default memo(UsersList);
\ No newline at end of file
import { Box } from "@mui/material";
import { memo } from "react";
import { projectRoles } from "../../../constants";
import ProjectUsersColumn from "./ProjectUsersColumn/ProjectUsersColumn";
const style = {
display: 'flex',
gap: '150px',
width: '100%',
marginTop: '20px',
justifyContent: 'space-evenly'
}
const ProjectUsersColumnsWrapper = ({ members, deleteMemberHandler, currentRoleInProject, dragMemberToNewRole, setCurrentMember}) => {
return (
<Box sx={style} justifyContent={'space-between'}>
{projectRoles.map((role, i) => {
return (
<ProjectUsersColumn
key={i}
role={role}
members={members}
deleteMemberHandler={deleteMemberHandler}
currentRoleInProject={currentRoleInProject}
dragMemberToNewRole={dragMemberToNewRole}
setCurrentMember={setCurrentMember}
/>
)
})}
</Box>
);
};
export default memo(ProjectUsersColumnsWrapper);
\ No newline at end of file
......@@ -23,4 +23,6 @@ export const priorities = [
export const AllHoursOneHourFormat = ['0:00', '1:00', '2:00', '3:00', '4:00', '5:00', '6:00', '7:00', '8:00', '9:00', '10:00', '11:00', '12:00', '13:00', '14:00', '15:00', '16:00', '17:00', '18:00', '19:00', '20:00', '21:00', '22:00', '23:00']
export const AllHoursTwoHourFormat = ['0:00', '2:00', '4:00', '6:00', '8:00', '10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00']
\ No newline at end of file
export const AllHoursTwoHourFormat = ['0:00', '2:00', '4:00', '6:00', '8:00', '10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00']
export const projectRoles = [{ value: 'admin', text: 'Админ' }, { value: 'user', text: 'Юзер' }, { value: 'watcher', text: 'Наблюдатель' }]
\ No newline at end of file
import { Card, CardActions, CardContent, Grid } from "@mui/material";
import { useParams } from "react-router-dom";
import { Grid } from "@mui/material";
import { useNavigate, useParams } from "react-router-dom";
import { useSelector, useDispatch } from "react-redux";
import { useEffect } from "react";
import { fetchProject } from "../../store/actions/projectsActions";
import ProjectTasksBody from "../../components/ProjectComponents/ProjectTasks/ProjectTasksBody";
import { useCallback, useEffect, useMemo, useState } from "react";
import { changeMemberRole, createMember, deleteMember, fetchProject } from "../../store/actions/projectsActions";
import { fetchUsers } from "../../store/actions/usersActions";
import ProjectMembersList from "../../components/ProjectComponents/ProjectMembersList/ProjectMembersList";
import NewMember from "../NewMember/NewMember";
import ProjectUsersColumnsWrapper from "../../components/ProjectComponents/ProjectUsersColumnsWrapper/ProjectUsersColumnsWrapper";
import ProjectInfo from "../../components/ProjectComponents/ProjectInfo/ProjectInfo";
import DefaultModal from "../../components/UI/DefaultModal/DefaultModal"
import NewMemberModalContent from "../../components/ProjectComponents/NewMemberModalContent/NewMemberModalContent";
const FullProject = () => {
const { projects, project } = useSelector(state => state.projects);
const users = useSelector(state => state.users.users);
const user = useSelector(state => state.users.user);
const { project } = useSelector(state => state.projects);
const [modal, setModal] = useState(false)
const [newMember, setNewMember] = useState(null)
const [currentMember, setCurrentMember] = useState(null)
const { user, users } = useSelector(state => state.users);
const dispatch = useDispatch();
const params = useParams()
const tasks = project.tasks;
console.log(projects);
console.log(tasks);
const navigate = useNavigate()
useEffect(() => {
dispatch(fetchProject(params.id))
dispatch(fetchUsers())
}, [dispatch]);
}, [params.id, dispatch]);
console.log(user)
const members = useMemo(() => {
return project?.project?.members || []
}, [project])
useEffect(() => {
dispatch(fetchProject(params.id))
}, [params.id, dispatch]);
console.log("project ", project);
const currentRoleInProject = useMemo(() => {
return members.find((member) => member.user.id === user.id)?.roleProject
}, [members, user.id])
const onChangeRoleHandler = useCallback((e, value) => {
setNewMember((prevState) => { return { ...prevState, roleProject: value?.value } });
}, []);
const onChangeNewMemberHandler = useCallback((e, value) => {
setNewMember((prevState) => { return { ...prevState, userId: value?.id } });
}, []);
const handleOpen = useCallback(async () => {
setModal(true)
}, [])
const handleClose = useCallback(() => {
setModal(false)
setNewMember(null)
}, [])
const createNewMemberHandler = useCallback(() => {
dispatch(createMember({ ...newMember, projectId: project?.project?.id }))
setModal(false)
setNewMember(null)
}, [dispatch, newMember, project?.project?.id])
const dragMemberToNewRole = useCallback((role) => {
if (currentMember?.id) {
dispatch(changeMemberRole(currentMember?.id, { newRoleProject: role?.value, projectId: project?.project?.id }))
}
}, [currentMember, dispatch, project?.project?.id])
const deleteMemberHandler = useCallback((id) => {
dispatch(deleteMember(id, project?.project?.id))
}, [dispatch, project?.project?.id])
const onClickTasksHandler = useCallback((id) => {
navigate('/workers-tasks')
}, [navigate])
return <>
<Grid item xs={12} sm={12} md={6} lg={4}>
<Card>
<h2>Проект - {project?.project?.title} </h2>
<CardContent>
<strong>
<br></br>
Дата создания проекта: {project?.project?.createdAt}
</strong>
<strong>
<br></br>
Цвет: {project?.project?.color}
</strong>
<strong>
<br></br>
Автор проекта: {project?.project?.members[0]?.user.displayName}
</strong>
<strong>
<br></br>
Роль в проекте: {project?.project?.members[0]?.roleProject}
</strong>
<strong>
<br></br>
<div style={{ display: 'flex', direction: 'column' }}>
Участники проекта: {(project?.project?.members[0]?.user.displayName === user.displayName) ? <NewMember members={project?.project?.members} /> : null}
</div>
<ProjectMembersList users={users} project={project} members={project?.project?.members} roleProjectOfAuthor={project?.project?.members[0]?.roleProject} authorOfProject={project?.project?.members[0]?.user.displayName} />
</strong>
<strong>
<br></br>
Задачи:
<br></br>
</strong>
<strong>
<br></br>
<ProjectTasksBody
tasks={tasks}
/>
</strong>
</CardContent>
<CardActions>
</CardActions>
</Card>
</Grid>
<Grid>
<ProjectInfo
project={project.project}
handleOpen={handleOpen}
currentRoleInProject={currentRoleInProject}
onClickTasksHandler={onClickTasksHandler}
/>
<ProjectUsersColumnsWrapper
members={members}
deleteMemberHandler={deleteMemberHandler}
currentRoleInProject={currentRoleInProject}
dragMemberToNewRole={dragMemberToNewRole}
setCurrentMember={setCurrentMember}
/>
<DefaultModal
modal={modal}
handleClose={() => { handleClose() }}
>
<NewMemberModalContent
users={users}
onChangeNewMemberHandler={onChangeNewMemberHandler}
onChangeRoleHandler={onChangeRoleHandler}
newMember={newMember}
handleClose={handleClose}
createNewMemberHandler={createNewMemberHandler}
members={members}
>
</NewMemberModalContent>
</DefaultModal>
</Grid>
</>
};
......
......@@ -189,7 +189,6 @@ export default function EnhancedTable() {
setRecievedTasks(tasksFilteredByProject)
setFilterProjectTumbler(true)
}
// if (
// tasks &&
// tasks?.length > 0
......
import {useNavigate} from "react-router-dom";
import {useDispatch, useSelector} from "react-redux";
import { useEffect } from "react";
import ProjectForm from "../../components/ProjectComponents/ProjectForm/ProjectForm";
import { createMember, createProject, fetchMembers, fetchProjects } from "../../store/actions/projectsActions";
import MemberForm from "../../components/MemberForm/MemberForm";
const NewMember = ({members}) => {
const dispatch = useDispatch();
const projects = useSelector(state => state.projects.projects);
const navigate = useNavigate();
const onSubmit = async (memberData) => {
await dispatch(createMember(memberData, navigate));
navigate("/projects/" + memberData.projectId)
console.log("memberData ", memberData)
};
// useEffect(()=> {
// dispatch(fetchMembers());
// }, [dispatch])
return (
<>
<MemberForm members={members} onSubmit={onSubmit} />
</>
);
};
export default NewMember;
\ No newline at end of file
import moment from 'moment';
import { useEffect, useState, useMemo, useCallback } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useNavigate } from 'react-router-dom';
import CreateCopyTasksModeBlock from '../../components/Calendars/CreateCopyTasksModeBlock/CreateCopyTasksModeBlock';
import CalendarModalWorkerContent from '../../components/Calendars/UI/CalendarModalWorkerContent/CalendarModalWorkerContent';
import WeekCalendarBody from '../../components/Calendars/WeekCalendar/WeekCalendarBody/WeekCalendarBody';
import WeekCalendarHeader from '../../components/Calendars/WeekCalendar/WeekCalendarHeader/WeekCalendarHeader';
......@@ -8,15 +11,16 @@ import DefaultModal from '../../components/UI/DefaultModal/DefaultModal';
import { AllHoursOneHourFormat, AllHoursTwoHourFormat } from '../../constants';
import { getWeekInfoString, getWeekFromCurrentDate, dateToISOLikeButLocal } from '../../helpers/CalendarHelpers';
import { fetchAllUserProjects } from '../../store/actions/projectsActions';
import { addCalendarTask, addCopyCalendarTask, deleteCalendarTask, editCalendarTask, fetchCalendarTasks } from '../../store/actions/tasksActions';
import { addCalendarTask, addCopyCalendarTask, deactivateCreateCopyTasksMode, deleteCalendarTask, editCalendarTask, fetchCalendarTasks } from '../../store/actions/tasksActions';
import { fetchCurrentCalendarDisplayName } from '../../store/actions/usersActions';
function WeekCalendar() {
const dispatch = useDispatch();
const { calendarTasks } = useSelector(state => state.tasks);
const navigate = useNavigate()
const { calendarTasks, copyMode } = useSelector(state => state.tasks);
const { user, currentCalendarDisplayName } = useSelector(state => state.users);
const { allUserProjects, project } = useSelector(state => state.projects)
const { allUserProjects } = useSelector(state => state.projects)
console.log(copyMode)
const [weekGoal, setWeekGoal] = useState('Наладить режим сна')
const [weekPriorities, setWeekPriorities] = useState({ priorityOne: 'Один', priorityTwo: 'Два', priorityThree: 'Три' })
const [workerInfo, setWorkerInfo] = useState({ project: '', worker: '' });
......@@ -27,14 +31,15 @@ function WeekCalendar() {
const [userCalendarId, setUserCalendarId] = useState(null)
const [modal, setModal] = useState(false)
const [userId, setUserId] = useState('')
console.log(copyTask)
useEffect(() => {
const year = new Date().getFullYear()
const month = new Date().getMonth()
const currentDay = moment().date()
setDateNow({ year: year, month: month, currentDay: currentDay })
dispatch(fetchCalendarTasks(user.id))
dispatch(fetchAllUserProjects())
return () => {
dispatch(deactivateCreateCopyTasksMode())
}
}, [dispatch, user.id])
useEffect(() => {
......@@ -200,26 +205,41 @@ function WeekCalendar() {
}, [currentTask, dispatch, user.id, userId])
const createCopyTask = useCallback(async (dayNumber, hour, month, year) => {
const hourDiff = copyTask.infoForCell.endHour - copyTask.infoForCell.startHour
const lastHour = hoursInDay[hoursInDay.length - 1].split(':')[0]
let due
if (hour + hourDiff >= lastHour) {
due = dateToISOLikeButLocal(new Date(year, month, dayNumber, lastHour, 59))
if (copyMode.working) {
const hourDiff = hourFormat ? 0 : 1
const due = dateToISOLikeButLocal(new Date(year, month, dayNumber, hour + hourDiff, 59))
const start = dateToISOLikeButLocal(new Date(year, month, dayNumber, hour, 0))
const newTask = {
...copyMode.task,
dateTimeStart: start,
dateTimeDue: due,
taskId: copyMode.task.id
}
delete newTask.infoForCell
delete newTask.id
await dispatch(addCopyCalendarTask(newTask, userId))
} else {
due = dateToISOLikeButLocal(new Date(year, month, dayNumber, hour + hourDiff, 59))
}
const start = dateToISOLikeButLocal(new Date(year, month, dayNumber, hour, 0))
const newTask = {
...copyTask,
dateTimeStart: start,
dateTimeDue: due,
taskId: copyTask.mainTaskId
const hourDiff = copyTask.infoForCell.endHour - copyTask.infoForCell.startHour
const lastHour = hoursInDay[hoursInDay.length - 1].split(':')[0]
let due
if (hour + hourDiff >= lastHour) {
due = dateToISOLikeButLocal(new Date(year, month, dayNumber, lastHour, 59))
} else {
due = dateToISOLikeButLocal(new Date(year, month, dayNumber, hour + hourDiff, 59))
}
const start = dateToISOLikeButLocal(new Date(year, month, dayNumber, hour, 0))
const newTask = {
...copyTask,
dateTimeStart: start,
dateTimeDue: due,
taskId: copyTask.mainTaskId
}
delete newTask.infoForCell
delete newTask.id
await dispatch(addCopyCalendarTask(newTask, userId))
setCopyTask(null)
}
delete newTask.infoForCell
delete newTask.id
await dispatch(addCopyCalendarTask(newTask, userId))
setCopyTask(null)
}, [copyTask, dispatch, hoursInDay, userId])
}, [copyTask, dispatch, hoursInDay, userId, copyMode.task, copyMode.working, hourFormat])
const dragTaskHandler = useCallback(async (dayNumber, hour, month, year) => {
const hourDiff = currentTask.infoForCell.endHour - currentTask.infoForCell.startHour
......@@ -243,8 +263,10 @@ function WeekCalendar() {
setCurrentTask({})
}, [currentTask, dispatch, hoursInDay, userId])
const deleteTaskHandler = useCallback(async (taskId) => {
dispatch(deleteCalendarTask(taskId, userId))
const deleteTaskHandler = useCallback(async (e, taskId) => {
console.log(e)
e.stopPropagation();
await dispatch(deleteCalendarTask(taskId, userId))
}, [dispatch, userId])
const handleClose = useCallback(() => {
......@@ -260,6 +282,15 @@ function WeekCalendar() {
setUserCalendarId(null)
}
}, [dispatch, user.id, userId])
const copyModeStay = useCallback(async () => {
dispatch(deactivateCreateCopyTasksMode())
}, [dispatch])
const copyModeReturn = useCallback(async () => {
navigate('/my-tasks')
}, [navigate])
return (
<>
<DefaultModal
......@@ -307,6 +338,13 @@ function WeekCalendar() {
copyTask={copyTask}
setCopyTask={setCopyTask}
dragTaskHandler={dragTaskHandler}
copyMode={copyMode}
/>
<CreateCopyTasksModeBlock
copyMode={copyMode.working}
copyModeStay={() => { copyModeStay() }}
copyModeReturn={() => { copyModeReturn() }}
/>
</>
);
......
......@@ -15,4 +15,8 @@ export const FETCH_ALL_USER_PROJECTS_SUCCESS = "FETCH_ALL_USER_PROJECTS_SUCCESS"
export const DELETE_PROJECT_REQUEST = "DELETE_PROJECT_REQUEST";
export const DELETE_PROJECT_SUCCESS = "DELETE_PROJECT_SUCCESS";
export const DELETE_PROJECT_FAILURE = "DELETE_PROJECT_FAILURE";
\ No newline at end of file
export const DELETE_PROJECT_FAILURE = "DELETE_PROJECT_FAILURE";
export const CHANGE_MEMBER_ROLE_REQUEST = "CHANGE_MEMBER_ROLE_REQUEST";
export const CHANGE_MEMBER_ROLE_SUCCESS = "CHANGE_MEMBER_ROLE_SUCCESS";
export const CHANGE_MEMBER_ROLE_FAILURE = "CHANGE_MEMBER_ROLE_FAILURE";
\ No newline at end of file
......@@ -28,4 +28,7 @@ export const DELETE_DATETIMETASK_FAILURE = "DELETE_TASK_FAILURE";
export const FETCH_ALL_TASKS_BY_MEMBERSHIP_REQUEST = "FETCH_ALL_TASKS_BY_MEMBERSHIP_REQUEST";
export const FETCH_ALL_TASKS_BY_MEMBERSHIP_SUCCESS = "FETCH_ALL_TASKS_BY_MEMBERSHIP_SUCCESS";
export const FETCH_ALL_TASKS_BY_MEMBERSHIP_FAILURE = "FETCH_ALL_TASKS_BY_MEMBERSHIP_FAILURE";
\ No newline at end of file
export const FETCH_ALL_TASKS_BY_MEMBERSHIP_FAILURE = "FETCH_ALL_TASKS_BY_MEMBERSHIP_FAILURE";
export const ACTIVATE_CREATE_COPY_TASKS_MODE = "ACTIVATE_CREATE_COPY_TASKS_MODE"
export const DEACTIVATE_CREATE_COPY_TASKS_MODE = "DEACTIVATE_CREATE_COPY_TASKS_MODE"
\ No newline at end of file
import axios from "../../axiosPlanner";
import { CREATE_MEMBER_SUCCESS, CREATE_PROJECT_SUCCESS, 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 { CHANGE_MEMBER_ROLE_FAILURE, CHANGE_MEMBER_ROLE_REQUEST, CHANGE_MEMBER_ROLE_SUCCESS, CREATE_MEMBER_SUCCESS, CREATE_PROJECT_SUCCESS, 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 { showNotification } from "./commonActions";
const fetchProjectsRequest = () => {
......@@ -51,10 +51,9 @@ export const deleteMember = (memberId, projectId) => {
return async (dispatch) => {
dispatch(deleteMemberRequest());
try {
const response = await axios.delete(`/projects/remove-user/${memberId}`, { data: { projectId: projectId } });
console.log("deleteMember ", response.data)
await axios.delete(`/projects/remove-user/${memberId}`, {data: {projectId: projectId}});
dispatch(deleteMemberSuccess())
dispatch(fetchProject(projectId))
await dispatch(fetchProject(projectId))
} catch (error) {
dispatch(deleteMemberFailure(error.response.data));
}
......@@ -92,7 +91,6 @@ export const fetchProject = (id) => {
try {
const response = await axios.get("/projects/" + id);
dispatch(fetchProjectSuccess(response.data));
console.log("fetch project ", response.data)
} catch (e) {
dispatch(fetchProjectsError(e));
}
......@@ -114,18 +112,15 @@ export const createProject = (projectData, navigate) => {
};
}
export const createMember = (memberData, navigate) => {
export const createMember = (memberData) => {
return async (dispatch) => {
dispatch(fetchProjectsRequest());
try {
console.log(memberData)
await axios.post("/projects/add-user", memberData);
dispatch(createMemberSuccess());
console.log(memberData)
navigate("/projects/")
dispatch(showNotification("Участник успешно добавлен"))
await dispatch(fetchProject(memberData?.projectId))
} catch (e) {
console.log(e);
dispatch(showNotification("Не удалось добавить участника", "error"))
dispatch(fetchProjectsError(e));
}
};
}
......@@ -146,3 +141,29 @@ export const fetchAllUserProjects = () => {
}
}
const changeMemberRoleFailure = (error) => {
return { type: CHANGE_MEMBER_ROLE_FAILURE, error }
};
const changeMemberRoleRequest = () => {
return { type: CHANGE_MEMBER_ROLE_REQUEST }
};
const changeMemberRoleSuccess = () => {
return { type: CHANGE_MEMBER_ROLE_SUCCESS }
};
export const changeMemberRole = (userId, data) => {
return async (dispatch) => {
dispatch(changeMemberRoleSuccess());
try {
const response = await axios.put(`/projects/change-project-role/${userId}`, data);
console.log(response.data)
dispatch(changeMemberRoleRequest());
await dispatch(fetchProject(data?.projectId))
} catch (e) {
dispatch(changeMemberRoleFailure(e));
}
}
}
......@@ -18,7 +18,9 @@ import {
DELETE_DATETIMETASK_FAILURE,
DELETE_DATETIMETASK_SUCCESS,
DELETE_DATETIMETASK_REQUEST,
FETCH_ALL_TASKS_BY_MEMBERSHIP_SUCCESS
FETCH_ALL_TASKS_BY_MEMBERSHIP_SUCCESS,
DEACTIVATE_CREATE_COPY_TASKS_MODE,
ACTIVATE_CREATE_COPY_TASKS_MODE
} from "../actionTypes/tasksTypes";
import axios from '../../axiosPlanner'
......@@ -294,4 +296,13 @@ export const addTaskToUserTasksTable = (task) => {
}
}
/** end */
\ No newline at end of file
/** end */
export const activateCreateCopyTasksMode = (task, navigate) => {
navigate('/')
return {type: ACTIVATE_CREATE_COPY_TASKS_MODE, task}
}
export const deactivateCreateCopyTasksMode = () => {
return {type: DEACTIVATE_CREATE_COPY_TASKS_MODE}
}
\ No newline at end of file
......@@ -118,7 +118,6 @@ export const fetchUsers = () => {
try {
const response = await axios.get("/users");
dispatch(fetchUsersSuccess(response.data.users));
console.log(response.data.users)
} catch (e) {
dispatch(fetchUsersFailure(e));
}
......
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 { CHANGE_MEMBER_ROLE_FAILURE, CHANGE_MEMBER_ROLE_REQUEST, CHANGE_MEMBER_ROLE_SUCCESS, 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: [],
......@@ -32,10 +32,16 @@ const projectsReducer = (state = initialState, action) => {
case DELETE_PROJECT_FAILURE:
return { ...state, loading: false, error: action.error };
case FETCH_ALL_USER_PROJECTS_SUCCESS:
const newArr = action.projects.map((project)=>{
return {value: project.id, text: project.title}
const newArr = action.projects.map((project) => {
return { value: project.id, text: project.title }
})
return { ...state, loading: false, allUserProjects: action.projects, allUserProjectsForModalTask: newArr}
return { ...state, loading: false, allUserProjects: action.projects, allUserProjectsForModalTask: newArr }
case CHANGE_MEMBER_ROLE_SUCCESS:
return { ...state, loading: false };
case CHANGE_MEMBER_ROLE_REQUEST:
return { ...state, loading: true };
case CHANGE_MEMBER_ROLE_FAILURE:
return { ...state, loading: false, error: action.error };
default:
return state;
}
......
......@@ -18,10 +18,17 @@ import {
DELETE_DATETIMETASK_FAILURE,
DELETE_DATETIMETASK_SUCCESS,
DELETE_DATETIMETASK_REQUEST,
FETCH_ALL_TASKS_BY_MEMBERSHIP_SUCCESS
FETCH_ALL_TASKS_BY_MEMBERSHIP_SUCCESS,
ACTIVATE_CREATE_COPY_TASKS_MODE,
DEACTIVATE_CREATE_COPY_TASKS_MODE
} from "../actionTypes/tasksTypes";
const initialState = {
copyMode: {
working: false,
task: null,
},
tasks: [],
calendarTasks: [],
loading: false,
error: null,
......@@ -42,6 +49,7 @@ const tasksReduсer = (state = initialState, action) => {
mainTaskId: task.id,
executor: task.executor,
author: task.author,
dateTimeDeadLine: task.dateTimeDeadLine,
priority: task.priority,
title: task.title,
description: task.description
......@@ -114,6 +122,10 @@ const tasksReduсer = (state = initialState, action) => {
return {...state, loading: true};
case DELETE_DATETIMETASK_FAILURE:
return {...state, loading: false, error: action.error};
case ACTIVATE_CREATE_COPY_TASKS_MODE:
return {...state, copyMode: {working: true, task: action.task}}
case DEACTIVATE_CREATE_COPY_TASKS_MODE:
return {...state, copyMode: {working: false, task: null}}
default:
return state;
}
......
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