diff --git a/src/Components/CollectionCommentSection.js b/src/Components/CollectionCommentSection.js index 7360158cbe59c85932850b89b1bb50d30bbcfc2a..280e749a626e31e164b58404d48e32f2825ce14f 100644 --- a/src/Components/CollectionCommentSection.js +++ b/src/Components/CollectionCommentSection.js @@ -18,14 +18,103 @@ along with Plataforma Integrada MEC. If not, see <http://www.gnu.org/licenses/> import React, { useState, useEffect } from 'react'; import { Grid } from '@material-ui/core'; +import Card from '@material-ui/core/Card'; import styled from 'styled-components'; import axios from 'axios'; import { apiUrl } from '../env'; +import CommentForm from './ResourcePageComponents/CommentForm.js'; +import Comment from './Comment.js'; +import Snackbar from '@material-ui/core/Snackbar'; +import MuiAlert from '@material-ui/lab/Alert'; 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 [reviews, setReviews] = useState([]); + + const forceUpdate = () => { setRenderState(!render_state); } + + const handlePostSnackbar = () => { + setPostSnackOpen(!post_snack_open); + } + + const handleDeleteSnackbar = () => { + setDeleteSnackOpen(!delete_snack_open); + } + + function Alert(props) { + return <MuiAlert elevation={6} variant="filled" {...props} />; + } + + useEffect(() => { + axios.get(apiUrl+'/collections/'+props.id+'/reviews') + .then(res => { + setReviews(res.data); + }); + }, [render_state]); return ( - <Grid container direction="row" justify="center" alignItems="center"> - </Grid> + <CommentAreaContainer container xs={12} direction="row" justify="center" alignItems="center"> + <Grid item xs={12}> + <CommentAreaCard> + <Title>Conte sua experiência com a coleção</Title> + <CommentForm colecao recursoId={props.id} + handleSnackbar={handlePostSnackbar} + rerenderCallback={forceUpdate}/> + <Title>{reviews.length} {reviews.length == 1 ? "Relato" : "Relatos"} sobre a Coleção</Title> + {reviews.map(r => { + return ( + <Comment + rerenderCallback={forceUpdate} + objectID={props.id} + reviewID={r.id} + reviewRatings={r.review_ratings} + authorID={r.user.id} + rating={r.rating_average} + authorName={r.user.name} + authorAvatar={r.user.avatar} + description={r.description} + createdAt={r.created_at} + handleSnackbar={handleDeleteSnackbar} + recurso={false} + /> + ); + })} + </CommentAreaCard> + </Grid> + <Snackbar + open={post_snack_open} + autoHideDuration={6000} + onClose={handlePostSnackbar} + anchorOrigin={{vertical: 'top', horizontal: 'right'}} + > + <Alert onClose={handlePostSnackbar} severity="info"> + Seu comentário foi publicado com sucesso! + </Alert> + </Snackbar> + <Snackbar + open={delete_snack_open} + autoHideDuration={6000} + onClose={handleDeleteSnackbar} + anchorOrigin={{vertical: 'top', horizontal: 'right'}} + > + <Alert onClose={handleDeleteSnackbar} severity="info"> + Comentário deletado com sucesso. + </Alert> + </Snackbar> + </CommentAreaContainer> ); } + +const CommentAreaContainer=styled(Grid)` + margin-left: 10%; + margin-right: 10%; +` +const CommentAreaCard=styled(Card)` + padding: 45px; +` +const Title=styled.h1` + font-weight: 100; + color: #666; +` diff --git a/src/Components/CollectionDescription.js b/src/Components/CollectionDescription.js index 09ffd828e6f744e8687baedbef36a7c4910eaef4..062a13bca5ba4b24c3eee0b3889131eda749b209 100644 --- a/src/Components/CollectionDescription.js +++ b/src/Components/CollectionDescription.js @@ -27,7 +27,7 @@ import styled from 'styled-components'; import LinearProgress from '@material-ui/core/LinearProgress'; import CollectionReview from './CollectionReview.js'; import FollowCollectionButton from './FollowCollectionButton.js'; -import { apiUrl } from '../env'; +import { apiUrl, apiDomain } from '../env'; export default function CollectionDescription(props) { const { state } = useContext(Store); @@ -41,9 +41,10 @@ export default function CollectionDescription(props) { axios .post(apiUrl+'/package', body) .catch(err => { - if (err.response && err.response.status === 302) - setDownloadUrl = apiUrl+'/'+err.response.data.url; - });}, []); + if (err.response && err.response.status === 302) { + setDownloadUrl(apiDomain+'/'+err.response.data.url); + } + });}, [props.collection_id]); return ( <Grid container direction="column" justify="center" alignItems="center"> @@ -62,7 +63,7 @@ export default function CollectionDescription(props) { direction="column" justify="center" alignItems="flex-end" > <Grid item style={{marginBottom: 10}}> - <a href={download_url} > + <DownloadAnchor href={download_url} > <DownloadButton variant="outlined" color="primary" @@ -71,7 +72,7 @@ export default function CollectionDescription(props) { > <ButtonText>Baixar Coleção</ButtonText> </DownloadButton> - </a> + </DownloadAnchor> </Grid> <Grid item> <FollowCollectionButton user_id={state.currentUser.id} collection_id={props.collection_id}/> @@ -97,3 +98,6 @@ const DownloadButton=styled(Button)` padding-right: 10; width: 250px; ` +const DownloadAnchor=styled.a` + text-decoration: none !important; +` diff --git a/src/Components/CollectionReview.js b/src/Components/CollectionReview.js index dd7876c0a20e64d1dfcc7c2414cb61558ed8b601..be63b1d3a1a81e92d4358956a3461ea6302f3c9d 100644 --- a/src/Components/CollectionReview.js +++ b/src/Components/CollectionReview.js @@ -55,7 +55,7 @@ export default function CollectionReview(props) { const handleLikeClick = () => { if (state.currentUser.id) { const url = apiUrl+'/collections/'+props.id+'/like'; - if (liked) + if (!liked) axios.put(url); else axios.delete(url); diff --git a/src/Components/FloatingDownloadButton.js b/src/Components/FloatingDownloadButton.js new file mode 100644 index 0000000000000000000000000000000000000000..5d78b87d0f5eebc66b5fd63a478b13fa00147ccd --- /dev/null +++ b/src/Components/FloatingDownloadButton.js @@ -0,0 +1,72 @@ +/*Copyright (C) 2019 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana + +This file is part of Plataforma Integrada MEC. + +Plataforma Integrada MEC is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Plataforma Integrada MEC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with Plataforma Integrada MEC. If not, see <http://www.gnu.org/licenses/>.*/ + +import React, { useState, useEffect } from 'react'; +import styled from 'styled-components'; +import axios from 'axios'; +import {apiUrl} from '../env'; +import GetAppIcon from '@material-ui/icons/GetApp'; +import Fab from '@material-ui/core/Fab'; +import Snackbar from '@material-ui/core/Snackbar'; +import MuiAlert from '@material-ui/lab/Alert'; + +function Alert(props) { + return <MuiAlert elevation={6} variant="filled" {...props} />; +} + +export default function FloatingDownloadButton (props) { + const [snackbar, setSnackbar] = useState(false); + + const handleClickDownload = () => { + if (props.empty_selection) + setSnackbar(true); + } + + const handleClose = () => { + setSnackbar(false); + } + + return ( + <div> + <DownloadAnchor href={props.url} alt="Baixar recursos selecionados"> + <FloatingDownload + color="primary" + aria-label="download" + onClick={handleClickDownload} + > + <GetAppIcon /> + </FloatingDownload> + </DownloadAnchor> + <Snackbar open={snackbar} autoHideDuration={6000} onClose={handleClose}> + <Alert onClose={handleClose} severity="alert"> + Selecione recursos para poder baixar + </Alert> + </Snackbar> + </div> + ); +} + +const DownloadAnchor=styled.a` + text-decoration: none !important; +` + +const FloatingDownload=styled(Fab)` + position: fixed !important; + right: 15px !important; + bottom: 25px !important; +` diff --git a/src/Components/FollowCollectionButton.js b/src/Components/FollowCollectionButton.js index 185a17f177fda0597157a6bf8d3dee3a0ef46743..5e3fd33c9ce3b789de2d15373e63e6858b937752 100644 --- a/src/Components/FollowCollectionButton.js +++ b/src/Components/FollowCollectionButton.js @@ -90,7 +90,7 @@ export default function FollowCollectionButton(props) { } }; - if (props.user_is_owner) + if (!props.user_is_owner) return ( <div> <FollowButton diff --git a/src/Components/ResourceList.js b/src/Components/ResourceList.js index d325074daf1e760277201527c43fe27eb6dddf6c..28203fddea969239b7876ca001cdb2e04df8a00a 100644 --- a/src/Components/ResourceList.js +++ b/src/Components/ResourceList.js @@ -16,21 +16,32 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with Plataforma Integrada MEC. If not, see <http://www.gnu.org/licenses/>.*/ -import React, { useState } from 'react'; +import React, { useState, useEffect } from 'react'; import { Grid } from '@material-ui/core'; import styled from 'styled-components'; +import axios from 'axios'; import Button from '@material-ui/core/Button'; import CheckBoxOutlineBlankIcon from '@material-ui/icons/CheckBoxOutlineBlank'; import CheckBoxIcon from '@material-ui/icons/CheckBox'; import GetAppIcon from '@material-ui/icons/GetApp'; import ResourceCardFunction from './ResourceCardFunction.js'; +import FloatingDownloadButton from './FloatingDownloadButton.js'; import CircularProgress from '@material-ui/core/CircularProgress'; +import Snackbar from '@material-ui/core/Snackbar'; +import MuiAlert from '@material-ui/lab/Alert'; +import { apiUrl } from '../env.js'; + +function Alert(props) { + return <MuiAlert elevation={6} variant="filled" {...props} />; +} export default function ResourceList(props) { const [selected, setSelected] = useState(Array.apply( null, {length: props.resources.length}).map(i => false)); const [selectable, setSelectable] = useState(false); + const [download_url, setDownloadUrl] = useState(''); + const [snackbar_open, setSnackbarOpen] = useState(false); const updateSelected = (index) => { let new_selected = selected.slice(); @@ -47,8 +58,33 @@ export default function ResourceList(props) { const handleDownloadSelection = () => { const selected_resources = props.resources.filter(resource => selected[props.resources.indexOf(resource)]); + setSnackbarOpen(true); } + useEffect(() => { + if (selectable) { + var resources = [] + let i = 0; + while (i < props.resources.length) { + if (selected[i]) + resources.push({"type": "LearningObject", "id": props.resources[i].id}); + i++; + } + const body = { + "package": { + "object": resources + }}; + if (resources.length) + axios + .post(apiUrl+'/package', body) + .catch(err => { + if (err.response && err.response.status === 302) { + setDownloadUrl(apiUrl.slice().replace('/v1', '')+'/'+err.response.data.url); + } + }); + } + }, [selected, selectable]); + return ( <ResourceListContainer> <Grid container direction="row" justify="space-around" alignItems="center"> @@ -67,14 +103,16 @@ export default function ResourceList(props) { </Button> </Grid> <Grid item> - <Button - color="primary" - variant="outlined" - startIcon={<GetAppIcon fontSize="large"/>} - onClick={handleDownloadSelection} - > - <PanelButtonText>baixar seleção</PanelButtonText> - </Button> + <UnstyledAnchor href={download_url}> + <Button + color="primary" + variant="outlined" + startIcon={<GetAppIcon fontSize="large"/>} + onClick={handleDownloadSelection} + > + <PanelButtonText>baixar seleção</PanelButtonText> + </Button> + </UnstyledAnchor> </Grid> </Grid> <Grid container direction="row" justify="flex-start" alignItems="center"> @@ -108,6 +146,17 @@ export default function ResourceList(props) { ); })} </Grid> + <Snackbar + open={snackbar_open} + autoHideDuration={6000} + onClose={() => setSnackbarOpen(false)} + anchorOrigin={{vertical: 'top', horizontal: 'right'}} + > + <Alert onClose={() => setSnackbarOpen(false)} severity="info"> + Os recursos serão baixados + </Alert> + </Snackbar> + <FloatingDownloadButton url={download_url} empty={selected.indexOf(true) == -1}/> </ResourceListContainer> ); } @@ -130,3 +179,6 @@ const PanelButtonText=styled.span` const ResourceGrid=styled(Grid)` padding-right: 7px; ` +const UnstyledAnchor=styled.a` + text-decoration: none !important; +` diff --git a/src/Pages/CollectionPage.js b/src/Pages/CollectionPage.js index 13d3ce17caeb40bd02c0b62fbd3233b7317ccf35..f7b3a32e0016fde9b1370e7f5d5024549a7b4ed5 100644 --- a/src/Pages/CollectionPage.js +++ b/src/Pages/CollectionPage.js @@ -2,7 +2,6 @@ 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 @@ -34,12 +33,11 @@ export default function CollectionPage(props) { }); const collection_id = props.match.params.id; const comment_ref = useRef(null); - + useEffect(()=>{ axios.get(apiUrl+'/collections/'+collection_id) .then(res => { setCollection(Object.assign({}, res.data)); - console.log(res.data); }); }, []); @@ -70,7 +68,7 @@ export default function CollectionPage(props) { collection_id={collection.id ? collection.id : 0}/> </Grid> - <Grid container item direction="row" justify="center" alignItems="center" style={{backgroundColor: '#f4f4f4'}}> + <Grid container item xs={12} direction="row" justify="center" alignItems="center" style={{backgroundColor: '#f4f4f4'}}> <Grid item xs={10}> <ResourceList resources={ collection.collection_items ? @@ -86,14 +84,15 @@ export default function CollectionPage(props) { avatar: i.collectionable.publisher.avatar, thumbnail: i.collectionable.thumbnail, tags: i.collectionable.tags.map(t => t.name), + id: i.collectionable.id, } }) : [] }/> </Grid> - <Grid item xs={10} style={{marginTop: 40}} ref={comment_ref}> - <CollectionCommentSection /> + <Grid container item xs={12} style={{marginTop: 40}} ref={comment_ref}> + <CollectionCommentSection id={collection_id}/> </Grid> </Grid> </Grid>