diff --git a/src/Admin/Components/Components/DataCards/GameficationCard.js b/src/Admin/Components/Components/DataCards/GameficationCard.js index 114a643c6441701a049014e3e7a3010bd6fdd13b..5fcff0c51741eba928a80e6770a6d247eb81ec2a 100644 --- a/src/Admin/Components/Components/DataCards/GameficationCard.js +++ b/src/Admin/Components/Components/DataCards/GameficationCard.js @@ -28,535 +28,535 @@ import { useStyles } from "../../Styles/DataCard"; import Grid from "@material-ui/core/Grid"; // Icons import EditRoundedIcon from "@material-ui/icons/EditRounded"; -import DeleteRoundedIcon from "@material-ui/icons/DeleteRounded"; //imports from local files import { GetAData, DeleteFilter, EditFilter } from "../../../Filters"; import { Link, useHistory } from "react-router-dom"; import LoadingSpinner from "../../../../Components/LoadingSpinner"; import SnackBar from "../../../../Components/SnackbarComponent"; import { - getRequest, - deleteRequest, - putRequest + getRequest, + deleteRequest, + putRequest } from "../../../../Components/HelperFunctions/getAxiosConfig"; import Paper from "@material-ui/core/Paper"; import { apiDomain } from "../../../../env"; import noAvatar from "../../../../img/default_profile.png"; const CollectionCard = ({ match }) => { - let history = useHistory(); - const classes = useStyles(); + let history = useHistory(); + const classes = useStyles(); - const [error, setError] = useState(false) //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 [reloadPage, setReloadPage] = useState(false); - const [snackInfo, setSnackInfo] = useState({ - message: "", - icon: "", - open: false, - color: "", - }); + const [error, setError] = useState(false) //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 [reloadPage, setReloadPage] = useState(false); + const [snackInfo, setSnackInfo] = useState({ + message: "", + icon: "", + open: false, + color: "", + }); - const DisplayDate = (date) => { - const convertedData = moment.utc(date); - return moment(convertedData) - .format("LLL") - .toString(); - }; + const DisplayDate = (date) => { + const convertedData = moment.utc(date); + return moment(convertedData) + .format("LLL") + .toString(); + }; - const HandleSnack = (message, state, icon, color) => { - setSnackInfo({ - message: message, - icon: icon, - open: state, - color: color, - }); - }; + const HandleSnack = (message, state, icon, color) => { + setSnackInfo({ + message: message, + icon: icon, + open: state, + color: color, + }); + }; - const inactiveItem = (item) => { - const body = { - "item": { - "state": "inactive" - } - } - putRequest( - EditFilter("items", item.id), - body, - (data) => { - if (data.errors) - HandleSnack("Ocorreu algum erro", true, "warning", "#FA8072"); - else { - HandleSnack( - "O item foi inativado com sucesso", - true, - "success", - "#228B22" - ); - } - setReloadPage(!reloadPage) - }, - (error) => { - HandleSnack("Ocorreu algum erro", true, "warning", "#FA8072"); - } - ) + const inactiveItem = (item) => { + const body = { + "item": { + "state": "inactive" + } } - - const activeItem = (item) => { - const body = { - "item": { - "state": "active" - } + putRequest( + EditFilter("items", item.id), + body, + (data) => { + if (data.errors) + HandleSnack("Ocorreu algum erro", true, "warning", "#FA8072"); + else { + HandleSnack( + "O item foi inativado com sucesso", + true, + "success", + "#228B22" + ); } - putRequest( - EditFilter("items", item.id), - body, - (data) => { - if (data.errors) - HandleSnack("Ocorreu algum erro", true, "warning", "#FA8072"); - else { - HandleSnack( - "O item foi ativado com sucesso", - true, - "success", - "#228B22" - ); - } - setReloadPage(!reloadPage) - }, - (error) => { - HandleSnack("Ocorreu algum erro", true, "warning", "#FA8072"); - } - ) - } + setReloadPage(!reloadPage) + }, + (error) => { + HandleSnack("Ocorreu algum erro", true, "warning", "#FA8072"); + } + ) + } - const deleteHandler = () => { - deleteRequest( - DeleteFilter("items", item.id), - (data) => { - if (data.errors) - HandleSnack("Ocorreu algum erro", true, "warning", "#FA8072"); - else { - HandleSnack( - "O item foi deletada com sucesso", - true, - "success", - "#228B22" - ); - } - history.goBack() - }, - (error) => { - HandleSnack("Ocorreu algum erro", true, "warning", "#FA8072"); - } - ) + const activeItem = (item) => { + const body = { + "item": { + "state": "active" + } } + putRequest( + EditFilter("items", item.id), + body, + (data) => { + if (data.errors) + HandleSnack("Ocorreu algum erro", true, "warning", "#FA8072"); + else { + HandleSnack( + "O item foi ativado com sucesso", + true, + "success", + "#228B22" + ); + } + setReloadPage(!reloadPage) + }, + (error) => { + HandleSnack("Ocorreu algum erro", true, "warning", "#FA8072"); + } + ) + } + const deleteHandler = () => { + deleteRequest( + DeleteFilter("items", item.id), + (data) => { + if (data.errors) + HandleSnack("Ocorreu algum erro", true, "warning", "#FA8072"); + else { + HandleSnack( + "O item foi deletada com sucesso", + true, + "success", + "#228B22" + ); + } + history.goBack() + }, + (error) => { + HandleSnack("Ocorreu algum erro", true, "warning", "#FA8072"); + } + ) + } - const FastActions = (item) => { - switch (item.state) { - case "removed": - return ( - <Grid container alignItems="center" spacing={1}> - <Grid item> - <Button - color="primary" - variant="contained" - style={{ backgroundColor: "#FF8C00", color: "#FFFAFA", width: "150px" }} - onClick={() => inactiveItem(item)} - > - Inativar + + const FastActions = (item) => { + switch (item.state) { + case "removed": + return ( + <Grid container alignItems="center" spacing={1}> + <Grid item> + <Button + color="primary" + variant="contained" + style={{ backgroundColor: "#FF8C00", color: "#FFFAFA", width: "150px" }} + onClick={() => inactiveItem(item)} + > + Inativar </Button> - </Grid> - <Grid item> - <Button - color="primary" - style={{ backgroundColor: "#228B22", color: "#FFFAFA", width: "150px" }} - variant="contained" - onClick={() => activeItem(item)} - > - Ativar + </Grid> + <Grid item> + <Button + color="primary" + style={{ backgroundColor: "#228B22", color: "#FFFAFA", width: "150px" }} + variant="contained" + onClick={() => activeItem(item)} + > + Ativar </Button> - </Grid> - </Grid> - ); - case "inactive": - return ( - <Grid container alignItems="center" spacing={1}> - <Grid item> - <Button - color="primary" - variant="contained" - style={{ backgroundColor: "#FA8072", color: "#FFFAFA", width: "150px" }} - onClick={deleteHandler} - > - Remover + </Grid> + </Grid> + ); + case "inactive": + return ( + <Grid container alignItems="center" spacing={1}> + <Grid item> + <Button + color="primary" + variant="contained" + style={{ backgroundColor: "#FA8072", color: "#FFFAFA", width: "150px" }} + onClick={deleteHandler} + > + Remover </Button> - </Grid> - <Grid item> - <Button - color="primary" - style={{ backgroundColor: "#228B22", color: "#FFFAFA", width: "150px" }} - variant="contained" - onClick={() => activeItem(item)} - > - Ativar + </Grid> + <Grid item> + <Button + color="primary" + style={{ backgroundColor: "#228B22", color: "#FFFAFA", width: "150px" }} + variant="contained" + onClick={() => activeItem(item)} + > + Ativar </Button> - </Grid> - </Grid> - ); - case "active": - return ( - <Grid container alignItems="center" spacing={1}> - <Grid item> - <Button - style={{ backgroundColor: "#FA8072", color: "#FFFAFA", width: "150px" }} - variant="contained" - onClick={deleteHandler} - > - Remover + </Grid> + </Grid> + ); + case "active": + return ( + <Grid container alignItems="center" spacing={1}> + <Grid item> + <Button + style={{ backgroundColor: "#FA8072", color: "#FFFAFA", width: "150px" }} + variant="contained" + onClick={deleteHandler} + > + Remover </Button> - </Grid> - <Grid item> - <Button - style={{ backgroundColor: "#FF8C00", color: "#FFFAFA", width: "150px" }} - variant="contained" - onClick={() => inactiveItem(item)} - > - Inativar + </Grid> + <Grid item> + <Button + style={{ backgroundColor: "#FF8C00", color: "#FFFAFA", width: "150px" }} + variant="contained" + onClick={() => inactiveItem(item)} + > + Inativar </Button> - </Grid> - </Grid> - ); - default: - return "NOTHING"; - } - }; - - const StateItem = (status) => { - switch (status) { - case "removed": - return ( - <Paper - style={{ - textAlign: "center", - padding: "0.5em", - backgroundColor: "#FA8072", - fontWeight: "500", - color: "#FFFAFA", - }} - > - REMOVIDO - </Paper> - ); - case "inactive": - return ( - <Paper - style={{ - textAlign: "center", - padding: "0.5em", - backgroundColor: "#FF8C00", - fontWeight: "500", - color: "#FFFAFA", - }} - > - INATIVO - </Paper> - ); - case "active": - return ( - <Paper - style={{ - textAlign: "center", - padding: "0.5em", - backgroundColor: "#228B22", - fontWeight: "500", - color: "#FFFAFA", - }} - > - ATIVO - </Paper> - ); - default: - return "NOTHING"; - } - }; - - useEffect(() => { - setIsLoaded(false) - getRequest( - GetAData("items", match.params.id), - (data, header) => { - setItem(data); - setIsLoaded(true); - setError(false); - }, - (error) => { - setIsLoaded(true); - setError(true); - } + </Grid> + </Grid> ); - }, [reloadPage]); + default: + return "NOTHING"; + } + }; - if (error) { - return <div>Houve um erro</div>; - } else if (!isLoaded) { - return <LoadingSpinner text="Carregando..." />; - } else { + const StateItem = (status) => { + switch (status) { + case "removed": + return ( + <Paper + style={{ + textAlign: "center", + padding: "0.5em", + backgroundColor: "#FA8072", + fontWeight: "500", + color: "#FFFAFA", + }} + > + REMOVIDO + </Paper> + ); + case "inactive": + return ( + <Paper + style={{ + textAlign: "center", + padding: "0.5em", + backgroundColor: "#FF8C00", + fontWeight: "500", + color: "#FFFAFA", + }} + > + INATIVO + </Paper> + ); + case "active": return ( - <> - <SnackBar - severity={snackInfo.icon} - text={snackInfo.message} - snackbarOpen={snackInfo.open} - color={snackInfo.color} - handleClose={() => - setSnackInfo({ - message: "", - icon: "", - open: false, - color: "", - }) - } - /> - <Grid container direction="row" spacing={1}> - <Grid item xs={12} md={6}> - <Card> - <CardContent> - <Grid - xs={12} - justify="space-between" - alignItems="center" - container - > - <Grid item> - <Typography - className={classes.title} - color="inherit" - gutterBottom - > - Informações do item + <Paper + style={{ + textAlign: "center", + padding: "0.5em", + backgroundColor: "#228B22", + fontWeight: "500", + color: "#FFFAFA", + }} + > + ATIVO + </Paper> + ); + default: + return "NOTHING"; + } + }; + + useEffect(() => { + setIsLoaded(false) + getRequest( + GetAData("items", match.params.id), + (data, header) => { + setItem(data); + setIsLoaded(true); + setError(false); + }, + (error) => { + setIsLoaded(true); + setError(true); + } + ); + }, [reloadPage]); + + if (error) { + return <div>Houve um erro</div>; + } else if (!isLoaded) { + return <LoadingSpinner text="Carregando..." />; + } else { + return ( + <> + <SnackBar + severity={snackInfo.icon} + text={snackInfo.message} + snackbarOpen={snackInfo.open} + color={snackInfo.color} + handleClose={() => + setSnackInfo({ + message: "", + icon: "", + open: false, + color: "", + }) + } + /> + <Grid container direction="row" spacing={1}> + <Grid item xs={12} md={6}> + <Card> + <CardContent> + <Grid + xs={12} + justify="space-between" + alignItems="center" + container + > + <Grid item> + <Typography + className={classes.title} + color="inherit" + gutterBottom + > + Informações do item </Typography> - </Grid> - <Grid item> - <Link - style={{ textDecoration: "none" }} - to={`/admin/gamefication`} - > - <Button - startIcon={<ListRoundedIcon />} - color="primary" - variant="outlined" - > - Listar - </Button> - </Link> - <Link - style={{ textDecoration: "none" }} - > - <Button - startIcon={<EditRoundedIcon />} - color="primary" - variant="outlined" - > - Editar + </Grid> + <Grid item> + <Link + style={{ textDecoration: "none" }} + to={`/admin/gamefication`} + > + <Button + startIcon={<ListRoundedIcon />} + color="primary" + variant="outlined" + > + Listar </Button> - </Link> - </Grid> - </Grid> - <div style={{ height: "1em" }} /> - <Grid container direction="row" spacing={3}> - <Grid item sm={5} xs={12} style={{}}> - <img - alt="Avatar of the item" - src={item.image ? apiDomain + item.image : noAvatar} - style={{ - height: "100%", - width: "100%", - aspectRatio: "16/9", - borderRight: "solid #d4d4d4 1px", - paddingRight: "0.6em", - }} - /> - </Grid> - <Grid item sm={7} xs={12}> - <Grid container direction="column" spacing={1}> - <Grid - container - direction="row" - justify="space-between" - alignItems="center" - > - <Grid item> - <Typography - color="initial" - className={classes.subTitle} - > - Nome - </Typography> - <Typography color="textSecondary"> - {item.name} - </Typography> - </Grid> - <Grid item> - <Typography - color="initial" - className={classes.subTitle} - > - Tipo - </Typography> - <Typography color="textSecondary"> - {item.item_type} + </Link> + <Link + to={`/admin/EditItem/${match.params.id}`} + style={{ textDecoration: "none" }} + > + <Button + startIcon={<EditRoundedIcon />} + color="primary" + variant="outlined" + > + Editar + </Button> + </Link> + </Grid> + </Grid> + <div style={{ height: "1em" }} /> + <Grid container direction="row" spacing={3}> + <Grid item sm={5} xs={12} style={{ + borderRight: "solid #d4d4d4 1px" + }}> + <img + alt="Avatar of the item" + src={item.image ? apiDomain + item.image : noAvatar} + style={{ + maxHeight: "100%", + objectFit: "cover", + maxWidth: "100%", + }} + /> + </Grid> + <Grid item sm={7} xs={12}> + <Grid container direction="column" spacing={1}> + <Grid + container + direction="row" + justify="space-between" + alignItems="center" + > + <Grid item> + <Typography + color="initial" + className={classes.subTitle} + > + Nome + </Typography> + <Typography color="textSecondary"> + {item.name} + </Typography> + </Grid> + <Grid item> + <Typography + color="initial" + className={classes.subTitle} + > + Tipo </Typography> - </Grid> - </Grid> - <Grid item> - <Grid - container - direction="row" - justify="space-between" - alignItems="center" - spacing={1} - > - <Grid item> - <Typography - color="initial" - className={classes.subTitle} - > - Preço - </Typography> - <Typography color="textSecondary"> - {item.price + " points"} + <Typography color="textSecondary"> + {item.item_type} + </Typography> + </Grid> + </Grid> + <Grid item> + <Grid + container + direction="row" + justify="space-between" + alignItems="center" + spacing={1} + > + <Grid item> + <Typography + color="initial" + className={classes.subTitle} + > + Preço </Typography> - </Grid> + <Typography color="textSecondary"> + {item.price + " points"} + </Typography> + </Grid> - <Grid item> - <Typography - color="initial" - className={classes.subTitle} - > - Desconto - </Typography> - <Typography style={{ color: "#FA8072" }}> - {"-" + item.discount + " points"} + <Grid item> + <Typography + color="initial" + className={classes.subTitle} + > + Desconto </Typography> - </Grid> + <Typography style={{ color: "#FA8072" }}> + {"-" + item.discount + " points"} + </Typography> + </Grid> - <Grid item> - <Typography - color="initial" - className={classes.subTitle} - > - Preço a se pagar - </Typography> - <Typography style={{ color: "#228B22" }}> - {item.price - item.discount + " points"} + <Grid item> + <Typography + color="initial" + className={classes.subTitle} + > + Preço a se pagar </Typography> - </Grid> - </Grid> - </Grid> - <Grid item> - <Typography - color="initial" - className={classes.subTitle} - > - Criado em - </Typography> - <Typography color="textSecondary"> - {DisplayDate(item.created_at)} - </Typography> - </Grid> - <Grid item> - <Typography - color="initial" - className={classes.subTitle} - > - Atualizado em + <Typography style={{ color: "#228B22" }}> + {item.price - item.discount + " points"} + </Typography> + </Grid> + </Grid> + </Grid> + <Grid item> + <Typography + color="initial" + className={classes.subTitle} + > + Criado em </Typography> - <Typography color="textSecondary"> - {DisplayDate(item.updated_at)} + <Typography color="textSecondary"> + {DisplayDate(item.created_at)} + </Typography> + </Grid> + <Grid item> + <Typography + color="initial" + className={classes.subTitle} + > + Atualizado em </Typography> - </Grid> - </Grid> - </Grid> - </Grid> - <Grid container direction="column" spacing={1}> - { - item.achievement ? - <> - <Grid item> - <Typography color="initial" className={classes.subTitle}> - Como desbloquear - </Typography> - <Typography color="textSecondary"> - {item.achievement.description} - </Typography> - </Grid> - <Grid item> - <Typography color="initial" className={classes.subTitle}> - Recompensa de xp - </Typography> - <Typography style={{ color: "#228B22" }}> - {"+" + item.achievement.reward_experience + " xp"} + <Typography color="textSecondary"> + {DisplayDate(item.updated_at)} + </Typography> + </Grid> + </Grid> + </Grid> + </Grid> + <Grid container direction="column" spacing={1}> + { + item.achievement ? + <> + <Grid item> + <Typography color="initial" className={classes.subTitle}> + Como desbloquear </Typography> - </Grid> - <Grid item> - <Typography color="initial" className={classes.subTitle}> - Recompensa de points + <Typography color="textSecondary"> + {item.achievement.description} + </Typography> + </Grid> + <Grid item> + <Typography color="initial" className={classes.subTitle}> + Recompensa de xp </Typography> - <Typography style={{ color: "#228B22" }}> - {"+" + item.achievement.reward_points + " points"} + <Typography style={{ color: "#228B22" }}> + {"+" + item.achievement.reward_experience + " xp"} + </Typography> + </Grid> + <Grid item> + <Typography color="initial" className={classes.subTitle}> + Recompensa de points </Typography> - </Grid> - </> - : null - } - <Grid item> - <Typography color="initial" className={classes.subTitle}> - Descrição - </Typography> - <Typography color="textSecondary"> - {item.description} + <Typography style={{ color: "#228B22" }}> + {"+" + item.achievement.reward_points + " points"} + </Typography> + </Grid> + </> + : null + } + <Grid item> + <Typography color="initial" className={classes.subTitle}> + Descrição </Typography> - </Grid> - </Grid> - </CardContent> - </Card> - </Grid> - <Grid item xs={12} md={6}> - <Card> - <CardContent> - <div className={classes.displayColumn}> - <Typography - className={classes.title} - color="inherit" - gutterBottom - > - Estado - </Typography> - <Typography color="textSecondary"> - {StateItem(item.state)} - </Typography> - </div> - <div className={classes.displayColumn}> - <Typography - className={classes.title} - color="inherit" - gutterBottom - > - Ações + <Typography color="textSecondary"> + {item.description} + </Typography> + </Grid> + </Grid> + </CardContent> + </Card> + </Grid> + <Grid item xs={12} md={6}> + <Card> + <CardContent> + <div className={classes.displayColumn}> + <Typography + className={classes.title} + color="inherit" + gutterBottom + > + Estado </Typography> - <Typography color="textSecondary"> - {FastActions(item)} + <Typography color="textSecondary"> + {StateItem(item.state)} + </Typography> + </div> + <div className={classes.displayColumn}> + <Typography + className={classes.title} + color="inherit" + gutterBottom + > + Ações </Typography> - </div> - </CardContent> - </Card> - </Grid> - </Grid> - </> - ); - } + <Typography color="textSecondary"> + {FastActions(item)} + </Typography> + </div> + </CardContent> + </Card> + </Grid> + </Grid> + </> + ); + } }; export default CollectionCard; diff --git a/src/Admin/Components/Components/Inputs/CreateItem/CompAddImg.js b/src/Admin/Components/Components/Inputs/CreateItem/CompAddImg.js index ea098984320a909feebd223bd2602d4c9679a0df..102ea0b081c55608e56da2785ea345eb6a22e517 100644 --- a/src/Admin/Components/Components/Inputs/CreateItem/CompAddImg.js +++ b/src/Admin/Components/Components/Inputs/CreateItem/CompAddImg.js @@ -16,28 +16,28 @@ 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, {useContext, useState} from 'react'; +import React, { useContext, useState } from 'react'; import { Button } from '@material-ui/core'; import styled from 'styled-components' import CloseIcon from '@material-ui/icons/Close'; import Profile from '../../../../../img/default_profile0.png' import Cropper from './Cropper.js' -function ChooseImage (props) { +function ChooseImage(props) { return ( - <div style={{marginTop:"0"}}> + <div style={{ marginTop: "0" }}> <DivAlterarFoto> <DivFlowHolder> <AvatarCircleDiv> <img src={props.avatar} - alt="user avatar" style={{height:"inherit", width:"inherit", objectFit:"cover"}} + alt="user avatar" style={{ height: "inherit", width: "inherit", objectFit: "cover" }} /> - <input accept="image/*" id="avatar-file" - type="file" - onChange={(e) => props.handleFile(e.target.files)} - style={{display : "none"}} + <input accept="image/*" id="avatar-file" + type="file" + onChange={(e) => props.handleFile(e.target.files)} + style={{ display: "none" }} /> - <label for="avatar-file" style={{width:"inherit"}}> + <label for="avatar-file" style={{ width: "inherit" }}> <ChangeAvatarDiv > <span>Alterar</span> </ChangeAvatarDiv> @@ -47,22 +47,20 @@ function ChooseImage (props) { </DivAlterarFoto> { props.tempImg && - <img alt="" src={props.tempImg}/> + <img alt="" src={props.tempImg} /> } <ButtonsDiv> <ButtonCancelar onClick={props.handleClose}> <span>Cancelar</span> </ButtonCancelar> - <ButtonConfirmar> - <span>Salvar Alterações</span> - </ButtonConfirmar> + </ButtonsDiv> </div> ) } -export default function ComponentAlterarAvatar (props) { +export default function ComponentAlterarAvatar(props) { const [uploadingImage, setUploading] = useState(false) const handleFile = (selectorFiles) => { @@ -80,65 +78,59 @@ export default function ComponentAlterarAvatar (props) { } const [crop] = useState({ - unit: "%" , - width : 30, + unit: "%", + width: 30, aspect: 1 }); const completeSelection = () => { - //newAvatar is a base64 encoded image file - let fdAvatar = new FormData() - fdAvatar.set('user[avatar]', newAvatar) props.handleComplete(newAvatar) } return ( <ModalDiv> <HeaderDiv> - <span style={{width:"32px"}}/> - <StyledH2>{uploadingImage ? 'Alterar foto do perfil' : 'Editar Foto'}</StyledH2> - <StyledCloseModalButton onClick={props.handleClose}> - <CloseIcon style={{color : "#666"}}/> - </StyledCloseModalButton> + <span style={{ width: "32px" }} /> + <StyledH2>{uploadingImage ? 'Alterar foto do Item' : 'Editar foto do Item'}</StyledH2> + <StyledCloseModalButton onClick={props.handleClose}> + <CloseIcon style={{ color: "#666" }} /> + </StyledCloseModalButton> </HeaderDiv> <DialogDiv> - { - uploadingImage ? - ( - [ - <> - <EditarDiv> - <TextoEditarDiv> - Clique nos ícones e arraste para selecionar a parte que você quer da foto - </TextoEditarDiv> - <div style={{maxWidth : "500px", maxHeight : "300px"}}> - <Cropper src={tempImgURL} crop={crop} circularCrop={true} update={updateAvatar}/> - </div> - </EditarDiv> - <FooterButtonsDiv> - <ButtonCancelar>ESCOLHER OUTRA</ButtonCancelar> - <div> - <ButtonCancelar onClick={props.handleClose}>CANCELAR</ButtonCancelar> - <ButtonConfirmar onClick={() => {completeSelection()}}>SELECIONAR FOTO</ButtonConfirmar> - </div> - </FooterButtonsDiv> - </> - ] - ) - : - ( - [ - <> - <ChooseImage - avatar={Profile} - handleFile={handleFile} - handleClose={props.handleClose} - tempImg={tempImgURL} - /> - </> - ] - ) - } + { + uploadingImage ? + ( + [ + <> + <EditarDiv> + <TextoEditarDiv> + Clique nos ícones e arraste para selecionar a parte que você quer da foto + </TextoEditarDiv> + <div style={{ maxWidth: "500px", maxHeight: "300px" }}> + <Cropper src={tempImgURL} crop={crop} circularCrop={true} update={updateAvatar} /> + </div> + </EditarDiv> + <FooterButtonsDiv> + <ButtonCancelar onClick={props.handleClose}>CANCELAR</ButtonCancelar> + <ButtonConfirmar onClick={() => { completeSelection() }}>SELECIONAR FOTO</ButtonConfirmar> + </FooterButtonsDiv> + </> + ] + ) + : + ( + [ + <> + <ChooseImage + avatar={Profile} + handleFile={handleFile} + handleClose={props.handleClose} + tempImg={tempImgURL} + /> + </> + ] + ) + } </DialogDiv> </ModalDiv> ) @@ -229,7 +221,7 @@ position : relative; overflow: hidden; ` -const DivFlowHolder =styled.div` +const DivFlowHolder = styled.div` align-self : auto; ` diff --git a/src/Admin/Components/Components/Inputs/CreateItem/CreateItem.js b/src/Admin/Components/Components/Inputs/CreateItem/CreateItem.js index 87b7f829e6ac309e8bd6beea33f1dd798cb8e456..39c4d62f36bd779e8b33e631329b3f7e1f818de0 100644 --- a/src/Admin/Components/Components/Inputs/CreateItem/CreateItem.js +++ b/src/Admin/Components/Components/Inputs/CreateItem/CreateItem.js @@ -25,10 +25,11 @@ import { Typography, TextField, Button, Grid } from '@material-ui/core'; import CircularProgress from '@material-ui/core/CircularProgress'; import AddRoundedIcon from '@material-ui/icons/AddRounded'; import ListRoundedIcon from '@material-ui/icons/ListRounded'; +import MenuItem from "@material-ui/core/MenuItem"; //imports local files import SnackBar from '../../../../../Components/SnackbarComponent'; import { Store } from '../../../../../Store'; -import { postRequest, deleteRequest } from '../../../../../Components/HelperFunctions/getAxiosConfig' +import { postRequest } from '../../../../../Components/HelperFunctions/getAxiosConfig' import Unauthorized from '../../Unauthorized'; import ModalAddPhoto from "./ModalAddPhoto" //router @@ -41,24 +42,27 @@ const CreateItem = (props) => { const [description, setDescription] = useState(''); const [price, setPrice] = useState(''); const [discount, setDiscount] = useState(''); - const [itemState, setItemState] = useState(''); - const [itemType, setItemType] = useState(''); + const [itemState, setItemState] = useState("active"); + const [itemType, setItemType] = useState('avatar_frame'); const [achievementID, setAchievementID] = useState(''); - const [img, setImg] = useState(null) const [isLoading, setIsLoading] = useState(false) const [open, setOpen] = useState(false) - - // Handle error in name const [errorInName, setErrorInName] = useState({ error: false, message: '', }) - - // Handle error in itemState - const [errorInitemState, setErrorInitemState] = useState({ + const [errorInDescription, setErrorInDescription] = useState({ error: false, message: '', }) + const [errorInPrice, setErrorInPrice] = useState({ + error: false, + message: '' + }) + const [errorInObjType, setErrorInObjType] = useState({ + error: false, + message: '' + }) const [snackInfo, setSnackInfo] = useState({ message: '', @@ -67,36 +71,61 @@ const CreateItem = (props) => { color: '', }) + const stateOptions = [ + { name: "active", value: "Ativo" }, + { name: "inactive", value: "Inativo" }, + { name: "removed", value: "Removido" }, + ]; + + const typesOptions = [ + { name: "avatar_frame", value: "Moldura de avatar" }, + { name: "badge", value: "Insígnia" }, + { name: "card_frame", value: "Moldura de card do usuário" }, + { name: "cover_frame", value: "Moldura de capa" }, + + ]; + + const NameHandler = (e) => { - setName(e.target.value) if (errorInName.error) { setErrorInName({ error: false, message: '' }) } + setName(e.target.value) } const DescriptionHandler = (e) => { + if (errorInDescription.error) + setErrorInDescription({ + error: false, + message: '' + }) setDescription(e.target.value) } const priceHandler = (e) => { + if (errorInPrice.error) + setErrorInPrice({ + error: false, + message: '' + }) setPrice(e.target.value) } + const itemTypeHandler = (e) => { + if (errorInObjType.error) + setErrorInObjType({ + error: false, + message: '' + }) + setItemType(e.target.value) + } const discountHandler = (e) => { setDiscount(e.target.value) } const itemStateHandler = (e) => { - if (errorInitemState.error) { - setErrorInitemState({ - error: false, - message: '' - }) - } + console.log(e) setItemState(e.target.value) } - const itemTypeHandler = (e) => { - setItemType(e.target.value) - } const achievementIdHandler = (e) => { setAchievementID(e.target.value) } @@ -132,33 +161,16 @@ const CreateItem = (props) => { async function onSubmit(img) { setIsLoading(true) const api = '/items' - console.log(name) - console.log(description) - - console.log(price) - - console.log(discount) - - console.log(itemState) - - console.log(itemType) - - console.log(achievementID) - - console.log(img) - let fdAvatar = new FormData() - fdAvatar.set('user[avatar]', img) - const body = { - "item" : { - "name" : name, - "description" : description, - "price" : price, - "discount" : discount, - "state" : itemState, - "item_type" : itemType, - "achievement_id" : achievementID, - "image" : img + "item": { + "name": name, + "description": description, + "price": parseInt(price), + "discount": parseInt(discount), + "state": itemState, + "item_type": itemType, + "achievement_id": parseInt(achievementID), + "image": img } } postRequest( @@ -166,9 +178,9 @@ const CreateItem = (props) => { body, (data) => { if (data.id) - HandleSnack('A instituição foi criada com sucesso', true, 'success', '#228B22') + HandleSnack('O item foi criada com sucesso', true, 'success', '#228B22') else { - if(data.errors){ + if (data.errors) { HandleSnack(`${data.errors[0]}`, true, 'warning', '#FA8072') } if (data.name) { @@ -181,6 +193,36 @@ const CreateItem = (props) => { message: nameError }) } + if (data.price) { + let priceError = ""; + data.price.map((msg) => ( + priceError = priceError + msg + " e " + )) + setErrorInPrice({ + error: true, + message: priceError + }) + } + if (data.description) { + let descriptionError = ""; + data.description.map((msg) => ( + descriptionError = descriptionError + msg + " e " + )) + setErrorInDescription({ + error: true, + message: descriptionError + }) + } + if (data.item_type) { + let objTypeError = ""; + data.objType.map((msg) => ( + objTypeError = objTypeError + msg + " e " + )) + setErrorInObjType({ + error: true, + message: objTypeError + }) + } } setIsLoading(false) }, @@ -194,6 +236,7 @@ const CreateItem = (props) => { // Fields const fields = [ { + select: false, label: 'Nome', value: name, required: true, @@ -202,40 +245,50 @@ const CreateItem = (props) => { onChange: (event) => NameHandler(event) }, { + select: false, label: 'Descrição', value: description, required: false, - + error: errorInDescription.error, + errorMessage: errorInDescription.message, onChange: (event) => DescriptionHandler(event) }, { + select: false, label: 'Preço', value: price, required: false, - + error: errorInPrice.error, + errorMessage: errorInPrice.message, onChange: (event) => priceHandler(event) }, { + select: false, label: 'Desconto', value: discount, required: false, onChange: (event) => discountHandler(event) }, { + select: true, label: 'Estado', value: itemState, + options: [...stateOptions], required: false, - error: errorInitemState.error, - errorMessage: errorInitemState.message, onChange: (event) => itemStateHandler(event) }, { + select: true, label: 'Tipo', value: itemType, required: false, + options: [...typesOptions], + error: errorInObjType.error, + errorMessage: errorInObjType.message, onChange: (event) => itemTypeHandler(event) }, { + select: false, label: 'ID do achievement', value: achievementID, required: false, @@ -248,9 +301,8 @@ const CreateItem = (props) => { <Card> <ModalAddPhoto open={open} - handleClose={() => {setOpen(false)}} - handleComplete = {(img) => { - setImg(img) + handleClose={() => { setOpen(false) }} + handleComplete={(img) => { setOpen(false) onSubmit(img) }} @@ -277,7 +329,7 @@ const CreateItem = (props) => { </Typography> </Grid> <Grid item> - <Link style={{ textDecoration: 'none' }} to={'/admin/intitutions'}> + <Link style={{ textDecoration: 'none' }} to={'/admin/gamefication'}> <Button onClick={props.BackToList} startIcon={<ListRoundedIcon />} @@ -294,18 +346,43 @@ const CreateItem = (props) => { <form style={{ display: 'flex', flexDirection: 'column' }}> {fields.map((field, index) => ( - <TextField - key={index} - required={field.required} - 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} - /> + field.select ? + <TextField + select + key={index} + required={field.required} + 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} + > + {field.options.map((option, index) => ( + <MenuItem + key={option.value} + value={option.name} + name={option.value} + > + {option.value} + </MenuItem> + ))} + </TextField> + : + <TextField + key={index} + required={field.required} + 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} + /> ))} </form> </CardContent> diff --git a/src/Admin/Components/Components/Inputs/EditItem/CompEditImg.js b/src/Admin/Components/Components/Inputs/EditItem/CompEditImg.js new file mode 100644 index 0000000000000000000000000000000000000000..4d2c2c2db2fb10a4d6e11b8c1b4eb71fb2780a5d --- /dev/null +++ b/src/Admin/Components/Components/Inputs/EditItem/CompEditImg.js @@ -0,0 +1,272 @@ +/*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 } from 'react'; +import { Button } from '@material-ui/core'; +import styled from 'styled-components' +import CloseIcon from '@material-ui/icons/Close'; +import Profile from '../../../../../img/default_profile0.png' +import Cropper from './Cropper.js' +import { apiDomain } from '../../../../../env' + +function ChooseImage(props) { + console.log(props) + return ( + <div style={{ marginTop: "0" }}> + <DivAlterarFoto> + <DivFlowHolder> + <AvatarCircleDiv> + <img src={props.avatar} + alt="user avatar" style={{ maxHeight: "inherit", maxWidth: "100%", objectFit: "cover" }} + /> + <input accept="image/*" id="avatar-file" + type="file" + onChange={(e) => props.handleFile(e.target.files)} + style={{ display: "none" }} + /> + <label for="avatar-file" style={{ width: "inherit" }}> + <ChangeAvatarDiv > + <span>Alterar</span> + </ChangeAvatarDiv> + </label> + </AvatarCircleDiv> + </DivFlowHolder> + </DivAlterarFoto> + { + props.tempImg && + <img alt="" src={props.tempImg} /> + } + <ButtonsDiv> + <ButtonCancelar onClick={() => props.handleComplete('')}> + <span>Cancelar</span> + </ButtonCancelar> + + </ButtonsDiv> + </div> + ) +} + + +export default function ComponentAlterarAvatar(props) { + const [uploadingImage, setUploading] = useState(false) + + const handleFile = (selectorFiles) => { + const objectURL = URL.createObjectURL(selectorFiles[0]) + console.log(objectURL) + setTempImg(objectURL) + setUploading(true) + } + + const [tempImgURL, setTempImg] = useState(null) + + const [newAvatar, setNewAvatar] = useState('') + const updateAvatar = (avatar) => { + setNewAvatar(avatar) + } + + const [crop] = useState({ + unit: "%", + width: 30, + aspect: 1 + }); + + const completeSelection = () => { + props.handleComplete(newAvatar) + } + + return ( + <ModalDiv> + <HeaderDiv> + <span style={{ width: "32px" }} /> + <StyledH2>{uploadingImage ? 'Alterar foto do Item' : 'Editar foto do Item'}</StyledH2> + <StyledCloseModalButton onClick={props.handleClose}> + <CloseIcon style={{ color: "#666" }} /> + </StyledCloseModalButton> + </HeaderDiv> + <DialogDiv> + { + uploadingImage ? + ( + [ + <> + <EditarDiv> + <TextoEditarDiv> + Clique nos ícones e arraste para selecionar a parte que você quer da foto + </TextoEditarDiv> + <div style={{ maxWidth: "500px", maxHeight: "300px" }}> + <Cropper src={tempImgURL} crop={crop} circularCrop={true} update={updateAvatar} /> + </div> + </EditarDiv> + <FooterButtonsDiv> + <ButtonCancelar onClick={props.handleClose}>CANCELAR</ButtonCancelar> + <ButtonConfirmar onClick={() => { completeSelection() }}>SELECIONAR FOTO</ButtonConfirmar> + </FooterButtonsDiv> + </> + ] + ) + : + ( + [ + <> + <ChooseImage + avatar={props.userAvatar ? apiDomain + props.userAvatar : Profile} + handleFile={handleFile} + handleClose={props.handleClose} + handleComplete={props.handleComplete} + tempImg={tempImgURL} + /> + </> + ] + ) + } + </DialogDiv> + </ModalDiv> + ) + +} + +const FooterButtonsDiv = styled.div` + padding : 0 30px 20px; + display : flex; + flex-direction : row; + align-content : center; + justify-content : space-between; + Button { + margin-top : 20px; + } +` + +const TextoEditarDiv = styled.div` + margin-bottom : 15px; + align-self : center; + text-align : center; + font-size : 15px; +` + +const EditarDiv = styled.div` + position : relative; + background-color : #f4f4f4; + padding : 20px 30px 40px; +` + +const ChangeAvatarDiv = styled.div` + color : rgba(255,255,255,.7); + background-color:rgba(0,0,0,.5); + position: absolute; + bottom: 0; + width: inherit; + text-align: center; + font-size: 18px; + padding-bottom: 5px; + font-weight: 400; + height: 30%; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; +` + +const ModalDiv = styled.div` + background-color : #fff; + border-radius : 4px; + min-width : 560px; + color : #666; + display: flex; + flex-direction : column; + @media screen and (max-width: 959px) { + height : 100%; + width : 100%; + } +` +const ButtonConfirmar = styled(Button)` + background-color : #00bcd4 !important; + color : #fff !important; + border-radius : 3px !important; +` + +const ButtonCancelar = styled(Button)` + &:hover { + background-color : rgba(158,158,158,0.2) !important; + } + background-color : #fff !important; + color : #666 !important; + text-decoration : none !important; + outline : none !important; + text-align : center !important; +` + +const ButtonsDiv = styled.div` +display : flex; +justify-content:flex-end; +` + +const AvatarCircleDiv = styled.div` +margin-bottom : 0; +border-radius : 50%; +height : 150px; +width : 150px; +position : relative; +overflow: hidden; +` + +const DivFlowHolder = styled.div` +align-self : auto; +` + +const DivAlterarFoto = styled.div` +display : flex; +margin-bottom : 30px; +flex-direction : row; +align-items : center; +justify-content :center; +` + +const DialogDiv = styled.div` +padding : 20px 30px; +overflow : visible !important; +` + +const HeaderDiv = styled.div` +display : flex; +flex-direction : row; +align-items : center; +align-content : center; +justify-content : space-between; +max-width : 100%; +` +const StyledH2 = styled.h2` +font-size : 26px; +font-weight : normal; +margin-top : 20px; +margin-bottom : 10px; +font-family: inherit; +line-height: 1.1; +color: inherit; +` +const StyledCloseModalButton = styled(Button)` +display : inline-block; +position : relative; +float : right !important; +background : transparent !important; +min-width: 0 !important; +width : 40px; +border-radius : 50%; +padding : 8px; +height : 40px; +margin : 0 6px; +` diff --git a/src/Admin/Components/Components/Inputs/EditItem/Cropper.js b/src/Admin/Components/Components/Inputs/EditItem/Cropper.js new file mode 100644 index 0000000000000000000000000000000000000000..ccccc4c2e57ca23d7b7de6500c630cf052a0a847 --- /dev/null +++ b/src/Admin/Components/Components/Inputs/EditItem/Cropper.js @@ -0,0 +1,140 @@ +/*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, { PureComponent } from 'react'; +import ReactCrop from 'react-image-crop'; +import 'react-image-crop/dist/ReactCrop.css'; + + +export default class Cropper extends PureComponent { + state = { + src: this.props.src, + crop:this.props.crop + }; + + + // If you setState the crop in here you should return false. + onImageLoaded = image => { + this.imageRef = image; + }; + + onCropComplete = crop => { + this.makeClientCrop(crop); + }; + + onCropChange = (crop, percentCrop) => { + // You could also use percentCrop: + // this.setState({ crop: percentCrop }); + this.setState({ crop }); + }; + + async makeClientCrop(crop) { + if (this.imageRef && crop.width && crop.height) { + // eslint-disable-next-line + const croppedImageUrl = await this.getCroppedImg( + this.imageRef, + crop, + 'newFile.jpeg' + ); + + + } + } + + + + getCroppedImg(image, crop, fileName) { + const canvas = document.createElement('canvas'); + const scaleX = image.naturalWidth / image.width; + const scaleY = image.naturalHeight / image.height; + canvas.width = crop.width; + canvas.height = crop.height; + const ctx = canvas.getContext('2d'); + + ctx.drawImage( + image, + crop.x * scaleX, + crop.y * scaleY, + crop.width * scaleX, + crop.height * scaleY, + 0, + 0, + crop.width, + crop.height + ); + const reader = new FileReader(); + canvas.toBlob(blob => { + reader.readAsDataURL(blob) + reader.onloadend = () => { + // {/*this.dataURLtoFile(reader.result, 'cropped.jpg')*/} + this.props.update(reader.result) + } + }) + + } + + render() { + // eslint-disable-next-line + const { crop, croppedImageUrl, src } = this.state; + + return ( + <> + {src && ( + <ReactCrop + src={src} + crop={crop} + circularCrop={this.props.circularCrop} + onImageLoaded={this.onImageLoaded} + onComplete={this.onCropComplete} + onChange={this.onCropChange} + style={{maxHeight : "300px", maxWidth : "100%"}} + /> + )} + {/*croppedImageUrl && ( + <img alt="Crop" style={{ maxWidth: '100%', maxHeight : "100%"}} src={croppedImageUrl} /> + )*/} + </> + ); + } +} + + + + +/*License for this component: +MIT License + +Copyright (c) 2020 ricardo.ch + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.*/ diff --git a/src/Admin/Components/Components/Inputs/EditItem/EditItem.js b/src/Admin/Components/Components/Inputs/EditItem/EditItem.js new file mode 100644 index 0000000000000000000000000000000000000000..189caff989c36a72ddab4f400ff73aef242f23a1 --- /dev/null +++ b/src/Admin/Components/Components/Inputs/EditItem/EditItem.js @@ -0,0 +1,453 @@ +/*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, useContext, useEffect } from 'react' +//imports material ui componets +import Card from "@material-ui/core/Card" +import CardContent from "@material-ui/core/CardContent" +import CardAction from '@material-ui/core/CardActions' +import { Typography, TextField, Button, Grid } from '@material-ui/core' +import CircularProgress from '@material-ui/core/CircularProgress' +import AddRoundedIcon from '@material-ui/icons/AddRounded' +import ListRoundedIcon from '@material-ui/icons/ListRounded' +import MenuItem from "@material-ui/core/MenuItem" +//imports local files +import SnackBar from '../../../../../Components/SnackbarComponent' +import { Store } from '../../../../../Store' +import Unauthorized from '../../Unauthorized' +import ModalEditPhoto from "./ModalEditPhoto" +import { getRequest, putRequest } from "../../../../../Components/HelperFunctions/getAxiosConfig" +import LoadingSpinner from '../../../../../Components/LoadingSpinner' +import { GetAData } from '../../../../Filters' +//router +import { Link } from 'react-router-dom' + +const EditItem = ({ match }) => { + const { state } = useContext(Store) + + const [name, setName] = useState('Editar Item') + const [description, setDescription] = useState('') + const [price, setPrice] = useState('') + const [discount, setDiscount] = useState('') + const [itemState, setItemState] = useState('') + const [itemType, setItemType] = useState('') + const [achievementID, setAchievementID] = useState('') + const [img, setImg] = useState('') + const [isLoading, setIsLoading] = useState(false) + const [open, setOpen] = useState(false) + const [isLoaded, setIsLoaded] = useState(false) + const [error, setError] = useState(false) + + const [errorInName, setErrorInName] = useState({ + error: false, + message: '', + }) + const [errorInDescription, setErrorInDescription] = useState({ + error: false, + message: '', + }) + const [errorInPrice, setErrorInPrice] = useState({ + error: false, + message: '' + }) + const [errorInObjType, setErrorInObjType] = useState({ + error: false, + message: '' + }) + + const [snackInfo, setSnackInfo] = useState({ + message: '', + icon: '', + open: false, + color: '', + }) + + const stateOptions = [ + { name: "active", value: "Ativo" }, + { name: "inactive", value: "Inativo" }, + { name: "removed", value: "Removido" }, + ] + + const typesOptions = [ + { name: "avatar_frame", value: "Moldura de avatar" }, + { name: "badge", value: "Insígnia" }, + { name: "card_frame", value: "Moldura de card do usuário" }, + { name: "cover_frame", value: "Moldura de capa" }, + ] + + + const NameHandler = (e) => { + if (errorInName.error) { + setErrorInName({ + error: false, + message: '' + }) + } + setName(e.target.value) + } + const DescriptionHandler = (e) => { + if (errorInDescription.error) + setErrorInDescription({ + error: false, + message: '' + }) + setDescription(e.target.value) + } + const priceHandler = (e) => { + if (errorInPrice.error) + setErrorInPrice({ + error: false, + message: '' + }) + setPrice(e.target.value) + } + const itemTypeHandler = (e) => { + if (errorInObjType.error) + setErrorInObjType({ + error: false, + message: '' + }) + setItemType(e.target.value) + } + const discountHandler = (e) => { + setDiscount(e.target.value) + } + const itemStateHandler = (e) => { + console.log(e) + setItemState(e.target.value) + } + const achievementIdHandler = (e) => { + setAchievementID(e.target.value) + } + + // 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 + } + + + //Handle submit + async function onSubmit(image) { + setIsLoading(true) + const api = `/items/${match.params.id}` + let body = {} + if (!image) + body = { + "item": { + "name": name, + "description": description, + "price": parseInt(price), + "discount": parseInt(discount), + "state": itemState, + "item_type": itemType, + "achievement_id": parseInt(achievementID), + } + } + else + body = { + "item": { + "name": name, + "description": description, + "price": parseInt(price), + "discount": parseInt(discount), + "state": itemState, + "item_type": itemType, + "achievement_id": parseInt(achievementID), + "image" : image + } + } + putRequest( + api, + body, + (data) => { + if (data.id) + HandleSnack('O item foi alterado com sucesso!', true, 'success', '#228B22') + else { + if (data.errors) { + HandleSnack(`${data.errors[0]}`, true, 'warning', '#FA8072') + } + if (data.name) { + let nameError = "" + data.name.map((msg) => ( + nameError = nameError + msg + " e " + )) + setErrorInName({ + error: true, + message: nameError + }) + } + if (data.price) { + let priceError = "" + data.price.map((msg) => ( + priceError = priceError + msg + " e " + )) + setErrorInPrice({ + error: true, + message: priceError + }) + } + if (data.description) { + let descriptionError = "" + data.description.map((msg) => ( + descriptionError = descriptionError + msg + " e " + )) + setErrorInDescription({ + error: true, + message: descriptionError + }) + } + if (data.item_type) { + let objTypeError = "" + data.objType.map((msg) => ( + objTypeError = objTypeError + msg + " e " + )) + setErrorInObjType({ + error: true, + message: objTypeError + }) + } + } + setIsLoading(false) + }, + (error) => { + HandleSnack('Ocorreu algum erro', true, 'warning', '#FA8072') + setIsLoading(false) + } + ) + } + + // Fields + const fields = [ + { + select: false, + label: 'Nome', + value: name, + required: true, + error: errorInName.error, + errorMessage: errorInName.message, + onChange: (event) => NameHandler(event) + }, + { + select: false, + label: 'Descrição', + value: description, + required: false, + error: errorInDescription.error, + errorMessage: errorInDescription.message, + onChange: (event) => DescriptionHandler(event) + }, + { + select: false, + label: 'Preço', + value: price, + required: false, + error: errorInPrice.error, + errorMessage: errorInPrice.message, + onChange: (event) => priceHandler(event) + }, + { + select: false, + label: 'Desconto', + value: discount, + required: false, + onChange: (event) => discountHandler(event) + }, + { + select: true, + label: 'Estado', + value: itemState, + options: [...stateOptions], + required: false, + onChange: (event) => itemStateHandler(event) + }, + { + select: true, + label: 'Tipo', + value: itemType, + required: false, + options: [...typesOptions], + error: errorInObjType.error, + errorMessage: errorInObjType.message, + onChange: (event) => itemTypeHandler(event) + }, + { + select: false, + label: 'ID do achievement', + value: achievementID, + required: false, + onChange: (event) => achievementIdHandler(event) + }, + ] + + useEffect(() => { + getRequest( + GetAData("items", match.params.id), + (data, header) => { + setName(data.name) + setDescription(data.description) + setPrice(data.price) + setDiscount(data.discount) + setItemState(data.state) + setItemType(data.item_type) + setAchievementID(data.achievement ? data.achievement.id : "") + setImg(data.image) + setError(false) + setIsLoaded(true) + }, + (error) => { + setIsLoaded(true) + setError(true) + } + ) + }, []) + + if (error) { + return <div> Error... </div> + } else if (!isLoaded) { + return <LoadingSpinner text="Carregando..." /> + } else if (CheckUserPermission()) { + return ( + <Card> + <ModalEditPhoto + open={open} + handleClose={() => { setOpen(false) }} + handleComplete={(img) => { + setOpen(false) + onSubmit(img) + }} + userAvatar={img} + id={state.currentUser.id} + /> + <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' alignContent="center" alignItems="center" xs={12}> + <Grid item> + <Typography variant='h4'> + {name} + </Typography> + </Grid> + <Grid item> + <Link style={{ textDecoration: 'none' }} to={'/admin/gamefication'}> + <Button + // onClick={props.BackToList} + startIcon={<ListRoundedIcon />} + variant='outlined' + color='primary' + > + Listar + </Button> + </Link> + </Grid> + </Grid> + + <div style={{ height: '1em' }}></div> + <form style={{ display: 'flex', flexDirection: 'column' }}> + {fields.map((field, index) => ( + field.select ? + <TextField + select + key={index} + required={field.required} + 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} + > + {field.options.map((option, index) => ( + <MenuItem + key={option.value} + value={option.name} + name={option.value} + > + {option.value} + </MenuItem> + ))} + </TextField> + : + <TextField + key={index} + required={field.required} + 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} + /> + ))} + </form> + </CardContent> + <CardAction> + <Button + onClick={() => { + setOpen(true) + }} + variant="contained" + color="primary" + disabled={isLoading} + startIcon={isLoading ? null : <AddRoundedIcon />} + > + { + isLoading ? <CircularProgress size={24} /> : 'Editar' + } + </Button> + </CardAction> + </Card> + ) + } else return <Unauthorized /> +} + +export default EditItem \ No newline at end of file diff --git a/src/Admin/Components/Components/Inputs/EditItem/ModalEditPhoto.js b/src/Admin/Components/Components/Inputs/EditItem/ModalEditPhoto.js new file mode 100644 index 0000000000000000000000000000000000000000..600e9fa2744473e314dc62be237fe252fd7b993a --- /dev/null +++ b/src/Admin/Components/Components/Inputs/EditItem/ModalEditPhoto.js @@ -0,0 +1,63 @@ +/*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 from 'react'; +import Modal from '@material-ui/core/Modal'; +import Backdrop from '@material-ui/core/Backdrop'; +import Fade from '@material-ui/core/Fade'; +import styled from 'styled-components' +import ComponentAddImage from './CompEditImg' + +const StyledModal = styled(Modal)` + display : flex; + align-items: center; + justify-content : center; + text-align : center; + padding : 10px !important; +` + +export default function ModalAddImage (props){ + + return ( + + <StyledModal + aria-labelledby="transition-modal-title" + aria-describedby="transition-modal-description" + open={props.open} + + centered="true" + onClose={props.handleClose} + closeAfterTransition + BackdropComponent={Backdrop} + BackdropProps={{ + timeout: 500, + }} + > + <Fade in={props.open} style={{ transitionDelay :"0.4ms"}}> + + <ComponentAddImage + userAvatar={props.userAvatar} + handleClose={props.handleClose} + handleComplete={props.handleComplete} + id={props.id} + /> + </Fade> + </StyledModal> + + ) +} diff --git a/src/Admin/Pages/Pages/SubPages/Gamefication.js b/src/Admin/Pages/Pages/SubPages/Gamefication.js index 7bb91150eb28f31adb45d2d95da821f7bbd693fd..e006a743ccf5025340d9f82f35f6a0d2017ec1f7 100644 --- a/src/Admin/Pages/Pages/SubPages/Gamefication.js +++ b/src/Admin/Pages/Pages/SubPages/Gamefication.js @@ -32,6 +32,8 @@ import LoadingSpinner from "../../../../Components/LoadingSpinner"; import PageHeader from "../../../Components/Components/PageHeader"; import SnackBar from "../../../../Components/SnackbarComponent"; import TableData from "../../../Components/Components/Table"; +import TextField from "@material-ui/core/TextField"; +import MenuItem from "@material-ui/core/MenuItem"; import TableBody from "@material-ui/core/TableBody"; import TableCell from "@material-ui/core/TableCell"; import TableRow from "@material-ui/core/TableRow"; @@ -49,604 +51,746 @@ import AlertDialog from "../../../Components/Components/AlertDialog" const StyledTableCell = withStyles((theme) => ({ - head: { - backgroundColor: theme.palette.common.black, - color: theme.palette.common.white, - }, - body: { - fontSize: 14, - }, + head: { + backgroundColor: theme.palette.common.black, + color: theme.palette.common.white, + }, + body: { + fontSize: 14, + }, }))(TableCell); const StyledTableRow = withStyles((theme) => ({ - root: { - "&:nth-of-type(odd)": { - backgroundColor: theme.palette.action.hover, - }, + root: { + "&:nth-of-type(odd)": { + backgroundColor: theme.palette.action.hover, }, + }, }))(TableRow); const Gamefication = () => { - const history = useHistory() - const WINDOW_WIDTH = window.innerWidth - const ADD_ONE_LENGHT = [""]; - const TOP_LABELS = [ - "ESTADO", - "ID", - "NAME", - "TIPO", - "CRIADO EM", - "ATUALIZADO EM", - "AÇÕES", - "VISUALIZAR" - ]; //Labels from Table - const { state } = useContext(Store); - const [currPage, setcurrPage] = useState(0); - const [error, setError] = useState(false); - const [loaded, setLoaded] = useState(true); - const [isLoadingMoreItems, setIsLoadingMoreItems] = useState(false); - const [showFilter, setShowFilter] = useState(false); - const [items, setItems] = useState([]); - const [open, setOpen] = useState(false) - const [deleteItem, setDeleteItem] = useState({}) - const [snackInfo, setSnackInfo] = useState({ - message: "", - icon: "", - open: false, - color: "", + const history = useHistory() + const WINDOW_WIDTH = window.innerWidth + const ADD_ONE_LENGHT = [""]; + const TOP_LABELS = [ + "ESTADO", + "ID", + "NAME", + "TIPO", + "CRIADO EM", + "ATUALIZADO EM", + "AÇÕES", + "VISUALIZAR" + ]; //Labels from Table + const { state } = useContext(Store); + const [currPage, setcurrPage] = useState(0); + const [error, setError] = useState(false); + const [loaded, setLoaded] = useState(true); + const [isLoadingMoreItems, setIsLoadingMoreItems] = useState(false); + const [showFilter, setShowFilter] = useState(false); + const [items, setItems] = useState([]); + const [stateOpt, setStateOpt] = useState(1) + const [typeOpt, setTypeOpt] = useState("") + const [open, setOpen] = useState(false) + const [deleteItem, setDeleteItem] = useState({}) + const [snackInfo, setSnackInfo] = useState({ + message: "", + icon: "", + open: false, + color: "", + }); + + const stateOptions = [ + { name: 0, value: "Inativo" }, + { name: 1, value: "Ativo" }, + { name: 2, value: "Removido" }, + ]; + + const typesOptions = [ + { name: "avatar_frame", value: "Moldura de avatar" }, + { name: "badge", value: "Insígnia" }, + { name: "card_frame", value: "Moldura de card do usuário" }, + { name: "cover_frame", value: "Moldura de capa" }, + + ]; + + //handle snack info + const HandleSnack = (message, state, icon, color) => { + setSnackInfo({ + message: message, + icon: icon, + open: state, + color: color, }); + }; - //handle snack info - 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; - } + const CheckUserPermission = () => { + let canUserEdit = false; - return canUserEdit; - }; - - const DisplayDate = (date) => { - const convertedData = moment.utc(date); - return moment(convertedData) - .format("LLL") - .toString(); - }; - - const FastActions = (item) => { - switch (item.state) { - case "removed": - return ( - <Grid container alignItems="center" justify={WINDOW_WIDTH <= 920 ? "flex-start" : "flex-end"} spacing={1}> - <Grid item> - <Button - color="primary" - variant="contained" - style={{ backgroundColor: "#FF8C00", color: "#FFFAFA", width: "150px" }} - onClick={() => inactiveItem(item)} - > - Inativar - </Button> - </Grid> - <Grid item> - <Button - color="primary" - style={{ backgroundColor: "#228B22", color: "#FFFAFA", width: "150px" }} - variant="contained" - onClick={() => activeItem(item)} - > - Ativar - </Button> - </Grid> - </Grid> - ); - case "inactive": - return ( - <Grid container alignItems="center" justify={WINDOW_WIDTH <= 920 ? "flex-start" : "flex-end"} spacing={1}> - <Grid item> - <Button - color="primary" - variant="contained" - style={{ backgroundColor: "#FA8072", color: "#FFFAFA", width: "150px" }} - onClick={() => handleAlertDialog(item)} - > - Remover + 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 DisplayDate = (date) => { + const convertedData = moment.utc(date); + return moment(convertedData) + .format("LLL") + .toString(); + }; + + const FastActions = (item, index) => { + switch (item.state) { + case "removed": + return ( + <Grid container alignItems="center" justify={WINDOW_WIDTH <= 920 ? "flex-start" : "flex-end"} spacing={1}> + <Grid item> + <Button + color="primary" + variant="contained" + style={{ backgroundColor: "#FF8C00", color: "#FFFAFA", width: "150px" }} + onClick={() => inactiveItem(item, index)} + > + Inativar + </Button> + </Grid> + <Grid item> + <Button + color="primary" + style={{ backgroundColor: "#228B22", color: "#FFFAFA", width: "150px" }} + variant="contained" + onClick={() => activeItem(item, index)} + > + Ativar </Button> - </Grid> - <Grid item> - <Button - color="primary" - style={{ backgroundColor: "#228B22", color: "#FFFAFA", width: "150px" }} - variant="contained" - onClick={() => activeItem(item)} - > - Ativar + </Grid> + </Grid> + ); + case "inactive": + return ( + <Grid container alignItems="center" justify={WINDOW_WIDTH <= 920 ? "flex-start" : "flex-end"} spacing={1}> + <Grid item> + <Button + color="primary" + variant="contained" + style={{ backgroundColor: "#FA8072", color: "#FFFAFA", width: "150px" }} + onClick={() => handleAlertDialog(item)} + > + Remover + </Button> + </Grid> + <Grid item> + <Button + color="primary" + style={{ backgroundColor: "#228B22", color: "#FFFAFA", width: "150px" }} + variant="contained" + onClick={() => activeItem(item, index)} + > + Ativar </Button> - </Grid> - </Grid> - ); - case "active": - return ( - <Grid container alignItems="center" justify={WINDOW_WIDTH <= 920 ? "flex-start" : "flex-end"} spacing={1}> - <Grid item> - <Button - style={{ backgroundColor: "#FA8072", color: "#FFFAFA", width: "150px" }} - variant="contained" - onClick={() => handleAlertDialog(item)} - > - Remover + </Grid> + </Grid> + ); + case "active": + return ( + <Grid container alignItems="center" justify={WINDOW_WIDTH <= 920 ? "flex-start" : "flex-end"} spacing={1}> + <Grid item> + <Button + style={{ backgroundColor: "#FA8072", color: "#FFFAFA", width: "150px" }} + variant="contained" + onClick={() => handleAlertDialog(item)} + > + Remover </Button> - </Grid> - <Grid item> - <Button - style={{ backgroundColor: "#FF8C00", color: "#FFFAFA", width: "150px" }} - variant="contained" - onClick={() => inactiveItem(item)} - > - Inativar + </Grid> + <Grid item> + <Button + style={{ backgroundColor: "#FF8C00", color: "#FFFAFA", width: "150px" }} + variant="contained" + onClick={() => inactiveItem(item, index)} + > + Inativar </Button> - </Grid> - </Grid> - ); - default: - return "NOTHING"; - } - }; - - const StateItem = (state) => { - switch (state) { - case "removed": - return ( - <Paper - style={{ - textAlign: "center", - padding: "0.5em", - backgroundColor: "#FA8072", - fontWeight: "500", - color: "#FFFAFA", - }} - > - REMOVIDO - </Paper> - ); - case "inactive": - return ( - <Paper - style={{ - textAlign: "center", - padding: "0.5em", - backgroundColor: "#FF8C00", - fontWeight: "500", - color: "#FFFAFA", - }} - > - INATIVO - </Paper> - ); - case "active": - return ( - <Paper - style={{ - textAlign: "center", - padding: "0.5em", - backgroundColor: "#228B22", - fontWeight: "500", - color: "#FFFAFA", - }} - > - ATIVO - </Paper> - ); - default: - return "NOTHING"; - } - }; - - const handleAlertDialog = (item) => { - setOpen(true) - setDeleteItem(item) + </Grid> + </Grid> + ); + default: + return "NOTHING"; } + }; - const deleteHandler = () => { - deleteRequest( - DeleteFilter("items", deleteItem.id), - (data) => { - if (data.errors) - HandleSnack("Ocorreu algum erro", true, "warning", "#FA8072"); - else { - HandleSnack( - "O item foi deletada com sucesso", - true, - "success", - "#228B22" - ); - } - setcurrPage(0) - }, - (error) => { - HandleSnack("Ocorreu algum erro", true, "warning", "#FA8072"); - } - ) + const StateItem = (state) => { + switch (state) { + case "removed": + return ( + <Paper + style={{ + textAlign: "center", + padding: "0.5em", + backgroundColor: "#FA8072", + fontWeight: "500", + color: "#FFFAFA", + }} + > + REMOVIDO + </Paper> + ); + case "inactive": + return ( + <Paper + style={{ + textAlign: "center", + padding: "0.5em", + backgroundColor: "#FF8C00", + fontWeight: "500", + color: "#FFFAFA", + }} + > + INATIVO + </Paper> + ); + case "active": + return ( + <Paper + style={{ + textAlign: "center", + padding: "0.5em", + backgroundColor: "#228B22", + fontWeight: "500", + color: "#FFFAFA", + }} + > + ATIVO + </Paper> + ); + default: + return "NOTHING"; } + }; + + const handleAlertDialog = (item) => { + setOpen(true) + setDeleteItem(item) + } + + const findIndexOfWantedItem = (item) => { + const index = items.findIndex((item) => item.id === deleteItem.id) + return index; + } - const inactiveItem = (item) => { - const body = { - "item": { - "state": "inactive" - } + const deleteHandler = () => { + deleteRequest( + DeleteFilter("items", deleteItem.id), + (data) => { + if (data.errors) + HandleSnack("Ocorreu algum erro", true, "warning", "#FA8072"); + else { + HandleSnack( + "O item foi deletada com sucesso", + true, + "success", + "#228B22" + ); + handleChangeStateItem(findIndexOfWantedItem(deleteItem), "removed") } - putRequest( - EditFilter("items", item.id), - body, - (data) => { - if (data.errors) - HandleSnack("Ocorreu algum erro", true, "warning", "#FA8072"); - else { - HandleSnack( - "O item foi inativado com sucesso", - true, - "success", - "#228B22" - ); - } - setcurrPage(0) - }, - (error) => { - HandleSnack("Ocorreu algum erro", true, "warning", "#FA8072"); - } - ) - } + setcurrPage(0) + }, + (error) => { + HandleSnack("Ocorreu algum erro", true, "warning", "#FA8072"); + } + ) + } - const activeItem = (item) => { - const body = { - "item": { - "state": "active" - } + const inactiveItem = (item, index) => { + const body = { + "item": { + "state": "inactive" + } + } + putRequest( + EditFilter("items", item.id), + body, + (data) => { + if (data.errors) + HandleSnack("Ocorreu algum erro", true, "warning", "#FA8072"); + else { + HandleSnack( + "O item foi inativado com sucesso", + true, + "success", + "#228B22" + ); } - putRequest( - EditFilter("items", item.id), - body, - (data) => { - if (data.errors) - HandleSnack("Ocorreu algum erro", true, "warning", "#FA8072"); - else { - HandleSnack( - "O item foi ativado com sucesso", - true, - "success", - "#228B22" - ); - } - setcurrPage(0) - }, - (error) => { - HandleSnack("Ocorreu algum erro", true, "warning", "#FA8072"); - } - ) + handleChangeStateItem(index, "inactive") + }, + (error) => { + HandleSnack("Ocorreu algum erro", true, "warning", "#FA8072"); + } + ) + } + + const activeItem = (item, index) => { + const body = { + "item": { + "state": "active" + } } + putRequest( + EditFilter("items", item.id), + body, + (data) => { + if (data.errors) + HandleSnack("Ocorreu algum erro", true, "warning", "#FA8072"); + else { + HandleSnack( + "O item foi ativado com sucesso", + true, + "success", + "#228B22" + ); + } + handleChangeStateItem(index, "active") + }, + (error) => { + HandleSnack("Ocorreu algum erro", true, "warning", "#FA8072"); + } + ) + } - useEffect(() => { - if (currPage === 0) - setLoaded(false) - else - setIsLoadingMoreItems(true) - getRequest( - Url("items", "", currPage, "DESC"), - (data, header) => { - const arrData = [...data] - if (arrData.length === 0) { - HandleSnack('Não há mais dados para serem carregados', true, 'warning', '#FFC125') - } else { - const arrItems = [...items] - if (currPage === 0) { - setItems(arrData.concat(ADD_ONE_LENGHT)) - setLoaded(true) - } - else { - arrItems.pop(); //Deleting the last position, that was used to display the button of load more items - const arrResult = arrItems.concat(arrData) - setItems(arrResult.concat(ADD_ONE_LENGHT)) - setIsLoadingMoreItems(false) - } - } - }, - (error) => { - HandleSnack('Erro ao carregar os dados', true, 'warning', '#FA8072') - setIsLoadingMoreItems(false) - } - ) - }, [currPage]) + const handleChangeStateItem = (index, state) => { + const currItems = [...items] + currItems[index].state = state + setItems(currItems) + } - if (error) { - return <div>Error</div>; - } else if (!loaded) { - return <LoadingSpinner text="Carregando..." />; - } else { - if (CheckUserPermission()) { - if (WINDOW_WIDTH <= 920) { - return ( - <> - <SnackBar - severity={snackInfo.icon} - text={snackInfo.message} - snackbarOpen={snackInfo.open} - color={snackInfo.color} - handleClose={() => - setSnackInfo({ - message: "", - icon: "", - open: false, - color: "", - }) - } - /> - <MobilePageHeader - title="Itens da gameficação" - actions={[ - { - name: "Atualizar", - isLoading: false, - func: () => { - setcurrPage(0); - }, - icon: <UpdateRoundedIcon />, - }, - { - name: "Filtrar", - isLoading: false, - func: () => { - setShowFilter(!showFilter); - }, - icon: <FilterListRoundedIcon />, - }, - { - name: "Novo", - isLoading: false, - func: () => { - history.push("/admin/createItem") - }, - icon: <AddRoundedIcon />, - }, - ]} + const buildUrl = (objType, state) => { + if (objType && (state >= 0 && state <= 2)) + return Url("/items", `"state" : ${stateOpt}, "item_type" : "${typeOpt}"`, currPage, "DESC") + else if (objType) + return Url("/items", `"item_type" : "${typeOpt}"`, currPage, "DESC") + else if (state >= 0 && state <= 2) + return Url("/items", `"state" : ${stateOpt}`, currPage, "DESC") + else + return Url("/items", "", currPage, "DESC") + } + + useEffect(() => { + if (currPage === 0) + setLoaded(false) + else + setIsLoadingMoreItems(true) + getRequest( + buildUrl(typeOpt, stateOpt), + (data, header) => { + const arrData = [...data] + if (arrData.length === 0) { + HandleSnack('Não há mais dados para serem carregados', true, 'warning', '#FFC125') + } else { + const arrItems = [...items] + if (currPage === 0) { + setItems(arrData.concat(ADD_ONE_LENGHT)) + } + else { + arrItems.pop(); //Deleting the last position, that was used to display the button of load more items + const arrResult = arrItems.concat(arrData) + setItems(arrResult.concat(ADD_ONE_LENGHT)) + } + } + setLoaded(true) + setIsLoadingMoreItems(false) + }, + (error) => { + HandleSnack('Erro ao carregar os dados', true, 'warning', '#FA8072') + setIsLoadingMoreItems(false) + } + ) + }, [currPage, typeOpt, stateOpt]) + + useEffect(() => { + setTypeOpt("") + setStateOpt(1) + }, [showFilter]) + + if (error) { + return <div>Error</div>; + } else if (!loaded) { + return <LoadingSpinner text="Carregando..." />; + } else { + if (CheckUserPermission()) { + if (WINDOW_WIDTH <= 950) { + return ( + <> + <AlertDialog + open={open} + OnDelete={deleteHandler} + deleteItem={deleteItem} + HandleClose={() => { + setOpen(false) + }} + /> + <SnackBar + severity={snackInfo.icon} + text={snackInfo.message} + snackbarOpen={snackInfo.open} + color={snackInfo.color} + handleClose={() => + setSnackInfo({ + message: "", + icon: "", + open: false, + color: "", + }) + } + /> + <MobilePageHeader + title="Itens da gameficação" + actions={[ + { + name: "Atualizar", + isLoading: false, + func: () => { + setcurrPage(0); + }, + icon: <UpdateRoundedIcon />, + }, + { + name: "Filtrar", + isLoading: false, + func: () => { + setShowFilter(!showFilter); + }, + icon: <FilterListRoundedIcon />, + }, + { + name: "Novo", + isLoading: false, + func: () => { + history.push("/admin/createItem") + }, + icon: <AddRoundedIcon />, + }, + ]} + > + {showFilter ? ( + <Grid + container + direction="row" + justify="space-between" + alignItems="center" + alignContent="flex-end" + spacing={3} + xs={12} + > + <Grid item> + <TextField + select + label="Estado" + value={stateOpt} + onChange={(e) => { setStateOpt(e.target.value) }} + helperText="Por favor, selecione uma das opções" + > + {stateOptions.map((option, index) => ( + <MenuItem + key={option.value} + value={option.name} + name={option.value} > - {showFilter ? ( - <> - <div style={{ height: "1em" }}> Filter area</div> - </> - ) : null} - </MobilePageHeader> - <div style={{ height: '2em' }}></div> - - {items.map((row, index) => - index === items.length - 1 ? ( - <StyledDivButton> - <Button - key={index} - color="primary" - variant="text" - // disabled={isLoadingMoreItems} - startIcon={<AddRoundedIcon />} - disabled={isLoadingMoreItems} - onClick={() => { - setcurrPage(currPage + 1) - }} - > - {isLoadingMoreItems ? ( - <CircularProgress size={24} /> - ) : ( - "Carregar mais itens" - )} - </Button> - </StyledDivButton> - ) : ( - <> - <MobileList - key={index} - title={row.name} - subtitle={row.id} - backColor={"#00bcd4"} - avatar={ - <img - src={row.image ? apiDomain + row.image : noAvatar} - alt="user avatar" - style={{ - height: "100%", - width: "100%", - borderRadius: "50%", - }} - /> - } - href={`/admin/item/${row.id}`} - reset={() => { }} - data={[ - - { - title: "Criado em", - subtitle: DisplayDate(row.created_at) - }, - { - title: "Atualizado em", - subtitle: DisplayDate(row.updated_at) - }, - { - title: "Tipo", - subtitle: row.item_type - }, - { - title: "Preço", - subtitle: row.price + " points" - }, - { - title: "Desconto", - subtitle: <Typography style={{ color: "#FA8072" }}> - {"-" + row.discount + " points"} - </Typography> - }, - { - title: "Preço a se pagar", - subtitle: <Typography style={{ color: "#228B22" }}> - {(row.price - row.discount) + " points"} - </Typography> - }, - { - title: "Descrição", - subtitle: row.description - }, - { - title: "Estado", - subtitle: StateItem(row.state) - }, - { - title: "Ações rapidos", - subtitle: FastActions(row) - }, - ]} - /> - <div style={{ height: "0.5em" }} /> - </> - ) - )} - </> - ) - } else { - return ( - <> - <SnackBar - severity={snackInfo.icon} - text={snackInfo.message} - snackbarOpen={snackInfo.open} - color={snackInfo.color} - handleClose={() => - setSnackInfo({ - message: "", - icon: "", - open: false, - color: "", - }) - } - /> - <PageHeader - title="Itens da gameficação" - actions={[ - { - name: "Atualizar", - isLoading: false, - func: () => { - setcurrPage(0); - }, - icon: <UpdateRoundedIcon />, - }, - { - name: "Filtrar", - isLoading: false, - func: () => { - setShowFilter(!showFilter); - }, - icon: <FilterListRoundedIcon />, - }, - { - name: "Novo", - isLoading: false, - func: () => { - history.push("/admin/createItem") - }, - icon: <AddRoundedIcon />, - }, - ]} + {option.value} + </MenuItem> + ))} + </TextField> + </Grid> + <Grid item> + <TextField + select + label="Tipo" + value={typeOpt} + onChange={(e) => { setTypeOpt(e.target.value) }} + helperText="Por favor, selecione uma das opções" + > + {typesOptions.map((option, index) => ( + <MenuItem + key={option.value} + value={option.name} + name={option.value} > - {showFilter ? ( - <> - <div style={{ height: "1em" }}> Filter area</div> - </> - ) : null} - </PageHeader> - - <div style={{ height: "2em" }}></div> - - <TableData top={TOP_LABELS}> - <TableBody> - {items.map((row, index) => - index === items.length - 1 ? ( - <StyledTableRow key={index} style={{ padding: "1em" }}> - {/* Button to load more data */} - <StyledTableCell> - <Button - color="primary" - variant="text" - // disabled={isLoadingMoreItems} - startIcon={<AddRoundedIcon />} - disabled={isLoadingMoreItems} - onClick={() => { - setcurrPage(currPage + 1); - }} - > - {isLoadingMoreItems ? ( - <CircularProgress size={24} /> - ) : ( - "Carregar mais itens" - )} - </Button> - </StyledTableCell> - </StyledTableRow> - ) : ( - <StyledTableRow key={index}> - <StyledTableCell component="th" scope="row"> - {StateItem(row.state)} - </StyledTableCell> - <StyledTableCell align="right">{row.id}</StyledTableCell> - <StyledTableCell align="right">{row.name}</StyledTableCell> - <StyledTableCell align="right"> - {row.item_type} - </StyledTableCell> - <StyledTableCell align="right"> - {DisplayDate(row.created_at)} - </StyledTableCell> - <StyledTableCell align="right"> - {DisplayDate(row.updated_at)} - </StyledTableCell> - <StyledTableCell align="right"> - {FastActions(row)} - </StyledTableCell> - <StyledTableCell align="right"> - <Link to={`/admin/item/${row.id}`}> - <IconButton> - <VisibilityIcon style={{ fill: "#00bcd4" }} /> - </IconButton> - </Link> - </StyledTableCell> - </StyledTableRow> - ) - )} - </TableBody> - </TableData> - <AlertDialog - open={open} - OnDelete={deleteHandler} - deleteItem={deleteItem} - HandleClose={() => { - setOpen(false) - }} + {option.value} + </MenuItem> + ))} + </TextField> + </Grid> + </Grid> + ) : null} + </MobilePageHeader> + <div style={{ height: '2em' }}></div> + + {items.map((row, index) => + index === items.length - 1 ? ( + <StyledDivButton> + <Button + key={index} + color="primary" + variant="text" + // disabled={isLoadingMoreItems} + startIcon={<AddRoundedIcon />} + disabled={isLoadingMoreItems} + onClick={() => { + setcurrPage(currPage + 1) + }} + > + {isLoadingMoreItems ? ( + <CircularProgress size={24} /> + ) : ( + "Carregar mais itens" + )} + </Button> + </StyledDivButton> + ) : ( + <> + <MobileList + key={index} + title={row.name} + subtitle={row.id} + backColor={"#00bcd4"} + avatar={ + <img + src={row.image ? apiDomain + row.image : noAvatar} + alt="user avatar" + style={{ + height: "100%", + width: "100%", + borderRadius: "50%", + }} /> - </> - ); - } - } else return <Unauthorized />; - } + } + href={`/admin/item/${row.id}`} + reset={() => { }} + data={[ + + { + title: "Criado em", + subtitle: DisplayDate(row.created_at) + }, + { + title: "Atualizado em", + subtitle: DisplayDate(row.updated_at) + }, + { + title: "Tipo", + subtitle: row.item_type + }, + { + title: "Preço", + subtitle: row.price + " points" + }, + { + title: "Desconto", + subtitle: <Typography style={{ color: "#FA8072" }}> + {"-" + row.discount + " points"} + </Typography> + }, + { + title: "Preço a se pagar", + subtitle: <Typography style={{ color: "#228B22" }}> + {(row.price - row.discount) + " points"} + </Typography> + }, + { + title: "Descrição", + subtitle: row.description + }, + { + title: "Estado", + subtitle: StateItem(row.state) + }, + { + title: "Ações rapidos", + subtitle: FastActions(row, index) + }, + ]} + /> + <div style={{ height: "0.5em" }} /> + </> + ) + )} + </> + ) + } else { + return ( + <> + <SnackBar + severity={snackInfo.icon} + text={snackInfo.message} + snackbarOpen={snackInfo.open} + color={snackInfo.color} + handleClose={() => + setSnackInfo({ + message: "", + icon: "", + open: false, + color: "", + }) + } + /> + <PageHeader + title="Itens da gameficação" + actions={[ + { + name: "Atualizar", + isLoading: false, + func: () => { + setcurrPage(0); + }, + icon: <UpdateRoundedIcon />, + }, + { + name: "Filtrar", + isLoading: false, + func: () => { + setShowFilter(!showFilter); + }, + icon: <FilterListRoundedIcon />, + }, + { + name: "Novo", + isLoading: false, + func: () => { + history.push("/admin/createItem") + }, + icon: <AddRoundedIcon />, + }, + ]} + > + {showFilter ? ( + <Grid + container + direction="row" + justify="space-between" + alignItems="center" + alignContent="flex-end" + spacing={3} + xs={12} + > + <Grid item> + <TextField + select + label="Estado" + value={stateOpt} + onChange={(e) => { setStateOpt(e.target.value) }} + helperText="Por favor, selecione uma das opções" + > + {stateOptions.map((option, index) => ( + <MenuItem + key={option.value} + value={option.name} + name={option.value} + > + {option.value} + </MenuItem> + ))} + </TextField> + </Grid> + <Grid item> + <TextField + select + label="Tipo" + value={typeOpt} + onChange={(e) => { setTypeOpt(e.target.value) }} + helperText="Por favor, selecione uma das opções" + > + {typesOptions.map((option, index) => ( + <MenuItem + key={option.value} + value={option.name} + name={option.value} + > + {option.value} + </MenuItem> + ))} + </TextField> + </Grid> + </Grid> + ) : null} + </PageHeader> + + <div style={{ height: "2em" }}></div> + + <TableData top={TOP_LABELS}> + <TableBody> + {items.map((row, index) => + index === items.length - 1 ? ( + <StyledTableRow key={index} style={{ padding: "1em" }}> + {/* Button to load more data */} + <StyledTableCell> + <Button + color="primary" + variant="text" + // disabled={isLoadingMoreItems} + startIcon={<AddRoundedIcon />} + disabled={isLoadingMoreItems} + onClick={() => { + setcurrPage(currPage + 1); + }} + > + {isLoadingMoreItems ? ( + <CircularProgress size={24} /> + ) : ( + "Carregar mais itens" + )} + </Button> + </StyledTableCell> + </StyledTableRow> + ) : ( + <StyledTableRow key={index}> + <StyledTableCell component="th" scope="row"> + {StateItem(row.state)} + </StyledTableCell> + <StyledTableCell align="right">{row.id}</StyledTableCell> + <StyledTableCell align="right">{row.name}</StyledTableCell> + <StyledTableCell align="right"> + {row.item_type} + </StyledTableCell> + <StyledTableCell align="right"> + {DisplayDate(row.created_at)} + </StyledTableCell> + <StyledTableCell align="right"> + {DisplayDate(row.updated_at)} + </StyledTableCell> + <StyledTableCell align="right"> + {FastActions(row, index)} + </StyledTableCell> + <StyledTableCell align="right"> + <Link to={`/admin/item/${row.id}`}> + <IconButton> + <VisibilityIcon style={{ fill: "#00bcd4" }} /> + </IconButton> + </Link> + </StyledTableCell> + </StyledTableRow> + ) + )} + </TableBody> + </TableData> + <AlertDialog + open={open} + OnDelete={deleteHandler} + deleteItem={deleteItem} + HandleClose={() => { + setOpen(false) + }} + /> + </> + ); + } + } else return <Unauthorized />; + } }; export default Gamefication;