diff --git a/src/Admin/Services.js b/src/Admin/Services.js deleted file mode 100644 index bce02eb72a414c7f04cbbdb8e0acbec383ca2fd6..0000000000000000000000000000000000000000 --- a/src/Admin/Services.js +++ /dev/null @@ -1,241 +0,0 @@ -/*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 axios from 'axios'; - -export function Delete(api) { - return new Promise(resolve => { - axios({ - method: 'delete', - url: api, - headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json; charset=utf-8', - 'access-token': sessionStorage.getItem('@portalmec/accessToken'), - 'client': sessionStorage.getItem('@portalmec/clientToken'), - 'uid': sessionStorage.getItem('@portalmec/uid'), - 'If-None-Match': null - }, - }).then(response => { - if (response.status === 200) { - resolve(true); - } else { - resolve(false); - } - SaveNewHeaders(response) - }).catch(err =>{ - resolve(false) - }) - }) -} - -export function SendEmail(api, body) { - return new Promise(resolve => { - axios({ - method: 'post', - url: api, - headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json; charset=utf-8', - 'access-token': sessionStorage.getItem('@portalmec/accessToken'), - 'client': sessionStorage.getItem('@portalmec/clientToken'), - 'uid': sessionStorage.getItem('@portalmec/uid'), - 'If-None-Match': null - }, - data: JSON.stringify(body) - }).then(response => { - console.log(response) - if (response.status === 200) { - resolve(true); - } else { - resolve(false); - } - SaveNewHeaders(response) - }).catch(err =>{ - resolve(false) - }) - }) -} - -export function Edit(api, body) { - return new Promise(resolve => { - axios({ - method: 'put', - url: api, - headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json; charset=utf-8', - 'access-token': sessionStorage.getItem('@portalmec/accessToken'), - 'client': sessionStorage.getItem('@portalmec/clientToken'), - 'uid': sessionStorage.getItem('@portalmec/uid'), - 'If-None-Match': null - }, - data: JSON.stringify(body) - }).then(response => { - console.log(response) - if (response.status === 200) { - resolve(true) - } else { - resolve(false) - } - SaveNewHeaders(response) - }).catch(err =>{ - resolve(false) - }) - }) -} - -export function Create(api, body) { - return new Promise(resolve => { - axios({ - method: 'post', - url: api, - headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json; charset=utf-8', - 'access-token': sessionStorage.getItem('@portalmec/accessToken'), - 'client': sessionStorage.getItem('@portalmec/clientToken'), - 'uid': sessionStorage.getItem('@portalmec/uid'), - 'If-None-Match': null - }, - data: JSON.stringify(body) - }).then(response => { - if (response.status === 201) { - resolve(true) - } else { - resolve(false) - } - SaveNewHeaders(response) - }).catch(err =>{ - resolve(false) - }) - }) -} - -export function HandleComplain(api) { - return new Promise(resolve => { - axios({ - method: 'post', - url: api, - headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json; charset=utf-8', - 'access-token': sessionStorage.getItem('@portalmec/accessToken'), - 'client': sessionStorage.getItem('@portalmec/clientToken'), - 'uid': sessionStorage.getItem('@portalmec/uid'), - 'If-None-Match': null - }, - }).then(response => { - if (response.status === 200) { - resolve(true) - } else { - resolve(false) - } - SaveNewHeaders(response) - }).catch(err =>{ - resolve(false) - }) - }) -} - -export function GetFullList(api, headers) { - - return new Promise(resolve => { - axios({ - method: 'get', - url: api, - headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json; charset=utf-8', - 'access-token': sessionStorage.getItem('@portalmec/accessToken'), - 'client': sessionStorage.getItem('@portalmec/clientToken'), - 'uid': sessionStorage.getItem('@portalmec/uid'), - 'If-None-Match': null - }, - }).then((res) => { - console.log(res) - if (res.status === 200) { - resolve({ - state: true, - data: res.data - }) - } else { - resolve({ - state: false, - data: {} - }) - } - SaveNewHeaders(res) - }).catch((err) => { - resolve({ - state: false, - data: {} - }) - }) - }, []); -} - -export function GetSpecificData(api, headers) { - return new Promise(resolve => { - axios({ - method: 'get', - url: api, - headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json; charset=utf-8', - 'access-token': sessionStorage.getItem('@portalmec/accessToken'), - 'client': sessionStorage.getItem('@portalmec/clientToken'), - 'uid': sessionStorage.getItem('@portalmec/uid'), - 'If-None-Match': null - }, - }).then((res) => { - console.log(res) - if (res.status === 200) { - resolve({ - state: true, - data: res.data - }) - } else { - resolve({ - state: false, - data: {} - }) - } - SaveNewHeaders(res) - }).catch((err) => { - resolve({ - state: false, - data: {} - }) - }) - }, []); -} - -const SaveNewHeaders = (response) => { - if ( - (response.headers['access-token'] === undefined || response.headers['access-token'] === null) && - (response.headers.client === undefined || response.headers.client === null) - ) { - - } else { - sessionStorage.setItem('@portalmec/accessToken', response.headers['access-token']) - sessionStorage.setItem('@portalmec/clientToken', response.headers.client) - console.log('saved') - } -} - diff --git a/src/Components/ColCardPublicOptions.js b/src/Components/ColCardPublicOptions.js index 6e374d7a159e18c51bc06a44038c0aa859c796d6..2b58c70f58000d4014fb53330c8901a65cbfc1b3 100644 --- a/src/Components/ColCardPublicOptions.js +++ b/src/Components/ColCardPublicOptions.js @@ -25,13 +25,14 @@ import OpenIcon from '@material-ui/icons/OpenInNew'; import { Link } from 'react-router-dom' import MoreVertIcon from '@material-ui/icons/MoreVert'; import styled from 'styled-components' -import ErrorIcon from '@material-ui/icons/Error'; +import FavoriteIcon from '@material-ui/icons/Favorite'; import ReportModal from './ReportModal.js' import ReportProblemIcon from '@material-ui/icons/ReportProblem'; import OpenInBrowserIcon from '@material-ui/icons/OpenInBrowser'; -import { deleteRequest } from '../Components/HelperFunctions/getAxiosConfig' +import AddIcon from '@material-ui/icons/Add'; +import ExitToAppIcon from '@material-ui/icons/ExitToApp'; -export default function ColCardPublicOptions(props) { +export default function ColCardPublicOptions({ id, userFollowingCol, handleLike, handleFollow, currentUserId, handleLogin, liked }) { const [anchorEl, setAnchorEl] = React.useState(null); function handleClick(event) { @@ -45,20 +46,13 @@ export default function ColCardPublicOptions(props) { const [reportModalOpen, toggleReportModal] = useState(false) const handleReportModal = (value) => { toggleReportModal(value) } - const handleUnfollow = () => { - if (props.currentUserId) - deleteRequest(`/collections/${props.id}/follow`, (data) => { console.log(data) }, (error) => { console.log(error) }) - else - props.handleLogin() - } - return ( <> <ReportModal open={reportModalOpen} handleClose={() => handleReportModal(false)} form="colecao" - complainableId={props.id} + complainableId={id} complainableType={"Collection"} /> <div style={{ fontSize: "12px" }}> @@ -78,7 +72,7 @@ export default function ColCardPublicOptions(props) { onClose={handleClose} > <StyledMenuItem> - <Link to={"/colecao-do-usuario/" + props.id}> + <Link to={"/colecao-do-usuario/" + id}> <ListItemIcon> <OpenIcon /> </ListItemIcon> @@ -88,7 +82,7 @@ export default function ColCardPublicOptions(props) { <StyledMenuItem onClick={() => - window.open("/colecao-do-usuario/" + props.id, "_blank") + window.open("/colecao-do-usuario/" + id, "_blank") } > <ListItemIcon> @@ -97,19 +91,38 @@ export default function ColCardPublicOptions(props) { Abrir em nova guia </StyledMenuItem> - <StyledMenuItem onClick={handleUnfollow}> + <StyledMenuItem onClick={handleLike}> + <ListItemIcon> + { + liked ? + <FavoriteIcon style={{ fill: 'red' }} /> : <FavoriteIcon style={{ fill: '#666' }} /> + } + </ListItemIcon> + { + liked ? + "Desfavoritar" : "Favoritar" + } + </StyledMenuItem> + + <StyledMenuItem onClick={handleFollow}> <ListItemIcon> - <ErrorIcon /> + { + userFollowingCol ? + <ExitToAppIcon /> : <AddIcon /> + } </ListItemIcon> - Deixar de Seguir + { + userFollowingCol ? + "Deixar de seguir" : "Seguir" + } </StyledMenuItem> <StyledMenuItem onClick={() => { - if (props.currentUserId) + if (currentUserId) handleReportModal(true); else - props.handleLogin() + handleLogin() }} > <ListItemIcon> diff --git a/src/Components/CollectionCardFunction.js b/src/Components/CollectionCardFunction.js index e09765dade75c3a4244236832b41c92bfb03ce93..ccfb87838cec4850aa89f3a550ad23dfe2f8223b 100644 --- a/src/Components/CollectionCardFunction.js +++ b/src/Components/CollectionCardFunction.js @@ -45,7 +45,7 @@ export default function CollectionCardFunction(props) { // eslint-disable-next-line const [userAvatar] = useState(props.avatar ? (`${apiDomain}` + props.avatar) : noAvatar) - const [userFollowingCol, toggleUserFollowingCol] = useState(props.followed ? props.followed : false) + const [userFollowingCol, toggleUserFollowingCol] = useState(props.followed) const handleToggleUserFollowingCol = () => { toggleUserFollowingCol(!userFollowingCol) } const [name, setName] = useState(props.name) @@ -297,7 +297,10 @@ export default function CollectionCardFunction(props) { } <ColCardPublicOptions id={props.id} - following={userFollowingCol} + userFollowingCol={userFollowingCol} + handleLike={handleLike} + handleFollow={handleFollow} + liked={liked} handleLogin={handleLogin} currentUserId={state.currentUser.id} /> diff --git a/src/Components/CollectionCommentSection.js b/src/Components/CollectionCommentSection.js index ccc7f079dae76494734addd6116bdaf6a331ae5d..24d4da5ca2c1450154c8a1ea2ae8f30aafd95933 100644 --- a/src/Components/CollectionCommentSection.js +++ b/src/Components/CollectionCommentSection.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, useState, useEffect } from 'react'; +import React, { useRef, useState, useEffect, Fragment } from 'react'; import { Grid } from '@material-ui/core'; import Card from '@material-ui/core/Card'; import Button from '@material-ui/core/Button'; @@ -27,12 +27,27 @@ import Comment from './Comment.js'; import Snackbar from '@material-ui/core/Snackbar'; import MuiAlert from '@material-ui/lab/Alert'; import Comentario from '../img/comentarios.png'; -import {getRequest} from '../Components/HelperFunctions/getAxiosConfig' +import { getRequest } from '../Components/HelperFunctions/getAxiosConfig' +import ExitToAppIcon from '@material-ui/icons/ExitToApp'; +import SignUpModal from './SignUpModal.js'; +import LoginModal from './LoginModal.js'; +import SnackBarComponent from './SnackbarComponent'; +import CircularProgress from '@material-ui/core/CircularProgress'; export default function CollectionCommentSection(props) { + const [post_snack_open, setPostSnackOpen] = useState(false); const [delete_snack_open, setDeleteSnackOpen] = useState(false); const [render_state, setRenderState] = useState(false); + const [sign_up_open, setSignUpOpen] = useState(false); + const [log_in_open, setLoginOpen] = useState(false); + const [is_loading, setIsLoading] = useState(false); + const [snackInfo, setSnackInfo] = useState({ + open: false, + text: '', + severity: '', + color: '' + }); const [reviews, setReviews] = useState([]); const comment_ref = useRef(null); @@ -50,30 +65,60 @@ export default function CollectionCommentSection(props) { window.scrollTo(0, comment_ref.current.offsetTop); } + function handleOpenSnackSignIn() { + const info = { + open: true, + text: 'Você foi logado com sucesso!', + severity: 'success', + color: '', + } + + handleSnackInfo(info) + } + + function handleSnackInfo(info) { + setSnackInfo({ + ...info + }) + } + + function handleCloseSnack() { + setSnackInfo({ + open: false, + text: '', + severity: '', + color: '', + }) + } + + function handleOpenSignUp() { + setSignUpOpen(true) + } + function Alert(props) { return <MuiAlert elevation={6} variant="filled" {...props} />; } const NoCommentsMessage = () => { - const NoCommentsContainer=styled.div` + const NoCommentsContainer = styled.div` text-align: center; margin-left: 9vw; margin-right: 9vw; ` - const BlueTitle=styled.h2` + const BlueTitle = styled.h2` color: #673ab7; ` - const Secondary=styled.h3` + const Secondary = styled.h3` font-weight: 100; ` - const ButtonText=styled.span` + const ButtonText = styled.span` font-weight: 900; ` - const Image=styled.img` + const Image = styled.img` ` return ( <NoCommentsContainer> - <Image src={Comentario} style={{width:"100%", maxWidth:234}}/> + <Image src={Comentario} style={{ width: "100%", maxWidth: 234 }} /> <BlueTitle>Compartilhe sua opinião com a rede!</BlueTitle> <Secondary>Gostou desta coleção? Comente e compartilhe com a rede sua opinião. Interagindo com a rede, você contribui para que mais coleções como esta sejam criadas.</Secondary> <Button @@ -94,6 +139,7 @@ export default function CollectionCommentSection(props) { {reviews.map(r => { return ( <Comment + isCollection={false} rerenderCallback={forceUpdate} objectID={props.id} reviewID={r.id} @@ -105,62 +151,136 @@ export default function CollectionCommentSection(props) { description={r.description} createdAt={r.created_at} handleSnackbar={handleDeleteSnackbar} + handlePost={handlePostSnackbar} recurso={false} /> - );})} + ); + })} </div> ); } useEffect(() => { - getRequest(`/collections/${props.id}/reviews`, (data) => {setReviews(data)}, (error) => {console.log(error)}) + setIsLoading(true) + getRequest(`/collections/${props.id}/reviews`, (data) => { setReviews(data); setIsLoading(false) }, (error) => { console.log(error); setIsLoading(false) }) }, [render_state]); return ( <CommentAreaContainer container xs={12} direction="row" justify="center" alignItems="center"> + <SnackBarComponent + snackbarOpen={snackInfo.open} + handleClose={handleCloseSnack} + severity={snackInfo.severity} + text={snackInfo.text} + color={snackInfo.color} + /> + <SignUpModal + open={sign_up_open} + handleClose={() => setSignUpOpen(false)} + openLogin={() => setLoginOpen(true)} + /> + <LoginModal + openSnackbar={handleOpenSnackSignIn} + open={log_in_open} + handleClose={() => setLoginOpen(false)} + openSignUp={handleOpenSignUp} + /> <Grid item xs={12} ref={comment_ref}> <CommentAreaCard> - <Title>Conte sua experiência com a coleção</Title> - <CommentForm colecao recursoId={props.id} - handleSnackbar={handlePostSnackbar} - rerenderCallback={forceUpdate} - /> - {reviews.length ? CollectionComments() : NoCommentsMessage()} + { + props.currentUserId ? + <Fragment> + <Title>Conte sua experiência com a coleção</Title> + <CommentForm + colecao + recursoId={props.id} + handleSnackbar={handlePostSnackbar} + rerenderCallback={forceUpdate} + /> + </Fragment> + : + <Grid item xs={12}> + <LogInToComment> + <span className="span-purple">Você precisa entrar para comentar</span> + <Button onClick={() => setSignUpOpen(true)} style={{ textTransform: "uppercase", color: "#666", fontWeight: "700" }}> + <ExitToAppIcon />ENTRAR + </Button> + </LogInToComment> + </Grid> + } + { + is_loading ? + <LoadingDiv> + <CircularProgress className="loading" /> + </LoadingDiv> + : + reviews.length ? CollectionComments() : NoCommentsMessage() + } </CommentAreaCard> </Grid> <Snackbar open={post_snack_open} autoHideDuration={6000} onClose={handlePostSnackbar} - anchorOrigin={{vertical: 'top', horizontal: 'right'}} + anchorOrigin={{ vertical: 'top', horizontal: 'right' }} > - <Alert onClose={handlePostSnackbar} severity="info"> + <Alert onClose={handlePostSnackbar} severity="info"> Seu comentário foi publicado com sucesso! </Alert> - </Snackbar> + </Snackbar> <Snackbar open={delete_snack_open} autoHideDuration={6000} onClose={handleDeleteSnackbar} - anchorOrigin={{vertical: 'top', horizontal: 'right'}} + anchorOrigin={{ vertical: 'top', horizontal: 'right' }} > - <Alert onClose={handleDeleteSnackbar} severity="info"> + <Alert onClose={handleDeleteSnackbar} severity="info"> Comentário deletado com sucesso. </Alert> - </Snackbar> + </Snackbar> </CommentAreaContainer> ); } +const LoadingDiv = styled.div` + margin: 1em; + display: flex; + justify-content: center; + align-items: center; + .loading{ + color: #673ab7; + size: 24px; + } +` + +const LogInToComment = styled.div` + display : flex; + flex-direction : column; + text-align : center; + padding : 20px; + align-items : center; + + .span-purple { + font-size : 24px; + font-weight : 700; + padding-bottom : 5px; + color : #673ab7; + } + + img { + object-fit : contain !important; + background-color : transparent !important; + } +` -const CommentAreaContainer=styled(Grid)` +const CommentAreaContainer = styled(Grid)` margin-left: 10%; margin-right: 10%; ` -const CommentAreaCard=styled(Card)` +const CommentAreaCard = styled(Card)` padding: 45px; ` -const Title=styled.h1` +const Title = styled.h1` font-weight: 100; color: #666; ` diff --git a/src/Components/CollectionDescription.js b/src/Components/CollectionDescription.js index aa35cb0df4909fa3205678aa145bc1e02f2802ad..60de747f5bb7c17d9dff5d1a9acb2f69d8c95808 100644 --- a/src/Components/CollectionDescription.js +++ b/src/Components/CollectionDescription.js @@ -30,35 +30,40 @@ export default function CollectionDescription(props) { useEffect(() => { const body = { "package": { - "object": [{"type": "Collection", "id": props.collection_id}] - }}; + "object": [{ "type": "Collection", "id": props.collection_id }] + } + }; axios - .post(apiUrl+'/package', body) + .post(apiUrl + '/package', body) .catch(err => { if (err.response && err.response.status === 302) { - setDownloadUrl(apiDomain+'/'+err.response.data.url); + setDownloadUrl(apiDomain + '/' + err.response.data.url); } - });}, [props.collection_id]); + }); + }, [props.collection_id]); return ( <Grid container direction="column" justify="center" alignItems="center" spacing={5}> - <Grid - item + <Grid + item justify="center" alignItems="center" > <Title>{props.title}</Title> </Grid> - <Grid + <Grid item - direction="row" - justify="center" + direction="row" + justify="center" alignItems="center" > <Grid item> - <CollectionReview + <CollectionReview + stars={props.stars} + liked={props.liked} + likes={props.likes} scrollToComment={props.scrollToComments} - id={props.collection_id}/> + id={props.collection_id} /> </Grid> {/* <Grid item container sm={8} direction="column" justify="center" alignItems="flex-end" @@ -85,7 +90,7 @@ export default function CollectionDescription(props) { ); } -const Title=styled.h1` +const Title = styled.h1` font-size: 2.5em; color: rgb(102, 102, 102); text-align: center diff --git a/src/Components/CollectionReview.js b/src/Components/CollectionReview.js index c9dc801016a770dd65acd4378c9db395b6c4d945..0d94757b2dbd235e2b3b9ef2b8077707b8a9a357 100644 --- a/src/Components/CollectionReview.js +++ b/src/Components/CollectionReview.js @@ -27,31 +27,30 @@ import { Store } from '../Store.js' import ReportModal from './ReportModal.js'; import SignUpModal from './SignUpModal.js'; import LoginModal from './LoginModal.js'; -import { putRequest, getRequest } from './HelperFunctions/getAxiosConfig.js' +import { putRequest } from './HelperFunctions/getAxiosConfig.js' +import SnackBarComponent from './SnackbarComponent'; export default function CollectionReview(props) { - const [likes, setLikes] = useState(0); - const [liked, setLiked] = useState(false); - const [stars, setStars] = useState(0); + const { state } = useContext(Store); + + const [likes, setLikes] = useState(); + const [liked, setLiked] = useState(); + const [stars, setStars] = useState(); const [reportOpen, setReportOpen] = useState(false); const [sign_up_open, setSignUpOpen] = useState(false); const [log_in_open, setLoginOpen] = useState(false); - const { state } = useContext(Store); - - function handleSuccessfulGet(data) { - setLikes(Number(data.likes_count)); - setLiked(data.liked); - } - - useEffect(() => { - const url = `/collections/${props.id}` - - getRequest(url, handleSuccessfulGet, (error) => { console.log(error) }) - - }, [props.id, state.currentUser.id]); + const [snackInfo, setSnackInfo] = useState({ + open: false, + text: '', + severity: '', + color: '' + }); const handleClickReport = () => { - setReportOpen(true); + if (state.currentUser.id) + setReportOpen(true); + else + setSignUpOpen(true) } function handleSuccess(data) { @@ -67,24 +66,62 @@ export default function CollectionReview(props) { setSignUpOpen(true); } - const handleSetStars = (value) => { - setStars(value); - props.scrollToComment(); - } - const handleCloseModal = () => { setReportOpen(false); } + function handleOpenSnackSignIn() { + const info = { + open: true, + text: 'Você foi logado com sucesso!', + severity: 'success', + color: '', + } + + handleSnackInfo(info) + } + + function handleSnackInfo(info) { + setSnackInfo({ + ...info + }) + } + + function handleCloseSnack() { + setSnackInfo({ + open: false, + text: '', + severity: '', + color: '', + }) + } + + function handleOpenSignUp() { + setSignUpOpen(true) + } + + useEffect(() => { + setLiked(props.liked) + setLikes(props.likes) + setStars(props.stars) + }, [props]) + return ( <Grid container direction="column"> + <SnackBarComponent + snackbarOpen={snackInfo.open} + handleClose={handleCloseSnack} + severity={snackInfo.severity} + text={snackInfo.text} + color={snackInfo.color} + /> <Grid sm={12} container direction="row" alignItems="center"> <Grid item> <Rating name="customized-empty" - value={stars} - onChange={(e, value) => handleSetStars(value)} - precision={0.5} + value={Number(stars)} + readOnly + onClick={props.scrollToComment} style={{ color: "#666" }} emptyIcon={<StarBorderIcon fontSize="inherit" />} /> @@ -116,8 +153,10 @@ export default function CollectionReview(props) { openLogin={() => setLoginOpen(true)} /> <LoginModal + openSnackbar={handleOpenSnackSignIn} open={log_in_open} handleClose={() => setLoginOpen(false)} + openSignUp={handleOpenSignUp} /> </Grid> ); diff --git a/src/Components/Comment.js b/src/Components/Comment.js index 09b66d5ad2f83e4ad3f10994de899960ca4f1b49..2a77cb0cee1f6e44c0d4d5ba92e7c382ae1cb37c 100644 --- a/src/Components/Comment.js +++ b/src/Components/Comment.js @@ -16,13 +16,13 @@ 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} from 'react' -import {Store} from '../Store.js' +import React, { useState, useContext } from 'react' +import { Store } from '../Store.js' import styled from 'styled-components' import Grid from '@material-ui/core/Grid'; import { Button } from '@material-ui/core'; -import {Link} from 'react-router-dom' -import {apiDomain} from '../env'; +import { Link } from 'react-router-dom' +import { apiDomain } from '../env'; import noAvatar from "../img/default_profile.png"; import Rating from '@material-ui/lab/Rating'; import StarBorderIcon from '@material-ui/icons/StarBorder'; @@ -31,9 +31,9 @@ import TextField from "@material-ui/core/TextField"; import Menu from '@material-ui/core/Menu'; import MenuItem from '@material-ui/core/MenuItem'; import ModalExcluir from './ModalExcluirComentario.js' -import {putRequest, deleteRequest} from './HelperFunctions/getAxiosConfig' +import { putRequest, deleteRequest } from './HelperFunctions/getAxiosConfig' -export default function Comment (props) { +export default function Comment(props) { /* Required props: @@ -52,7 +52,7 @@ export default function Comment (props) { */ var moment = require('moment') - const {state} = useContext(Store) + const { state } = useContext(Store) const [displayedComment, setDisplayedComment] = useState(props.description) const [editando, setEditando] = useState(false) const [anchorEl, setAnchorEl] = React.useState(null); @@ -65,47 +65,57 @@ export default function Comment (props) { const [modalOpen, toggleModal] = useState(false) const [comment, setComment] = useState({ - error : false, - value : props.description + error: false, + value: props.description }) const handleChange = (e) => { const userInput = e.target.value const flag = (userInput.length === 0 ? true : false); - setComment({...comment, error : flag, value : userInput}) + setComment({ ...comment, error: flag, value: userInput }) } - function handleOnSuccessfulComment (data) { + function handleOnSuccessfulComment(data) { setDisplayedComment(comment.value) setEditando(false) - props.handleSnackbar(2) + props.handlePost() } const updateComment = () => { const finalComment = comment + let url; + + if (props.isCollection) + url = `/collections/${props.objectID}/reviews/${props.reviewID}` + else + url = `/learning_objects/${props.objectID}/reviews/${props.reviewID}` + if (!finalComment.error) { let payload = { - "review" : { - "name":null, - "description":finalComment.value, - "pros":null, - "cons":null, - "review_ratings_attributes" : props.reviewRatings + "review": { + "description": finalComment.value, + "review_ratings_attributes": props.reviewRatings } } - putRequest(`/learning_objects/${props.objectID}/reviews/`, payload, handleOnSuccessfulComment, (error) => {console.log(error)}) + putRequest(url, payload, handleOnSuccessfulComment, (error) => { console.log(error) }) } } - function handleSuccessDeleteComment (data) { + function handleSuccessDeleteComment(data) { props.rerenderCallback() - props.handleSnackbar(3) + props.handleSnackbar() } const deleteComment = () => { + let url; - deleteRequest(`/learning_objects/${props.objectID}/reviews/${props.reviewID}`, handleSuccessDeleteComment, (error) => {console.log(error)}) + if (props.isCollection) + url = `/collections/${props.objectID}/reviews/${props.reviewID}` + else + url = `/learning_objects/${props.objectID}/reviews/${props.reviewID}` + + deleteRequest(url, handleSuccessDeleteComment, (error) => { console.log(error) }) toggleModal(false) @@ -113,113 +123,112 @@ export default function Comment (props) { return ( <React.Fragment> - <ModalExcluir - open={modalOpen} handleClose={() => {toggleModal(false)}} - handleConfirm={deleteComment} + <ModalExcluir + open={modalOpen} handleClose={() => { toggleModal(false) }} + handleConfirm={deleteComment} /> - <Grid container style={{paddingLeft : "20px"}}> - - <Grid item xs={1}> - { - props.authorID && - <AvatarDiv> - <Link to={'/usuario-publico/' + props.authorID}> - <img src={props.authorAvatar ? apiDomain + props.authorAvatar : noAvatar} alt="author avatar"/> - </Link> - </AvatarDiv> - } - </Grid> - - <Grid item xs={10}> - <Comentario> - <div className="star-rating-container"> - <Rating - name="read-only" - value={props.rating} - readOnly - size="small" - style={{color:"#666"}} - emptyIcon={<StarBorderIcon fontSize="inherit" style={{color : "#a5a5a5"}} />} - /> - </div> + <Grid container style={{ paddingLeft: "20px" }}> + <Grid item xs={1}> { - props.name && - <strong>{props.name}</strong> + props.authorID && + <AvatarDiv> + <Link to={'/usuario-publico/' + props.authorID}> + <img src={props.authorAvatar ? apiDomain + props.authorAvatar : noAvatar} alt="author avatar" /> + </Link> + </AvatarDiv> } + </Grid> + <Grid item xs={10}> + <Comentario> + <div className="star-rating-container"> + <Rating + name="read-only" + value={props.rating} + readOnly + size="small" + style={{ color: "#666" }} + emptyIcon={<StarBorderIcon fontSize="inherit" style={{ color: "#a5a5a5" }} />} + /> + </div> - <div> { - editando ? - ( - <React.Fragment> - <div style={{marginTop : "5%", padding : "2px"}}> - <StyledTextField - colecao={!props.recurso} - id = "input-comentario" - label = {"Editar Comentário"} - margin = "normal" - value = {comment.value} - multiline={true} - rows="5" - onChange = {(e) => {handleChange(e)}} - style={{width:"100%"}} - /> - </div> - <div style={{float : "right"}}> - <StyledButton - style={props.recurso ? {backgroundColor : "#ff7f00"} : {backgroundColor : "#673ab7"}} - onClick={() => {setEditando(false)}} - > - Fechar - </StyledButton> - <StyledButton - style={props.recurso ? {backgroundColor : "#ff7f00"} : {backgroundColor : "#673ab7"}} - onClick={() => updateComment()} - > - Salvar + props.name && + <strong>{props.name}</strong> + } + + <div> + { + editando ? + ( + <React.Fragment> + <div style={{ marginTop: "5%", padding: "2px" }}> + <StyledTextField + colecao={!props.recurso} + id="input-comentario" + label={"Editar Comentário"} + margin="normal" + value={comment.value} + multiline={true} + rows="5" + onChange={(e) => { handleChange(e) }} + style={{ width: "100%" }} + /> + </div> + <div style={{ float: "right" }}> + <StyledButton + style={props.recurso ? { backgroundColor: "#ff7f00" } : { backgroundColor: "#673ab7" }} + onClick={() => { setEditando(false) }} + > + Fechar </StyledButton> - </div> - </React.Fragment> - ) - : - ( - <React.Fragment> - <p> - { - props.authorID && - <Link - to={'/usuario-publico/' + props.authorID} - style={{ - fontWeight : "bolder", - color : props.recurso ? "#ff7f00" : "#673ab7" - }} + <StyledButton + style={props.recurso ? { backgroundColor: "#ff7f00" } : { backgroundColor: "#673ab7" }} + onClick={() => updateComment()} > - {props.authorName} - </Link> - } + Salvar + </StyledButton> + </div> + </React.Fragment> + ) + : + ( + <React.Fragment> + <p> + { + props.authorID && + <Link + to={'/usuario-publico/' + props.authorID} + style={{ + fontWeight: "bolder", + color: props.recurso ? "#ff7f00" : "#673ab7" + }} + > + {props.authorName} + </Link> + } : {displayedComment} - </p> - { - props.authorID !== state.currentUser.id && - <span className="date"> - {moment(props.createdAt).format("DD/MM/YYYY")} - </span> - } - </React.Fragment> - ) - } - </div> - - </Comentario> - </Grid> + </p> + { + props.authorID !== state.currentUser.id && + <span className="date"> + {moment(props.createdAt).format("DD/MM/YYYY")} + </span> + } + </React.Fragment> + ) + } + </div> + + </Comentario> + </Grid> - { - props.authorID === state.currentUser.id && - <Grid item xs={1}> - <StyledDiv> - <Button onClick={handleClick}><EditIcon/></Button> + { + props.authorID === state.currentUser.id && + <Grid item xs={1}> + <StyledDiv> + <Button onClick={handleClick}><EditIcon /></Button> <Menu id="simple-menu" anchorEl={anchorEl} @@ -227,13 +236,13 @@ export default function Comment (props) { open={Boolean(anchorEl)} onClose={handleClose} > - <MenuItem onClick={() => {setEditando(true); handleClose()}}>Editar</MenuItem> - <MenuItem onClick={() => {toggleModal(true);handleClose()}}>Excluir</MenuItem> + <MenuItem onClick={() => { setEditando(true); handleClose() }}>Editar</MenuItem> + <MenuItem onClick={() => { toggleModal(true); handleClose() }}>Excluir</MenuItem> </Menu> - </StyledDiv> - </Grid> - } - </Grid> + </StyledDiv> + </Grid> + } + </Grid> </React.Fragment> ) } diff --git a/src/Components/FollowCollectionButton.js b/src/Components/FollowCollectionButton.js index 974a56fd3492cf7440b46679794fb061ea237e7a..e89f8901c0e586124c99df453dc70ac627027f63 100644 --- a/src/Components/FollowCollectionButton.js +++ b/src/Components/FollowCollectionButton.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, { useState, useEffect, useContext } from 'react'; +import React, { useState, useEffect } from 'react'; import Button from '@material-ui/core/Button'; import CheckIcon from '@material-ui/icons/Check'; import AddIcon from '@material-ui/icons/Add'; @@ -24,13 +24,12 @@ import styled from 'styled-components'; import SignUpModal from './SignUpModal.js'; import LoginModal from './LoginModal'; import SnackBarComponent from './SnackbarComponent'; -import { getRequest, putRequest } from './HelperFunctions/getAxiosConfig' -import { Store } from '../Store' +import { putRequest } from './HelperFunctions/getAxiosConfig' export default function FollowCollectionButton(props) { - const { state } = useContext(Store) + const [icon, setIcon] = useState(<AddIcon fontSize="large" />); - const [button_text, setButtonText] = useState("Seguir Coleção"); + const [button_text, setButtonText] = useState("Seguir coleção"); const [variant, setVariant] = useState("outlined"); const [sign_up_open, setSignUpOpen] = useState(false); const [open_login, setOpenLogin] = useState(false); @@ -42,51 +41,20 @@ export default function FollowCollectionButton(props) { }); const [following, setFollowing] = useState(false); //user following collection - function handleSuccessGet(data) { - if (!data.errors) - data.map((e) => { - if (e["followable"]["id"] === Number(props.collection_id)) { - setVariant("contained"); - setButtonText("Seguindo"); - setIcon(<CheckIcon fontSize="large" />) - setFollowing(true); - } - return undefined - }) - else { - const info = { - open: true, - text: 'Falha ao verificar se o usuário segue a coleção!', - severity: 'error', - color: 'red' - } - - handleSnackInfo(info) - } - } useEffect(() => { - if (state.currentUser.id) { - const url = `/users/${props.user_id}/following/Collection` - getRequest( - url, - handleSuccessGet, - (error) => { - const info = { - open: true, - text: 'Falha ao verificar se o usuário segue a coleção!', - severity: 'error', - color: 'red' - } - handleSnackInfo(info) - }) + if (props.followed) { + setFollowing(true) + setButtonText("Seguindo") + setVariant("contained") + setIcon(<CheckIcon fontSize="large" />); } else { - setIcon(<AddIcon fontSize="large" />) - setButtonText("Seguir Coleção") - setVariant("outlined") setFollowing(false) + setButtonText("Seguir coleção") + setVariant("outlined") + setIcon(<AddIcon fontSize="large" />); } - }, [state.currentUser.id]); + }, [props]) //handleMouse{Enter, Leave} only do anything when user follows given collection: const handleMouseEnter = () => { diff --git a/src/Components/Header.js b/src/Components/Header.js index 57cc42f248418e141996fa0023bb6793938441a2..54e02feaa381434678d74c13bb418de8fa126924 100644 --- a/src/Components/Header.js +++ b/src/Components/Header.js @@ -54,7 +54,7 @@ export default function Header(props) { } useEffect(() => { - if (sessionStorage.getItem('@portalmec/auth_headers')) { + if (localStorage.getItem('@portalmec/auth_headers')) { const url = `/auth/validate_token/` getRequest(url, handleSuccessValidateToken, (error) => { console.log(error) }) } diff --git a/src/Components/HelperFunctions/getAxiosConfig.js b/src/Components/HelperFunctions/getAxiosConfig.js index 6d1608bc91648d8b83374f9c4949a9ada3401cdd..8ced7d5be70b3d08d7b2cb3f7864f801b8c2d484 100644 --- a/src/Components/HelperFunctions/getAxiosConfig.js +++ b/src/Components/HelperFunctions/getAxiosConfig.js @@ -2,16 +2,18 @@ import {apiUrl} from '../../env.js' export function getAxiosConfigFromJSON () { let config = { - headers : JSON.parse(sessionStorage.getItem('@portalmec/auth_headers')) + headers : JSON.parse(localStorage.getItem('@portalmec/auth_headers')) } return config } export function updateHeaders (newHeaders) { - sessionStorage.setItem('@portalmec/accessToken', newHeaders['access-token']) + let newToken = getNewAccessToken(newHeaders['access-token']) - let auth_headers = JSON.parse(sessionStorage.getItem('@portalmec/auth_headers')) + localStorage.setItem('@portalmec/accessToken', newToken) + + let auth_headers = JSON.parse(localStorage.getItem('@portalmec/auth_headers')) /*const auth_headers = { client: newHeaders.get('client'), "access-token": newHeaders.get('access-token'), @@ -20,7 +22,7 @@ export function updateHeaders (newHeaders) { "token-type": "Bearer" } - sessionStorage.setItem('@portalmec/auth_headers', JSON.stringify(auth_headers))*/ + localStorage.setItem('@portalmec/auth_headers', JSON.stringify(auth_headers))*/ if (auth_headers) { auth_headers['access-token'] = newHeaders['access-token'] } @@ -33,11 +35,11 @@ export function updateHeaders (newHeaders) { "token-type": "Bearer" } } - sessionStorage.setItem('@portalmec/auth_headers', JSON.stringify(auth_headers)) + localStorage.setItem('@portalmec/auth_headers', JSON.stringify(auth_headers)) } function fetchHeaders () { - let auth_headers = JSON.parse(sessionStorage.getItem('@portalmec/auth_headers')) + let auth_headers = JSON.parse(localStorage.getItem('@portalmec/auth_headers')) var myHeaders = undefined if (auth_headers) { @@ -58,12 +60,12 @@ function fetchHeaders () { function checkPreviousTokens (new_token) { - let prev_tokens = JSON.parse(sessionStorage.getItem('@portalmec/tokens')) + let prev_tokens = JSON.parse(localStorage.getItem('@portalmec/tokens')) if (prev_tokens) { if (!prev_tokens.hasOwnProperty(new_token)) { prev_tokens[new_token] = 1 - sessionStorage.setItem('@portalmec/tokens', JSON.stringify(prev_tokens)) + localStorage.setItem('@portalmec/tokens', JSON.stringify(prev_tokens)) return true } else { @@ -73,25 +75,36 @@ function checkPreviousTokens (new_token) { else { let tokens = {} tokens[new_token] = 1 - sessionStorage.setItem('@portalmec/tokens', JSON.stringify(tokens)) + localStorage.setItem('@portalmec/tokens', JSON.stringify(tokens)) return true } } +function getNewAccessToken (newAccessToken) { + if (!newAccessToken || newAccessToken.trim().length === 0) { + return localStorage.getItem('@portalmec/accessToken') + } + else { + return newAccessToken + } +} + + function updateAccessToken (newAccessToken) { + let newToken = getNewAccessToken(newAccessToken) - if (checkPreviousTokens(newAccessToken)) { + if (checkPreviousTokens(newToken)) { - sessionStorage.setItem('@portalmec/accessToken', newAccessToken) + localStorage.setItem('@portalmec/accessToken', newToken) - let auth_headers = JSON.parse(sessionStorage.getItem('@portalmec/auth_headers')) + let auth_headers = JSON.parse(localStorage.getItem('@portalmec/auth_headers')) if (auth_headers) { - auth_headers['access-token'] = newAccessToken + auth_headers['access-token'] = newToken } - sessionStorage.setItem('@portalmec/auth_headers', JSON.stringify(auth_headers)) + localStorage.setItem('@portalmec/auth_headers', JSON.stringify(auth_headers)) } } @@ -263,7 +276,8 @@ export const validateGoogleLoginToken = (url, config, onSuccess, onError) => { "token-type": "Bearer" } - sessionStorage.setItem('@portalmec/auth_headers', JSON.stringify(auth_headers)) + localStorage.setItem('@portalmec/auth_headers', JSON.stringify(auth_headers)) + localStorage.setItem('@portalmec/accessToken', auth_headers["access-token"]) return response.json().catch(err => { return {}; @@ -297,7 +311,8 @@ export async function authentication (url, payload, onSuccess, onError) { "token-type": "Bearer" } - sessionStorage.setItem('@portalmec/auth_headers', JSON.stringify(auth_headers)) + localStorage.setItem('@portalmec/auth_headers', JSON.stringify(auth_headers)) + localStorage.setItem('@portalmec/accessToken', auth_headers["access-token"]) let json = await response.json().catch(err => { return {}; @@ -317,7 +332,7 @@ export async function authentication (url, payload, onSuccess, onError) { // "token-type": "Bearer" // } // - // sessionStorage.setItem('@portalmec/auth_headers', JSON.stringify(auth_headers)) + // localStorage.setItem('@portalmec/auth_headers', JSON.stringify(auth_headers)) // // return response.json().catch(err => { // return {}; diff --git a/src/Components/ResourcePageComponents/CommentsArea.js b/src/Components/ResourcePageComponents/CommentsArea.js index 946ce4d4fc3e276b95e673a742b58a973f6fe065..37db3024dfaf7c41c6d0f54976d9e74bef267cca 100644 --- a/src/Components/ResourcePageComponents/CommentsArea.js +++ b/src/Components/ResourcePageComponents/CommentsArea.js @@ -16,34 +16,36 @@ 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' -import {Store} from '../../Store.js' +import React, { useState, useContext, useEffect } from 'react' +import { Store } from '../../Store.js' import styled from 'styled-components' import Grid from '@material-ui/core/Grid'; import { Button } from '@material-ui/core'; import ExitToAppIcon from '@material-ui/icons/ExitToApp'; import Comentarios from '../../img/comentarios.png' -import {apiDomain} from '../../env'; +import { apiDomain } from '../../env'; import CommentForm from './CommentForm.js' import Comment from '../Comment.js' -import {getRequest} from '../HelperFunctions/getAxiosConfig' +import { getRequest } from '../HelperFunctions/getAxiosConfig' import LoginModal from './../LoginModal.js' import Snackbar from '@material-ui/core/Snackbar'; import SignUpModal from './../SignUpModal' import MuiAlert from '@material-ui/lab/Alert'; +import CircularProgress from '@material-ui/core/CircularProgress'; function Alert(props) { return <MuiAlert elevation={6} variant="filled" {...props} />; } -export default function CommentsArea (props) { - const {state} = useContext(Store) +export default function CommentsArea(props) { + const { state } = useContext(Store) const [comentarios, setComentarios] = useState([]) const [gambiarra, setState] = useState(0) - const forceUpdate = () => {setState(gambiarra + 1)} + const forceUpdate = () => { setState(gambiarra + 1) } const [loginOpen, setLogin] = useState(false) const [successfulLoginOpen, handleSuccessfulLogin] = useState(false) const [signUpOpen, setSignUp] = useState(false) + const [isLoading, setIsLoading] = useState(false) const handleSignUp = () => { setSignUp(!signUpOpen) @@ -57,18 +59,19 @@ export default function CommentsArea (props) { if (reason === 'clickaway') { return; } - - handleSuccessfulLogin(false); + + handleSuccessfulLogin(false); } - function handleSuccess (data) { + function handleSuccess(data) { + setIsLoading(false) setComentarios(data.sort((a, b) => a.updated_at > b.updated_at ? -1 : 1)) } - useEffect( () => { + useEffect(() => { + setIsLoading(true) const url = `/learning_objects/${props.recursoId}/reviews` - - getRequest(url, handleSuccess, (error) => {console.log(error)}) + getRequest(url, handleSuccess, (error) => { console.log(error); setIsLoading(false) }) }, [gambiarra]) return ( @@ -83,17 +86,17 @@ export default function CommentsArea (props) { openSnackbar={() => { handleSuccessfulLogin(true) }} /> <SignUpModal open={signUpOpen} handleClose={handleSignUp} openLogin={handleLogin} /> - {/*----------------------------------------------------------------------------*/} - <Grid container spacing={2} style={{padding : "10px"}}> + {/*----------------------------------------------------------------------------*/} + <Grid container spacing={2} style={{ padding: "10px" }}> { (state.currentUser.id !== '') ? - ( + ( <Grid item xs={12} > <GrayContainer> <h3>Conte sua experiência com o Recurso</h3> - <Grid container style={{paddingTop : "20px"}}> - <Grid item xs={2} style={{paddingLeft : "15px", paddingRight : "15px"}}> - <img src={apiDomain + state.currentUser.avatar} className="minha-imagem" alt="user avatar"/> + <Grid container style={{ paddingTop: "20px" }}> + <Grid item xs={2} style={{ paddingLeft: "15px", paddingRight: "15px" }}> + <img src={apiDomain + state.currentUser.avatar} className="minha-imagem" alt="user avatar" /> </Grid> <Grid item xs={10}> <CommentForm @@ -101,70 +104,86 @@ export default function CommentsArea (props) { handleSnackbar={props.handleSnackbar} rerenderCallback={forceUpdate} recurso={props.recurso} - /> + /> </Grid> </Grid> </GrayContainer> </Grid> - ) - : - ( + ) + : + ( <Grid item xs={12}> <LogInToComment> <span className="span-laranja">Você precisa entrar para comentar</span> - <Button onClick={() => handleLogin(true)} style={{textTransform : "uppercase", color : "#666", fontWeight : "700"}}> - <ExitToAppIcon/>ENTRAR + <Button onClick={() => handleLogin(true)} style={{ textTransform: "uppercase", color: "#666", fontWeight: "700" }}> + <ExitToAppIcon />ENTRAR </Button> </LogInToComment> </Grid> - ) + ) } { - comentarios.length !== 0 ? - ( + isLoading ? + <LoadingDiv> + <CircularProgress className="loading" /> + </LoadingDiv> + : + comentarios.length !== 0 ? + ( <ComentariosBox> <h3>{comentarios.length} {comentarios.length !== 1 ? 'Relatos' : 'Relato'} sobre o uso do Recurso</h3> { - comentarios.map( comentario => - <div className="comentario-template" key={comentario.id}> - <Comment - authorID={comentario.user ? comentario.user.id : null} - authorAvatar={comentario.user ? comentario.user.avatar : null} - authorName={comentario.user ? comentario.user.name : null} - name={comentario.name} - rating={comentario.rating_average} - reviewRatings = {comentario.review_ratings} - description={comentario.description} - createdAt={comentario.created_at} - recurso={true} - reviewID={comentario.id} - objectID={props.recursoId} - rerenderCallback={forceUpdate} - handleSnackbar={props.handleSnackbar} - /> - </div> + comentarios.map(comentario => + <div className="comentario-template" key={comentario.id}> + <Comment + isCollection={false} + authorID={comentario.user ? comentario.user.id : null} + authorAvatar={comentario.user ? comentario.user.avatar : null} + authorName={comentario.user ? comentario.user.name : null} + name={comentario.name} + rating={comentario.rating_average} + reviewRatings={comentario.review_ratings} + description={comentario.description} + createdAt={comentario.created_at} + recurso={true} + reviewID={comentario.id} + objectID={props.recursoId} + rerenderCallback={forceUpdate} + handleSnackbar={props.handleSnackbar} + /> + </div> ) } </ComentariosBox> - ) - : - ( - <Grid item xs={12}> - <LogInToComment> - <img alt="" src={Comentarios} /> - <span className="span-laranja">Compartilhe sua experiência com a Rede!</span> - <AoRelatar> - Ao relatar sua experiência de uso do Recurso você estará auxiliando professores de todo país. + ) + : + ( + <Grid item xs={12}> + <LogInToComment> + <img alt="" src={Comentarios} /> + <span className="span-laranja">Compartilhe sua experiência com a Rede!</span> + <AoRelatar> + Ao relatar sua experiência de uso do Recurso você estará auxiliando professores de todo país. </AoRelatar> - </LogInToComment> - </Grid> - ) + </LogInToComment> + </Grid> + ) } </Grid> </React.Fragment> ) } +const LoadingDiv = styled.div` + margin: 1em; + display: flex; + justify-content: center; + align-items: center; + .loading{ + color: #ff7f00; + size: 24px; + } +` const ComentariosBox = styled.div` display : flex; @@ -221,18 +240,15 @@ const GrayContainer = styled.div` display : flex; flex-direction : column; justify-content : space-between; -<<<<<<< HEAD font-size : 14px; padding-bottom : 20px; @media screen and (min-width : 990px) { padding-right : 15px; padding-left : 15px; } -======= padding-right : 15px; padding-left : 15px; padding-bottom : 20px; ->>>>>>> fead909286087ce07b01b25f6d8f46f74dc494c8 h3 { font-family : 'Roboto Light','Roboto Regular',Roboto; diff --git a/src/Components/ResourcePageComponents/VideoPlayer.js b/src/Components/ResourcePageComponents/VideoPlayer.js index 940917df9190d882df8c4d5f77798cbe04b4bb93..57b1b06c0271db6a4d36133db6426159f7082255 100644 --- a/src/Components/ResourcePageComponents/VideoPlayer.js +++ b/src/Components/ResourcePageComponents/VideoPlayer.js @@ -19,58 +19,61 @@ along with Plataforma Integrada MEC. If not, see <http://www.gnu.org/licenses/> import React from 'react' import styled from 'styled-components' -function GetEmbeddedLink (link) { +function GetEmbeddedLink(link) { var embed = undefined var link_id = undefined if (link.indexOf("youtube") !== -1) { //plain youtebe.com/ link - if(link.indexOf("embed/") !== -1) { //if it's already an embedded link, return it + if (link.indexOf("embed/") !== -1) { //if it's already an embedded link, return it return link } link = link.split("&")[0] //else remove features and other queries link_id = link.split("v=")[1] //get video id embed = "https://www.youtube.com/embed/" + link_id; //create embedded link - } - else if (link.indexOf("youtu.be") !== -1) { //if it's a youtu.be link - link = link.split("&")[0].split("?")[0] //remove queries and features if existent - link_id = link.split(".be/")[1] //get video id - embed = "https://www.youtube.com/embed/" + link_id; //create embedded link - } - else if (link.indexOf("vimeo") !== -1) { //if the 13th character = o (vimeo videos) - link_id = link.split("?")[0].split("/") - console.log(link_id) //key # = from 19th character on - embed = "https://player.vimeo.com/video/" + link_id.pop(); //Add vimeo link before key # - } - return embed + } + else if (link.indexOf("youtu.be") !== -1) { //if it's a youtu.be link + link = link.split("&")[0].split("?")[0] //remove queries and features if existent + link_id = link.split(".be/")[1] //get video id + embed = "https://www.youtube.com/embed/" + link_id; //create embedded link + } + else if (link.indexOf("vimeo") !== -1) { //if the 13th character = o (vimeo videos) + link_id = link.split("?")[0].split("/") + console.log(link_id) //key # = from 19th character on + embed = "https://player.vimeo.com/video/" + link_id.pop(); //Add vimeo link before key # + } + return embed } -export default function VideoPlayer (props) { +export default function VideoPlayer(props) { return ( <> - { - props.urlVerified ? - ( - <VideoContainer> - <iframe - title="Video Player" - src={GetEmbeddedLink(props.link)} - frameBorder="0" allowFullScreen className="video" - /> - </VideoContainer> - ) - : - ( - <VideoContainer> - <video controls className="video"> - <source src={props.videoUrl} type="video/webm"/> - <source src={props.videoUrl} type="video/mp4"/> - <p>Seu navegador não permite a exibição deste vídeo. É necessário baixar o vídeo para poder visualizá-lo.</p> - </video> - </VideoContainer> - - ) - } + { + props.urlVerified ? + ( + <VideoContainer> + <iframe + title="Video Player" + src={GetEmbeddedLink(props.link)} + frameBorder="0" allowFullScreen className="video" + /> + </VideoContainer> + ) + : + ( + props.videoType === "video/mp4" ? + <VideoContainer> + <video controls className="video"> + <source src={props.videoUrl} type="video/webm" /> + <source src={props.videoUrl} type="video/mp4" /> + </video> + </VideoContainer> + : + <ErrorParagraph> + Seu navegador não permite a exibição deste vídeo. É necessário baixar o vídeo para poder visualizá-lo. + </ErrorParagraph> + ) + } </> ) } @@ -89,3 +92,7 @@ const VideoContainer = styled.div` left : 0; } ` + +const ErrorParagraph = styled.p` + text-align: center; +` diff --git a/src/Components/TabPanels/PanelComponents/ButtonsArea.js b/src/Components/TabPanels/PanelComponents/ButtonsArea.js index 848001761ebc4f63beb1f5cc1c46a317dc8158ab..1b8633ae0b05f6578b98fbbba427a3172775ed96 100644 --- a/src/Components/TabPanels/PanelComponents/ButtonsArea.js +++ b/src/Components/TabPanels/PanelComponents/ButtonsArea.js @@ -29,16 +29,15 @@ export function ButtonsAreaRecurso(props) { </p> { - props.end ? - null : - <React.Fragment> - <ButtonMostrarMaisRecurso onClick={() => props.showMore(4)}> - <span style={{ color: "#fff", fontSize: "14px", fontWeight: "500" }}>MOSTRAR MAIS 4</span> - </ButtonMostrarMaisRecurso> - <ButtonMostrarTodos onClick={() => { props.showMore(20) }}> - <span style={{ color: "#666", fontSize: "14px", fontWeight: "500" }}>MOSTRAR MAIS 20</span> - </ButtonMostrarTodos> - </React.Fragment> + !props.end && + <React.Fragment> + <ButtonMostrarMaisRecurso onClick={() => props.showMore(4)}> + <span style={{ color: "#fff", fontSize: "14px", fontWeight: "500" }}>MOSTRAR MAIS 4</span> + </ButtonMostrarMaisRecurso> + <ButtonMostrarTodos onClick={() => { props.showMore(20) }}> + <span style={{ color: "#666", fontSize: "14px", fontWeight: "500" }}>MOSTRAR MAIS 20</span> + </ButtonMostrarTodos> + </React.Fragment> } </Carregados> @@ -52,18 +51,16 @@ export function ButtonsAreaColecao(props) { {props.sliceLength} coleções carregadas de {props.total} </p> { - props.end ? - null - : - <React.Fragment> - <ButtonMostrarMaisColecao onClick={() => { props.showMore(4) }}> - <span style={{ color: "#fff", fontSize: "14px", fontWeight: "500" }}>MOSTRAR MAIS 4</span> - </ButtonMostrarMaisColecao> - - <ButtonMostrarTodos onClick={() => { props.showMore(20) }}> - <span style={{ color: "#666", fontSize: "14px", fontWeight: "500" }}>MOSTRAR MAIS 20</span> - </ButtonMostrarTodos> - </React.Fragment> + !props.end && + <React.Fragment> + <ButtonMostrarMaisColecao onClick={() => { props.showMore(4) }}> + <span style={{ color: "#fff", fontSize: "14px", fontWeight: "500" }}>MOSTRAR MAIS 4</span> + </ButtonMostrarMaisColecao> + + <ButtonMostrarTodos onClick={() => { props.showMore(20) }}> + <span style={{ color: "#666", fontSize: "14px", fontWeight: "500" }}>MOSTRAR MAIS 20</span> + </ButtonMostrarTodos> + </React.Fragment> } </Carregados> ) @@ -77,18 +74,16 @@ export function ButtonsAreaRede(props) { </p> { - props.end ? - null - : - <React.Fragment> - <ButtonMostrarMaisRede onClick={() => { props.showMore(4) }}> - <span style={{ color: "#fff", fontSize: "14px", fontWeight: "500" }}>MOSTRAR MAIS 4</span> - </ButtonMostrarMaisRede> - - <ButtonMostrarTodos onClick={() => { props.showMore(20) }}> - <span style={{ color: "#666", fontSize: "14px", fontWeight: "500" }}>MOSTRAR MAIS 20</span> - </ButtonMostrarTodos> - </React.Fragment> + !props.end && + <React.Fragment> + <ButtonMostrarMaisRede onClick={() => { props.showMore(4) }}> + <span style={{ color: "#fff", fontSize: "14px", fontWeight: "500" }}>MOSTRAR MAIS 4</span> + </ButtonMostrarMaisRede> + + <ButtonMostrarTodos onClick={() => { props.showMore(20) }}> + <span style={{ color: "#666", fontSize: "14px", fontWeight: "500" }}>MOSTRAR MAIS 20</span> + </ButtonMostrarTodos> + </React.Fragment> } </Carregados> diff --git a/src/Components/TabPanels/PanelComponents/NoContent.js b/src/Components/TabPanels/PanelComponents/NoContent.js index ef129ecef30c18abc9ab58d501330ab8b778678f..7c8c7141476c3c2793931b448168ce3db00ddc50 100644 --- a/src/Components/TabPanels/PanelComponents/NoContent.js +++ b/src/Components/TabPanels/PanelComponents/NoContent.js @@ -18,13 +18,21 @@ along with Plataforma Integrada MEC. If not, see <http://www.gnu.org/licenses/> import React from 'react' import styled from 'styled-components' +import defaultNoContent from '../../../img/img-16.png' -export default function NoContent (props) { + + +export default function NoContent({text, image}) { return ( <DivTextoNoPublications> <InnerDiv> - <NoPubSpan>{props.text}</NoPubSpan> + <ImgDiv> + <img alt="" src={image || defaultNoContent } style={{ width: "130px", verticalAlign: "middle", border: "0" }} /> + </ImgDiv> + <TextDiv> + <NoPubSpan>{text}</NoPubSpan> + </TextDiv> </InnerDiv> </DivTextoNoPublications> ) @@ -44,11 +52,18 @@ const InnerDiv = styled.div` transform : translateY(-50%); ` +const ImgDiv = styled.div` + margin-bottom: 25px; +` + +const TextDiv = styled.div` +` + export const DivTextoNoPublications = styled.div` height : 360px; - text-align : center; padding-left : 15px; padding-right : 15px; + text-align : center; ` // {/*const DivConteudoNaoPublicado = styled.div` diff --git a/src/Components/TabPanels/PanelComponents/TemplateColecao.js b/src/Components/TabPanels/PanelComponents/TemplateColecao.js index 7af99a6cf6e901be5a1c03276475edb85a4dc44e..b1526eb584834bb5c45f03436eef946c512b8512 100644 --- a/src/Components/TabPanels/PanelComponents/TemplateColecao.js +++ b/src/Components/TabPanels/PanelComponents/TemplateColecao.js @@ -24,6 +24,7 @@ import Title from './PanelTitle.js' import { WhiteContainer, StyledGrid } from '../StyledComponents.js' import { ButtonsAreaColecao } from './ButtonsArea' import LoadingSpinner from '../../LoadingSpinner.js' +import noCollFound from '../../../img/Pagina_vazia_colecao.png' export default function PanelTemplateColecao(props) { const RenderFollowedColCard = (card, followerBoolean) => { @@ -86,7 +87,10 @@ export default function PanelTemplateColecao(props) { : props.length === 0 ? ( - <NoContent text={props.noContentText} /> + <NoContent + text={props.noContentText} + image={noCollFound} + /> ) : ( @@ -109,7 +113,7 @@ export default function PanelTemplateColecao(props) { length={props.length} showMore={props.showMore} total={props.end} - end={String(props.sliceArr.length) === props.end} + end={String(props.sliceArr.length) === props.end || Number(props.sliceArr.length) === props.end} /> } </React.Fragment> diff --git a/src/Components/TabPanels/PanelComponents/TemplateCuradoria.js b/src/Components/TabPanels/PanelComponents/TemplateCuradoria.js index 4426a239ded8dc1c3d42925e8f83caa7c59598d7..d03415734eb03a7a7ea0ecb7671a50840240c815 100644 --- a/src/Components/TabPanels/PanelComponents/TemplateCuradoria.js +++ b/src/Components/TabPanels/PanelComponents/TemplateCuradoria.js @@ -83,7 +83,7 @@ export default function Template(props) { sliceLength={props.sliceArr.length} length={props.length} showMore={props.showMore} - end={String(props.sliceArr.length) === props.end} + end={String(props.sliceArr.length) === props.end || Number(props.sliceArr.length) === props.end} total={props.end} /> } diff --git a/src/Components/TabPanels/PanelComponents/TemplateRecurso.js b/src/Components/TabPanels/PanelComponents/TemplateRecurso.js index 6bf05604c0d56eef5e435c449b2b8cc103517572..d77f0208d3f072a5385a598d9d99c74e963cead2 100644 --- a/src/Components/TabPanels/PanelComponents/TemplateRecurso.js +++ b/src/Components/TabPanels/PanelComponents/TemplateRecurso.js @@ -24,6 +24,7 @@ import Title from './PanelTitle.js' import { WhiteContainer, StyledGrid } from '../StyledComponents.js' import { ButtonsAreaRecurso } from './ButtonsArea' import LoadingSpinner from '../../LoadingSpinner.js' +import noLearnObjFound from '../../../img/Pagina_vazia_Sem_publicar.png' export default function Template(props) { @@ -44,7 +45,10 @@ export default function Template(props) { : props.length === 0 ? ( - <NoContent text={props.noContentText} /> + <NoContent + text={props.noContentText} + image={noLearnObjFound} + /> ) : ( @@ -82,7 +86,7 @@ export default function Template(props) { length={props.length} showMore={props.showMore} total={props.end} - end={String(props.slice.length) === props.end} + end={Number(props.slice.length) === props.end || String(props.slice.length) === props.end} /> } diff --git a/src/Components/TabPanels/PanelComponents/TemplateRede.js b/src/Components/TabPanels/PanelComponents/TemplateRede.js index c792b7d2de531c63ef2ec1b44b2f4a61b992b163..e5d2a845a2b2cc388331c622912ac904844379be 100644 --- a/src/Components/TabPanels/PanelComponents/TemplateRede.js +++ b/src/Components/TabPanels/PanelComponents/TemplateRede.js @@ -94,7 +94,7 @@ export default function PanelTemplateRede(props) { length={props.length} showMore={props.showMore} total={props.end} - end={String(props.sliceArr.length) === props.end} + end={String(props.sliceArr.length) === props.end || Number(props.sliceArr.length) === props.end} /> } </React.Fragment> diff --git a/src/Components/TabPanels/PublicUserPageTabs/TabColecoes.js b/src/Components/TabPanels/PublicUserPageTabs/TabColecoes.js index 4b46dc0700385baa2b787e847b8a671ed3f1f262..9b987347a51274465b78e7db062a99bd6d9a2273 100644 --- a/src/Components/TabPanels/PublicUserPageTabs/TabColecoes.js +++ b/src/Components/TabPanels/PublicUserPageTabs/TabColecoes.js @@ -21,7 +21,7 @@ import { fetchAllRequest, getRequest } from '../../HelperFunctions/getAxiosConfi import PanelTemplateColecao from '../PanelComponents/TemplateColecao.js' import LoadingSpinner from '../../LoadingSpinner.js' -export default function TabColecoes(props) { +export default function TabColecoes({id, username}) { const [loading, handleLoading] = useState(true) const [errorInUserColl, setErrorInUserColl] = useState(false) @@ -52,7 +52,7 @@ export default function TabColecoes(props) { const getInfo = () => { const urls = [ - `/users/${props.id}/collections?offset=0&limit=4`, + `/users/${id}/collections?offset=0&limit=4`, ] fetchAllRequest(urls, handleSuccess, handleError) } @@ -66,7 +66,7 @@ export default function TabColecoes(props) { const limit = limite; setLoadingMoreUserColl(true); setCurrLimitUserColl(currLimitUserColl + limit) - const url = `/users/${props.id}/collections?offset=${currLimitUserColl}&limit=${limit}`; + const url = `/users/${id}/collections?offset=${currLimitUserColl}&limit=${limit}`; getRequest(url, (data) => { if (data.errors) { @@ -98,14 +98,14 @@ export default function TabColecoes(props) { { loading ? ( - <LoadingSpinner text={'CARREGANDO COLEÇÕES'} /> + <LoadingSpinner text={`Carregando coleções de ${username}`} /> ) : ( <PanelTemplateColecao title={"Coleções Públicas"} length={userCollections.length} - noContentText={props.username + " não possui nenhuma coleção."} + noContentText={username + " não possui nenhuma coleção."} sliceArr={userCollections} showMore={showMoreUserCollections} loadingMore={loadingMoreUserColl} diff --git a/src/Components/TabPanels/PublicUserPageTabs/TabInicio.js b/src/Components/TabPanels/PublicUserPageTabs/TabInicio.js index 0663a44c4412e545429c7b560bf9eb2ca9e88126..7965d58e5111ad748a22cdf2672c25f05bc3f3ce 100644 --- a/src/Components/TabPanels/PublicUserPageTabs/TabInicio.js +++ b/src/Components/TabPanels/PublicUserPageTabs/TabInicio.js @@ -19,11 +19,8 @@ along with Plataforma Integrada MEC. If not, see <http://www.gnu.org/licenses/> import React from 'react' import styled from 'styled-components' import UserDescription from './UserDescription.js' -import NoContentImage from '../../../img/img-16.png' -import Grid from '@material-ui/core/Grid'; -import LastLearnObjs from './LastLearnObj.js' -import LastCols from './LastCollections.js' -import {ContainerStyled} from '../StyledComponents.js' +import Template from '../PanelComponents/TemplateRecurso' +import PanelTemplateColecao from '../PanelComponents/TemplateColecao.js' const NoContentContainer = styled.div` height : 250px; @@ -46,11 +43,11 @@ const NoContentContainer = styled.div` } ` /*Displays given image and text saying user hasn't posted anything yet*/ -export function NoContent (props) { +export function NoContent(props) { return ( <NoContentContainer> - <div style={{paddingTop : "1em"}}> - <img alt="" src={props.image} style={{width : "130px", verticalAlign : "middle", border : "0"}}/> + <div style={{ paddingTop: "1em" }}> + <img alt="" src={props.image} style={{ width: "130px", verticalAlign: "middle", border: "0" }} /> <h3> {props.text1} </h3> @@ -63,55 +60,36 @@ export function NoContent (props) { ) } -export default function TabInicio (props) { - +export default function TabInicio({ id, user, learningObjs, collections }) { return ( <React.Fragment> {/*display user description*/} - {props.user.description && - <UserDescription text={props.user.description}/> - } { - props.user.learning_objects_count === 0 && props.user.collections_count === 0 ? - ( - [ - <ContainerStyled> - <Grid container> - <Grid item xs={12}> - <NoContent - image={NoContentImage} - text1={props.user.name + " ainda não disponibilizou nenhum recurso ou coleção."} - text2={"Quando disponibilizar, eles aparecerão aqui."} - /> - </Grid> - </Grid> - </ContainerStyled> - ] - ) - : - ( - [ - <React.Fragment> - <ContainerStyled style={{flexDirection : "column"}}> - <LastLearnObjs - count={props.user.learning_objects_count} - username={props.user.name} - learningObjs={props.learningObjs} - /> - </ContainerStyled> - - <ContainerStyled style={{flexDirection : "column", paddingTop : "1em"}}> - <LastCols - count={props.user.collections_count} - username={props.user.name} - collections={props.collections} - /> - </ContainerStyled> - </React.Fragment> - ] - ) + user.description && + <UserDescription text={user.description} /> } - {/*display last published learning objects and last alterations in user collections*/} + <Template + length={learningObjs.length} + titleText={learningObjs.length === 1 ? `Último Recurso de ${user.name}` : `Últimos recursos de ${user.name}`} + noContentText={`${user.name} não publicou nenhum recursos ainda`} + slice={learningObjs} + showMore={() => { }} // there is no function here, because we don't want to display more resources in this tab + loadingMore={false} + end={learningObjs.length} + error={false} + /> + <PanelTemplateColecao + title={`Últimas coleçoes de ${user.name}`} + length={collections.length} + noContentText={`${user.name} não publicou nenhuma coleção ainda`} + sliceArr={collections} + showMore={() => { }} // there is no function here, because we don't want to display more collections in this tab + loadingMore={false} + end={collections.length} + followed={false} + error={false} + /> + </React.Fragment> diff --git a/src/Components/TabPanels/PublicUserPageTabs/TabRecursos.js b/src/Components/TabPanels/PublicUserPageTabs/TabRecursos.js index bbce193bcde870391dda55ee9a67c79aacb768b4..b8f38e36b55e62c26f5df389ba6b80bbdba6a301 100644 --- a/src/Components/TabPanels/PublicUserPageTabs/TabRecursos.js +++ b/src/Components/TabPanels/PublicUserPageTabs/TabRecursos.js @@ -17,94 +17,92 @@ You should have received a copy of the GNU Affero General Public License along with Plataforma Integrada MEC. If not, see <http://www.gnu.org/licenses/>.*/ import React, { useState, useEffect } from 'react' -import { HeaderGrid, ContainerStyled, Carregados } from '../StyledComponents.js' -import Grid from '@material-ui/core/Grid'; -import ResourceCardFunction from '../../ResourceCardFunction.js' -import { ButtonMostrarMaisRecurso } from '../PanelComponents/ButtonsArea' +import LoadingSpinner from '../../LoadingSpinner.js' +import Template from '../PanelComponents/TemplateRecurso.js' import { getRequest } from '../../HelperFunctions/getAxiosConfig' -import { StyledGrid } from '../StyledComponents' - -export default function TabRecursos(props) { - const [arr, setArr] = useState([]) - const [objsSlice, setSlice] = useState([]) - const handleSlice = (newArr) => { setSlice(newArr) } - useEffect(() => { - setArr(props.learningObjs) - setSlice(props.learningObjs.slice(0, 4)) - }, []) +export default function TabPanelAtividades({id, username}) { + const [loading, handleLoading] = useState(true) - function handleSuccess(data) { - setArr(data) - setSlice(data) - } - const showMore = (quantity) => { - var sliceLength = objsSlice.length - var newLength = sliceLength + quantity + const [errorInLearnObj, setErrorInLearnObj] = useState(false) + const [loadingMoreLearnObj, setLoadingMoreLearnObj] = useState(false) + const [currLimitLearnObj, setCurrLimitLearnObj] = useState(4); + const [endOfLearnObj, setEndofLearndObj] = useState(0); + const [learningObjects, setLearningObjects] = useState([]); - if (newLength > 12) { - const url = `/users/${props.id}/learning_objects?limit=${newLength}$offset=4` - getRequest(url, handleSuccess, (error) => { console.log(error) }) + function handleSuccess(data, headers) { + setErrorInLearnObj(data.errors ? true : false) + setLearningObjects(data) + if (headers.has('X-Total-Count')) { + setEndofLearndObj(headers.get('X-Total-Count')); } - else { - handleSlice(arr.slice(0, sliceLength + quantity)) - } - + handleLoading(false) } - return ( - <ContainerStyled style={{ flexDirection: "column" }}> + function handleError(error) { + handleLoading(false) + setErrorInLearnObj(true) + } - <HeaderGrid container> - <Grid item xs={12}> - <h3>Recursos Publicados <b style={{ fontWeight: "500" }}>({props.count})</b></h3> - </Grid> - </HeaderGrid> + useEffect(() => { + const url = `/users/${id}/learning_objects?offset=0&limit=4`; + handleLoading(true); + getRequest(url, handleSuccess, handleError); + }, []) - <StyledGrid container spacing={1} style={{ paddingLeft: "30px", paddingRight: "15px" }}> - { - objsSlice.map((card) => - <Grid item xs={12} sm={6} md={'auto'} lg={3} key={card.id}> - <ResourceCardFunction - avatar={card.publisher.avatar} - id={card.id} - thumbnail={card.thumbnail} - type={card.object_type ? card.object_type : "Outros"} - title={card.name} - published={card.state === "published" ? true : false} - likeCount={card.likes_count} - liked={card.liked} - rating={card.review_average} - author={card.publisher.name} - tags={card.tags} - href={"/recurso/" + card.id} - downloadableLink={card.default_attachment_location} - /> - </Grid> - ) + const showMoreLearnObj = (limite) => { + setLoadingMoreLearnObj(true); + const limit = limite; + setCurrLimitLearnObj(currLimitLearnObj + limit) + const url = `/users/${id}/learning_objects?offset=${currLimitLearnObj}&limit=${limit}`; + getRequest(url, + (data) => { + if (data.errors) { + setLoadingMoreLearnObj(false); + setErrorInLearnObj(true) } - </StyledGrid> - - <Carregados> - <p style={{ margin: "0 0 10px", fontSize: "14px" }}> - Carregados {objsSlice.length} de {arr.length} - </p> - - { - props.count > 5 && - <React.Fragment> - <ButtonMostrarMaisRecurso onClick={() => { showMore(4) }}> - <span style={{ color: "#fff", fontSize: "14px", fontWeight: "500" }}>MOSTRAR MAIS 4</span> - </ButtonMostrarMaisRecurso> - - <ButtonMostrarMaisRecurso onClick={() => { showMore(20) }}> - <span style={{ color: "#fff", fontSize: "14px", fontWeight: "500" }}>MOSTRAR MAIS 20</span> - </ButtonMostrarMaisRecurso> - </React.Fragment> + else if (data.length >= 1) { + let currData = [...learningObjects]; + currData = [...currData.concat(data)]; + setLoadingMoreLearnObj(false); + setLearningObjects(currData); } + else { + setLoadingMoreLearnObj(false); + } + }, + (error) => { + setLoadingMoreLearnObj(false); + setErrorInLearnObj(true) + } + ) + } - </Carregados> - - </ContainerStyled> + return ( + <> + { + loading ? + ( + <LoadingSpinner text={`Carregando os recursos de ${username}`} /> + ) + : + ( + [ + <React.Fragment> + <Template + length={learningObjects.length} + titleText={learningObjects.length === 1 ? `Recurso publicado de ${username}` : `Recursos publicados ${username}`} + noContentText={`${username} ainda não publicou nenhum Recurso!`} + slice={learningObjects} + showMore={showMoreLearnObj} + loadingMore={loadingMoreLearnObj} + end={endOfLearnObj} + error={errorInLearnObj} + /> + </React.Fragment> + ] + ) + } + </> ) } diff --git a/src/Components/TabPanels/PublicUserPageTabs/TabRede.js b/src/Components/TabPanels/PublicUserPageTabs/TabRede.js index 6b8a8a8ee73eb0ede45b2b3ed40785697169cbac..81334d46c6edc88b10c8df88fa0df5366edec587 100644 --- a/src/Components/TabPanels/PublicUserPageTabs/TabRede.js +++ b/src/Components/TabPanels/PublicUserPageTabs/TabRede.js @@ -21,7 +21,7 @@ import PanelTemplateRede from '../PanelComponents/TemplateRede.js' import { fetchAllRequest, getRequest } from '../../HelperFunctions/getAxiosConfig' import LoadingSpinner from '../../LoadingSpinner.js' -export default function TabRede (props) { +export default function TabRede ({id, username}) { const [loading, handleLoading] = useState(true) const [errorInFollowing, setErrorInFollowing] = useState(false) @@ -41,7 +41,7 @@ export default function TabRede (props) { setLoadingFollowing(true); const limit = limite; setCurrFollowingLimit(currFollowingLimit + limit) - const url = `/users/${props.id}/following/User?offset=${currFollowingLimit}&limit=${limit}`; + const url = `/users/${id}/following/User?offset=${currFollowingLimit}&limit=${limit}`; getRequest(url, (data) => { if (data.errors) { @@ -72,7 +72,7 @@ export default function TabRede (props) { setLoadingMoreFollowers(true); const limit = limite; setFollowersLimit(currFollowerLimit + limit) - const url = `/users/${props.id}/followers?offset=${currFollowerLimit}&limit=${limit}`; + const url = `/users/${id}/followers?offset=${currFollowerLimit}&limit=${limit}`; getRequest(url, (data) => { if (data.errors) { @@ -125,7 +125,7 @@ export default function TabRede (props) { useEffect( () => { handleLoading(true) - const urls = [`/users/${props.id}/followers`, `/users/${props.id}/following/User`] + const urls = [`/users/${id}/followers`, `/users/${id}/following/User`] fetchAllRequest(urls, handleSuccess, handleErrors) }, []) @@ -136,7 +136,7 @@ export default function TabRede (props) { loading ? ( [ - <LoadingSpinner text={'CARREGANDO...'} /> + <LoadingSpinner text={`Carregando dados de ${username}`} /> ] ) : @@ -144,7 +144,7 @@ export default function TabRede (props) { [ <React.Fragment> <PanelTemplateRede - title={"Seguidores"} + title={`Seguidores de ${username}`} length={followersList.length} sliceArr={followersList} showMore={showMoreFollowers} @@ -152,11 +152,11 @@ export default function TabRede (props) { end={endOfFollowers} loadingMore={loadingMoreFollowers} error={errorInFollowers} - noContentText={props.username + ' não possui nenhum seguidor'} + noContentText={username + ' não possui nenhum seguidor'} /> <PanelTemplateRede - title={"Seguindo"} + title={`${username} está seguindo`} length={followingList.length} sliceArr={followingList} showMore={showMoreFollowing} @@ -164,7 +164,7 @@ export default function TabRede (props) { end={endOfFollowing} loadingMore={loadingMoreFollowing} error={errorInFollowing} - noContentText={props.username + ' não segue nenhum usuário'} + noContentText={username + ' não segue nenhum usuário'} /> </React.Fragment> ] diff --git a/src/Components/TabPanels/UserPageTabs/PanelColecoes.js b/src/Components/TabPanels/UserPageTabs/PanelColecoes.js index eef4d1eaa7df0728081c75d13d87e15db0f199b7..3abc14f58d9dae31f8a949f890890dcfa0f85c25 100644 --- a/src/Components/TabPanels/UserPageTabs/PanelColecoes.js +++ b/src/Components/TabPanels/UserPageTabs/PanelColecoes.js @@ -23,7 +23,6 @@ import Grid from '@material-ui/core/Grid'; import LoadingSpinner from '../../LoadingSpinner.js' import PanelTemplateColecao from '../PanelComponents/TemplateColecao.js' import PaginaVaziaColecao from '../../../img/Pagina_vazia_colecao.png' -import NoContent from '../PanelComponents/NoContent.js' import { WhiteContainer, StyledGrid } from '../StyledComponents.js' import CreateNewFolderIcon from '@material-ui/icons/CreateNewFolder'; import Title from '../PanelComponents/PanelTitle.js' @@ -47,12 +46,12 @@ export default function TabPanelColecoes(props) { const [loadingMoreUserColl, setLoadingMoreUserColl] = useState(false); const [loadingMoreFollowedColl, setLoadingMoreFollowedColl] = useState(false); - const [endOfUserColl, setEndOfUserColl] = useState(false); - const [endOfFollowedColl, setEndOfFollowedColl] = useState(false); + const [endOfUserColl, setEndOfUserColl] = useState(0); + const [endOfFollowedColl, setEndOfFollowedColl] = useState(0); - const removeColl = (itemId) => { - let newSlice = userCollections.filter(item => item.id !== itemId); - setUserCollections(newSlice); + const removeColl = (itemId) => { + let newSlice = userCollections.filter(item => item.id !== itemId); + setUserCollections(newSlice); setEndOfUserColl(String(endOfUserColl - 1)) }; @@ -100,7 +99,6 @@ export default function TabPanelColecoes(props) { (data) => { if (data.errors) { setLoadingMoreUserColl(false); - setEndOfUserColl(true) setErrorInUserColl(true) } else if (data.length >= 1) { @@ -111,12 +109,10 @@ export default function TabPanelColecoes(props) { } else { setLoadingMoreUserColl(false); - setEndOfUserColl(true) } }, (error) => { setLoadingMoreUserColl(false); - setEndOfUserColl(true) setErrorInUserColl(true) } ) @@ -131,7 +127,6 @@ export default function TabPanelColecoes(props) { (data) => { if (data.errors) { setLoadingMoreFollowedColl(false); - setEndOfFollowedColl(true) setErrorInFollowedColl(true) } else if (data.length >= 1) { @@ -142,12 +137,10 @@ export default function TabPanelColecoes(props) { } else { setLoadingMoreFollowedColl(false); - setEndOfFollowedColl(true) } }, (error) => { setLoadingMoreFollowedColl(false); - setEndOfFollowedColl(true) setErrorInFollowedColl(true) } ) @@ -168,18 +161,23 @@ export default function TabPanelColecoes(props) { title={"Minhas Coleções"} length={userCollections.length} noContentText={ - <div> - <img src={PaginaVaziaColecao} alt="PaginaVaziaColecao" style={{ height: "150px", width: "150px", verticalAlign: "middle", border: "0" }} /> - <br /> - <span style={{ fontFamily: "Roboto", fontWeight: "lighter", fontSize: "24px" }}> - Criamos a sua primeira Coleção! - </span> - <p style={{ fontFamily: "Roboto", fontSize: "16px", margin: "10px 0 0", fontWeight: "normal" }}> - Adicione nela recursos que você queira acessar mais tarde. - <br /> - Crie novas coleções clicando no cartão roxo "Criar Colecão". - </p> - </div> + <Grid direction='column' justify='center' alignItems='center'> + <Grid item> + <img src={PaginaVaziaColecao} alt="PaginaVaziaColecao" style={{ height: "150px", width: "150px", verticalAlign: "middle", border: "0" }} /> + </Grid> + <Grid> + <span style={{ fontFamily: "Roboto", fontWeight: "lighter", fontSize: "24px", textAlign: 'center' }}> + Criamos a sua primeira Coleção! + </span> + </Grid> + <Grid> + <p style={{ fontFamily: "Roboto", fontSize: "16px", margin: "10px 0 0", fontWeight: "normal" }}> + Adicione nela recursos que você queira acessar mais tarde. + <br /> + Crie novas coleções clicando no cartão roxo "Criar Colecão". + </p> + </Grid> + </Grid> } sliceArr={userCollections} showMore={showMoreUserCollections} @@ -254,7 +252,9 @@ function Tentativa(props) { ( [ <Grid item lg={6} md={4} sm={6} xs={12}> - <NoContent text={props.noContentText} /> + <div> + {props.noContentText} + </div> </Grid> ] ) diff --git a/src/Components/TabPanels/UserPageTabs/PanelCuradoria.js b/src/Components/TabPanels/UserPageTabs/PanelCuradoria.js index d9a3ac296fd3d2f0b6faa3c765bb701323c1f09c..084f865b9077e0752df8b34d221debade2a35492 100644 --- a/src/Components/TabPanels/UserPageTabs/PanelCuradoria.js +++ b/src/Components/TabPanels/UserPageTabs/PanelCuradoria.js @@ -27,7 +27,7 @@ export default function TabPanelCuradoria(props) { const [errorCurating, setErrorCurating] = useState(false) const [loadingMoreCurating, setLoadingMoreCurating] = useState(false) const [currLimitCurating, setcurrLimitCurating] = useState(4); - const [endOfCurating, setEndofCurating] = useState(); + const [endOfCurating, setEndofCurating] = useState(0); const [curating, setCurating] = useState([]); const showMoreCurating = (limite) => { diff --git a/src/Components/TabPanels/UserPageTabs/PanelFavoritos.js b/src/Components/TabPanels/UserPageTabs/PanelFavoritos.js index 8c9fff1ba0a9dce2b90cdd477ddc0decf8242c32..9cf489886054275662595ce75d29302caf0ab2a0 100644 --- a/src/Components/TabPanels/UserPageTabs/PanelFavoritos.js +++ b/src/Components/TabPanels/UserPageTabs/PanelFavoritos.js @@ -36,8 +36,8 @@ export default function TabPanelFavoritos(props) { const [loadingMoreLearnObj, setLoadingMoreLearnObj] = useState(false) const [loadingMoreColl, setLoadingMoreColl] = useState(false) - const [endOfLearnObj, setEndofLearndObj] = useState(false) - const [endOfColl, setEndoffColl] = useState(false) + const [endOfLearnObj, setEndofLearndObj] = useState(0) + const [endOfColl, setEndoffColl] = useState(0) function handleSuccess(responseArr, headersArr) { @@ -82,7 +82,6 @@ export default function TabPanelFavoritos(props) { (data) => { if (data.errors) { setLoadingMoreLearnObj(false); - setEndofLearndObj(true); setErrorInLikedInLearnObj(true); } else if (data.length >= 1) { @@ -93,12 +92,10 @@ export default function TabPanelFavoritos(props) { } else { setLoadingMoreLearnObj(false); - setEndofLearndObj(true) } }, (error) => { setLoadingMoreLearnObj(false); - setEndofLearndObj(true); setErrorInLikedInLearnObj(true); } ) @@ -113,7 +110,6 @@ export default function TabPanelFavoritos(props) { (data) => { if (data.errors) { setLoadingMoreColl(false); - setEndoffColl(true) setErrorInLikedInColl(true) } if (data.length >= 1) { @@ -124,12 +120,10 @@ export default function TabPanelFavoritos(props) { } else { setLoadingMoreColl(false); - setEndoffColl(true) } }, (error) => { setLoadingMoreColl(false); - setEndoffColl(true) setErrorInLikedInColl(true) } ) @@ -147,14 +141,9 @@ export default function TabPanelFavoritos(props) { [ <React.Fragment> <Template - length={endOfLearnObj} - titleText={"Recursos Favoritados"} - noContentText={<p style={{ fontFamily: "Roboto", fontSize: "16px" }}>Quando você favorita um recurso ele aparece nesta seção. Além disso, você - <br /> - aumenta o prestígio dele na Plataforma. Para favoritar, basta clicar no ícone de - <br /> - coração que aparece nos Recursos. - </p>} + length={likedLearnObjs.length} + titleText={likedLearnObjs.length === 1 ? "Recurso favoritado" : "Recursos favoritados"} + noContentText={"Você não favoritou nenhum recurso ainda"} slice={likedLearnObjs} showMore={showMoreLikedLearnObj} loadingMore={loadingMoreLearnObj} @@ -164,7 +153,7 @@ export default function TabPanelFavoritos(props) { <PanelTemplateColecao title={"Coleções favoritadas"} - length={endOfColl} + length={likedCollections.length} noContentText={"Você ainda não curtiu nenhuma coleção."} sliceArr={likedCollections} showMore={showMoreLikedCollections} diff --git a/src/Components/TabPanels/UserPageTabs/PanelMeusRecursos.js b/src/Components/TabPanels/UserPageTabs/PanelMeusRecursos.js index c6c3099a11ac3007bb63adc605896512d79caea1..46400fa191908298e8c373e83a5971b74da1dcf3 100644 --- a/src/Components/TabPanels/UserPageTabs/PanelMeusRecursos.js +++ b/src/Components/TabPanels/UserPageTabs/PanelMeusRecursos.js @@ -105,7 +105,6 @@ export default function TabPanelAtividades(props) { } else { setLoadingMoreLearnObj(false); - setEndofLearndObj(true) } }, (error) => { @@ -136,7 +135,6 @@ export default function TabPanelAtividades(props) { } else { setLoadingMoreDrafts(false); - setEndofDrafts(true); } }, (error) => { @@ -165,7 +163,6 @@ export default function TabPanelAtividades(props) { } else { setLoadingMoreCurating(false); - setEndofCurating(true); } }, @@ -187,7 +184,7 @@ export default function TabPanelAtividades(props) { ( [ <React.Fragment> - <Template + <Template length={learningObjects.length} titleText={learningObjects.length === 1 ? "Recurso Publicado" : "Recursos Publicados"} noContentText={"Você ainda não publicou nenhum Recurso!"} diff --git a/src/Components/TabPanels/UserPageTabs/PanelRede.js b/src/Components/TabPanels/UserPageTabs/PanelRede.js index 03f4083bb18f0ad729f2a6234ef16c455666cef8..ba5741a5044359462e57d866a74e946c4ae0d444 100644 --- a/src/Components/TabPanels/UserPageTabs/PanelRede.js +++ b/src/Components/TabPanels/UserPageTabs/PanelRede.js @@ -31,12 +31,12 @@ export default function TabPanelRede(props) { const [followingList, setFollowing] = useState([]) const [currFollowingLimit, setCurrFollowingLimit] = useState(12) const [loadingMoreFollowing, setLoadingFollowing] = useState(false) - const [endOfFollowing, setEndOfFollowing] = useState(false) + const [endOfFollowing, setEndOfFollowing] = useState(0) const [followersList, setFollowers] = useState([]) const [currFollowerLimit, setFollowersLimit] = useState(12) const [loadingMoreFollowers, setLoadingMoreFollowers] = useState(false) - const [endOfFollowers, setEndOfFollowers] = useState(false) + const [endOfFollowers, setEndOfFollowers] = useState(0) const showMoreFollowing = (limite) => { setLoadingFollowing(true); @@ -47,7 +47,6 @@ export default function TabPanelRede(props) { (data) => { if (data.errors) { setLoadingFollowing(false); - setEndOfFollowing(true); setErrorInFollowing(true); } else if (data.length >= 1) { @@ -58,12 +57,10 @@ export default function TabPanelRede(props) { } else { setLoadingFollowing(false); - setEndOfFollowing(true); } }, (error) => { setLoadingFollowing(false); - setEndOfFollowing(true); setErrorInFollowing(true); } ) @@ -78,7 +75,6 @@ export default function TabPanelRede(props) { (data) => { if (data.errors) { setLoadingMoreFollowers(false); - setEndOfFollowers(true); setErrorInFollowers(true); } else { @@ -90,13 +86,11 @@ export default function TabPanelRede(props) { } else { setLoadingMoreFollowers(false); - setEndOfFollowers(true) } } }, (error) => { setLoadingMoreFollowers(false); - setEndOfFollowers(true); setErrorInFollowers(true); } ) @@ -118,7 +112,6 @@ export default function TabPanelRede(props) { function handleErrors() { setLoadingMoreFollowers(false); - setEndOfFollowers(true); setErrorInFollowers(true); } diff --git a/src/Components/UploadPageComponents/FileToUpload.ts b/src/Components/UploadPageComponents/FileToUpload.ts index fddbf404078bdb1eed4d04a666955d63ccdbac87..60b6ecb0435943d67b7eae390c06aefa47f167b7 100644 --- a/src/Components/UploadPageComponents/FileToUpload.ts +++ b/src/Components/UploadPageComponents/FileToUpload.ts @@ -34,7 +34,7 @@ export default class FileToUpload { if(this.readyState === XMLHttpRequest.DONE){ if (this.getResponseHeader('access-token') != null) { console.log(this.getResponseHeader('access-token')) - sessionStorage.setItem('@portalmec/accessToken', this.getResponseHeader('access-token')!) + localStorage.setItem('@portalmec/accessToken', this.getResponseHeader('access-token')!) } } } @@ -58,14 +58,14 @@ export default class FileToUpload { //set necessary headers this.request.setRequestHeader('Content-Range', `bytes ${this.currentChunkStartByte}-${this.currentChunkFinalByte}/${this.file.size}`); - if (sessionStorage.getItem('@portalmec/uid') != undefined) { - this.request.setRequestHeader('uid', sessionStorage.getItem('@portalmec/uid')!) + if (localStorage.getItem('@portalmec/uid') != undefined) { + this.request.setRequestHeader('uid', localStorage.getItem('@portalmec/uid')!) } - if (sessionStorage.getItem('@portalmec/clientToken') != undefined) { - this.request.setRequestHeader('client', String(sessionStorage.getItem('@portalmec/clientToken'))) + if (localStorage.getItem('@portalmec/clientToken') != undefined) { + this.request.setRequestHeader('client', String(localStorage.getItem('@portalmec/clientToken'))) } - if (sessionStorage.getItem('@portalmec/accessToken') != undefined) { - this.request.setRequestHeader('access-token', String(sessionStorage.getItem('@portalmec/accessToken'))) + if (localStorage.getItem('@portalmec/accessToken') != undefined) { + this.request.setRequestHeader('access-token', String(localStorage.getItem('@portalmec/accessToken'))) } this.request.onload = () => { diff --git a/src/Pages/CollectionPage.js b/src/Pages/CollectionPage.js index 3ccb5ab1929d32cc3be204d59fa939664b85596f..52a26eb90d29edfd109b41dd6cf90604e130f449 100644 --- a/src/Pages/CollectionPage.js +++ b/src/Pages/CollectionPage.js @@ -28,12 +28,15 @@ import DowloadButton from '../Components/CollectionDowloadButton.js'; import Breadcrumbs from "@material-ui/core/Breadcrumbs"; import { Link } from 'react-router-dom'; import FollowCollectionButton from '../Components/FollowCollectionButton'; -import { Store } from '../Store.js' -import { getRequest } from '../Components/HelperFunctions/getAxiosConfig.js' +import { Store } from '../Store.js'; +import Button from '@material-ui/core/Button'; +import { getRequest } from '../Components/HelperFunctions/getAxiosConfig.js'; export default function CollectionPage(props) { const { state } = useContext(Store); + const [error, setError] = useState(false) + const [collection, setCollection] = useState({ name: '', id: 0, @@ -44,81 +47,111 @@ export default function CollectionPage(props) { useEffect(() => { const url = `/collections/${collection_id}` - getRequest(url, (data) => { setCollection(Object.assign({}, data)) }, (error) => { console.log(error) }) - }, []); + getRequest(url, (data) => { setCollection(Object.assign({}, data)) }, (error) => { setError(true) }) + }, [state.currentUser.id]); const handleScrollToComments = () => { comment_ref.current.scrollIntoView({ behavior: 'smooth' }) } - return ( - <> - <BreadCrumbsDiv> - <StyledBreadCrumbs> - <Link to="/">Página Inicial</Link> - <span>Coleções</span> - </StyledBreadCrumbs> - </BreadCrumbsDiv> - <Grid container direction="row" justify="center" alignItems="center"> - <Grid item md={3}> - <CollectionAuthor - author_id={collection.owner ? collection.owner.id : 0} - name={collection.owner ? collection.owner.name : ""} - imgsrc={collection.owner ? apiDomain + collection.owner.avatar : ''} /> - </Grid> - - <Grid item md={5}> - <CollectionDescription - scrollToComments={handleScrollToComments} - title={collection.name ? collection.name : ""} - collection_id={collection.id ? collection.id : 0} /> + if (error) + return <CollectionNotFound> + <Grid container direction='column' justify='center' alignItems='center' spacing={1}> + <Grid item> + <p className="not-found"> + A coleção não foi encontrado em nossa base de dados. + </p> </Grid> - - <Grid item md={3}> - <DowloadButton - id={collection.id ? collection.id : 0} - /> - <div style={{ height: 12 }}></div> - <FollowCollectionButton - user_id={state.currentUser.id} - collection_id={collection_id} /> + <Grid item> + <Link className="link" to="/busca?query=*&search_class=Collection"> + <Button + variant='contained' + className="back-button" + > + Voltar para a busca de coleções. + </Button> + </Link> </Grid> </Grid> - - <VerticalRuler width={1} height={100} color="rgb(238, 238, 238)" /> - - <Grid container justify="center" style={{ backgroundColor: '#f4f4f4' }}> - {/* <Grid item xs={1}/> */} - <Grid item xs={10}> - <ResourceList resources={ - collection.collection_items ? - collection.collection_items.map(i => { - return { - type: i.collectionable.object_type, - author: i.collectionable.author, - title: i.collectionable.name, - rating: i.collectionable.review_average, - likeCount: i.collectionable.likes_count, - liked: i.collectionable.liked, - avatar: i.collectionable.publisher.avatar, - thumbnail: i.collectionable.thumbnail, - tags: i.collectionable.tags.map(t => t), - id: i.collectionable.id, - downloadableLink: i.collectionable.default_attachment_location, - publisher: i.collectionable.publisher.name, - published: i.collectionable.state - } - }) - : [] - } /> - + </CollectionNotFound> + else + return ( + <> + <BreadCrumbsDiv> + <StyledBreadCrumbs> + <Link to="/">Página Inicial</Link> + <span>Coleções</span> + </StyledBreadCrumbs> + </BreadCrumbsDiv> + <Grid container direction="row" justify="center" alignItems="center"> + <Grid item md={3}> + <CollectionAuthor + author_id={collection.owner ? collection.owner.id : 0} + name={collection.owner ? collection.owner.name : ""} + imgsrc={collection.owner ? apiDomain + collection.owner.avatar : ''} /> + </Grid> + + + <Grid item md={5}> + <CollectionDescription + stars={collection.review_average} + likes={collection.likes_count} + liked={collection.liked} + scrollToComments={handleScrollToComments} + title={collection.name ? collection.name : ""} + collection_id={collection.id ? collection.id : 0} /> + </Grid> + + <Grid item md={3}> + <DowloadButton + id={collection.id ? collection.id : 0} + /> + <div style={{ height: 12 }}></div> + <FollowCollectionButton + followed={collection.followed} + user_id={state.currentUser.id} + collection_id={collection_id} /> + </Grid> </Grid> - <Grid container item xs={12} style={{ marginTop: 40, paddingBottom: 40 }} ref={comment_ref}> - <CollectionCommentSection id={collection_id} /> + + <VerticalRuler width={1} height={100} color="rgb(238, 238, 238)" /> + + <Grid container justify="center" style={{ backgroundColor: '#f4f4f4' }}> + {/* <Grid item xs={1}/> */} + <Grid item xs={10}> + <ResourceList resources={ + collection.collection_items ? + collection.collection_items.map(i => { + return { + type: i.collectionable.object_type, + author: i.collectionable.author, + title: i.collectionable.name, + rating: i.collectionable.review_average, + likeCount: i.collectionable.likes_count, + liked: i.collectionable.liked, + avatar: i.collectionable.publisher.avatar, + thumbnail: i.collectionable.thumbnail, + tags: i.collectionable.tags.map(t => t), + id: i.collectionable.id, + downloadableLink: i.collectionable.default_attachment_location, + publisher: i.collectionable.publisher.name, + published: i.collectionable.state + } + }) + : [] + } /> + + </Grid> + <Grid container item xs={12} style={{ marginTop: 40, paddingBottom: 40 }} ref={comment_ref}> + <CollectionCommentSection + id={collection_id} + currentUserId={state.currentUser.id} + + /> + </Grid> </Grid> - </Grid> - </> - ); + </> + ); } const StyledBreadCrumbs = styled(Breadcrumbs)` @@ -133,6 +166,27 @@ const StyledBreadCrumbs = styled(Breadcrumbs)` } `; +const CollectionNotFound = styled.div` + margin: 1em; + + .not-found{ + font-family: 'Roboto', sans-serif; + font-weight: 500; + text-align: left; + padding: 0; + margin: 0; + } + + .back-button{ + background-color: #673ab7; + color: whitesmoke; + } + + .link{ + text-decoration: none; + } +` + const BreadCrumbsDiv = styled.div` padding: 10px; display: flex; diff --git a/src/Pages/EditProfilePage.js b/src/Pages/EditProfilePage.js index 0cf1e91667ca942dca98460c73cb6223519de77c..f85c888d5bc7624c7988c6f76119554ba0c5da05 100644 --- a/src/Pages/EditProfilePage.js +++ b/src/Pages/EditProfilePage.js @@ -59,11 +59,11 @@ export default function EditProfilePage(props) { } function handleSuccessUpdateEmail(data) { - let auth_headers = JSON.parse(sessionStorage.getItem('@portalmec/auth_headers')) + let auth_headers = JSON.parse(localStorage.getItem('@portalmec/auth_headers')) auth_headers['uid'] = data.uid - sessionStorage.setItem('@portalmec/auth_headers', JSON.stringify(auth_headers)) + localStorage.setItem('@portalmec/auth_headers', JSON.stringify(auth_headers)) const target = state.currentUser const source = { uid: data.uid } diff --git a/src/Pages/PublicUserPage.js b/src/Pages/PublicUserPage.js index 070d3cb4f7e265299ddf3efe5dfbad3124f57cbe..9b561ab6c4fd473bbcd734cb2cf80f8f0a83756b 100644 --- a/src/Pages/PublicUserPage.js +++ b/src/Pages/PublicUserPage.js @@ -37,6 +37,9 @@ import { HeaderContainer, UserProfileContainer, CoverContainer, UserProfileInfoD import { fetchAllRequest } from '../Components/HelperFunctions/getAxiosConfig' import Typography from '@material-ui/core/Typography'; import CircularProgress from '@material-ui/core/CircularProgress'; +import LoadingSpinner from '../Components/LoadingSpinner'; +import Button from '@material-ui/core/Button' +import { Link } from 'react-router-dom' function RenderFollowContainer(props) { const { state } = useContext(Store) @@ -112,9 +115,13 @@ export default function PublicUserPage(props) { setUserData(data) } /*---------------------------------------------------------*/ - const [following, setFollowing] = useState([]); + const [following, setFollowing] = useState(0); const fillFollowing = (data) => { - setFollowing(data); + if (data) + if (data.errors) + setFollowing('Você precisa logar para ver o que usuário está '); + else + setFollowing(data.length); } /*content control variables--------------------------------*/ @@ -142,7 +149,7 @@ export default function PublicUserPage(props) { handleCollections(responseArr[2]) - fillFollowing(responseArr[3]); + fillFollowing(responseArr[3]) setLoading(false); } @@ -156,8 +163,30 @@ export default function PublicUserPage(props) { }, [state.currentUser.id, props.match.params.userId]) /*---------------------------------------------------------*/ - return ( - <React.Fragment> + if (loading) + return <LoadingSpinner text="Carregando dados do usuário..." /> + else if (!userData && !following && !learningObjArr && !collectionsArr) + return <UserNotFoundDiv> + <Grid container direction='column' justify='center' alignItems='center' spacing={1}> + <Grid item> + <p className="not-found"> + O usuário não foi encontrado em nossa base de dados. + </p> + </Grid> + <Grid item> + <Link className="link" to="/busca?query=*&search_class=User"> + <Button + variant='contained' + className="back-button" + > + Voltar para a busca de usuários. + </Button> + </Link> + </Grid> + </Grid> + </UserNotFoundDiv> + else + return <React.Fragment> <link href="https://fonts.googleapis.com/css?family=Roboto:100,400,500&display=swap" rel="stylesheet" /> <BackgroundDiv> <CustomizedBreadcrumbs @@ -191,7 +220,7 @@ export default function PublicUserPage(props) { </Grid> <Grid style={{ marginTop: '0.5em', marginBottom: '0.5em', borderTop: "0.5px solid #DCDCDC", borderBottom: "0.5px solid #DCDCDC" }} container spacing={4} justify="center" alignItems="center" direction="row"> <Grid item> - <Typography variant="h6" > + <Typography variant="h6" style={{ textAlign: 'center' }}> { loading ? <CircularProgress size={20} /> : @@ -200,13 +229,11 @@ export default function PublicUserPage(props) { </Typography> </Grid> <Grid item> - <Typography variant="h6" > + <Typography variant="h6" style={{ textAlign: 'center' }} > { loading ? <CircularProgress size={20} /> : - following ? - `${following.length} seguindo` : - "0 seguindo" + `${following} seguindo` } </Typography> </Grid> @@ -221,7 +248,7 @@ export default function PublicUserPage(props) { onChange={handleChangeTab} indicatorColor="primary" textColor="primary" - variant="fullwidth" + variant="scrollable" scrollButtons="desktop" TabIndicatorProps={{ style: { background: "#00bcd4" } }} > @@ -246,7 +273,7 @@ export default function PublicUserPage(props) { {tabValue === 0 && <TabInicio id={id} user={userData} learningObjs={learningObjArr} collections={collectionsArr} />} {tabValue === 1 && - <TabRecursos count={userData.learning_objects_count} learningObjs={learningObjArr} id={id} />} + <TabRecursos id={id} username={userData.name} />} {tabValue === 2 && <TabColecoes id={id} username={userData.name} />} {tabValue === 3 && @@ -256,7 +283,6 @@ export default function PublicUserPage(props) { </Grid> </BackgroundDiv> </React.Fragment> - ) } @@ -285,6 +311,26 @@ const ProfileAvatarDiv = styled.div` } ` +const UserNotFoundDiv = styled.div` + margin: 1em; + + .not-found{ + font-family: 'Roboto', sans-serif; + font-weight: 500; + text-align: left; + padding: 0; + margin: 0; + } + + .back-button{ + background-color: #00bcd4; + color: whitesmoke; + } + + .link{ + text-decoration: none; + } +` const FollowContainer = styled.div` padding : 4px 10px; diff --git a/src/Pages/ResourcePage.js b/src/Pages/ResourcePage.js index 915b22b3fe753fefb8fe60439a012df7c6b550e1..de617c87b18f62af0c7455b16896ace3a2211ec9 100644 --- a/src/Pages/ResourcePage.js +++ b/src/Pages/ResourcePage.js @@ -36,6 +36,8 @@ import ButtonAvaliarRecurso from "../Components/ButtonAvaliarRecurso"; import ModalAvaliarRecurso from "../Components/ModalAvaliarRecurso"; import ModalConfirmarCuradoria from "../Components/ModalConfirmarCuradoria"; import { getRequest } from "../Components/HelperFunctions/getAxiosConfig"; +import Button from '@material-ui/core/Button'; +import { Link } from 'react-router-dom'; function urlVerify(url) { return url @@ -47,6 +49,7 @@ export default function LearningObjectPage(props) { const { state } = useContext(Store); const id = props.match.params.recursoId; const [carregando, toggle] = useState(true); + const [erro, setErro] = useState(false); const [recurso, setRecurso] = useState({}); function handleSuccessfulGet(data) { @@ -60,6 +63,7 @@ export default function LearningObjectPage(props) { url, handleSuccessfulGet, (error) => { + setErro(true) toggle(false); handleSnackbar(7) } @@ -137,178 +141,200 @@ export default function LearningObjectPage(props) { ); }; - return ( - <React.Fragment> - <Snackbar - open={snackbarOpen} - autoHideDuration={6000} - onClose={toggleSnackbar} - anchorOrigin={{ vertical: "top", horizontal: "right" }} - > - <Alert severity="info" - style={{ backgroundColor: "#00acc1" }}> - {snackbarText[snackbarIndex]} - </Alert> - </Snackbar> - - <ModalAvaliarRecurso - open={modalCuradoriaOpen} - handleClose={() => { - handleModalCuradoria(false); - }} - title={recurso.name} - confirm={handleConfirm} - setCriteria={setReportCriteria} - /> - <ModalConfirmarCuradoria - aceito={submissionAccepted} - reportCriteria={reportCriteria} - justificativa={justificativa} - open={modalConfirmarCuradoriaOpen} - handleClose={() => { - handleModalConfirmarCuradoria(false); - }} - cancel={() => { - handleModalCuradoria(true); - }} - recursoId={recurso.submission_id} - finalizeCuratorshipFlow={finalizeCuratorshipFlow} - handleErrorAprove={() => { - handleSnackbar(6) - }} - /> - <Background> - {carregando ? ( - <LoadingSpinner text={"Carregando Recurso"} /> - ) : ( - <> - <Grid container spacing={2}> - {recurso.object_type === "Vídeo" && !recurso.link ? ( + if (erro) + return <LearnObjectNotFound> + <Grid container direction='column' justify='center' alignItems='center' spacing={1}> + <Grid item> + <p className="not-found"> + O recurso não foi encontrado em nossa base de dados. + </p> + </Grid> + <Grid item> + <Link className="link" to="/busca?query=*&search_class=LearningObject"> + <Button + variant='contained' + className="back-button" + > + Voltar para a busca de recursos. + </Button> + </Link> + </Grid> + </Grid> + </LearnObjectNotFound> + else + return ( + <React.Fragment> + <Snackbar + open={snackbarOpen} + autoHideDuration={6000} + onClose={toggleSnackbar} + anchorOrigin={{ vertical: "top", horizontal: "right" }} + > + <Alert severity="info" + style={{ backgroundColor: "#00acc1" }}> + {snackbarText[snackbarIndex]} + </Alert> + </Snackbar> + + <ModalAvaliarRecurso + open={modalCuradoriaOpen} + handleClose={() => { + handleModalCuradoria(false); + }} + title={recurso.name} + confirm={handleConfirm} + setCriteria={setReportCriteria} + /> + <ModalConfirmarCuradoria + aceito={submissionAccepted} + reportCriteria={reportCriteria} + justificativa={justificativa} + open={modalConfirmarCuradoriaOpen} + handleClose={() => { + handleModalConfirmarCuradoria(false); + }} + cancel={() => { + handleModalCuradoria(true); + }} + recursoId={recurso.submission_id} + finalizeCuratorshipFlow={finalizeCuratorshipFlow} + handleErrorAprove={() => { + handleSnackbar(6) + }} + /> + <Background> + {carregando ? ( + <LoadingSpinner text={"Carregando Recurso"} /> + ) : ( + <> + <Grid container spacing={2}> + {recurso.object_type === "Vídeo" && !recurso.link ? ( + <Grid item xs={12}> + <Card> + <VideoPlayer + link={recurso.link} + urlVerified={false} + videoUrl={recurso.default_attachment_location} + videoType={recurso.default_mime_type} + /> + </Card> + </Grid> + ) : ( + urlVerify(recurso.link) && ( + <Grid item xs={12}> + <Card> + <VideoPlayer link={recurso.link} urlVerified={true} /> + </Card> + </Grid> + ) + )} + <Grid item xs={12}> <Card> - <VideoPlayer - link={recurso.link} - urlVerified={false} - videoUrl={recurso.default_attachment_location} - /> - </Card> - </Grid> - ) : ( - urlVerify(recurso.link) && ( - <Grid item xs={12}> - <Card> - <VideoPlayer link={recurso.link} urlVerified={true} /> - </Card> - </Grid> - ) - )} + <div> + {recurso.thumbnail && ( + <img alt="" src={apiDomain + recurso.thumbnail} /> + )} - <Grid item xs={12}> - <Card> - <div> - {recurso.thumbnail && ( - <img alt="" src={apiDomain + recurso.thumbnail} /> - )} + <TextoObjeto + name={recurso.name} + rating={recurso.review_average} + recursoId={id} + likesCount={recurso.likes_count} + likedBool={recurso.liked} + objType={recurso.object_type} + subjects={recurso.subjects} + educationalStages={recurso.educational_stages} + viewCount={recurso.views_count} + downloadCount={recurso.downloads_count} + id={recurso.publisher ? recurso.publisher.id : undefined} + stateRecurso={recurso.state} + attachments={recurso.attachments} + audioUrl={recurso.default_attachment_location} + /> + </div> - <TextoObjeto - name={recurso.name} - rating={recurso.review_average} + <Footer recursoId={id} - likesCount={recurso.likes_count} - likedBool={recurso.liked} - objType={recurso.object_type} - subjects={recurso.subjects} - educationalStages={recurso.educational_stages} - viewCount={recurso.views_count} - downloadCount={recurso.downloads_count} - id={recurso.publisher ? recurso.publisher.id : undefined} - stateRecurso={recurso.state} - attachments={recurso.attachments} - audioUrl={recurso.default_attachment_location} + downloadableLink={recurso.default_attachment_location} + handleSnackbar={handleSnackbar} + link={recurso.link} + title={recurso.name} + thumb={recurso.thumbnail} + currPageLink={window.location.href} + complained={recurso.complained} /> - </div> - - <Footer - recursoId={id} - downloadableLink={recurso.default_attachment_location} - handleSnackbar={handleSnackbar} - link={recurso.link} - title={recurso.name} - thumb={recurso.thumbnail} - currPageLink={window.location.href} - complained={recurso.complained} - /> - </Card> - </Grid> - - <Grid item xs={12}> - <Card> - {/*todo: change render method on additional item info*/} - <Sobre - avatar={ - recurso.publisher - ? recurso.publisher.avatar - ? apiDomain + recurso.publisher.avatar - : noAvatar - : noAvatar - } - publisher={ - recurso.publisher ? recurso.publisher.name : undefined - } - id={recurso.publisher ? recurso.publisher.id : undefined} - description={recurso.description} - author={recurso.author} - tags={recurso.tags} - attachments={recurso.attachments} - language={recurso.language} - mimeType={recurso.default_mime_type} - createdAt={recurso.created_at} - updatedAt={recurso.updated_at} - license={recurso.license} - followed={recurso.publisher ? recurso.publisher.followed : undefined} - /> - </Card> - </Grid> + </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} + {/*todo: change render method on additional item info*/} + <Sobre + avatar={ + recurso.publisher + ? recurso.publisher.avatar + ? apiDomain + recurso.publisher.avatar + : noAvatar + : noAvatar + } + publisher={ + recurso.publisher ? recurso.publisher.name : undefined + } + id={recurso.publisher ? recurso.publisher.id : undefined} + description={recurso.description} + author={recurso.author} + tags={recurso.tags} + attachments={recurso.attachments} + language={recurso.language} + mimeType={recurso.default_mime_type} + createdAt={recurso.created_at} + updatedAt={recurso.updated_at} + license={recurso.license} + followed={recurso.publisher.followed} /> </Card> </Grid> - )} - </Grid> - - {recurso.state === "submitted" && checkAccessLevel("curator") && ( - <AppBar - position="fixed" - color="primary" - className={classes.appBar} - > - <StyledAppBarContainer> - <div className="container"> - <div className="botoes"> - <ButtonAvaliarRecurso - callback={() => { - handleModalCuradoria(true); - }} + + {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> + + {recurso.state === "submitted" && checkAccessLevel("curator") && ( + <AppBar + position="fixed" + color="primary" + className={classes.appBar} + > + <StyledAppBarContainer> + <div className="container"> + <div className="botoes"> + <ButtonAvaliarRecurso + callback={() => { + handleModalCuradoria(true); + }} + /> + </div> </div> - </div> - </StyledAppBarContainer> - </AppBar> - )} - </> - )} - </Background> - </React.Fragment> - ); + </StyledAppBarContainer> + </AppBar> + )} + </> + )} + </Background> + </React.Fragment> + ); } const useStyles = makeStyles((theme) => ({ @@ -353,6 +379,27 @@ const Background = styled.div` padding-top: 30px; `; +const LearnObjectNotFound = styled.div` + margin: 1em; + + .not-found{ + font-family: 'Roboto', sans-serif; + font-weight: 500; + text-align: left; + padding: 0; + margin: 0; + } + + .back-button{ + background-color: #ff7f00; + color: whitesmoke; + } + + .link{ + text-decoration: none; + } +` + const Card = styled.div` background-color: #fff; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24); diff --git a/src/Pages/Search.js b/src/Pages/Search.js index 9b6689c2f054f3f37a010e9f8f9d1f3e35a76870..df73156155fd5ba1405a6601bd900df4448c7efa 100644 --- a/src/Pages/Search.js +++ b/src/Pages/Search.js @@ -142,8 +142,10 @@ export default function Search(props) { }, [window.history.state === null ? true : window.history.state.key, state.currentUser.id]) useEffect(() => { - //setIsLoading(true); - collectStuff(option); + if (resultsPerPage > 12) { + setIsLoading(true); + collectStuff(option); + } }, [resultsPerPage]); return ( diff --git a/src/Store.js b/src/Store.js index 2cf8d373cb9b4f3f88c18bfd71199b893af0886d..0cb5c0333ff49866a8125e8eb30e88582a815db9 100644 --- a/src/Store.js +++ b/src/Store.js @@ -91,7 +91,7 @@ function reducer(state, action) { currentUser:action.user } case 'USER_LOGGED_OUT': - sessionStorage.clear() + localStorage.clear() return { ...state, userIsLoggedIn:action.userLoggedOut, diff --git a/src/index.css b/src/index.css index c58acf407174355d6850f9fb9dc97e2d466826c5..0e81d082e9db63e3b8940c84cdff4756272f0d94 100755 --- a/src/index.css +++ b/src/index.css @@ -22,6 +22,7 @@ body { overflow-x: hidden; margin: 0; padding: 0; + overflow-x: hidden; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;