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 ...@@ -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>=>{ router.post('/add-user/', async (req: Request, res: Response):Promise<Response>=>{
const {userId, projectId, roleProject} = req.body; const {userId, projectId, roleProject} = req.body;
console.log("req body" + req.body)
const newMember:Member = new Member(); const newMember:Member = new Member();
try{ try{
newMember.user= userId; newMember.user= userId;
......
import { 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}) => { ...@@ -45,7 +45,7 @@ const ProjectForm = ({onSubmit}) => {
return ( return (
<div > <div >
<Button onClick={handleOpen} >Add project</Button> <Button onClick={handleOpen} >Добавить проект</Button>
<Modal <Modal
open={open} open={open}
onClose={handleClose} onClose={handleClose}
...@@ -56,7 +56,7 @@ const ProjectForm = ({onSubmit}) => { ...@@ -56,7 +56,7 @@ const ProjectForm = ({onSubmit}) => {
<Box sx={style}> <Box sx={style}>
<form > <form >
<Grid container direction="column" spacing={2}> <Grid container direction="column" spacing={2}>
<Typography variant="h4">New project</Typography> <Typography variant="h4">Новый проект</Typography>
<FormElement <FormElement
onChange={inputChangeHandler} onChange={inputChangeHandler}
name={"title"} name={"title"}
...@@ -70,7 +70,7 @@ const ProjectForm = ({onSubmit}) => { ...@@ -70,7 +70,7 @@ const ProjectForm = ({onSubmit}) => {
variant="contained" variant="contained"
> >
Create Создать
</Button> </Button>
</Grid> </Grid>
</Grid> </Grid>
......
...@@ -7,12 +7,12 @@ import { useDispatch, useSelector } from "react-redux"; ...@@ -7,12 +7,12 @@ import { useDispatch, useSelector } from "react-redux";
const ProjectItem = ({ title, tasks, id }) => { const ProjectItem = ({ title, tasks, id }) => {
const user = useSelector(state => state.users.user); const user = useSelector(state => state.users.user);
const dispatch = useDispatch(); const dispatch = useDispatch();
console.log(tasks) console.log(user)
return <> return <>
<Grid item xs={12} sm={12} md={6} lg={4}> <Grid item xs={12} sm={12} md={6} lg={4}>
<Card> <Card>
<CardContent> <CardContent >
<strong> <strong>
<br></br> <br></br>
Название проекта: {title} Название проекта: {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 { Link } from "react-router-dom";
import ArrowForwardIcon from "@mui/icons-material/ArrowForward"; import ArrowForwardIcon from "@mui/icons-material/ArrowForward";
import { useDispatch, useSelector } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
import DeleteIcon from "@mui/icons-material/Delete";
const ProjectMembersItem = ({ displayName, roleProject, id, roleProjectOfAuthor }) => {
const ProjectMembersItem = ({ displayName, id }) => { console.log(displayName)
const dispatch = useDispatch(); const dispatch = useDispatch();
const user = useSelector(state => state.users)
console.log(user)
const { projects, project } = useSelector(state => state.projects); const { projects, project } = useSelector(state => state.projects);
return <> return <>
...@@ -18,11 +21,22 @@ const ProjectMembersItem = ({ displayName, id }) => { ...@@ -18,11 +21,22 @@ const ProjectMembersItem = ({ displayName, id }) => {
</strong> </strong>
<strong> <strong>
<br></br> <br></br>
роль: {project?.project?.members[0]?.roleProject} роль: {roleProject}
</strong> </strong>
<strong> <strong>
<br></br>
<button>delete</button> {roleProjectOfAuthor === "admin" ?
(<strong>
<Tooltip title="Удалить">
<IconButton
onClick={(id) => {
// deleteHandle(task.id);
}}
>
<DeleteIcon style={{ marginTop: "-5px" }} />
</IconButton>
</Tooltip>
</strong>) : null}
</strong> </strong>
</CardContent> </CardContent>
</Card> </Card>
......
import {Grid} from "@mui/material"; import {Grid} from "@mui/material";
import ProjectMembersItem from "../ProjectMembersItem/ProjectMembersItem"; import ProjectMembersItem from "../ProjectMembersItem/ProjectMembersItem";
const ProjectMembersList = ({users}) => { const ProjectMembersList = ({members, roleProjectOfAuthor}) => {
console.log(users) console.log("members ", members)
return ( return (
<Grid item container direction="row" spacing={1}> <Grid item container direction="column" spacing={1}>
{users?.map(user => { {members?.map(member => {
return <ProjectMembersItem return <ProjectMembersItem
displayName={user.displayName} displayName={member?.user?.displayName}
id={user.id} roleProject={member?.roleProject}
key={user.id} id={member.id}
key={member.id}
roleProjectOfAuthor={roleProjectOfAuthor}
/> />
})} })}
</Grid> </Grid>
......
...@@ -2,8 +2,9 @@ import {Grid} from "@mui/material"; ...@@ -2,8 +2,9 @@ import {Grid} from "@mui/material";
import ProjectItem from "../ProjectItem/ProjectItem"; import ProjectItem from "../ProjectItem/ProjectItem";
const ProjectsList = ({projects}) => { const ProjectsList = ({projects}) => {
console.log(projects)
return ( return (
<Grid item container direction="row" spacing={1}> <Grid item container direction="column" spacing={1}>
{projects?.map(project => { {projects?.map(project => {
return <ProjectItem return <ProjectItem
tasks={project.tasks} tasks={project.tasks}
......
import { Grid, TextField, MenuItem } from "@mui/material"; import { Grid, TextField, MenuItem } from "@mui/material";
import PropTypes from "prop-types"; 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 let inputChildren = null
if (select) { if (select) {
...@@ -19,6 +19,7 @@ const FormElement = ({ name, label, state, error, onChange, select, options, typ ...@@ -19,6 +19,7 @@ const FormElement = ({ name, label, state, error, onChange, select, options, typ
type={type} type={type}
variant="outlined" variant="outlined"
value={state?.[name]} value={state?.[name]}
users={users}
onChange={onChange} onChange={onChange}
error={!!error} error={!!error}
helperText={error} helperText={error}
......
...@@ -6,6 +6,7 @@ import { fetchProject } from "../../store/actions/projectsActions"; ...@@ -6,6 +6,7 @@ import { fetchProject } from "../../store/actions/projectsActions";
import ProjectTasksBody from "../../components/ProjectTasks/ProjectTasksBody"; import ProjectTasksBody from "../../components/ProjectTasks/ProjectTasksBody";
import { fetchUsers } from "../../store/actions/usersActions"; import { fetchUsers } from "../../store/actions/usersActions";
import ProjectMembersList from "../../components/ProjectMembersList/ProjectMembersList"; import ProjectMembersList from "../../components/ProjectMembersList/ProjectMembersList";
import NewMember from "../NewMember/NewMember";
const FullProject = () => { const FullProject = () => {
...@@ -28,7 +29,7 @@ const FullProject = () => { ...@@ -28,7 +29,7 @@ const FullProject = () => {
useEffect(() => { useEffect(() => {
dispatch(fetchProject(params.id)) dispatch(fetchProject(params.id))
}, [params.id, dispatch]); }, [params.id, dispatch]);
console.log(project); console.log("project ", project);
return <> return <>
<Grid item xs={12} sm={12} md={6} lg={4}> <Grid item xs={12} sm={12} md={6} lg={4}>
...@@ -53,9 +54,13 @@ const FullProject = () => { ...@@ -53,9 +54,13 @@ const FullProject = () => {
</strong> </strong>
<strong> <strong>
<br></br> <br></br>
<div style={{display: 'flex', direction: 'column'}}>
Участники проекта: Участники проекта:
<NewMember members={project?.project?.members} />
<ProjectMembersList users={users} project={project}/> </div>
<ProjectMembersList users={users} project={project} members={project?.project?.members} roleProjectOfAuthor={project?.project?.members[0]?.roleProject} />
</strong> </strong>
<strong> <strong>
<br></br> <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 = () => { ...@@ -13,7 +13,6 @@ const NewProject = () => {
const onSubmit = async (projectData) => { const onSubmit = async (projectData) => {
await dispatch(createProject(projectData, navigate)); await dispatch(createProject(projectData, navigate));
console.log(projectData) console.log(projectData)
}; };
useEffect(()=> { useEffect(()=> {
......
...@@ -12,6 +12,7 @@ const Projects = () => { ...@@ -12,6 +12,7 @@ const Projects = () => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const { projects, loading } = useSelector(state => state.projects.projects); const { projects, loading } = useSelector(state => state.projects.projects);
const {users} = useSelector(state => state.users); const {users} = useSelector(state => state.users);
const members = useSelector(state => state.projects.projects)
console.log(projects) console.log(projects)
console.log(users) console.log(users)
...@@ -32,7 +33,7 @@ const Projects = () => { ...@@ -32,7 +33,7 @@ const Projects = () => {
> >
<Grid item> <Grid item>
<Typography variant="h4"> <Typography variant="h4">
Projects Проекты
</Typography> </Typography>
</Grid> </Grid>
<HasAccess roles={["superuser", "admin", "user"]} > <HasAccess roles={["superuser", "admin", "user"]} >
...@@ -42,7 +43,7 @@ const Projects = () => { ...@@ -42,7 +43,7 @@ const Projects = () => {
</HasAccess> </HasAccess>
</Grid> </Grid>
<Loader loading={loading} /> <Loader loading={loading} />
<ProjectsList projects={projects} /> <ProjectsList projects={projects} members={members} />
</Grid> </Grid>
</>) : </>) :
<h1>Созданных проектов нет</h1> <h1>Созданных проектов нет</h1>
......
export const FETCH_PROJECTS_REQUEST = "FETCH_PROJECTS_REQUEST"; export const FETCH_PROJECTS_REQUEST = "FETCH_PROJECTS_REQUEST";
export const FETCH_PROJECTS_SUCCESS = "FETCH_PROJECTS_SUCCESS"; export const FETCH_PROJECTS_SUCCESS = "FETCH_PROJECTS_SUCCESS";
export const FETCH_PROJECTS_ERROR = "FETCH_PROJECTS_ERROR"; export const FETCH_PROJECTS_ERROR = "FETCH_PROJECTS_ERROR";
export const FETCH_PROJECT_SUCCESS = "FETCH_PROJECT_SUCCESS"; export const FETCH_PROJECT_SUCCESS = "FETCH_PROJECT_SUCCESS";
export const CREATE_PROJECT_SUCCESS = "CREATE_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 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"; import { showNotification } from "./commonActions";
const fetchProjectsRequest = () => { const fetchProjectsRequest = () => {
...@@ -8,17 +8,21 @@ const fetchProjectsRequest = () => { ...@@ -8,17 +8,21 @@ const fetchProjectsRequest = () => {
const fetchProjectsSuccess = (projects) => { const fetchProjectsSuccess = (projects) => {
return {type: FETCH_PROJECTS_SUCCESS, projects}; return {type: FETCH_PROJECTS_SUCCESS, projects};
}; };
const fetchProjectSuccess = (project) => {
return {type: FETCH_PROJECT_SUCCESS, project};
};
const fetchProjectsError = (error) => { const fetchProjectsError = (error) => {
return {type: FETCH_PROJECTS_ERROR, error}; return {type: FETCH_PROJECTS_ERROR, error};
} }
const fetchProjectSuccess = (project) => {
return {type: FETCH_PROJECT_SUCCESS, project};
};
const createProjectSuccess = () => { const createProjectSuccess = () => {
return {type: CREATE_PROJECT_SUCCESS}; return {type: CREATE_PROJECT_SUCCESS};
}; };
const createMemberSuccess = (member) => {
return {type: CREATE_MEMBER_SUCCESS, member};
};
export const fetchProjects = () => { export const fetchProjects = () => {
return async dispatch => { return async dispatch => {
dispatch(fetchProjectsRequest()); dispatch(fetchProjectsRequest());
...@@ -37,6 +41,7 @@ export const fetchProject = (id) => { ...@@ -37,6 +41,7 @@ export const fetchProject = (id) => {
try { try {
const response = await axios.get("/projects/" + id); const response = await axios.get("/projects/" + id);
dispatch(fetchProjectSuccess(response.data)); dispatch(fetchProjectSuccess(response.data));
console.log("fetch project "+response.data)
} catch (e) { } catch (e) {
dispatch(fetchProjectsError(e)); dispatch(fetchProjectsError(e));
} }
...@@ -57,3 +62,20 @@ export const createProject = (projectData, navigate) => { ...@@ -57,3 +62,20 @@ export const createProject = (projectData, navigate) => {
} }
}; };
} }
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