diff --git a/src/Components/AchievementDescriptionCard.js b/src/Components/AchievementDescriptionCard.js index ae7d17ac4d6aea382668e6cd8a72cbef68d23878..8bd0bbb6def079fc7d9acd4929798b7fa1095042 100644 --- a/src/Components/AchievementDescriptionCard.js +++ b/src/Components/AchievementDescriptionCard.js @@ -15,161 +15,48 @@ 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, { useEffect } from 'react'; -import { makeStyles } from '@material-ui/core/styles'; -import clsx from 'clsx'; +import React from 'react'; +import styled from 'styled-components'; +import Grid from '@material-ui/core/Grid'; import Card from '@material-ui/core/Card'; -import CardHeader from '@material-ui/core/CardHeader'; import CardContent from '@material-ui/core/CardContent'; -import CardActions from '@material-ui/core/CardActions'; -import Collapse from '@material-ui/core/Collapse'; -import Avatar from '@material-ui/core/Avatar'; -import IconButton from '@material-ui/core/IconButton'; -import Typography from '@material-ui/core/Typography'; -import { red } from '@material-ui/core/colors'; -import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; -import List from '@material-ui/core/List'; -import ListItem from '@material-ui/core/ListItem'; -import ListItemText from '@material-ui/core/ListItemText'; -import PropTypes from 'prop-types'; -import CircularProgress from '@material-ui/core/CircularProgress'; -import Box from '@material-ui/core/Box'; -import { ListItemAvatar, Button } from '@material-ui/core'; -import Tooltip from '@material-ui/core/Tooltip'; -import Badge from '@material-ui/core/Badge'; - - -const useStyles = makeStyles((theme) => ({ - root: { - maxWidth: 345, - }, - media: { - height: 0, - paddingTop: '56.25%', // 16:9 - }, - expand: { - transform: 'rotate(0deg)', - marginLeft: 'auto', - transition: theme.transitions.create('transform', { - duration: theme.transitions.duration.shortest, - }), - }, - expandOpen: { - transform: 'rotate(180deg)', - }, - avatar: { - backgroundColor: red[500], - }, -})); - -export default function BadgeCard({ name, description, goal, counter }) { - const classes = useStyles(); - - const [invisibleBadge, setInvisibleBadge] = React.useState(true); - const [disabledButton, setDisabledButton] = React.useState(true); - const [expanded, setExpanded] = React.useState(false); - - const handleExpandClick = () => { - setExpanded(!expanded); - setInvisibleBadge(true); - }; - - function CircularProgressWithLabel(props) { - return ( - <Box position="relative" display="inline-flex"> - <CircularProgress variant="determinate" {...props} /> - <Box - top={0} - left={0} - bottom={0} - right={0} - position="absolute" - display="flex" - alignItems="center" - justifyContent="center" - > - <Typography variant="caption" component="div" color="textSecondary">{`${Math.round( - props.value, - )}%`}</Typography> - </Box> - </Box> - ); - } - - CircularProgressWithLabel.propTypes = { - /** - * The value of the progress indicator for the determinate variant. - * Value between 0 and 100. - */ - value: PropTypes.number.isRequired, - }; - - const Progress = (steps, currStep) => { - return (currStep / steps) * 100 - } - - const Color = (steps, currStep) => { - const progress = (currStep / steps) * 100; - - if (progress === 100) - return "#28B463"; - else if (progress < 30) - return "#CB4335"; - return "#2874A6"; - } - +import CheckCircleOutlineIcon from '@material-ui/icons/CheckCircleOutline'; + +const ItemName = styled.h3` + display: -webkit-box; + -webkit-line-clamp: 3; + -webkit-box-orient: vertical; + overflow: hidden; + font-size: 1.5em; + font-weight: lighter; + color: #666666; + width: 100%; + word-break: break-word; + line-height: 1.3; +` + +const ItemDescription = styled.p` + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; + font-size: 1.2em; + color: #666666; + line-height: 1.3; +` + +export default function ItemCard({ name, description }) { return ( - <Card className={classes.root}> - <CardHeader - avatar={ - <Avatar /> - } - title={name} - action={ - <IconButton - className={clsx(classes.expand, { - [classes.expandOpen]: expanded, - })} - onClick={handleExpandClick} - aria-expanded={expanded} - aria-label="show more" - > - <Badge color="secondary" variant="dot" invisible={invisibleBadge}> - <ExpandMoreIcon /> - </Badge> - </IconButton> - - - } - /> - <Collapse in={expanded} timeout="auto" unmountOnExit> + <Grid item xs={11} sm={3} md={2} > + <Card style={{ textAlign: 'center'}}> <CardContent> + <ItemName>{name}</ItemName> + <ItemDescription>{description}</ItemDescription> <div> - <Typography variant="h6" color="textPrimary" component="p"> - Descrição - </Typography> - <Typography variant="body2" color="textSecondary" component="p"> - {description} - </Typography> - </div> - - <div style={{ marginTop: "8px" }}> - <Typography variant="h6" color="textPrimary" component="p"> - Requisitos - </Typography> - <List component="nav" aria-label="mailbox folders"> - <ListItem divider> - <Tooltip arrow title={`${counter} / ${goal}`}> - <ListItemAvatar> - <CircularProgressWithLabel value={Progress(goal, counter)} style={{ color: Color(goal, counter) }} /> - </ListItemAvatar> - </Tooltip> - <ListItemText primary={name} /> - </ListItem> - </List> + <CheckCircleOutlineIcon style={{fill : 'green'}}/> </div> </CardContent> - </Collapse> - </Card> - ); + </Card> + </Grid> + ) } diff --git a/src/Components/ProgressDescriptionCard.js b/src/Components/ProgressDescriptionCard.js new file mode 100644 index 0000000000000000000000000000000000000000..52f52b3b5f0d47871ccfbaa056b1d2177981e728 --- /dev/null +++ b/src/Components/ProgressDescriptionCard.js @@ -0,0 +1,112 @@ +/*Copyright (C) 2019 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana + +This file is part of Plataforma Integrada MEC. + +Plataforma Integrada MEC is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Plataforma Integrada MEC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with Plataforma Integrada MEC. If not, see <http://www.gnu.org/licenses/>.*/ +import React from 'react'; +import styled from 'styled-components'; +import Grid from '@material-ui/core/Grid'; +import Card from '@material-ui/core/Card'; +import CardContent from '@material-ui/core/CardContent'; +import Typography from '@material-ui/core/Typography'; +import PropTypes from 'prop-types'; +import CircularProgress from '@material-ui/core/CircularProgress'; +import Box from '@material-ui/core/Box'; +import Tooltip from '@material-ui/core/Tooltip' +import ListItemAvatar from '@material-ui/core/ListItemAvatar' + +const ItemName = styled.h3` + display: -webkit-box; + -webkit-line-clamp: 3; + -webkit-box-orient: vertical; + overflow: hidden; + font-size: 1.5em; + font-weight: lighter; + color: #666666; + width: 100%; + word-break: break-word; + line-height: 1.3; +` + +export default function ItemCard({ description, goal, counter }) { + + function CircularProgressWithLabel(props) { + return ( + <Box position="relative" display="inline-flex"> + <CircularProgress variant="determinate" {...props} /> + <Box + top={0} + left={0} + bottom={0} + right={0} + position="absolute" + display="flex" + alignItems="center" + justifyContent="center" + > + <Typography variant="caption" component="div" color="textSecondary">{`${Math.round( + props.value, + )}%`}</Typography> + </Box> + </Box> + ); + } + + CircularProgressWithLabel.propTypes = { + /** + * The value of the progress indicator for the determinate variant. + * Value between 0 and 100. + */ + value: PropTypes.number.isRequired, + }; + + const showToolTip = (steps, currSteps) => { + if (currSteps >= steps) + return 'Completado' + return `${currSteps} / ${steps}` + } + + const Progress = (steps, currStep) => { + if (currStep >= steps) + return 100 + else + return (currStep / steps) * 100 + } + + const Color = (steps, currStep) => { + const progress = (currStep / steps) * 100; + + if (progress >= 100) + return "#28B463"; + else if (progress < 30) + return "#CB4335"; + return "#2874A6"; + } + + return ( + <Grid item xs={11} sm={3} md={2} > + <Card style={{ textAlign: 'center' }}> + <CardContent> + <ItemName>{description}</ItemName> + <Tooltip arrow title={showToolTip(goal, counter)}> + <ListItemAvatar> + <CircularProgressWithLabel value={Progress(goal, counter)} style={{ color: Color(goal, counter) }} /> + </ListItemAvatar> + </Tooltip> + </CardContent> + </Card> + </Grid> + ) +} diff --git a/src/Components/TabPanels/AchivementsCarrosel.js b/src/Components/TabPanels/AchivementsCarrosel.js new file mode 100644 index 0000000000000000000000000000000000000000..638544f2c807b4ebc58ebec20c7dbde089e68312 --- /dev/null +++ b/src/Components/TabPanels/AchivementsCarrosel.js @@ -0,0 +1,82 @@ +/*Copyright (C) 2019 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana + +This file is part of Plataforma Integrada MEC. + +Plataforma Integrada MEC is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Plataforma Integrada MEC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with Plataforma Integrada MEC. If not, see <http://www.gnu.org/licenses/>.*/ +import React, { useState } from 'react'; +import Grid from '@material-ui/core/Grid'; +import ArrowBackIcon from '@material-ui/icons/ArrowBack'; +import ArrowForwardIcon from '@material-ui/icons/ArrowForward'; +import IconButton from '@material-ui/core/IconButton'; +import AchievementDescriptionCard from '../AchievementDescriptionCard.js' + +export default function AchievementsCarousel(props) { + const [left, setLeft] = useState(0); + const [right, setRight] = useState(objectsPerPage()); + + function objectsPerPage() { + var pageWidth = window.innerWidth + if (pageWidth >= 1000) { + return 5 + } + else { + if (pageWidth > 766) { + return 3 + } + else { + return 1 + } + } + } + + const goLeft = () => { + setRight(right === 0 ? props.items.length - 1 : right - 1); + setLeft(left === 0 ? props.items.length - 1 : left - 1); + } + + const goRight = () => { + if (right === props.items.length - 2) + if (!props.stop) + props.setCurrPage() + setRight(right === props.items.length - 1 ? 0 : right + 1); + setLeft(left === props.items.length - 1 ? 0 : left + 1); + } + + return ( + <Grid + item container + direction="row" + justify="center" + alignItems="center" + spacing={3} + > + <IconButton onClick={goLeft}> + <ArrowBackIcon /> + </IconButton> + {(left > right ? + props.items.slice(left, props.items.length).concat(props.items.slice(0, right)) + : props.items.slice(left, right) + ).map((i) => { + return <AchievementDescriptionCard + name={i.achievement.name} + description={i.achievement.description} + /> + })} + <IconButton onClick={goRight} disabled={props.disabled}> + <ArrowForwardIcon /> + </IconButton> + </Grid> + ) +} diff --git a/src/Components/TabPanels/ProgressCarrosel.js b/src/Components/TabPanels/ProgressCarrosel.js new file mode 100644 index 0000000000000000000000000000000000000000..6831ca40542fa98b838655083a823972feccb36a --- /dev/null +++ b/src/Components/TabPanels/ProgressCarrosel.js @@ -0,0 +1,83 @@ +/*Copyright (C) 2019 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana + +This file is part of Plataforma Integrada MEC. + +Plataforma Integrada MEC is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Plataforma Integrada MEC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with Plataforma Integrada MEC. If not, see <http://www.gnu.org/licenses/>.*/ +import React, { useState } from 'react'; +import Grid from '@material-ui/core/Grid'; +import ArrowBackIcon from '@material-ui/icons/ArrowBack'; +import ArrowForwardIcon from '@material-ui/icons/ArrowForward'; +import IconButton from '@material-ui/core/IconButton'; +import ProgressDescriptionCard from '../ProgressDescriptionCard.js' + +export default function AchievementsCarousel(props) { + const [left, setLeft] = useState(0); + const [right, setRight] = useState(objectsPerPage()); + + function objectsPerPage() { + var pageWidth = window.innerWidth + if (pageWidth >= 1000) { + return 5 + } + else { + if (pageWidth > 766) { + return 3 + } + else { + return 1 + } + } + } + + const goLeft = () => { + setRight(right === 0 ? props.items.length - 1 : right - 1); + setLeft(left === 0 ? props.items.length - 1 : left - 1); + } + + const goRight = () => { + if (right === props.items.length - 2) + if (!props.stop) + props.setCurrPage() + setRight(right === props.items.length - 1 ? 0 : right + 1); + setLeft(left === props.items.length - 1 ? 0 : left + 1); + } + + return ( + <Grid + item container + direction="row" + justify="center" + alignItems="center" + spacing={3} + > + <IconButton onClick={goLeft}> + <ArrowBackIcon /> + </IconButton> + {(left > right ? + props.items.slice(left, props.items.length).concat(props.items.slice(0, right)) + : props.items.slice(left, right) + ).map((i) => { + return <ProgressDescriptionCard + counter={i.counter} + goal={i.requirement.goal} + description={i.requirement.description} + /> + })} + <IconButton onClick={goRight} disabled={props.disabled}> + <ArrowForwardIcon /> + </IconButton> + </Grid> + ) +} diff --git a/src/Components/TabPanels/TabPanelStatusEConquistas.js b/src/Components/TabPanels/TabPanelStatusEConquistas.js index 0494848245e512def9bff5ae01acd09e984f6ad1..23417d7d15f412f33d8a292b8ffe46d8c5fc33a2 100644 --- a/src/Components/TabPanels/TabPanelStatusEConquistas.js +++ b/src/Components/TabPanels/TabPanelStatusEConquistas.js @@ -22,26 +22,59 @@ import styled from 'styled-components' import Paper from '@material-ui/core/Paper'; import { UserProfileContainer } from './StyledComponents.js' import LevelDescriptionCard from '../LevelDescriptionCard.js' -import AchievementDescriptionCard from '../AchievementDescriptionCard.js' -import { Grid } from '@material-ui/core' import { getRequest } from '../HelperFunctions/getAxiosConfig' +import AchievementsCarosel from './AchivementsCarrosel' +import ProgressCarosel from './ProgressCarrosel' export default function TabPanelStatusEConquistas({ id, level, levelXP, points, experience }) { + const [achievements, setAchievements] = useState([]) + const [totalAchievements, setTotalAchievements] = useState(0) + const [currPageAchievements, setCurrPageAchievements] = useState(0) + const [disableAchievements, setDisableAchievements] = useState(false) + const [stopAchievements, setStopAchievements] = useState(false) + const [progress, setProgress] = useState([]) + const [totalProgress, setTotalProgress] = useState(0) const [currPageProgress, setCurrPageProgress] = useState(0) + const [disableProgress, setDisableProgress] = useState(false) + const [stopProgress, setStopProgress] = useState(false) - const buildUrl = (page) => { - return `/progresses?page=${page}&range=[0,9]&results_per_page=10&sort=["id","DESC"]` + const buildUrl = (page, type) => { + return `/${type}?page=${page}&range=[0,9]&results_per_page=10&sort=["id","DESC"]` } useEffect(() => { + setDisableAchievements(true) getRequest( - buildUrl(currPageProgress), + buildUrl(currPageAchievements, 'unlocked_achievements'), (data, header) => { - setProgress((previousState) => previousState.concat(data)) + if (data.length === 0) + setStopAchievements(true) + if (header.has('X-Total-Count')) + setTotalAchievements(header.get('X-Total-Count')) + setAchievements((previousState) => previousState.concat(data)) + setDisableAchievements(false) }, (error) => { + setDisableAchievements(false) + } + ) + }, [currPageAchievements]) + useEffect(() => { + setDisableProgress(true) + getRequest( + buildUrl(currPageProgress, 'progresses'), + (data, header) => { + if (data.length === 0) + setStopProgress(true) + if (header.has('X-Total-Count')) + setTotalProgress(header.get('X-Total-Count')) + setProgress((previousState) => previousState.concat(data)) + setDisableProgress(false) + }, + (error) => { + setDisableProgress(false) } ) }, [currPageProgress]) @@ -63,24 +96,29 @@ export default function TabPanelStatusEConquistas({ id, level, levelXP, points, <Paper elevation={3} style={{ padding: '1em' }}> <AchievementsList> <AchievementsSectionTitle> - Progresso + Últimas conquistas ({totalAchievements}) + </AchievementsSectionTitle> + <AchievementsCarosel + items={achievements} + setCurrPage={() => { setCurrPageAchievements(currPageAchievements + 1) }} + disabled={disableAchievements} + stop={stopAchievements} + /> + </AchievementsList> + </Paper> + </UserProfileContainer> + <UserProfileContainer> + <Paper elevation={3} style={{ padding: '1em' }}> + <AchievementsList> + <AchievementsSectionTitle> + Progressos ({totalProgress}) </AchievementsSectionTitle> - <Grid container direction="row" justify="center" alignItems="center" spacing={4} xs={12}> - {progress.map( - (a, index) => { - return ( - <Grid item key={new Date().toISOString() + index}> - <AchievementDescriptionCard - name={a.requirement.description} - description={a.requirement.description} - goal={a.requirement.goal} - counter={a.counter} - /> - </Grid> - ) - } - )} - </Grid> + <ProgressCarosel + items={progress} + setCurrPage={() => { setCurrPageProgress(currPageProgress + 1) }} + disabled={disableProgress} + stop={stopProgress} + /> </AchievementsList> </Paper> </UserProfileContainer> diff --git a/src/Pages/ItemStore.js b/src/Pages/ItemStore.js index 5833de28f3f13e566a92db13771ecf69a5753cca..12cd35fcab4f8058d91faaf5da0f738c26256b1c 100644 --- a/src/Pages/ItemStore.js +++ b/src/Pages/ItemStore.js @@ -123,6 +123,7 @@ export default function ItemStoreContainer(props) { }, (error) => { setErrInBadge(true) + setDisabledBadges(false) } ) }, [currBadgePage]) @@ -141,6 +142,7 @@ export default function ItemStoreContainer(props) { }, (error) => { setErrInAvatarFrame(true) + setDisabledAvatarFrame(false) } ) }, [currAvatarFramePage]) @@ -159,6 +161,7 @@ export default function ItemStoreContainer(props) { }, (error) => { setErrInCoverFrame(true) + setDisabledCoverFrame(false) } ) }, [currCoverFramePage]) @@ -177,6 +180,7 @@ export default function ItemStoreContainer(props) { }, (error) => { setErrInCardFrame(true) + setDisabledCardFrame(false) } ) }, [currCardFramePage])