diff --git a/src/Admin/Components/Components/Inputs/EditUser.js b/src/Admin/Components/Components/Inputs/EditUser.js new file mode 100644 index 0000000000000000000000000000000000000000..67d0521b92b5c76830b6eae6f44054776884a9aa --- /dev/null +++ b/src/Admin/Components/Components/Inputs/EditUser.js @@ -0,0 +1,507 @@ +/*Copyright (C) 2019 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana + +This file is part of Plataforma Integrada MEC. + +Plataforma Integrada MEC is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Plataforma Integrada MEC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with Plataforma Integrada MEC. If not, see <http://www.gnu.org/licenses/>.*/ + +import React, { useState, useEffect, useContext } from 'react'; +//imports material ui components +import { Typography, TextField, Button, Grid } from '@material-ui/core'; +import CircularProgress from '@material-ui/core/CircularProgress'; +import Card from "@material-ui/core/Card"; +import CardContent from "@material-ui/core/CardContent"; +import CardAction from '@material-ui/core/CardActions'; +import ListRoundedIcon from '@material-ui/icons/ListRounded'; +import Chip from '@material-ui/core/Chip'; +import { makeStyles } from '@material-ui/core/styles'; +import SaveIcon from '@material-ui/icons/Save'; +import DeleteRoundedIcon from '@material-ui/icons/DeleteRounded'; +import MenuItem from '@material-ui/core/MenuItem'; +//imports local files +import SnackBar from '../../../../Components/SnackbarComponent'; +import { Store } from '../../../../Store'; +import LoadingSpinner from '../../../../Components/LoadingSpinner'; +//imports services +import { getRequest, putRequest, deleteRequest } from '../../../../Components/HelperFunctions/getAxiosConfig' +import { EditFilter, GetAData, DeleteFilter } from '../../../Filters'; +//routers +import { Link } from 'react-router-dom'; +import Unauthorized from '../Unauthorized'; +import styled from 'styled-components'; + +const useStyles = makeStyles((theme) => ({ + root: { + display: 'flex', + justifyContent: 'center', + flexWrap: 'wrap', + listStyle: 'none', + padding: theme.spacing(0.5), + margin: 0, + }, + chip: { + margin: theme.spacing(0.5), + }, +})); + +const EditUser = ({ match }) => { + const classes = useStyles(); + const { state, dispatch } = useContext(Store); + + const [error, setError] = useState(null); //Necessary to consult the API, catch errors + const [isLoaded, setIsLoaded] = useState(false); //Necessary to consult the API, wait until complete + + const [isLoading, setIsLoading] = useState(false); + const id = match.params.id + const [name, setName] = useState("") + const [email, setEmail] = useState("") + const [description, setDescription] = useState("") + const [pass, setPass] = useState("") + const [confirmPass, setConfirmPass] = useState("") + const [rolesList, setRolesList] = useState([ + { + id: 1, + value: "teacher" + }, + { + id: 2, + value: "student" + }, + { + id: 3, + value: "admin" + }, + { + id: 4, + value: "curator" + }, + { + id: 5, + value: "moderator" + }, + { + id: 6, + value: "supervisor" + }, + { + id: 7, + value: "editor" + }, + { + id: 9, + value: "partner" + }, + { + id: 10, + value: "publisher" + }, + { + id: 11, + value: "submitter" + }, + ]) + const [userRoles, setUserRoles] = useState([]) + + + const [errorInName, setErrorInName] = useState({ + error: false, + message: '' + }) + const [errorInEmail, setErrorInEmail] = useState({ + error: false, + message: '' + }) + const [errorInDesc, setErrorInDesc] = useState({ + error: false, + message: '' + }) + const [errorInPass, setErrorInPass] = useState({ + error: false, + message: '' + }) + const [errorInConfirmPass, setErrorInConfirmPass] = useState({ + error: false, + message: '' + }) + + const [snackInfo, setSnackInfo] = useState({ + message: '', + icon: '', + open: false, + color: '', + }) + + const NameHandler = (e) => { + if (errorInName.error) { + setErrorInName({ + error: false, + message: '' + }) + } + setName(e.target.value) + } + + const EmailHandler = (e) => { + if (errorInEmail.error) { + setErrorInEmail({ + error: false, + message: '' + }) + } + setEmail(e.target.value) + } + + const DescHandler = (e) => { + if (errorInDesc.error) { + setErrorInDesc({ + error: false, + message: '' + }) + } + setDescription(e.target.value) + } + + const PassHandler = (e) => { + if (errorInPass.error) { + setErrorInPass({ + error: false, + message: '' + }) + } + setPass(e.target.value) + } + + const ConfirmPassHandler = (e) => { + if (errorInConfirmPass.error) { + setErrorInConfirmPass({ + error: false, + message: '' + }) + } + setConfirmPass(e.target.value) + } + + //Verify if the string is empty + const isEmpty = (text) => { + return text.length === 0 ? true : false; + } + + // Fields + const fields = [ + { + label: 'ID', + value: id, + default: true, + type: 'text' + }, + { + label: 'Nome', + value: name, + error: errorInName.error, + errorMessage: errorInName.message, + onChange: (event) => NameHandler(event), + default: false, + type: 'text', + }, + { + label: 'Email', + value: email, + error: errorInEmail.error, + errorMessage: errorInEmail.message, + onChange: (event) => EmailHandler(event), + default: false, + type: 'text' + }, + { + label: 'Descrição', + value: description, + error: errorInDesc.error, + errorMessage: errorInDesc.message, + onChange: (event) => DescHandler(event), + default: false, + type: 'text' + }, + { + label: 'Senha', + value: pass, + error: errorInPass.error, + errorMessage: errorInPass.message, + onChange: (event) => PassHandler(event), + default: false, + type: 'text' + }, + { + label: 'Confirmar senha', + value: confirmPass, + error: errorInConfirmPass.error, + errorMessage: errorInConfirmPass.message, + onChange: (event) => ConfirmPassHandler(event), + default: false, + type: 'text' + }, + ] + + // Handle snack infos + const HandleSnack = (message, state, icon, color) => { + setSnackInfo({ + message: message, + icon: icon, + open: state, + color: color + }) + } + + const CheckUserPermission = () => { + let canUserEdit = false; + + if (state.userIsLoggedIn) { + const roles = [...state.currentUser.roles]; + for (let i = 0; i < roles.length; i++) + if (roles[i].name === 'admin' || roles[i].name === 'editor') + canUserEdit = true; + } + else { + canUserEdit = false; + } + + return canUserEdit; + } + + const handleDelete = (chipToDelete) => () => { + const currRolesList = [...rolesList]; + currRolesList.push({ + id: chipToDelete.id, + value: chipToDelete.name + }) + setRolesList(currRolesList) + setUserRoles((chips) => chips.filter((chip) => chip.id !== chipToDelete.id)); + }; + + const deleteUser = (userId) => { + deleteRequest( + DeleteFilter(`/users/${userId}`), + (data) => { + HandleSnack(`${name} deletado com sucesso!`, true, "success", "#228B22"); + }, + (error) => { + HandleSnack("Erro!", true, "warning", "#FA8072"); + } + ) + } + + const onSubmit = async () => { + // setIsLoading(true) + let userRolesID = []; + if (!isEmpty(name) && !isEmpty(email)) { + const api = EditFilter('user', id) + userRoles.map((role) => { + userRolesID.push(role.id); + }) + const body = { + "user": { + "name": name, + "subjects" : [], + "role_ids": userRolesID, + "institution_ids" : [] + } + } + console.log(body); + putRequest( + api, + body, + (data) => { + HandleSnack('A linguagem foi alterada com sucesso', true, 'success', '#228B22') + setIsLoading(false) + }, + (error) => { + HandleSnack('Ocorreu algum erro', true, 'warning', '#FA8072') + setIsLoading(false) + } + ) + } + else { + HandleSnack('Você precisa preencher algumas informações obrigatórias', true, 'warning', '#FFC125') + if (isEmpty(name)) { + setErrorInName({ + error: true, + message: 'Este campo precisa ser preenchido' + }) + } + if (isEmpty(email)) { + setErrorInEmail({ + error: true, + message: 'Este campo precisa ser preenchido' + }) + } + setIsLoading(false) + } + } + + const handleChange = (id, value) => { + const currUserRoles = [...userRoles]; + currUserRoles.push( + { + id: id, + name: value, + } + ) + setRolesList((chips) => chips.filter((chip) => chip.id !== id)); + setUserRoles(currUserRoles); + }; + + useEffect(() => { + getRequest( + GetAData("users", match.params.id), + (data, header) => { + const currRolesList = [...rolesList]; + const auxiliarRolesId = [ + 1, 2, 3, 4, 5, 6, 7, 9, 10, 11 + ] + data.role_ids.map((data) => { + const index = auxiliarRolesId.indexOf(data); + currRolesList.splice(index, 1); + }) + setRolesList(currRolesList); + setName(data.name) + setEmail(data.email) + setDescription(data.description) + setUserRoles(data.roles) + setIsLoaded(true); + }, + (error) => { + setIsLoaded(true); + setError(error); + } + ) + }, []); + + if (error) { + return <div> Houve um erro... </div> + } else if (!isLoaded) { + return <LoadingSpinner text="Carregando..." /> + } else if (CheckUserPermission()) { + return ( + <Card> + <SnackBar + severity={snackInfo.icon} + text={snackInfo.message} + snackbarOpen={snackInfo.open} + color={snackInfo.color} + handleClose={() => setSnackInfo({ + message: '', + icon: '', + open: false, + color: '' + })} + /> + <CardContent> + <Grid container direction='row' justify='space-between' alignItems="center"> + <Grid item> + <Typography variant='h4'> + {name} + </Typography> + </Grid> + <Grid item> + <Grid container direction="row"> + <Grid item> + <Link style={{ textDecoration: 'none' }} to={'/admin/users/teacher_requests'}> + <Button + startIcon={<ListRoundedIcon />} + variant='outlined' + color='primary' + > + Listar + </Button> + </Link> + </Grid> + <Grid item> + <Button + startIcon={<DeleteRoundedIcon />} + color="secondary" + variant="outlined" + onClick={() => { deleteUser(id) }} + > + Deletar + </Button> + </Grid> + </Grid> + </Grid> + </Grid> + <div style={{ height: '1em' }}></div> + <form style={{ display: 'flex', flexDirection: 'column' }}> + {fields.map((field, index) => ( + <TextField + key={index} + required={field.required} + disabled={field.default} + error={field.error} + helperText={field.error ? field.errorMessage : ''} + style={{ width: '250px', marginBottom: '1em' }} + label={field.label} + value={field.value} + onChange={field.onChange} + type="search" + multiline={true} + /> + ))} + {userRoles.map((data) => { + return ( + <li key={data.id} style={{ listStyleType: "none" }}> + <Chip + label={data.name} + onDelete={data === 'React' ? undefined : handleDelete(data)} + className={classes.chip} + /> + </li> + ); + })} + <TextField + id="standard-select-currency" + select + label="Permissões" + style={{ width: '250px', marginBottom: '1em' }} + > + {rolesList.map((option) => ( + <MenuItem key={option.id} value={option.value} onClick={() => { handleChange(option.id, option.value) }}> + {option.value} + </MenuItem> + ))} + </TextField> + </form> + </CardContent> + <CardAction> + <Button + onClick={() => { + onSubmit(); + }} + variant="contained" + color="primary" + disabled={isLoading} + startIcon={isLoading ? null : <SaveIcon />} + > + { + isLoading ? <CircularProgress size={24} /> : 'Salvar' + } + </Button> + </CardAction> + </Card> + ) + } else return <Unauthorized /> +} + +export default EditUser; + +const SizedBox = styled.div` + height : 3em; +` \ No newline at end of file