Commit 487bdf00 authored by Ibadullina Inabat's avatar Ibadullina Inabat

Merge branch 'task-83-feature/add_members_to_project_front' into 'development'

реализовано добавление участника в проект

See merge request !64
parents 5d1dedbf fec54d89
......@@ -121,6 +121,7 @@ router.get('/user/:userId', async (req : Request, res : Response): Promise<Respo
router.post('/add-user/', async (req: Request, res: Response):Promise<Response>=>{
const {userId, projectId, roleProject} = req.body;
console.log("req body" + req.body)
const newMember:Member = new Member();
try{
newMember.user= userId;
......@@ -128,7 +129,7 @@ router.post('/add-user/', async (req: Request, res: Response):Promise<Response>=
newMember.roleProject=roleProject
await newMember.save()
return res.send({newMember})
} catch(e){
} catch(e){
return res.send({message:"add user to project failed" })
}
......
import { Box, Button, Grid, Modal } from "@mui/material";
import { useState } from "react";
import { useSelector } from "react-redux";
import FormElement from "../UI/Form/FormElement/FormElement";
import { Typography } from "@mui/material";
import TextField from '@mui/material/TextField';
import Stack from '@mui/material/Stack';
import Autocomplete from '@mui/material/Autocomplete';
import { useParams } from "react-router-dom";
import PersonAddIcon from '@mui/icons-material/PersonAdd';
const style = {
position: 'absolute',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
width: 400,
bgcolor: 'background.paper',
border: '2px solid #000',
boxShadow: 24,
p: 4,
};
const MemberForm = ({ onSubmit }) => {
const users = useSelector(state => state.users.users)
const [role, setRole] = useState([{ role: "user" }, { role: "admin" }, { role: "watcher" }])
const params = useParams()
console.log(users)
const [open, setOpen] = useState(false);
const handleOpen = () => setOpen(true);
const handleClose = () => setOpen(false);
const [state, setState] = useState({
displayName: "",
roleProject: "",
userId: "",
projectId: ""
});
const submitFormHandler = (e) => {
e.preventDefault();
let idOfUser = users?.map((user) => (user.displayName === state.displayName) ? user.id : null)
let idOfUser1 = users?.map((user) => {
console.log(user)
return null
})
console.log(idOfUser1)
console.log(idOfUser)
console.log("state of submit " + state);
let members = {roleProject: state.roleProject, projectId: params.id, userId: idOfUser }
console.log(members);
onSubmit(members);
};
// const onChange = (e) => {
// const value = e.target.value;
// const name = e.target.name;
// const newState= { ...state, [name]: value };
// console.log("newState " + newState)
// console.log("e.target " + e.target)
// console.log("e " + e)
// setState(newState);
// };
const memberChangeHandler = (e, value) => {
setState(() => { return { ...state, member: value, userId: state.userId} });
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"}} >Добавить участника</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?.map((user) => user.displayName)}
onChange={memberChangeHandler}
name={"userId"}
value={state.userId}
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
......@@ -45,7 +45,7 @@ const ProjectForm = ({onSubmit}) => {
return (
<div >
<Button onClick={handleOpen} >Add project</Button>
<Button onClick={handleOpen} >Добавить проект</Button>
<Modal
open={open}
onClose={handleClose}
......@@ -56,7 +56,7 @@ const ProjectForm = ({onSubmit}) => {
<Box sx={style}>
<form >
<Grid container direction="column" spacing={2}>
<Typography variant="h4">New project</Typography>
<Typography variant="h4">Новый проект</Typography>
<FormElement
onChange={inputChangeHandler}
name={"title"}
......@@ -70,7 +70,7 @@ const ProjectForm = ({onSubmit}) => {
variant="contained"
>
Create
Создать
</Button>
</Grid>
</Grid>
......
......@@ -7,12 +7,12 @@ import { useDispatch, useSelector } from "react-redux";
const ProjectItem = ({ title, tasks, id }) => {
const user = useSelector(state => state.users.user);
const dispatch = useDispatch();
console.log(tasks)
console.log(user)
return <>
<Grid item xs={12} sm={12} md={6} lg={4}>
<Grid item xs={12} sm={12} md={6} lg={4}>
<Card>
<CardContent>
<CardContent >
<strong>
<br></br>
Название проекта: {title}
......
import { Card, CardActions, CardContent, Grid, IconButton } from "@mui/material";
import { Card, CardActions, CardContent, Grid, IconButton, Tooltip } from "@mui/material";
import { Link } from "react-router-dom";
import ArrowForwardIcon from "@mui/icons-material/ArrowForward";
import { useDispatch, useSelector } from "react-redux";
import DeleteIcon from "@mui/icons-material/Delete";
const ProjectMembersItem = ({ displayName, id }) => {
const ProjectMembersItem = ({ displayName, roleProject, id, roleProjectOfAuthor }) => {
console.log(displayName)
const dispatch = useDispatch();
const user = useSelector(state => state.users)
console.log(user)
const { projects, project } = useSelector(state => state.projects);
return <>
<Grid item xs={12} sm={12} md={6} lg={4}>
<Card>
<CardContent>
<strong>
<br></br>
{displayName}
</strong>
<strong>
<br></br>
роль: {project?.project?.members[0]?.roleProject}
</strong>
<strong>
<br></br>
<button>delete</button>
</strong>
</CardContent>
</Card>
</Grid>
return <>
<Grid item xs={12} sm={12} md={6} lg={4}>
<Card>
<CardContent>
<strong>
<br></br>
{displayName}
</strong>
<strong>
<br></br>
роль: {roleProject}
</strong>
<strong>
{roleProjectOfAuthor === "admin" ?
(<strong>
<Tooltip title="Удалить">
<IconButton
onClick={(id) => {
// deleteHandle(task.id);
}}
>
<DeleteIcon style={{ marginTop: "-5px" }} />
</IconButton>
</Tooltip>
</strong>) : null}
</strong>
</CardContent>
</Card>
</Grid>
</>
};
......
import {Grid} from "@mui/material";
import ProjectMembersItem from "../ProjectMembersItem/ProjectMembersItem";
const ProjectMembersList = ({users}) => {
console.log(users)
const ProjectMembersList = ({members, roleProjectOfAuthor}) => {
console.log("members ", members)
return (
<Grid item container direction="row" spacing={1}>
{users?.map(user => {
<Grid item container direction="column" spacing={1}>
{members?.map(member => {
return <ProjectMembersItem
displayName={user.displayName}
id={user.id}
key={user.id}
displayName={member?.user?.displayName}
roleProject={member?.roleProject}
id={member.id}
key={member.id}
roleProjectOfAuthor={roleProjectOfAuthor}
/>
})}
</Grid>
......
......@@ -2,8 +2,9 @@ import {Grid} from "@mui/material";
import ProjectItem from "../ProjectItem/ProjectItem";
const ProjectsList = ({projects}) => {
console.log(projects)
return (
<Grid item container direction="row" spacing={1}>
<Grid item container direction="column" spacing={1}>
{projects?.map(project => {
return <ProjectItem
tasks={project.tasks}
......
import { Grid, TextField, MenuItem } from "@mui/material";
import PropTypes from "prop-types";
const FormElement = ({ name, label, state, error, onChange, select, options, type = "'text" }) => {
const FormElement = ({ name, label, state, error, onChange, select, options, type = "'text", users}) => {
let inputChildren = null
if (select) {
......@@ -19,6 +19,7 @@ const FormElement = ({ name, label, state, error, onChange, select, options, typ
type={type}
variant="outlined"
value={state?.[name]}
users={users}
onChange={onChange}
error={!!error}
helperText={error}
......
......@@ -6,13 +6,14 @@ import { fetchProject } from "../../store/actions/projectsActions";
import ProjectTasksBody from "../../components/ProjectTasks/ProjectTasksBody";
import { fetchUsers } from "../../store/actions/usersActions";
import ProjectMembersList from "../../components/ProjectMembersList/ProjectMembersList";
import NewMember from "../NewMember/NewMember";
const FullProject = () => {
const { projects, project } = useSelector(state => state.projects);
const users = useSelector(state => state.users.users);
const dispatch = useDispatch();
const params = useParams()
const tasks = project.tasks;
......@@ -22,13 +23,13 @@ const FullProject = () => {
useEffect(() => {
dispatch(fetchUsers())
}, [dispatch]);
console.log(users)
useEffect(() => {
dispatch(fetchProject(params.id))
}, [params.id, dispatch]);
console.log(project);
console.log("project ", project);
return <>
<Grid item xs={12} sm={12} md={6} lg={4}>
......@@ -53,9 +54,13 @@ const FullProject = () => {
</strong>
<strong>
<br></br>
<div style={{display: 'flex', direction: 'column'}}>
Участники проекта:
<NewMember members={project?.project?.members} />
</div>
<ProjectMembersList users={users} project={project}/>
<ProjectMembersList users={users} project={project} members={project?.project?.members} roleProjectOfAuthor={project?.project?.members[0]?.roleProject} />
</strong>
<strong>
<br></br>
......
import {useNavigate} from "react-router-dom";
import {useDispatch, useSelector} from "react-redux";
import { useEffect } from "react";
import ProjectForm from "../../components/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.id)
console.log("memberData ", memberData)
};
// useEffect(()=> {
// dispatch(fetchMembers());
// }, [dispatch])
return (
<>
<MemberForm members={members} onSubmit={onSubmit} />
</>
);
};
export default NewMember;
\ No newline at end of file
......@@ -13,7 +13,6 @@ const NewProject = () => {
const onSubmit = async (projectData) => {
await dispatch(createProject(projectData, navigate));
console.log(projectData)
};
useEffect(()=> {
......
......@@ -12,6 +12,7 @@ const Projects = () => {
const dispatch = useDispatch();
const { projects, loading } = useSelector(state => state.projects.projects);
const {users} = useSelector(state => state.users);
const members = useSelector(state => state.projects.projects)
console.log(projects)
console.log(users)
......@@ -32,7 +33,7 @@ const Projects = () => {
>
<Grid item>
<Typography variant="h4">
Projects
Проекты
</Typography>
</Grid>
<HasAccess roles={["superuser", "admin", "user"]} >
......@@ -42,7 +43,7 @@ const Projects = () => {
</HasAccess>
</Grid>
<Loader loading={loading} />
<ProjectsList projects={projects} />
<ProjectsList projects={projects} members={members} />
</Grid>
</>) :
<h1>Созданных проектов нет</h1>
......
export const FETCH_PROJECTS_REQUEST = "FETCH_PROJECTS_REQUEST";
export const FETCH_PROJECTS_SUCCESS = "FETCH_PROJECTS_SUCCESS";
export const FETCH_PROJECTS_ERROR = "FETCH_PROJECTS_ERROR";
export const FETCH_PROJECT_SUCCESS = "FETCH_PROJECT_SUCCESS";
export const CREATE_PROJECT_SUCCESS = "CREATE_PROJECT_SUCCESS";
export const CREATE_MEMBER_SUCCESS = "CREATE_MEMBER_SUCCESS";
\ No newline at end of file
import axios from "../../axiosPlanner";
import { CREATE_PROJECT_SUCCESS, FETCH_PROJECTS_ERROR, FETCH_PROJECTS_REQUEST, FETCH_PROJECTS_SUCCESS, FETCH_PROJECT_SUCCESS } from "../actionTypes/projectsActionTypes";
import { CREATE_MEMBER_SUCCESS, CREATE_PROJECT_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";
const fetchProjectsRequest = () => {
......@@ -8,17 +8,21 @@ const fetchProjectsRequest = () => {
const fetchProjectsSuccess = (projects) => {
return {type: FETCH_PROJECTS_SUCCESS, projects};
};
const fetchProjectSuccess = (project) => {
return {type: FETCH_PROJECT_SUCCESS, project};
};
const fetchProjectsError = (error) => {
return {type: FETCH_PROJECTS_ERROR, error};
}
const fetchProjectSuccess = (project) => {
return {type: FETCH_PROJECT_SUCCESS, project};
};
const createProjectSuccess = () => {
return {type: CREATE_PROJECT_SUCCESS};
};
const createMemberSuccess = (member) => {
return {type: CREATE_MEMBER_SUCCESS, member};
};
export const fetchProjects = () => {
return async dispatch => {
dispatch(fetchProjectsRequest());
......@@ -37,6 +41,7 @@ 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));
}
......@@ -56,4 +61,21 @@ export const createProject = (projectData, navigate) => {
dispatch(showNotification("Не удалось создать проект", "error"))
}
};
}
\ No newline at end of file
}
export const createMember = (memberData, navigate) => {
return async (dispatch) => {
try {
console.log(memberData)
const response = await axios.post("/projects/add-user", memberData);
dispatch(createMemberSuccess());
console.log(memberData)
navigate("/projects/")
dispatch(showNotification("Участник успешно добавлен"))
} catch (e) {
console.log(e);
dispatch(showNotification("Не удалось добавить участника", "error"))
}
};
}
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