diff --git a/src/Components/ModalAvaliarRecurso.js b/src/Components/ModalAvaliarRecurso.js index 61ce422482cfbebdefbfc5d71784136c32b99a6d..f4a00c2891a1fa7499cd9de8cf19b0334166babb 100644 --- a/src/Components/ModalAvaliarRecurso.js +++ b/src/Components/ModalAvaliarRecurso.js @@ -16,7 +16,7 @@ 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, {useRef} from 'react'; +import React, {useState} from 'react'; import { Button } from '@material-ui/core'; import Modal from '@material-ui/core/Modal'; import Backdrop from '@material-ui/core/Backdrop'; @@ -31,30 +31,87 @@ import Radio from '@material-ui/core/Radio'; import FormControl from '@material-ui/core/FormControl'; import FormControlLabel from '@material-ui/core/FormControlLabel'; import CloseModalButton from './CloseModalButton' +import Snackbar from '@material-ui/core/Snackbar'; +import Alert from '../Components/Alert.js'; +import TextField from '@material-ui/core/TextField'; +import { withStyles } from '@material-ui/core/styles'; + +const StyledRadio = withStyles({ + root: { + color: '#666', + '&$checked': { + color: '#ff7f00', + }, + }, + checked: {}, +})((props) => <Radio color="default" {...props} />); export default function ModalAvaliarRecurso (props) { const options = [ { - text : "O recurso apresenta conteúdo de cunho polÃtico-partidário? (Ex: o conteúdo expressa qualquer forma de manifestação que se caracterize como propaganda polÃtica)?", value : "", id : 1 + text : "O recurso apresenta conteúdo de cunho polÃtico-partidário? (Ex: o conteúdo expressa qualquer forma de manifestação que se caracterize como propaganda polÃtica)?", id : 1 }, { - text : "O recurso apresenta conteúdo ofensivo? (Ex: material pornográfico e/ou que invada a privacidade de terceiros, viole os Direitos Humanos ou seja ilegal, ofensivo, e que incite a violência)?", value : "", id : 2 + text : "O recurso apresenta conteúdo ofensivo? (Ex: material pornográfico e/ou que invada a privacidade de terceiros, viole os Direitos Humanos ou seja ilegal, ofensivo, e que incite a violência)?", id : 2 }, { - text : "O recurso apresenta algum tipo de propaganda ou marca? (Ex: o conteúdo tem cunho comercial)?", value : "", id : 3 + text : "O recurso apresenta algum tipo de propaganda ou marca? (Ex: o conteúdo tem cunho comercial)?", id : 3 }, { - text : "Outro motivo para rejeição (falta de descrição, autor, objeto, erros)? Indicar na justificativa se for o caso?", value : "", id : 4 + text : "Outro motivo para rejeição (falta de descrição, autor, objeto, erros)? Indicar na justificativa se for o caso?", id : 4 } ] + const [avaliacao, setAvaliacao] = useState([null,null,null,null]) + const handleRadios = (event, id) => { - console.log(event.target.value) - console.log(id) + let newValue = avaliacao + newValue[id - 1] = (event.target.value === "Sim" ? true : false) + setAvaliacao(newValue) + + if(avaliacao.indexOf(null) === -1) { + toggleDisableButton(false) + } + } + + const [justificativa, setJustificativa] = useState("") + const handleChangeJustificativa = (e) => { + setJustificativa(e.target.value) + } + + const [snackbarCancelar, toggleSnackbarCancelar] = useState(false) + const handleSnackbarCancelar = (value) => toggleSnackbarCancelar(value) + + const handleCancel = () => { + handleSnackbarCancelar(true) + + props.handleClose() + } + + const [buttonDisabled, toggleDisableButton] = useState(true) + + const handleAvaliar = () => { + let criteria = options + avaliacao.map((criterium, index) => + criteria[index]['accepted'] = !criterium + ) + props.confirm(criteria, justificativa) + returnToDefault() + } + + const returnToDefault = () => { + setAvaliacao([null,null,null,null]) + setJustificativa('') + toggleDisableButton(true) } return ( + <> + <Snackbar open={snackbarCancelar} autoHideDuration={1000} onClose={toggleSnackbarCancelar} + anchorOrigin = {{ vertical:'top', horizontal:'right' }} + message="Você cancelou a avaliação deste recurso." + /> <StyledModal aria-labelledby="transition-modal-title" aria-describedby="transition-modal-description" @@ -71,7 +128,7 @@ export default function ModalAvaliarRecurso (props) { <Container> <Header> <h2>Você está avaliando o recurso - <span style={{fontWeight : "bolder"}}>{props.title}</span> + <span style={{fontWeight : "bolder"}}> {props.title}</span> </h2> <CloseModalButton handleClose={props.handleClose}/> </Header> @@ -79,21 +136,23 @@ export default function ModalAvaliarRecurso (props) { <Content> <Grid container> <Grid item xs={12}> - <p>Esse recurso está em conformidade com os critérios? Marque as opções e justifique aquela(s)que não estiverem em conformidade.</p> + <p>Esse recurso está em conformidade com os critérios? Marque as opções e justifique aquela(s) que não estiverem em conformidade.</p> </Grid> <FormControl component="fieldset" style={{display:"BlockRuby"}} fullWidth={true}> { options.map( (option) => - <Grid item xs={12} key={option.id}> + <Grid item xs={12} key={option.id} style={{paddingTop : "10px"}}> <Grid container> <Grid item xs={10}> - <p>{option.text}</p> + <div style={{height : "100%", display : "flex", alignItems : "center"}}> + <p>{option.text}</p> + </div> </Grid> <Grid item xs={2}> <RadioGroup row onChange={(e) => {handleRadios(e, option.id)}}> - <FormControlLabel value={true} control={<Radio color="primary"/>} label="Sim"/> - <FormControlLabel value={false} control={<Radio color="primary"/>} label="Não"/> + <FormControlLabel value={"Sim"} control={<StyledRadio/>} label="Sim"/> + <FormControlLabel value={"Não"} control={<StyledRadio/>} label="Não"/> </RadioGroup> </Grid> </Grid> @@ -101,31 +160,37 @@ export default function ModalAvaliarRecurso (props) { ) } </FormControl> + + <Grid item xs={12}> + <FormControl style={{width : "100%", height : "100px"}}> + <StyledTextField + id = {"title-form"} + label={"Justificativa (opcional)"} + type = {"text"} + value = {justificativa} + onChange = {e => {handleChangeJustificativa(e)}} + multiline + fullWidth + /> + </FormControl> </Grid> + + <Grid item xs={12}> + <ButtonsDiv> + <ButtonEnviarAvaliar disabled={buttonDisabled} onClick={() => {handleAvaliar()}}>ENVIAR AVALIAÇÂO</ButtonEnviarAvaliar> + <GreyButton onClick={ () => {handleCancel()}}>CANCELAR</GreyButton> + </ButtonsDiv> + </Grid> + </Grid> </Content> </Container> </Fade> </StyledModal> + </> ) } -const ShareButton = styled(Button)` - text-align :center; - margin : 0 !important; - - .MuiButton-label { - display : flex !important; - flex-direction : column !important; - justify-content : center !important; - font-weight : 700 !important; - } - - p { - margin : 0 0 10px; - } -` - const Content = styled.div` padding : 10px 75px 0 75px; overflow : visible; @@ -148,15 +213,22 @@ const Content = styled.div` const Header = styled.div` display : flex; flex-direction : row; - padding : 10px 75px 0 75px; + padding : 20px 75px 0 75px; align-items : center; justify-content : space-between; - height : 64px; + color : #666; + + @media screen and (min-width : 990px) { + height : 64px; + } + @media screen and (max-width : 989px) { + max-height : none; + } h2 { font-size : 26px; font-weight : lighter; - color : #666 + } ` @@ -194,12 +266,10 @@ const Container = styled.div` max-height : none; position : relative; border-radius : 4px; - - @media screen and (min-width : 700px) { - max-width : 100%; - } + max-width : 100%; @media screen and (max-width : 699px) { + overflow : scroll; width : 100%; height : 100%; } @@ -208,3 +278,68 @@ const Container = styled.div` margin : 0 0 10px; } ` +const StyledTextField = styled(TextField)` + font-size : 14px; + width : 100% !important; + full-width : 100% !important; + + .MuiFormControl-root { + margin : 18px 0 !important; + } + + label.Mui-focused { + color : #ff7f00; + } + + label.Mui-focused.Mui-error { + color : red; + } + + .MuiInput-underline::after { + border-bottom: 2px solid #ff7f00; + } +` + +const ButtonsDiv = styled.div` + display : flex; + max-width : 100%; + text-align : start; + align-items : center; + padding : 0 0 20px 0; + + @media screen and (min-width : 990px) { + flex-direction : row; + } + @media screen and (max-width : 989px) { + flex-direction : column; + } +` +const GreyButton = styled(Button)` + &:hover { + background-color : rgba(158,158,158,0.2) !important; + } + max-height : 36px !important; + + background-color : transparent !important; + color : #666 !important; + text-decoration : none !important; + outline : none !important; + text-align : center !important; + font-weight : 600 !important; + + +` + +const ButtonEnviarAvaliar = styled(Button)` + color : ${(props) => props.disabled ? "rgba(0,0,0,0.38)" : "rgba(255,255,255,0.87) !important"}; + box-shadow : ${(props) => props.disabled ? "none !important" : "0 2px 5px 0 rgba(0,0,0,.26) !important"}; + font-weight : 600 !important; + background-color : ${(props) => props.disabled ? "#e9e9e9 !important" : "#ff7f00 !important"}; + margin-left : 8px !important; + margin-right : 8px !important; + + .MuiButton-label { + padding-left : 32px !important; + padding-right : 32px !important; + } +` diff --git a/src/Components/ModalConfirmarCuradoria.js b/src/Components/ModalConfirmarCuradoria.js new file mode 100644 index 0000000000000000000000000000000000000000..9e12906b13c7e0a0457819160a1dd358515c7b24 --- /dev/null +++ b/src/Components/ModalConfirmarCuradoria.js @@ -0,0 +1,260 @@ +/*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 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 {Store} from '../Store.js' +import axios from 'axios' +import {apiDomain, apiUrl} from '../env'; +import Grid from '@material-ui/core/Grid'; +import RadioGroup from '@material-ui/core/RadioGroup'; +import Radio from '@material-ui/core/Radio'; +import FormControl from '@material-ui/core/FormControl'; +import FormControlLabel from '@material-ui/core/FormControlLabel'; +import CloseModalButton from './CloseModalButton' +import {getAxiosConfig} from './HelperFunctions/getAxiosConfig' + +export default function ModalConfirmarCuradoriaOpen (props) { + + const handleCancel = () => { + props.handleClose() + props.cancel() + } + + const transformReportCriteria = (criteria) => { + let newArr = [] + criteria.map((criterium) => + newArr.push({"question_id" : criterium.id, "accepted" : criterium.accepted}) + ) + return newArr + } + + const handleConfirmation = () => { + let config = getAxiosConfig() + + let payload = { + "submission" : { + "justification" : props.justificativa, + "answers" : transformReportCriteria(props.reportCriteria) + } + } + + axios.post( (`${apiUrl}/submissions/` + props.recursoId + '/answer'), payload, config).then( + (response) => { + if ( response.headers['access-token'] ) { + sessionStorage.setItem('@portalmec/accessToken', response.headers['access-token']) + } + console.log(response.data) + props.finalizeCuratorshipFlow() + }, (error) => {console.log(error)} + ) + } + + 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}> + <Container recusado={!props.aceito}> + <Header> + <span style={{width:"32px"}}/> + <h2>Recurso a ser {props.aceito ? 'aprovado' : 'recusado'}</h2> + <CloseModalButton handleClose={props.handleClose}/> + </Header> + <Content> + { + props.aceito ? + ( + <p>Este recurso será publicado na plataforma. Você confirma essa avaliação? + </p> + ) + : + ( + <> + <p>Agradecemos a sua contribuição. Você avaliou que o recurso não está em conformidade com o(s) seguinte(s) critério(s): + </p> + { + props.reportCriteria.filter((criterium) => criterium.accepted === false).map( (criterium) => + <p key={criterium.id} className="reason-offensive">{criterium.text}</p> + ) + } + <p>Você confirma essa avaliação? Ao confirmar, o recurso não será publicado na plataforma.</p> + </> + ) + } + <ButtonsDiv> + { + props.aceito ? + ( + <ButtonEnviarAvaliar onClick={() => {handleConfirmation()}}>SIM, CONFIRMAR</ButtonEnviarAvaliar> + ) + : + ( + <ButtonEnviarAvaliar onClick={() => {handleConfirmation()}}>SIM, CONFIRMAR</ButtonEnviarAvaliar> + ) + } + <GreyButton onClick={handleCancel}>NÃO, ALTERAR AVALIAÇÃO</GreyButton> + </ButtonsDiv> + </Content> + </Container> + </Fade> + </StyledModal> + ) +} + + +const Content = styled.div` + padding : 30px; + overflow : visible; + max-width : 100%; + color : #666; + font-size : 16px; + text-align : start; + .reason-offensive { + font-weight : 700; + } + + p { + margin : 0 0 10px; + } +` + +const Header = styled.div` + display : flex; + flex-direction : row; + align-items : center; + max-height : none; + justify-content : space-between; + color : #666; + + h2 { + font-size : 30px; + margin-top : 20px; + margin-bottom : 10px; + font-weight : lighter; + } +` + +const StyledCloseModalButton = styled(Button)` + display : inline-block; + position : relative; + float : right !important; + margin-right : 4px !important; + background : transparent !important; + min-width: 0 !important; + width : 40px; +` + +const StyledModal = styled(Modal)` + .djXaxP{ + margin : 0 !important; + } + display : flex; + align-items: center; + justify-content : center; + text-align : center; + padding : 10px !important; + max-width : none; + max-height : none; +` + +const Container = styled.div` + box-sizing : border-box; + box-shadow : 0 7px 8px -4px rgba(0,0,0,.2),0 13px 19px 2px rgba(0,0,0,.14),0 5px 24px 4px rgba(0,0,0,.12); + background-color : #fff; + align : center; + display : flex; + flex-direction : column; + min-width : 240px; + position : relative; + border-radius : 4px; + max-width : 100%; + max-height : ${props => props.recusado ? 'none' : '370px'}; + + @media screen and (max-width : 699px) { + overflow : ${props => props.recusado ? 'scroll' : 'visible'}; + width : 100%; + height : 100%; + } + + p { + margin : 0 0 10px; + } +` +const ButtonsDiv = styled.div` + display : flex; + max-width : 100%; + text-align : center; + align-items : center; + justify-content : center; + padding-top : 20px; + + @media screen and (min-width : 990px) { + flex-direction : row; + } + @media screen and (max-width : 989px) { + flex-direction : column; + } +` +const GreyButton = styled(Button)` + &:hover { + background-color : rgba(158,158,158,0.2) !important; + } + max-height : 36px !important; + + background-color : transparent !important; + color : #666 !important; + text-decoration : none !important; + outline : none !important; + text-align : center !important; + font-weight : 600 !important; + .MuiButton-label { + padding-left : 16px !important; + padding-right : 16px !important; + } + @media screen and (max-width : 989px) { + margin-top : 10px !important; + } +` + +const ButtonEnviarAvaliar = styled(Button)` + color : rgba(255,255,255,0.87) !important; + box-shadow : 0 2px 5px 0 rgba(0,0,0,.26) !important; + font-weight : 600 !important; + background-color : #ff7f00 !important; + margin-left : 8px !important; + margin-right : 8px !important; + + .MuiButton-label { + padding-left : 16px !important; + padding-right : 16px !important; + } +` diff --git a/src/Pages/ResourcePage.js b/src/Pages/ResourcePage.js index 1b11710df4a3c715c460b0badda424444e88d6be..c20305b2403b86cad49d0c12139491ac67e0cfbb 100644 --- a/src/Pages/ResourcePage.js +++ b/src/Pages/ResourcePage.js @@ -35,6 +35,8 @@ import { makeStyles } from '@material-ui/core/styles'; import AppBar from '@material-ui/core/AppBar'; import ButtonAvaliarRecurso from '../Components/ButtonAvaliarRecurso' import ModalAvaliarRecurso from '../Components/ModalAvaliarRecurso' +import ModalConfirmarCuradoria from '../Components/ModalConfirmarCuradoria' +import {getAxiosConfig} from '../Components/HelperFunctions/getAxiosConfig' function urlVerify (url) { return (url ? url.indexOf("youtu") !== -1 || url.indexOf("vimeo") !== -1 : false) @@ -67,7 +69,7 @@ export default function LearningObjectPage (props){ console.log(response) setRecurso(response.data) toggle(false) - }, (error) => {console.log(error); toggle(false)}) + }, (error) => {console.log(error);}) }, [, state.currentUser]) @@ -86,7 +88,6 @@ export default function LearningObjectPage (props){ const handleModalCuradoria = (value) => {toggleModalCuradoria(value)} const checkAccessLevel = (levelToCheck) => { - console.log(state.currentUser) if (state.currentUser.id != '') { return(checkUserRole(levelToCheck)) } @@ -99,6 +100,33 @@ export default function LearningObjectPage (props){ return(state.currentUser.roles.filter((role) => role.name === userRole).length > 0) } + const [modalConfirmarCuradoriaOpen, toggleModalConfirmarCuradoria] = useState(false) + const handleModalConfirmarCuradoria = (value) => {toggleModalConfirmarCuradoria(value)} + const [reportCriteria, setReportCriteria] = useState([]) + const [justificativa, setJustificativa] = useState('') + + const handleConfirm = (criteria, justification) => { + console.log('criteria: ', criteria) + console.log('justification: ', justification) + setReportCriteria(criteria) + setJustificativa(justification) + handleModalCuradoria(false) + handleModalConfirmarCuradoria(true) + } + + const finalizeCuratorshipFlow = () => { + handleModalConfirmarCuradoria(false) + let config = getAxiosConfig() + axios.get( (`${apiUrl}/learning_objects/` + id), config + ).then( (response) => { + if ( response.headers['access-token'] ) { + sessionStorage.setItem('@portalmec/accessToken', response.headers['access-token']) + } + console.log(response) + setRecurso(response.data) + }, (error) => {console.log(error);}) + } + return ( <React.Fragment> <Snackbar open={snackbarOpen} autoHideDuration={1000} onClose={toggleSnackbar} @@ -110,7 +138,11 @@ export default function LearningObjectPage (props){ </Snackbar> <ModalAvaliarRecurso open={modalCuradoriaOpen} handleClose={() => {handleModalCuradoria(false)}} - title={recurso.name}/> + title={recurso.name} confirm={handleConfirm} setCriteria={setReportCriteria} + /> + <ModalConfirmarCuradoria aceito={reportCriteria.length === 0} reportCriteria={reportCriteria} justificativa={justificativa} open={modalConfirmarCuradoriaOpen} handleClose={() => {handleModalConfirmarCuradoria(false)}} cancel={() => {handleModalCuradoria(true)}} recursoId={id} + finalizeCuratorshipFlow={finalizeCuratorshipFlow} + /> <Background> { carregando ? @@ -211,18 +243,20 @@ export default function LearningObjectPage (props){ </Card> </Grid> - - <Grid item xs={12}> - <Card> - {/*adicionar funcionalidade ao botao de entrar*/} - <CommentsArea - recursoId = {id} - handleSnackbar={handleSnackbar} - objType={recurso.object_type} - recurso={true} - /> - </Card> - </Grid> + { + recurso.state !== "submitted" && + <Grid item xs={12}> + <Card> + {/*adicionar funcionalidade ao botao de entrar*/} + <CommentsArea + recursoId = {id} + handleSnackbar={handleSnackbar} + objType={recurso.object_type} + recurso={true} + /> + </Card> + </Grid> + } </Grid> {