diff --git a/src/Admin/Components/Components/DataCards/UserCard.js b/src/Admin/Components/Components/DataCards/UserCard.js new file mode 100644 index 0000000000000000000000000000000000000000..71142353c936618d176afb780bbae88a543da6fb --- /dev/null +++ b/src/Admin/Components/Components/DataCards/UserCard.js @@ -0,0 +1,570 @@ +/*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 } from "react"; +import moment from 'moment'; +// Maerial ui components +import Card from "@material-ui/core/Card"; +import CardContent from "@material-ui/core/CardContent"; +import Typography from "@material-ui/core/Typography"; +import Button from "@material-ui/core/Button"; +import Paper from "@material-ui/core/Paper"; +import Grid from "@material-ui/core/Grid"; +import ListRoundedIcon from "@material-ui/icons/ListRounded"; +import Chip from '@material-ui/core/Chip'; +import { useStyles } from "../../Styles/DataCard"; +import EmailRoundedIcon from '@material-ui/icons/EmailRounded'; +import EditRoundedIcon from '@material-ui/icons/EditRounded'; +import DeleteRoundedIcon from '@material-ui/icons/DeleteRounded'; +import CheckRoundedIcon from "@material-ui/icons/CheckRounded"; +import CloseRoundedIcon from "@material-ui/icons/CloseRounded"; +//imports from local files +import { GetAData, DeleteFilter } from "../../../Filters"; +import { apiDomain} from '../../../../env'; +import noAvatar from "../../../../img/default_profile.png"; +import { Link } from "react-router-dom"; +import LoadingSpinner from '../../../../Components/LoadingSpinner'; +import SnackBar from '../../../../Components/SnackbarComponent'; +import { getRequest, postRequest, deleteRequest } from '../../../../Components/HelperFunctions/getAxiosConfig' +//styles +import styled from 'styled-components'; + +const CollectionCard = ({ match }) => { + const classes = useStyles(); + + const roles = [ + "", "professor", "aluno", "admin", "curador", "moderador", "supervisor", "editor", "parceiro", "publicador", "submetedor", + ]; + + 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 [item, setItem] = useState({}); + + const [snackInfo, setSnackInfo] = useState({ + message: '', + icon: '', + open: false, + color: '', + }) + + const ComplaintStatus = (status) => { + switch (status) { + case "accepted": + return ( + <Paper + style={{ + textAlign: "center", + padding: "0.5em", + backgroundColor: "#228B22", + fontWeight: "500", + color: "#FFFAFA", + }} + > + ACEITO + </Paper> + ); + case "requested": + return ( + <Paper + style={{ + textAlign: "center", + padding: "0.5em", + backgroundColor: "#FF8C00", + fontWeight: "500", + color: "#FFFAFA", + }} + > + PENDENTE + </Paper> + ); + case "rejected": + return ( + <Paper + style={{ + textAlign: "center", + padding: "0.5em", + backgroundColor: "#FA8072", + fontWeight: "500", + color: "#FFFAFA", + }} + > + Rejeitado + </Paper> + ); + default: + return ( + <Paper + style={{ + textAlign: "center", + padding: "0.5em", + backgroundColor: "#797D7F ", + fontWeight: "500", + color: "#FFFAFA", + }} + > + Não requisitado + </Paper> + ) + } + }; + + const DisplayDate = (date) => { + const convertedData = moment.utc(date); + return moment(convertedData).format("LLL").toString(); + } + + // Handle snack infos + const HandleSnack = (message, state, icon, color) => { + setSnackInfo({ + message: message, + icon: icon, + open: state, + color: color + }) + } + + const handleAprove = (userId, userName) => { + const url = `/users/${userId}/add_teacher` + const body = { + "approves": true + } + postRequest( + url, + body, + (data) => { + HandleSnack(`${userName} aceito como professor!`, true, "success", "#228B22"); + }, + (error) => { + HandleSnack("Erro!", true, "warning", "#FA8072"); + } + ) + } + + const handleReject = (userId, userName) => { + const url = `/users/${userId}/add_teacher` + const body = { + "user": { + "approves": false + } + } + postRequest( + url, + body, + (data) => { + HandleSnack(`${userName} rejeitado como professor!`, true, "success", "#228B22"); + }, + (error) => { + HandleSnack("Erro!", true, "warning", "#FA8072"); + } + ) + } + + const displayUserRole = (rolID) => { + if (rolID >= 9) + return roles[rolID - 1]; + return roles[rolID]; + } + + const deleteUser = (userId) => { + deleteRequest( + DeleteFilter(`/users/${userId}`), + (data) => { + HandleSnack(`${item.name} deletado com sucesso!`, true, "success", "#228B22"); + }, + (error) => { + HandleSnack("Erro!", true, "warning", "#FA8072"); + } + ) + } + + useEffect(() => { + getRequest( + GetAData("users", match.params.id), + (data, header) => { + setItem(data) + console.log(data); + setIsLoaded(true); + setError(false); + }, + (error) => { + setError(true); + } + ) + }, []); + + if (error) { + return <div>Houve um erro</div>; + } else if (!isLoaded) { + return <LoadingSpinner text="Carregando..." /> + } else { + return ( + <Grid + container + spacing={3} + > + <SnackBar + severity={snackInfo.icon} + text={snackInfo.message} + snackbarOpen={snackInfo.open} + color={snackInfo.color} + handleClose={() => setSnackInfo({ + message: '', + icon: '', + open: false, + color: '' + })} + /> + <Grid + item + md={6} + xs={12} + > + <Card> + <CardContent> + <Grid container justify="space-between"> + <Grid item xs={12}> + <Typography + className={classes.title} + color="inherit" + gutterBottom + > + Identificação do usuário + </Typography> + </Grid> + <Grid container xs={12}> + <Grid item> + <Link + style={{ textDecoration: "none" }} + to={`/admin/users/teacher_requests`} + > + <Button + startIcon={<ListRoundedIcon />} + color="primary" + variant="outlined" + > + Listar + </Button> + </Link> + </Grid> + <Grid item> + <Button + startIcon={<DeleteRoundedIcon />} + color="secondary" + variant="outlined" + onClick={() => { deleteUser(item.id) }} + > + Deletar + </Button> + </Grid> + <Grid item> + <Link to={`/admin/EditUser/${item.id}`} style={{ textDecoration: "none" }}> + <Button + startIcon={<EditRoundedIcon />} + color="primary" + variant="outlined" + > + Editar + </Button> + </Link> + </Grid> + </Grid> + </Grid> + <SizedBox /> + <Grid container direction="row" justify="flex-start" alignItems="center" spacing={3}> + <Grid item justify="center" alignItems="center"> + <AvatarDiv> + <img src={item.avatar ? apiDomain + item.avatar : noAvatar} alt='user avatar' + style={{ height: "100%", width: "100%", borderRadius: "50%" }} /> + </AvatarDiv> + </Grid> + <Grid item> + <div className={classes.displayColumn}> + <Typography color="initial" className={classes.subTitle}> + Nome + </Typography> + <Typography color="textSecondary"> + {item.name === null ? "Sem dados" : item.name} + </Typography> + </div> + <div className={classes.displayColumn}> + <Typography color="initial" className={classes.subTitle}> + Email + </Typography> + { + item.email ? + <Link to={`/admin/sendEmail/${item.email}`} style={{ textDecoration: 'none' }}> + <Button + variant='text' + color='primary' + startIcon={<EmailRoundedIcon />} + > + {item.email} + </Button> + </Link> : null + } + </div> + <div className={classes.displayColumn}> + <Typography color="initial" className={classes.subTitle}> + Cpf + </Typography> + <Typography color="textSecondary"> + {item.cpf === null ? "Sem dados" : item.cpf} + </Typography> + </div> + </Grid> + </Grid> + <Grid> + <div className={classes.displayColumn}> + <Typography color="initial" className={classes.subTitle}> + Escola + </Typography> + <Typography color="textSecondary"> + {item.school ? item.school.name : "Sem dados"} + </Typography> + </div> + <div className={classes.displayColumn}> + <Typography color="initial" className={classes.subTitle}> + Telefone da escola + </Typography> + <Typography color="textSecondary"> + {item.school ? item.school.phone : "Sem dados"} + </Typography> + </div> + <div className={classes.displayColumn}> + <Typography color="initial" className={classes.subTitle}> + UF + </Typography> + <Typography color="textSecondary"> + {item.school ? item.school.uf : "Sem dados"} + </Typography> + </div> + <div className={classes.displayColumn}> + <Typography color="initial" className={classes.subTitle}> + MunÃcipo + </Typography> + <Typography color="textSecondary"> + {item.school ? item.school.city : "Sem dados"} + </Typography> + </div> + </Grid> + </CardContent> + </Card> + </Grid> + + <Grid + item + md={6} + xs={12} + > + <Grid item> + <Card> + <CardContent> + <Typography variant="h5" component="h2"> + Informações do perfil + </Typography> + + {ComplaintStatus(item.submitter_request)} + + <SizedBox /> + + <Grid container justify="flex-start"> + <Grid item> + <div className={classes.displayColumn}> + <Typography color="initial" className={classes.subTitle}> + Descrição + </Typography> + <Typography color="textSecondary"> + {item.description} + </Typography> + </div> + </Grid> + + <Grid container direction="row" justify="space-between" spacing={1} alignItems="center"> + <Grid item> + <div className={classes.displayColumn}> + <Typography color="initial" className={classes.subTitle}> + Criado em + </Typography> + <Typography color="textSecondary"> + {DisplayDate(item.created_at)} + </Typography> + </div> + </Grid> + + <Grid item> + <div className={classes.displayColumn}> + <Typography color="initial" className={classes.subTitle}> + Atualizado em + </Typography> + <Typography color="textSecondary"> + {DisplayDate(item.updated_at)} + </Typography> + </div> + </Grid> + </Grid> + + <Grid item> + <div className={classes.displayColumn}> + <Typography color="initial" className={classes.subTitle}> + Permissões + </Typography> + <Grid container direction="row"> + { + item.role_ids.map((tag, index) => { + return ( + <ChipDiv key={index}> + <Chip label={displayUserRole(tag)} /> + </ChipDiv> + ) + }) + } + </Grid> + </div> + </Grid> + + <Grid container direction="row" spacing={1} justify="space-between" alignItems="center"> + <Grid item> + <div className={classes.displayColumn}> + <Typography color="initial" className={classes.subTitle}> + Nota + </Typography> + <Typography color="textSecondary"> + {item.score} + </Typography> + </div> + </Grid> + + <Grid item> + <div className={classes.displayColumn}> + <Typography color="initial" className={classes.subTitle}> + Seguidores + </Typography> + <Typography color="textSecondary"> + {item.follows_count} + </Typography> + </div> + </Grid> + + <Grid item> + <div className={classes.displayColumn}> + <Typography color="initial" className={classes.subTitle}> + Likes + </Typography> + <Typography color="textSecondary"> + {item.likes_count} + </Typography> + </div> + </Grid> + + <Grid item> + <div className={classes.displayColumn}> + <Typography color="initial" className={classes.subTitle}> + Objetos educacionais + </Typography> + <Typography color="textSecondary"> + {item.learning_objects_count} + </Typography> + </div> + </Grid> + + <Grid item> + <div className={classes.displayColumn}> + <Typography color="initial" className={classes.subTitle}> + Coleções + </Typography> + <Typography color="textSecondary"> + {item.collections_count} + </Typography> + </div> + </Grid> + </Grid> + <StyledDivider> + </StyledDivider> + <Grid container direction="column"> + <Grid item> + <Typography variant="h5" component="h2"> + Ações + </Typography> + </Grid> + <SizedBox /> + <Grid container direction="row" spacing={1}> + <Grid item> + <Button + variant="contained" + color="secondary" + style={{ width: "100%" }} + disabled={ + item.submitter_request === "requested" ? false : true + } + startIcon={ + <CloseRoundedIcon style={{ fill: "#FFFAFA" }} /> + } + onClick={() => { handleReject(item.id, item.name) }} + > + Recusar + </Button> + </Grid> + <Grid item> + <Button + variant="contained" + color="primary" + style={{ width: "100%" }} + disabled={ + item.submitter_request === "requested" ? false : true + } + startIcon={ + <CheckRoundedIcon style={{ fill: "#FFFAFA" }} /> + } + onClick={() => { handleAprove(item.id, item.name) }} + > + Aceitar + </Button> + </Grid> + </Grid> + </Grid> + </Grid> + </CardContent> + </Card> + </Grid> + </Grid> + </Grid> + ); + } +}; + +export default CollectionCard; + +const AvatarDiv = styled.div` + border-radius : 100%; + height : 126px; + width : 126px; + border : 2px solid #d4d4d4; +` +const ChipDiv = styled.div` + margin-right : 0.5em; + margin-bottom : 0.5em; +` +const SizedBox = styled.div` + height : 1em; +` +const StyledDivider = styled.div` + width : 100%; + border-radius : 100%; + margin-bottom : 0.6em; + border : 0.5px solid #d4d4d4; +` \ No newline at end of file