From 4be4d25298745149cc057de940ef58b4ad100dfb Mon Sep 17 00:00:00 2001 From: Raul Almeida <rgpa18@inf.ufpr.br> Date: Tue, 3 Mar 2020 12:00:24 -0300 Subject: [PATCH 01/16] Add level description component This component has a progress bar for user's current XP; TO-DO: * [] add information from backend DOING: * [] list users achievements --- src/Components/LevelDescriptionCard.js | 77 +++++++++++++++++++ src/Components/ShinyProgressBar.js | 55 +++++++++++++ .../TabPanels/TabPanelStatusEConquistas.js | 42 ++++++++++ 3 files changed, 174 insertions(+) create mode 100644 src/Components/LevelDescriptionCard.js create mode 100644 src/Components/ShinyProgressBar.js create mode 100644 src/Components/TabPanels/TabPanelStatusEConquistas.js diff --git a/src/Components/LevelDescriptionCard.js b/src/Components/LevelDescriptionCard.js new file mode 100644 index 00000000..96c00d37 --- /dev/null +++ b/src/Components/LevelDescriptionCard.js @@ -0,0 +1,77 @@ +import React, { Component, useState, useEffect } from 'react'; + +import {Container} from 'react-grid-system'; +import Card from '@material-ui/core/Card'; +import CardContent from '@material-ui/core/CardContent'; + +import styled from 'styled-components' +import ShinyProgressBar from './ShinyProgressBar.js' +import { Grid } from '@material-ui/core' + +import axios from 'axios'; +import { apiUrl } from '../env'; + +export default function LevelDescriptionCard(props) { + + return ( + <LevelDescDiv> + <Grid container direction="row" justify="space-between" alignItems="center"> + <Grid item xs={6} md={4}> + <CurrentLevelNumber> + Nível + </CurrentLevelNumber> + <CurrentLevelXP> + XP 4096 + </CurrentLevelXP> + </Grid> + <Grid item xs={6} md={4} alignContent='flex-end'> + <CurrentCoins> + 256 COINS + </CurrentCoins> + <NextLevelXP> + 512 XP PARA O NÍVEL 32 + </NextLevelXP> + </Grid> + <ShinyProgressBar percentage='66' /> + </Grid> + </LevelDescDiv> + ); +} + +const NextLevelXP = styled.p` + text-align: right; + font-size: large; + font-weight: 500; + color: #575757; + margin-right: 30px; +` + +const CurrentCoins = styled.p` + text-align: right; + font-size: x-large; + font-weight: 500; + color: #575757; + margin-right: 30px; +` + +const CurrentLevelInfo = styled.div` + background-color: red; +` +const CurrentLevelNumber = styled.h1` + font-weight: 500; + font-size: 40px; + color: #646464; + margin-left: 30px; +` + +const CurrentLevelXP = styled.h2` + font-size: x-large; + font-weight: 500; + color: #00A5B9; + margin-left: 30px; +` + +const LevelDescDiv = styled.div` + margin: 20px; + padding: 20px; +` \ No newline at end of file diff --git a/src/Components/ShinyProgressBar.js b/src/Components/ShinyProgressBar.js new file mode 100644 index 00000000..f2d1cc03 --- /dev/null +++ b/src/Components/ShinyProgressBar.js @@ -0,0 +1,55 @@ +import React, {Component} from 'react'; +import {Container} from 'react-grid-system'; +import Card from '@material-ui/core/Card'; +import CardContent from '@material-ui/core/CardContent'; +import styled from 'styled-components' + + +export default function ShinyProgressBar(props) { + return ( + <ProgressBar> + <ShinyFiller percentage={props.percentage}/> + </ProgressBar> + ); +} + +const ShinyFiller = (props) => { + return ( + <StyledFiller style={{ width: `${props.percentage}%` }}> + <FillerShine/> + </StyledFiller> + ); +} + +const FillerShine = (props) => { + return <StyledShine/> +} + +const ProgressBar = styled.div` + background: #C4C4C4; + position: relative; + height: 30px; + width: 100%; + border-radius: 50px; + margin-left:20px; + margin-right:20px; +` + +const StyledFiller = styled.div` + background: #02A4B9; + height: 100%; + border-radius: 50px; + transition: width 1s ease-in; +` + +const StyledShine = styled.div` + position: relative; + top: 5px; + left: 15px; + background: #03C0CE; + height: 25%; + width: 95%; + border-radius: 50px; + transition: width 1s ease-in; + z-index: +1; +` \ No newline at end of file diff --git a/src/Components/TabPanels/TabPanelStatusEConquistas.js b/src/Components/TabPanels/TabPanelStatusEConquistas.js new file mode 100644 index 00000000..63d6243e --- /dev/null +++ b/src/Components/TabPanels/TabPanelStatusEConquistas.js @@ -0,0 +1,42 @@ +import React, {useContext, useState, useEffect} from 'react' +import styled from 'styled-components' +import { Container } from 'react-grid-system' +import Paper from '@material-ui/core/Paper'; +import Button from '@material-ui/core/Button'; +import {ContainerDivStyled} from './TabPanelMeusRecursos.js' +import {NoPubSpan, DivConteudoNaoPublicado, DivTextoNoPublications} from './TabPanelMeusRecursos.js' +import LoadingSpinner from '../LoadingSpinner.js' +import PaginaVaziaColecao from '../../img/Pagina_vazia_colecao.png' +import axios from 'axios' +import {apiUrl} from '../../env'; +import LevelDescriptionCard from '../LevelDescriptionCard.js' +import AchievementDescriptionCard from '../AchievementDescriptionCard.js' + +export default function TabPanelStatusEConquistas (props) { + return ( + <div> + <ContainerDivStyled> + <Paper elevation={3}> + <LevelDescriptionCard/> + </Paper> + </ContainerDivStyled> + <AchievementsContainer> + <AchievementsSectionTitle> + Conquistas + </AchievementsSectionTitle> + </AchievementsContainer> + </div> + ); +} + +const AchievementsSectionTitle = styled.h1` + font-weight: 400; +` +const AchievementsContainer = styled.div` + max-width : 1140px; + margin-left : auto; + margin-right : auto; + margin-left : 20em; + margin-bottom: 30px; + margin-top: 70px; +` \ No newline at end of file -- GitLab From e3aac2d13ee0821df708d70f547e7b197b57451c Mon Sep 17 00:00:00 2001 From: Raul Almeida <rgpa18@inf.ufpr.br> Date: Thu, 5 Mar 2020 10:52:27 -0300 Subject: [PATCH 02/16] =?UTF-8?q?Cria=20aba=20status=20e=20conquistas=20no?= =?UTF-8?q?=20perfil=20de=20usu=C3=A1rio?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Também inicia a lista de conquistas TODO: * [ ] Transformar os itens da lista de conquistas em um componente --- src/Components/MenuBar.js | 9 +++-- .../TabPanels/TabPanelStatusEConquistas.js | 40 +++++++++++++++++++ src/Pages/UserPage.js | 13 +++--- 3 files changed, 53 insertions(+), 9 deletions(-) diff --git a/src/Components/MenuBar.js b/src/Components/MenuBar.js index f3632a4c..2349423e 100644 --- a/src/Components/MenuBar.js +++ b/src/Components/MenuBar.js @@ -110,10 +110,11 @@ export default function MenuBar(props){ const minhaArea = [ { name: "Perfil e Atividades", href: "/perfil", value : '0'}, - { name: "Recursos Publicados", href: "/perfil", value : '1'}, - { name: "Favoritos", href: "/perfil", value : '2'}, - { name: "Coleções", href: "/perfil", value : '3'}, - { name: "Rede", href: "/perfil", value : '4'}, + { name: "Status e Conquistas", href: "/perfil", value: '1'}, + { name: "Recursos Publicados", href: "/perfil", value : '2'}, + { name: "Favoritos", href: "/perfil", value : '3'}, + { name: "Coleções", href: "/perfil", value : '4'}, + { name: "Rede", href: "/perfil", value : '5'}, { name: "Configurações", href: "/editarperfil"}, ] diff --git a/src/Components/TabPanels/TabPanelStatusEConquistas.js b/src/Components/TabPanels/TabPanelStatusEConquistas.js index 63d6243e..f8d04824 100644 --- a/src/Components/TabPanels/TabPanelStatusEConquistas.js +++ b/src/Components/TabPanels/TabPanelStatusEConquistas.js @@ -11,6 +11,7 @@ import axios from 'axios' import {apiUrl} from '../../env'; import LevelDescriptionCard from '../LevelDescriptionCard.js' import AchievementDescriptionCard from '../AchievementDescriptionCard.js' +import { Grid } from '@material-ui/core' export default function TabPanelStatusEConquistas (props) { return ( @@ -24,6 +25,29 @@ export default function TabPanelStatusEConquistas (props) { <AchievementsSectionTitle> Conquistas </AchievementsSectionTitle> + <AchievementsList> + <Grid container direction="row" justify="space-around" alignItems="center"> + <Grid container item xs={12} md={3} direction="row" justify="space-around" alignItems="center"> + <Grid item xs={5}> + <AchievementImg src="https://lojabagaggio.vteximg.com.br/arquivos/ids/2262429/Garrafas-e-Squeeze.jpg?v=636996613696070000"/> + </Grid> + <Grid item xs={5}> + <AchievementTitle> + Conquistador de Conquistas + </AchievementTitle> + <AchievementDescription> + Conquiste conquistas. + </AchievementDescription> + </Grid> + </Grid> + <Grid container item xs={12} md={3}> + Algo como ao lado + </Grid> + <Grid container item xs={12} md={3}> + Algo como ao lado + </Grid> + </Grid> + </AchievementsList> </AchievementsContainer> </div> ); @@ -39,4 +63,20 @@ const AchievementsContainer = styled.div` margin-left : 20em; margin-bottom: 30px; margin-top: 70px; +` +const AchievementsList = styled.div` + margin: 30px; + padding: 30px; +` + +const AchievementImg = styled.img` + border-radius: 100px; + width: 100px; + height: 100px; +` + +const AchievementTitle = styled.h1` +` + +const AchievementDescription = styled.p` ` \ No newline at end of file diff --git a/src/Pages/UserPage.js b/src/Pages/UserPage.js index 420912ac..f6efec56 100644 --- a/src/Pages/UserPage.js +++ b/src/Pages/UserPage.js @@ -37,6 +37,7 @@ import TabPanelMeusRecursos from '../Components/TabPanels/TabPanelMeusRecursos.j import TabPanelFavoritos from '../Components/TabPanels/TabPanelFavoritos.js' import TabPanelColecoes from '../Components/TabPanels/TabPanelColecoes.js' import TabPanelRede from '../Components/TabPanels/TabPanelRede.js' +import TabPanelStatusEConquistas from '../Components/TabPanels/TabPanelStatusEConquistas.js' import axios from 'axios' import {apiUrl} from '../env'; import ModalAlterarAvatar from '../Components/ModalAlterarAvatar.js' @@ -222,6 +223,7 @@ export default function UserPage (props){ <StyledTab label={tabs[2]}/> <StyledTab label={tabs[3]}/> <StyledTab label={tabs[4]}/> + <StyledTab label={tabs[5]}/> </StyledTabs> </NavBarContentContainer> </RodapeDiv> @@ -229,11 +231,12 @@ export default function UserPage (props){ </Paper> </MainContainerDesktop> </div> - {tabValue === 0 && <TabPanelAtividades id={id} config={config}/>} - {tabValue === 1 && <TabPanelMeusRecursos id={id} config={config}/>} - {tabValue === 2 && <TabPanelFavoritos id={id} config={config}/>} - {tabValue === 3 && <TabPanelColecoes id={id} config={config}/>} - {tabValue === 4 && <TabPanelRede id={id} config={config}/>} + {tabValue === 0 && <TabPanelAtividades id={id} config={config}/>} + {tabValue === 1 && <TabPanelStatusEConquistas id={id} config={config}/>} + {tabValue === 2 && <TabPanelMeusRecursos id={id} config={config}/>} + {tabValue === 3 && <TabPanelFavoritos id={id} config={config}/>} + {tabValue === 4 && <TabPanelColecoes id={id} config={config}/>} + {tabValue === 5 && <TabPanelRede id={id} config={config}/>} </ContainerNoPad> </HeaderDiv> </React.Fragment> -- GitLab From b130be9013ec2bc37d25f85ebabd0456abdd8063 Mon Sep 17 00:00:00 2001 From: Raul Almeida <rgpa18@inf.ufpr.br> Date: Thu, 5 Mar 2020 11:48:02 -0300 Subject: [PATCH 03/16] WIP Add Achievement Description Component --- src/Components/AchievementDescriptionCard.js | 33 +++++++++++++++++ .../TabPanels/TabPanelStatusEConquistas.js | 35 +++---------------- 2 files changed, 37 insertions(+), 31 deletions(-) create mode 100644 src/Components/AchievementDescriptionCard.js diff --git a/src/Components/AchievementDescriptionCard.js b/src/Components/AchievementDescriptionCard.js new file mode 100644 index 00000000..ebe9e5cd --- /dev/null +++ b/src/Components/AchievementDescriptionCard.js @@ -0,0 +1,33 @@ +import React from 'react' +import styled from 'styled-components' +import { Container } from 'react-grid-system' +import Paper from '@material-ui/core/Paper'; +import { Grid } from '@material-ui/core' + +export default function AchievementDescriptionCard(props) { + return ( + <Paper elevation={3}> + <Grid container direction="row" justify="space-around" alignItems="center"> + <Grid item xs={5}> + <AchievementImg src={props.src ? props.src : "https://material-ui.com/static/images/grid/complex.jpg"}/> + </Grid> + <Grid item xs={5}> + <AchievementTitle>{props.title ? props.title : "Conquistador de conquistas"}</AchievementTitle> + <AchievementDescription>{props.description ? props.description : "Conquiste conquistas"}</AchievementDescription> + </Grid> + </Grid> + </Paper> + ); +} + +const AchievementImg = styled.img` + border-radius: 100px; + width: 100px; + height: 100px; +` + +const AchievementTitle = styled.h1` +` + +const AchievementDescription = styled.p` +` \ No newline at end of file diff --git a/src/Components/TabPanels/TabPanelStatusEConquistas.js b/src/Components/TabPanels/TabPanelStatusEConquistas.js index f8d04824..be46d532 100644 --- a/src/Components/TabPanels/TabPanelStatusEConquistas.js +++ b/src/Components/TabPanels/TabPanelStatusEConquistas.js @@ -27,24 +27,11 @@ export default function TabPanelStatusEConquistas (props) { </AchievementsSectionTitle> <AchievementsList> <Grid container direction="row" justify="space-around" alignItems="center"> - <Grid container item xs={12} md={3} direction="row" justify="space-around" alignItems="center"> - <Grid item xs={5}> - <AchievementImg src="https://lojabagaggio.vteximg.com.br/arquivos/ids/2262429/Garrafas-e-Squeeze.jpg?v=636996613696070000"/> - </Grid> - <Grid item xs={5}> - <AchievementTitle> - Conquistador de Conquistas - </AchievementTitle> - <AchievementDescription> - Conquiste conquistas. - </AchievementDescription> - </Grid> + <Grid item xs={12} md={5}> + <AchievementDescriptionCard/> </Grid> - <Grid container item xs={12} md={3}> - Algo como ao lado - </Grid> - <Grid container item xs={12} md={3}> - Algo como ao lado + <Grid item xs={12} md={5}> + <AchievementDescriptionCard/> </Grid> </Grid> </AchievementsList> @@ -65,18 +52,4 @@ const AchievementsContainer = styled.div` margin-top: 70px; ` const AchievementsList = styled.div` - margin: 30px; - padding: 30px; -` - -const AchievementImg = styled.img` - border-radius: 100px; - width: 100px; - height: 100px; -` - -const AchievementTitle = styled.h1` -` - -const AchievementDescription = styled.p` ` \ No newline at end of file -- GitLab From b9221dea824984d06be9145da9d073df774a302f Mon Sep 17 00:00:00 2001 From: Raul Almeida <rgpa18@inf.ufpr.br> Date: Thu, 12 Mar 2020 09:49:28 -0300 Subject: [PATCH 04/16] Store link in menubar and start achievement description on user profile --- src/Components/AchievementDescriptionCard.js | 18 +++- src/Components/MenuBar.js | 5 +- src/Components/RequirementsDialog.js | 104 +++++++++++++++++++ 3 files changed, 122 insertions(+), 5 deletions(-) create mode 100644 src/Components/RequirementsDialog.js diff --git a/src/Components/AchievementDescriptionCard.js b/src/Components/AchievementDescriptionCard.js index ebe9e5cd..50be1eee 100644 --- a/src/Components/AchievementDescriptionCard.js +++ b/src/Components/AchievementDescriptionCard.js @@ -3,17 +3,26 @@ import styled from 'styled-components' import { Container } from 'react-grid-system' import Paper from '@material-ui/core/Paper'; import { Grid } from '@material-ui/core' +import RequirementDialog from './RequirementsDialog.js'; export default function AchievementDescriptionCard(props) { + var teste = [ + {name: "Casas", description: "Construa três casas"} + ]; return ( <Paper elevation={3}> <Grid container direction="row" justify="space-around" alignItems="center"> - <Grid item xs={5}> + <Grid item xs={3}> <AchievementImg src={props.src ? props.src : "https://material-ui.com/static/images/grid/complex.jpg"}/> </Grid> - <Grid item xs={5}> + <Grid item xs={7}> <AchievementTitle>{props.title ? props.title : "Conquistador de conquistas"}</AchievementTitle> <AchievementDescription>{props.description ? props.description : "Conquiste conquistas"}</AchievementDescription> + <RequirementDialog + title="Conquistador de conquistas" + description="Conquiste conquistas" + requirements={teste} + /> </Grid> </Grid> </Paper> @@ -24,10 +33,11 @@ const AchievementImg = styled.img` border-radius: 100px; width: 100px; height: 100px; + margin: 30px; ` -const AchievementTitle = styled.h1` +const AchievementTitle = styled.h2` ` const AchievementDescription = styled.p` -` \ No newline at end of file +` diff --git a/src/Components/MenuBar.js b/src/Components/MenuBar.js index 2349423e..cb2ab092 100644 --- a/src/Components/MenuBar.js +++ b/src/Components/MenuBar.js @@ -126,7 +126,10 @@ export default function MenuBar(props){ <Dropdown name="Ajuda" items={menuAjuda}/> <a href="http://educacaoconectada.mec.gov.br/" rel="noopener noreferrer" target="_blank" > <ButtonStyled >Educação Conectada</ButtonStyled> - </a> + </a> + <a href="/store"> + <ButtonStyled>Lojinha</ButtonStyled> + </a> <ButtonStyled onClick={props.openSearchBar} ><IconSearchStyled />Buscar</ButtonStyled> </Left> <Right> diff --git a/src/Components/RequirementsDialog.js b/src/Components/RequirementsDialog.js new file mode 100644 index 00000000..7299b51f --- /dev/null +++ b/src/Components/RequirementsDialog.js @@ -0,0 +1,104 @@ +import React from 'react'; +import { withStyles } from '@material-ui/core/styles'; +import Button from '@material-ui/core/Button'; +import Dialog from '@material-ui/core/Dialog'; +import MuiDialogTitle from '@material-ui/core/DialogTitle'; +import MuiDialogContent from '@material-ui/core/DialogContent'; +import MuiDialogActions from '@material-ui/core/DialogActions'; +import IconButton from '@material-ui/core/IconButton'; +import CloseIcon from '@material-ui/icons/Close'; +import Typography from '@material-ui/core/Typography'; +import DetailsIcon from '@material-ui/icons/Details'; +import styled from 'styled-components' +import { spacing } from '@material-ui/system' + +const styles = theme => ({ + root: { + margin: 0, + padding: theme.spacing(2), + }, + closeButton: { + position: 'absolute', + right: theme.spacing(1), + top: theme.spacing(1), + color: theme.palette.grey[500], + }, +}); + +const DialogTitle = withStyles(styles)(props => { + const { children, classes, onClose, ...other } = props; + return ( + <MuiDialogTitle disableTypography className={classes.root} {...other}> + <Typography variant="h6" mr={8} pr={8}>{children}</Typography> + {onClose ? ( + <IconButton aria-label="close" className={classes.closeButton} onClick={onClose}> + <CloseIcon /> + </IconButton> + ) : null} + </MuiDialogTitle> + ); +}); + +const DialogContent = withStyles(theme => ({ + root: { + padding: theme.spacing(2), + }, +}))(MuiDialogContent); + +const DialogActions = withStyles(theme => ({ + root: { + margin: 0, + padding: theme.spacing(1), + }, +}))(MuiDialogActions); + +export default function RequirementDialog(props) { + const [open, setOpen] = React.useState(false); + + const handleClickOpen = () => { + setOpen(true); + }; + const handleClose = () => { + setOpen(false); + }; + + return ( + <div> + <Button variant="outlined" color="primary" onClick={handleClickOpen}> + <DetailsIcon /> Saiba mais + </Button> + <Dialog onClose={handleClose} aria-labelledby="customized-dialog-title" open={open}> + <DialogTitle pr={5} mr={5} w-75 id="customized-dialog-title" onClose={handleClose}> + {props.title} + </DialogTitle> + <DialogContent dividers> + <Typography gutterBottom> + {props.description} + <h2>Requisitos</h2> + {props.requirements.map( + (r) => { + return (<div> + <RequirementTitle>{r.name}</RequirementTitle> + <RequirementDescription>{r.description}</RequirementDescription> + </div> + );} + )} + </Typography> + </DialogContent> + <DialogActions> + <Button autoFocus onClick={handleClose} color="primary"> + Save changes + </Button> + </DialogActions> + </Dialog> + </div> + ); +} + +const RequirementDescription = styled.p` + margin-left: 20px; + margin-right: 20px; +` + +const RequirementTitle = styled.h3` +` \ No newline at end of file -- GitLab From 977df3744ec6c0fa7f3a1b52dff24e02d7289d92 Mon Sep 17 00:00:00 2001 From: Raul Almeida <haltsimog@gmail.com> Date: Mon, 23 Mar 2020 10:49:16 -0300 Subject: [PATCH 05/16] Restart requirements dialog for better sizing --- src/Components/RequirementsDialog.js | 122 ++++++++++----------------- 1 file changed, 46 insertions(+), 76 deletions(-) diff --git a/src/Components/RequirementsDialog.js b/src/Components/RequirementsDialog.js index 7299b51f..c890878b 100644 --- a/src/Components/RequirementsDialog.js +++ b/src/Components/RequirementsDialog.js @@ -1,104 +1,74 @@ import React from 'react'; -import { withStyles } from '@material-ui/core/styles'; +import { makeStyles } from '@material-ui/core/styles'; import Button from '@material-ui/core/Button'; import Dialog from '@material-ui/core/Dialog'; -import MuiDialogTitle from '@material-ui/core/DialogTitle'; -import MuiDialogContent from '@material-ui/core/DialogContent'; -import MuiDialogActions from '@material-ui/core/DialogActions'; -import IconButton from '@material-ui/core/IconButton'; -import CloseIcon from '@material-ui/icons/Close'; -import Typography from '@material-ui/core/Typography'; -import DetailsIcon from '@material-ui/icons/Details'; -import styled from 'styled-components' -import { spacing } from '@material-ui/system' +import DialogActions from '@material-ui/core/DialogActions'; +import DialogContent from '@material-ui/core/DialogContent'; +import DialogContentText from '@material-ui/core/DialogContentText'; +import DialogTitle from '@material-ui/core/DialogTitle'; +import FormControl from '@material-ui/core/FormControl'; +import FormControlLabel from '@material-ui/core/FormControlLabel'; +import InputLabel from '@material-ui/core/InputLabel'; +import MenuItem from '@material-ui/core/MenuItem'; +import Select from '@material-ui/core/Select'; +import Switch from '@material-ui/core/Switch'; -const styles = theme => ({ - root: { - margin: 0, - padding: theme.spacing(2), +const useStyles = makeStyles(theme => ({ + form: { + display: 'flex', + flexDirection: 'column', + margin: 'auto', + width: 'fit-content', }, - closeButton: { - position: 'absolute', - right: theme.spacing(1), - top: theme.spacing(1), - color: theme.palette.grey[500], + formControl: { + marginTop: theme.spacing(2), + minWidth: 120, }, -}); - -const DialogTitle = withStyles(styles)(props => { - const { children, classes, onClose, ...other } = props; - return ( - <MuiDialogTitle disableTypography className={classes.root} {...other}> - <Typography variant="h6" mr={8} pr={8}>{children}</Typography> - {onClose ? ( - <IconButton aria-label="close" className={classes.closeButton} onClick={onClose}> - <CloseIcon /> - </IconButton> - ) : null} - </MuiDialogTitle> - ); -}); - -const DialogContent = withStyles(theme => ({ - root: { - padding: theme.spacing(2), + formControlLabel: { + marginTop: theme.spacing(1), }, -}))(MuiDialogContent); +})); -const DialogActions = withStyles(theme => ({ - root: { - margin: 0, - padding: theme.spacing(1), - }, -}))(MuiDialogActions); - -export default function RequirementDialog(props) { +export default function MaxWidthDialog(props) { + const classes = useStyles(); const [open, setOpen] = React.useState(false); + const fullWidth = true; + const maxWidth = 'sm'; const handleClickOpen = () => { setOpen(true); }; + const handleClose = () => { setOpen(false); }; return ( - <div> + <React.Fragment> <Button variant="outlined" color="primary" onClick={handleClickOpen}> - <DetailsIcon /> Saiba mais + Mais </Button> - <Dialog onClose={handleClose} aria-labelledby="customized-dialog-title" open={open}> - <DialogTitle pr={5} mr={5} w-75 id="customized-dialog-title" onClose={handleClose}> - {props.title} - </DialogTitle> - <DialogContent dividers> - <Typography gutterBottom> - {props.description} - <h2>Requisitos</h2> - {props.requirements.map( - (r) => { - return (<div> - <RequirementTitle>{r.name}</RequirementTitle> - <RequirementDescription>{r.description}</RequirementDescription> - </div> - );} - )} - </Typography> + <Dialog + fullWidth={fullWidth} + maxWidth={maxWidth} + open={open} + onClose={handleClose} + aria-labelledby="max-width-dialog-title" + > + <DialogTitle id="max-width-dialog-title">Detalhes - {props.title}</DialogTitle> + <DialogContent> + <DialogContentText> + {props.description} + <h4>Requisitos</h4> + </DialogContentText> </DialogContent> <DialogActions> - <Button autoFocus onClick={handleClose} color="primary"> - Save changes + <Button onClick={handleClose} color="primary"> + Fechar </Button> </DialogActions> </Dialog> - </div> + </React.Fragment> ); } -const RequirementDescription = styled.p` - margin-left: 20px; - margin-right: 20px; -` - -const RequirementTitle = styled.h3` -` \ No newline at end of file -- GitLab From 250ec11705e28ad70f0864597565562bbc3f85b5 Mon Sep 17 00:00:00 2001 From: Raul Almeida <haltsimog@gmail.com> Date: Tue, 24 Mar 2020 10:37:00 -0300 Subject: [PATCH 06/16] Add functional requirement description dialog --- src/Components/AchievementDescriptionCard.js | 5 ++++- src/Components/RequirementsDialog.js | 13 ++++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/Components/AchievementDescriptionCard.js b/src/Components/AchievementDescriptionCard.js index 50be1eee..58eb3a17 100644 --- a/src/Components/AchievementDescriptionCard.js +++ b/src/Components/AchievementDescriptionCard.js @@ -7,7 +7,10 @@ import RequirementDialog from './RequirementsDialog.js'; export default function AchievementDescriptionCard(props) { var teste = [ - {name: "Casas", description: "Construa três casas"} + {name: "Casas", description: "Construa três casas"}, + {name: "Carros", description: "Dirija três carros"}, + {name: "Esportes", description: "Pratique três esportes"}, + {name: "Noites", description: "Sobreviva a três noites"} ]; return ( <Paper elevation={3}> diff --git a/src/Components/RequirementsDialog.js b/src/Components/RequirementsDialog.js index c890878b..a8f5f208 100644 --- a/src/Components/RequirementsDialog.js +++ b/src/Components/RequirementsDialog.js @@ -55,11 +55,22 @@ export default function MaxWidthDialog(props) { onClose={handleClose} aria-labelledby="max-width-dialog-title" > - <DialogTitle id="max-width-dialog-title">Detalhes - {props.title}</DialogTitle> + <DialogTitle id="max-width-dialog-title">{props.title}</DialogTitle> <DialogContent> <DialogContentText> {props.description} <h4>Requisitos</h4> + <dl> + {props.requirements.map( + (r) => { + return( + <div> + <dt>{r.name}</dt> + <dd>{r.description}</dd> + </div> + ); + })} + </dl> </DialogContentText> </DialogContent> <DialogActions> -- GitLab From 4e5475f9b186a672a0bf417e63fd29eb0edbd934 Mon Sep 17 00:00:00 2001 From: Raul Almeida <haltsimog@gmail.com> Date: Fri, 27 Mar 2020 11:58:38 -0300 Subject: [PATCH 07/16] Replace placeholders with actual functionality AchievementDescriptionCard isn't just dummy text anymore; it works with actual parameters passed by his parent TabPanel. The tabpanel itself doesn't get information from the API yet. --- src/Components/AchievementDescriptionCard.js | 18 ++--- .../TabPanels/TabPanelStatusEConquistas.js | 81 +++++++++++-------- 2 files changed, 55 insertions(+), 44 deletions(-) diff --git a/src/Components/AchievementDescriptionCard.js b/src/Components/AchievementDescriptionCard.js index 58eb3a17..3af102fe 100644 --- a/src/Components/AchievementDescriptionCard.js +++ b/src/Components/AchievementDescriptionCard.js @@ -6,25 +6,19 @@ import { Grid } from '@material-ui/core' import RequirementDialog from './RequirementsDialog.js'; export default function AchievementDescriptionCard(props) { - var teste = [ - {name: "Casas", description: "Construa três casas"}, - {name: "Carros", description: "Dirija três carros"}, - {name: "Esportes", description: "Pratique três esportes"}, - {name: "Noites", description: "Sobreviva a três noites"} - ]; return ( <Paper elevation={3}> <Grid container direction="row" justify="space-around" alignItems="center"> <Grid item xs={3}> - <AchievementImg src={props.src ? props.src : "https://material-ui.com/static/images/grid/complex.jpg"}/> + <AchievementImg src={props.src}/> </Grid> <Grid item xs={7}> - <AchievementTitle>{props.title ? props.title : "Conquistador de conquistas"}</AchievementTitle> - <AchievementDescription>{props.description ? props.description : "Conquiste conquistas"}</AchievementDescription> + <AchievementTitle>{props.title}</AchievementTitle> + <AchievementDescription>{props.description}</AchievementDescription> <RequirementDialog - title="Conquistador de conquistas" - description="Conquiste conquistas" - requirements={teste} + title={props.title} + description={props.description} + requirements={props.requirements} /> </Grid> </Grid> diff --git a/src/Components/TabPanels/TabPanelStatusEConquistas.js b/src/Components/TabPanels/TabPanelStatusEConquistas.js index be46d532..b90d79c6 100644 --- a/src/Components/TabPanels/TabPanelStatusEConquistas.js +++ b/src/Components/TabPanels/TabPanelStatusEConquistas.js @@ -14,42 +14,59 @@ import AchievementDescriptionCard from '../AchievementDescriptionCard.js' import { Grid } from '@material-ui/core' export default function TabPanelStatusEConquistas (props) { - return ( - <div> - <ContainerDivStyled> - <Paper elevation={3}> - <LevelDescriptionCard/> - </Paper> - </ContainerDivStyled> - <AchievementsContainer> - <AchievementsSectionTitle> - Conquistas - </AchievementsSectionTitle> - <AchievementsList> - <Grid container direction="row" justify="space-around" alignItems="center"> - <Grid item xs={12} md={5}> - <AchievementDescriptionCard/> - </Grid> - <Grid item xs={12} md={5}> - <AchievementDescriptionCard/> - </Grid> - </Grid> - </AchievementsList> - </AchievementsContainer> - </div> - ); + const [achievements, setAchievements] = useState([]); + + useEffect(() => { + axios.get(`https://api.portalmec.c3sl.ufpr.br/v1/users/1`) + .then(res => { + const achievements = res.data; + console.log("Teste"); + console.log(achievements); + //this.setAchievements(achievements); + }) + }, []) + + return ( + <div> + <ContainerDivStyled> + <Paper elevation={3}> + <LevelDescriptionCard/> + </Paper> + </ContainerDivStyled> + <AchievementsContainer> + <AchievementsSectionTitle> + Conquistas + </AchievementsSectionTitle> + <AchievementsList> + <Grid container direction="row" justify="space-around" alignItems="center"> + {achievements.map( + (a) => { return ( + <Grid item xs={12} md={5}> + <AchievementDescriptionCard + title={a.title} + description={a.description} + src={a.imgsrc} + requirements={a.requirements} /> + //requirements={[{name: "teste", description: "teste"}]}/> + </Grid> + )} + )} + </Grid> + </AchievementsList> + </AchievementsContainer> + </div> + ); } const AchievementsSectionTitle = styled.h1` - font-weight: 400; + font-weight: 400; ` const AchievementsContainer = styled.div` - max-width : 1140px; - margin-left : auto; - margin-right : auto; - margin-left : 20em; - margin-bottom: 30px; - margin-top: 70px; + max-width : 1140px; + margin-left : auto; + margin-right : auto; + margin-bottom: 30px; + margin-top: 70px; ` const AchievementsList = styled.div` -` \ No newline at end of file +` -- GitLab From a2d2530fd78d9fdb4a62e9492c6bfc494b2cdeae Mon Sep 17 00:00:00 2001 From: Raul Almeida <haltsimog@gmail.com> Date: Tue, 31 Mar 2020 11:54:11 -0300 Subject: [PATCH 08/16] Add get to level description card TODO: backend percentage to next level --- src/Components/LevelDescriptionCard.js | 12 +++--- .../TabPanels/TabPanelStatusEConquistas.js | 38 ++++++++++++++----- 2 files changed, 35 insertions(+), 15 deletions(-) diff --git a/src/Components/LevelDescriptionCard.js b/src/Components/LevelDescriptionCard.js index 96c00d37..90e43b78 100644 --- a/src/Components/LevelDescriptionCard.js +++ b/src/Components/LevelDescriptionCard.js @@ -18,21 +18,21 @@ export default function LevelDescriptionCard(props) { <Grid container direction="row" justify="space-between" alignItems="center"> <Grid item xs={6} md={4}> <CurrentLevelNumber> - Nível + Nível {props.level} </CurrentLevelNumber> <CurrentLevelXP> - XP 4096 + XP {props.xp} </CurrentLevelXP> </Grid> <Grid item xs={6} md={4} alignContent='flex-end'> <CurrentCoins> - 256 COINS + {props.coins} COINS </CurrentCoins> <NextLevelXP> - 512 XP PARA O NÍVEL 32 + {props.xp_to_next_lvl} XP PARA O NÍVEL {props.level+1} </NextLevelXP> </Grid> - <ShinyProgressBar percentage='66' /> + <ShinyProgressBar percentage={props.bar_size} /> </Grid> </LevelDescDiv> ); @@ -74,4 +74,4 @@ const CurrentLevelXP = styled.h2` const LevelDescDiv = styled.div` margin: 20px; padding: 20px; -` \ No newline at end of file +` diff --git a/src/Components/TabPanels/TabPanelStatusEConquistas.js b/src/Components/TabPanels/TabPanelStatusEConquistas.js index b90d79c6..d126b660 100644 --- a/src/Components/TabPanels/TabPanelStatusEConquistas.js +++ b/src/Components/TabPanels/TabPanelStatusEConquistas.js @@ -1,4 +1,5 @@ import React, {useContext, useState, useEffect} from 'react' +import { Store } from '../../Store.js' import styled from 'styled-components' import { Container } from 'react-grid-system' import Paper from '@material-ui/core/Paper'; @@ -15,22 +16,41 @@ import { Grid } from '@material-ui/core' export default function TabPanelStatusEConquistas (props) { const [achievements, setAchievements] = useState([]); + const [level, setLevel] = useState(0); + const [xp, setXP] = useState(0); + const [coins, setCoins] = useState(0); + const [barSize, setBarSize] = useState(0); + const [xpToNextLevel, setXpToNextLevel] = useState(0); + const { state } = useContext(Store) useEffect(() => { - axios.get(`https://api.portalmec.c3sl.ufpr.br/v1/users/1`) - .then(res => { - const achievements = res.data; - console.log("Teste"); - console.log(achievements); - //this.setAchievements(achievements); - }) + axios.all( + ['xp_to_next_lvl', 'percent_to_next_level', 'points', 'xp', 'get_level', + 'completed_achievements'].map((r) => { + return axios.get(apiUrl + '/' + r + '/' + state.currentUser.id); + }).then(axios.spread((xp_to_next_lvl, percent_to_next_level, points, + xp, level, completed_achievements) => { + this.setXpToNextLevel(xp_to_next_lvl); + this.setBarSize(100-percent_to_next_level); + this.setCoins(points); + this.setXP(xp); + this.setLevel(level); + this.setAchievements(completed_achievements); + }))) + }, []) return ( <div> <ContainerDivStyled> <Paper elevation={3}> - <LevelDescriptionCard/> + <LevelDescriptionCard + xp_to_next_lvl={xpToNextLevel} + bar_size={barSize} + coins={coins} + xp={xp} + level={level} + /> </Paper> </ContainerDivStyled> <AchievementsContainer> @@ -43,7 +63,7 @@ export default function TabPanelStatusEConquistas (props) { (a) => { return ( <Grid item xs={12} md={5}> <AchievementDescriptionCard - title={a.title} + name={a.title} description={a.description} src={a.imgsrc} requirements={a.requirements} /> -- GitLab From 26c16cc74986c02a46ce86046ab44d53bb42d3e4 Mon Sep 17 00:00:00 2001 From: Raul Almeida <haltsimog@gmail.com> Date: Thu, 2 Apr 2020 12:10:38 -0300 Subject: [PATCH 09/16] Fix axios calls --- src/Components/TabPanels/TabPanelStatusEConquistas.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Components/TabPanels/TabPanelStatusEConquistas.js b/src/Components/TabPanels/TabPanelStatusEConquistas.js index d126b660..9b41ad4f 100644 --- a/src/Components/TabPanels/TabPanelStatusEConquistas.js +++ b/src/Components/TabPanels/TabPanelStatusEConquistas.js @@ -28,7 +28,7 @@ export default function TabPanelStatusEConquistas (props) { ['xp_to_next_lvl', 'percent_to_next_level', 'points', 'xp', 'get_level', 'completed_achievements'].map((r) => { return axios.get(apiUrl + '/' + r + '/' + state.currentUser.id); - }).then(axios.spread((xp_to_next_lvl, percent_to_next_level, points, + })).then(axios.spread((xp_to_next_lvl, percent_to_next_level, points, xp, level, completed_achievements) => { this.setXpToNextLevel(xp_to_next_lvl); this.setBarSize(100-percent_to_next_level); @@ -36,8 +36,7 @@ export default function TabPanelStatusEConquistas (props) { this.setXP(xp); this.setLevel(level); this.setAchievements(completed_achievements); - }))) - + })); }, []) return ( -- GitLab From 66049ab2618c44dd430144a2425a5bd76a4b2b0f Mon Sep 17 00:00:00 2001 From: Raul Almeida <haltsimog@gmail.com> Date: Mon, 13 Apr 2020 09:48:18 -0300 Subject: [PATCH 10/16] WIP gamification store --- src/App.js | 3 +- src/Components/ItemCard.js | 77 ++++++++++++++++++++++++++++++ src/Components/ItemCarousel.js | 41 ++++++++++++++++ src/Components/StoreGuide.js | 69 ++++++++++++++++++++++++++ src/Components/UserCardGamified.js | 38 +++++++++++++++ src/Pages/ItemStore.js | 60 +++++++++++++++++++++++ src/img/gamification/gem.svg | 17 +++++++ 7 files changed, 304 insertions(+), 1 deletion(-) create mode 100644 src/Components/ItemCard.js create mode 100644 src/Components/ItemCarousel.js create mode 100644 src/Components/StoreGuide.js create mode 100644 src/Components/UserCardGamified.js create mode 100644 src/Pages/ItemStore.js create mode 100644 src/img/gamification/gem.svg diff --git a/src/App.js b/src/App.js index be9f0b03..8cdaf45e 100644 --- a/src/App.js +++ b/src/App.js @@ -40,7 +40,7 @@ import { Store } from './Store' import TermsPage from './Pages/TermsPage.js' import PublicationPermissionsPage from './Pages/PublicationPermissionsPage.js' import TabPlataformaMEC from './Pages/TabsHelp/TabPlataformaMEC'; - +import ItemStore from './Pages/ItemStore.js' import EditProfilePage from './Pages/EditProfilePage.js' export default function App(){ @@ -99,6 +99,7 @@ export default function App(){ <Route path="/plataforma-mec" component={TabPlataformaMEC}/> <Route path="/recuperar-senha" component={PasswordRecoveryPage}/> <Route path='/professor' component={PageProfessor}/> + <Route path='/loja' component={ItemStore} /> </Switch> <EcFooter/> <GNUAGPLfooter/> diff --git a/src/Components/ItemCard.js b/src/Components/ItemCard.js new file mode 100644 index 00000000..82a6bbc4 --- /dev/null +++ b/src/Components/ItemCard.js @@ -0,0 +1,77 @@ +/*Copyright (C) 2019 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana + +This file is part of Plataforma Integrada MEC. + +Plataforma Integrada MEC is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Plataforma Integrada MEC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with Plataforma Integrada MEC. If not, see <http://www.gnu.org/licenses/>.*/ +import React, {useState, useContext} from 'react'; +import styled from 'styled-components'; +import Grid from '@material-ui/core/Grid'; +import Card from '@material-ui/core/Card'; +import CardActions from '@material-ui/core/CardActions'; +import CardContent from '@material-ui/core/CardContent'; +import gem from '../img/gamification/gem.svg'; + +const ItemImage = styled.img` + border-radius: 150; + max-width: 100%; +` + +const ItemName = styled.h3` + font-size: 0.8em; + font-weight: lighter; + color: #666666; +` + +const ItemDescription = styled.p` + font-size: 0.5em; + color: #666666; +` + +const actionStyle = (operation) => { + var stl = { + fontSize: '0.5em', + paddingTop: '1em', + marginBottom: 0, + fontWeight: 'bold', + } + stl.color = operation != 'buy' ? '#02a5c3' : '#666666'; + return stl; +} + +const GemImg = styled.img` + height: 23px; + position: relative; + top: 8px; + padding-right: 5px; +` + +export default function ItemCard (props) { + return ( + <Grid item xs={9} sm={2}> + <Card style={{textAlign: 'center'}}> + <CardContent> + <ItemImage src="https://upload.wikimedia.org/wikipedia/en/9/90/The_DuckDuckGo_Duck.png"/> + <ItemName>Avatar um</ItemName> + <ItemDescription>Descrição | Descrição</ItemDescription> + <p style={actionStyle(props.action)}> + {props.action == 'buy' ? <GemImg src={gem}/> : <span/>} + {props.action == 'buy' ? "COMPRAR" : + props.action == 'equip' ? "USAR" : "TIRAR"} + </p> + </CardContent> + </Card> + </Grid> + ) +} diff --git a/src/Components/ItemCarousel.js b/src/Components/ItemCarousel.js new file mode 100644 index 00000000..851da0f9 --- /dev/null +++ b/src/Components/ItemCarousel.js @@ -0,0 +1,41 @@ +/*Copyright (C) 2019 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana + +This file is part of Plataforma Integrada MEC. + +Plataforma Integrada MEC is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Plataforma Integrada MEC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with Plataforma Integrada MEC. If not, see <http://www.gnu.org/licenses/>.*/ +import React, {useState, useContext} from 'react'; +import styled from 'styled-components'; +import Grid from '@material-ui/core/Grid'; +import Card from '@material-ui/core/Card'; +import CardActions from '@material-ui/core/CardActions'; +import CardContent from '@material-ui/core/CardContent'; +import ItemCard from './ItemCard.js'; + +export default function ItemCarousel (props) { + return ( + <Grid + item container + direction="row" + justify="center" + alignItems="center" + xs={12} + spacing={3} + > + {[1, 2, 3, 4, 5, 6].map(() => { + return <ItemCard action="buy"/> + })} + </Grid> + ) +} diff --git a/src/Components/StoreGuide.js b/src/Components/StoreGuide.js new file mode 100644 index 00000000..03bcf8a2 --- /dev/null +++ b/src/Components/StoreGuide.js @@ -0,0 +1,69 @@ +/*Copyright (C) 2019 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana + +This file is part of Plataforma Integrada MEC. + +Plataforma Integrada MEC is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Plataforma Integrada MEC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with Plataforma Integrada MEC. If not, see <http://www.gnu.org/licenses/>.*/ +import React, {useState, useContext} 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'; + +const StoreTitle = styled.h1` + margin-top: 0; +` + +const StoreTopic = styled.h2` + padding-top: 0.5em; + font-size: 1em; + font-weight: 100; +` + +const StoreBody = styled.p` + font-size: 0.8em; +` +export default function ItemStoreContainer (props) { + return ( + <Grid item xs={10} sm={7}> + <Card> + <CardContent> + <StoreTitle> + Lojinha + </StoreTitle> + <StoreTopic> + O que são "gemas"? + </StoreTopic> + <StoreBody> + Aqui eu explico muito bem o que são "gemas" + </StoreBody> + <StoreTopic> + Regras + </StoreTopic> + <StoreBody> + 1st RULE: You do not talk about FIGHT CLUB. + 2nd RULE: You DO NOT talk about FIGHT CLUB. + 3rd RULE: If someone says "stop" or goes limp, taps out the fight is over. + 4th RULE: Only two guys to a fight. + 5th RULE: One fight at a time. + 6th RULE: No shirts, no shoes. + 7th RULE: Fights will go on as long as they have to. + 8th RULE: If this is your first night at FIGHT CLUB, you HAVE to fight. + </StoreBody> + </CardContent> + </Card> + </Grid> + ) +} diff --git a/src/Components/UserCardGamified.js b/src/Components/UserCardGamified.js new file mode 100644 index 00000000..711b9ee4 --- /dev/null +++ b/src/Components/UserCardGamified.js @@ -0,0 +1,38 @@ +/*Copyright (C) 2019 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana + +This file is part of Plataforma Integrada MEC. + +Plataforma Integrada MEC is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Plataforma Integrada MEC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with Plataforma Integrada MEC. If not, see <http://www.gnu.org/licenses/>.*/ +import React, {useState, useContext} from 'react'; +import styled from 'styled-components'; +import Grid from '@material-ui/core/Grid'; +import Card from '@material-ui/core/Card'; +import CardActions from '@material-ui/core/CardActions'; +import CardContent from '@material-ui/core/CardContent'; + +export default function UserCardGamified (props) { + return ( + <Grid item xs={6} sm={3}> + <Card style={{backgroundColor:'pink'}}> + <CardContent> + Eu serei o card da pessoa + </CardContent> + <CardActions> + Learn more + </CardActions> + </Card> + </Grid> + ) +} diff --git a/src/Pages/ItemStore.js b/src/Pages/ItemStore.js new file mode 100644 index 00000000..9ecc408b --- /dev/null +++ b/src/Pages/ItemStore.js @@ -0,0 +1,60 @@ +/*Copyright (C) 2019 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana + +This file is part of Plataforma Integrada MEC. + +Plataforma Integrada MEC is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Plataforma Integrada MEC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with Plataforma Integrada MEC. If not, see <http://www.gnu.org/licenses/>.*/ +import React, {useState, useContext} from 'react'; +import styled from 'styled-components'; +import Grid from '@material-ui/core/Grid'; +import Card from '@material-ui/core/Card'; +import CardActions from '@material-ui/core/CardActions'; +import CardContent from '@material-ui/core/CardContent'; +import Container from '@material-ui/core/Container'; +import UserCardGamified from '../Components/UserCardGamified.js'; +import StoreGuide from '../Components/StoreGuide.js'; +import ItemCarousel from '../Components/ItemCarousel.js'; + +const StoreSection = styled.h2` + font-weight: 100; +` + +export default function ItemStoreContainer (props) { + return ( + <Container> + <Grid container + direction="row" + justify="space-around" + alignItems="stretch" + style={{ + marginTop: '2em', + marginBottom: '2em', + }} + > + <UserCardGamified/> + <StoreGuide/> + </Grid> + <StoreSection> + Avatares + <ItemCarousel/> + </StoreSection> + <StoreSection> + Itens + </StoreSection> + <StoreSection> + Bordas + </StoreSection> + </Container> + ) +} diff --git a/src/img/gamification/gem.svg b/src/img/gamification/gem.svg new file mode 100644 index 00000000..4f083b2c --- /dev/null +++ b/src/img/gamification/gem.svg @@ -0,0 +1,17 @@ +<svg width="203" height="307" viewBox="0 0 203 307" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M51.5765 127.504L2.37646 102.604L51.5765 127.504Z" fill="#CA1818"/> +<path d="M51.7765 127.504L101.076 1.80389L2.37646 102.604L51.7765 127.504Z" fill="#CA1818"/> +<path d="M51.7766 129.304C51.3766 129.304 50.8766 129.204 50.4766 129.004L1.0766 104.104C0.576595 103.804 0.176595 103.404 0.0765953 102.904C-0.0234047 102.404 0.0765953 101.904 0.476595 101.504L99.1766 0.703867C99.8766 0.00386721 101.077 -0.196133 102.077 0.203867C103.077 0.603867 103.577 1.50387 103.277 2.30387L54.0766 128.004C53.8766 128.504 53.3766 129.004 52.6766 129.204C52.3766 129.304 52.0766 129.304 51.7766 129.304ZM5.7766 102.204L50.5766 124.704L95.0766 10.9039L5.7766 102.204Z" fill="white"/> +<path d="M150.277 127.504L199.777 102.604L101.077 1.80389L150.277 127.504Z" fill="#CA1818"/> +<path d="M150.276 129.304C149.976 129.304 149.776 129.304 149.476 129.204C148.776 129.004 148.277 128.604 148.076 128.004L98.8765 2.30387C98.5765 1.50387 99.0765 0.603867 100.077 0.203867C101.077 -0.196133 102.277 0.00386721 102.977 0.703867L201.677 101.504C202.077 101.904 202.176 102.404 202.076 102.904C201.977 103.404 201.576 103.804 201.076 104.104L151.576 129.004C151.176 129.204 150.676 129.304 150.276 129.304ZM107.077 10.8039L151.576 124.704L196.377 102.104L107.077 10.8039Z" fill="white"/> +<path d="M150.276 127.504L101.076 304.304L199.776 102.604L150.276 127.504Z" fill="#CA1818"/> +<path d="M101.076 306.104C100.876 306.104 100.676 306.104 100.376 306.004C99.1763 305.704 98.4763 304.804 98.7763 303.904L147.976 127.104C148.076 126.604 148.476 126.204 148.976 126.004L198.476 101.104C199.276 100.704 200.376 100.704 201.176 101.204C201.976 101.704 202.276 102.504 201.876 103.204L103.176 304.904C102.876 305.604 101.976 306.104 101.076 306.104ZM152.376 128.604L109.876 281.304L195.076 107.104L152.376 128.604Z" fill="white"/> +<path d="M51.7765 127.504L2.37646 102.604L101.076 304.304L51.7765 127.504Z" fill="#CA1818"/> +<path d="M101.076 306.104C100.176 306.104 99.2764 305.704 98.8764 304.904L0.176405 103.204C-0.223595 102.504 0.0764047 101.704 0.876405 101.204C1.6764 100.704 2.7764 100.704 3.5764 101.104L53.0764 126.004C53.5764 126.304 53.9764 126.704 54.0764 127.104L103.376 303.904C103.676 304.804 102.876 305.704 101.776 306.004C101.476 306.104 101.276 306.104 101.076 306.104ZM7.0764 107.104L92.2764 281.304L49.7764 128.604L7.0764 107.104Z" fill="white"/> +<path d="M51.7764 127.504H150.276L101.076 1.80383L51.7764 127.504Z" fill="#CA1818"/> +<path d="M150.276 129.304H51.7764C51.0764 129.304 50.3764 129.004 49.8764 128.604C49.4764 128.204 49.2764 127.604 49.4764 127.004L98.7764 1.30385C99.0764 0.503845 99.9764 0.00384521 101.076 0.00384521C102.176 0.00384521 102.976 0.503845 103.276 1.30385L152.476 127.004C152.676 127.504 152.576 128.104 152.076 128.604C151.676 129.004 150.976 129.304 150.276 129.304ZM54.9764 125.704H147.176L101.076 8.00385L54.9764 125.704Z" fill="white"/> +<path d="M51.8764 127.504L51.7764 127.804H101.076H150.376L150.276 127.504H101.076H51.8764Z" fill="#CA1818"/> +<path d="M150.276 127.504H51.7764L101.076 304.304L150.276 127.504Z" fill="#CA1818"/> +<path d="M101.076 306.104C99.9764 306.104 99.0763 305.504 98.7763 304.704L49.5764 127.904C49.4764 127.404 49.5764 126.804 50.0764 126.404C50.4764 126.004 51.1764 125.704 51.8764 125.704H150.276C150.976 125.704 151.676 125.904 152.076 126.404C152.476 126.804 152.676 127.404 152.576 127.904L103.376 304.704C103.076 305.504 102.176 306.104 101.076 306.104ZM54.6763 129.304L101.076 295.804L147.376 129.304H54.6763Z" fill="white"/> +</svg> + -- GitLab From e4242f06678fb8918c2ed02f9775fd2354e5b3ca Mon Sep 17 00:00:00 2001 From: Lucas Schoenfelder <les17@inf.ufpr.br> Date: Wed, 15 Apr 2020 08:56:32 -0300 Subject: [PATCH 11/16] added paddingTop 2em to Container --- src/Pages/ItemStore.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Pages/ItemStore.js b/src/Pages/ItemStore.js index 9ecc408b..e32598d6 100644 --- a/src/Pages/ItemStore.js +++ b/src/Pages/ItemStore.js @@ -32,7 +32,7 @@ const StoreSection = styled.h2` export default function ItemStoreContainer (props) { return ( - <Container> + <Container style={{paddingTop : "2em", backgroundColor : "purple"}}> <Grid container direction="row" justify="space-around" -- GitLab From 8f756b70edc46e9af2438a6fa9cdbd5b51294316 Mon Sep 17 00:00:00 2001 From: Raul Almeida <haltsimog@gmail.com> Date: Thu, 16 Apr 2020 10:57:24 -0300 Subject: [PATCH 12/16] WIP Item cards pretty much done, store progresses --- src/Components/ItemCard.js | 30 ++------- src/Components/ItemCardAction.js | 109 +++++++++++++++++++++++++++++++ src/Components/ItemCarousel.js | 20 +++++- src/Pages/ItemStore.js | 36 ++++++++-- 4 files changed, 163 insertions(+), 32 deletions(-) create mode 100644 src/Components/ItemCardAction.js diff --git a/src/Components/ItemCard.js b/src/Components/ItemCard.js index 82a6bbc4..21f87f4f 100644 --- a/src/Components/ItemCard.js +++ b/src/Components/ItemCard.js @@ -22,6 +22,7 @@ import Card from '@material-ui/core/Card'; import CardActions from '@material-ui/core/CardActions'; import CardContent from '@material-ui/core/CardContent'; import gem from '../img/gamification/gem.svg'; +import ItemCardAction from './ItemCardAction.js'; const ItemImage = styled.img` border-radius: 150; @@ -39,37 +40,16 @@ const ItemDescription = styled.p` color: #666666; ` -const actionStyle = (operation) => { - var stl = { - fontSize: '0.5em', - paddingTop: '1em', - marginBottom: 0, - fontWeight: 'bold', - } - stl.color = operation != 'buy' ? '#02a5c3' : '#666666'; - return stl; -} - -const GemImg = styled.img` - height: 23px; - position: relative; - top: 8px; - padding-right: 5px; -` export default function ItemCard (props) { return ( <Grid item xs={9} sm={2}> <Card style={{textAlign: 'center'}}> <CardContent> - <ItemImage src="https://upload.wikimedia.org/wikipedia/en/9/90/The_DuckDuckGo_Duck.png"/> - <ItemName>Avatar um</ItemName> - <ItemDescription>Descrição | Descrição</ItemDescription> - <p style={actionStyle(props.action)}> - {props.action == 'buy' ? <GemImg src={gem}/> : <span/>} - {props.action == 'buy' ? "COMPRAR" : - props.action == 'equip' ? "USAR" : "TIRAR"} - </p> + <ItemImage src={props.src}/> + <ItemName>{props.name}</ItemName> + <ItemDescription>{props.description}</ItemDescription> + <ItemCardAction operation={props.action}/> </CardContent> </Card> </Grid> diff --git a/src/Components/ItemCardAction.js b/src/Components/ItemCardAction.js new file mode 100644 index 00000000..2922dc3d --- /dev/null +++ b/src/Components/ItemCardAction.js @@ -0,0 +1,109 @@ +/*Copyright (C) 2019 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana + +This file is part of Plataforma Integrada MEC. + +Plataforma Integrada MEC is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Plataforma Integrada MEC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with Plataforma Integrada MEC. If not, see <http://www.gnu.org/licenses/>.*/ +import React, {useState, useContext} from 'react'; +import styled from 'styled-components'; +import Card from '@material-ui/core/Card'; +import CardActions from '@material-ui/core/CardActions'; +import CardContent from '@material-ui/core/CardContent'; +import Snackbar from '@material-ui/core/Snackbar'; +import MuiAlert from '@material-ui/lab/Alert'; +import Button from '@material-ui/core/Button'; +import gem from '../img/gamification/gem.svg'; + +function Alert(props) { + return <MuiAlert elevation={6} variant="filled" {...props} />; +} + +const actionStyle = (operation) => { + var stl = { + fontSize: '0.5em', + paddingTop: '1em', + marginBottom: 0, + fontWeight: 'bold', + cursor: 'pointer' + } + stl.color = operation != 'buy' ? '#02a5c3' : '#666666'; + return stl; +} + +const GemImg = styled.img` + height: 23px; + position: relative; + top: 8px; + padding-right: 5px; +` +export default function ItemCardAction (props) { + const [success, setSuccess] = useState(false); + const [failure, setFailure] = useState(false); + const [message, setMessage] = useState("beerarea"); + const [info, setInfo] = useState(false); + + const handleClose = (snackbar) => { + if (snackbar == 'success') + setSuccess(false); + else if (snackbar == 'info') + setInfo(false); + else + setFailure(false); + } + + const handleClick = () => { + // this will become an axios get + if (true) { + setInfo(true); + setMessage("Item retirado"); + } + else if (true) { + setInfo(true); + setMessage("Item equipado"); + } + else if (true) { + setSuccess(true); + setMessage("Item comprado"); + } + else { + setFailure(true); + setMessage("Compra falhou"); + } + } + + return ( + <div> + <Snackbar open={info} autoHideDuration={6000} onClose={() => handleClose('info')}> + <Alert onClose={handleClose} severity="info"> + {message} + </Alert> + </Snackbar> + <Snackbar open={success} autoHideDuration={6000} onClose={() => handleClose('success')}> + <Alert onClose={handleClose} severity="success"> + {message} + </Alert> + </Snackbar> + <Snackbar open={failure} autoHideDuration={6000} onClose={() => handleClose('failure')}> + <Alert onClose={handleClose} severity="error"> + {message} + </Alert> + </Snackbar> + <span style={actionStyle(props.operation)} onClick={handleClick}> + {props.operation == 'buy' ? <GemImg src={gem}/> : <span/>} + {props.operation == 'buy' ? "COMPRAR" : + props.operation == 'equip' ? "USAR" : "TIRAR"} + </span> + </div> + ) +} diff --git a/src/Components/ItemCarousel.js b/src/Components/ItemCarousel.js index 851da0f9..4dfdf2d9 100644 --- a/src/Components/ItemCarousel.js +++ b/src/Components/ItemCarousel.js @@ -23,7 +23,19 @@ import CardActions from '@material-ui/core/CardActions'; import CardContent from '@material-ui/core/CardContent'; import ItemCard from './ItemCard.js'; +//url/user_items/index?q={"item_type": umdaqueles, "op": "none", "unlock_rule": "purchase"} export default function ItemCarousel (props) { + var items = [ + { + src: "https://upload.wikimedia.org/wikipedia/en/9/90/The_DuckDuckGo_Duck.png", + action: "equip", + name: "Avatar um", + description: "Descrição | Descrição" + } + ]; + for (let i = 0; i < 2; i++) + items = items.concat(items); + return ( <Grid item container @@ -33,8 +45,12 @@ export default function ItemCarousel (props) { xs={12} spacing={3} > - {[1, 2, 3, 4, 5, 6].map(() => { - return <ItemCard action="buy"/> + {items.map((i) => { + return <ItemCard + src={i.src} + action={i.action} + name={i.name} + description={i.description}/> })} </Grid> ) diff --git a/src/Pages/ItemStore.js b/src/Pages/ItemStore.js index 9ecc408b..60832379 100644 --- a/src/Pages/ItemStore.js +++ b/src/Pages/ItemStore.js @@ -15,8 +15,9 @@ 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 React, {useState, useContext, useEffect} from 'react'; import styled from 'styled-components'; +import axios from 'axios'; import Grid from '@material-ui/core/Grid'; import Card from '@material-ui/core/Card'; import CardActions from '@material-ui/core/CardActions'; @@ -25,12 +26,31 @@ import Container from '@material-ui/core/Container'; import UserCardGamified from '../Components/UserCardGamified.js'; import StoreGuide from '../Components/StoreGuide.js'; import ItemCarousel from '../Components/ItemCarousel.js'; +import {apiUrl} from '../env'; const StoreSection = styled.h2` font-weight: 100; ` export default function ItemStoreContainer (props) { + const [avatar_frames, setAvatarFrames] = useState([]); + const [card_frames, setCardFrames] = useState([]); + const [cover_frames, setCoverFrames] = useState([]); + const [badges, setBadges] = useState([]); + + useEffect(() => { + axios.all( + ['avatar_frame', 'card_frame', 'cover_frame', 'badge'].map((r) => { + return axios.get(apiUrl + '/' + 'user_items/index?q={"item_type":' + + r + ', "op": "none", "unlock_rule": "purchase"}'); + })).then(axios.spread((avatar, card, cover, badge) => { + setAvatarFrames(avatar); + setCardFrames(card); + setCoverFrames(cover); + setBadges(badge); + })); + }, []) + return ( <Container> <Grid container @@ -46,14 +66,20 @@ export default function ItemStoreContainer (props) { <StoreGuide/> </Grid> <StoreSection> - Avatares - <ItemCarousel/> + Bordas de avatar + <ItemCarousel items={avatar_frames}/> + </StoreSection> + <StoreSection> + Insígnias + <ItemCarousel items={badges}/> </StoreSection> <StoreSection> - Itens + Bordas de card + <ItemCarousel items={card_frames}/> </StoreSection> <StoreSection> - Bordas + Bordas de capa de perfil + <ItemCarousel items={cover_frames}/> </StoreSection> </Container> ) -- GitLab From 13807c1215431a5e134530ebdb51291051f7693f Mon Sep 17 00:00:00 2001 From: Raul Almeida <haltsimog@gmail.com> Date: Thu, 16 Apr 2020 11:52:49 -0300 Subject: [PATCH 13/16] WIP Item Carousel --- src/Components/ItemCardAction.js | 6 +++--- src/Components/ItemCarousel.js | 26 +++++++++++++++----------- src/Pages/ItemStore.js | 21 ++++++++++++++++----- 3 files changed, 34 insertions(+), 19 deletions(-) diff --git a/src/Components/ItemCardAction.js b/src/Components/ItemCardAction.js index 2922dc3d..c02455ea 100644 --- a/src/Components/ItemCardAction.js +++ b/src/Components/ItemCardAction.js @@ -64,15 +64,15 @@ export default function ItemCardAction (props) { const handleClick = () => { // this will become an axios get - if (true) { + if (props.operation == 'unequip') { setInfo(true); setMessage("Item retirado"); } - else if (true) { + else if (props.operation == 'equip') { setInfo(true); setMessage("Item equipado"); } - else if (true) { + else if (props.operation == 'buy') { setSuccess(true); setMessage("Item comprado"); } diff --git a/src/Components/ItemCarousel.js b/src/Components/ItemCarousel.js index 4dfdf2d9..260a26c5 100644 --- a/src/Components/ItemCarousel.js +++ b/src/Components/ItemCarousel.js @@ -25,16 +25,18 @@ import ItemCard from './ItemCard.js'; //url/user_items/index?q={"item_type": umdaqueles, "op": "none", "unlock_rule": "purchase"} export default function ItemCarousel (props) { - var items = [ - { - src: "https://upload.wikimedia.org/wikipedia/en/9/90/The_DuckDuckGo_Duck.png", - action: "equip", - name: "Avatar um", - description: "Descrição | Descrição" - } - ]; - for (let i = 0; i < 2; i++) - items = items.concat(items); + const [left, setLeft] = useState(0); + const [right, setRight] = useState(5); + + const goLeft = () => { + setLeft(left-1); + setRight(right-1); + } + + const goRight = () => { + setRight(right+1); + setLeft(left+1); + } return ( <Grid @@ -45,7 +47,9 @@ export default function ItemCarousel (props) { xs={12} spacing={3} > - {items.map((i) => { + <p onClick={goLeft}>ESQUERDA</p> + <p onClick={goRight}>DIREITA</p> + {props.items.slice(left, right).map((i) => { return <ItemCard src={i.src} action={i.action} diff --git a/src/Pages/ItemStore.js b/src/Pages/ItemStore.js index 3f762005..76cd9658 100644 --- a/src/Pages/ItemStore.js +++ b/src/Pages/ItemStore.js @@ -50,9 +50,20 @@ export default function ItemStoreContainer (props) { setBadges(badge); })); }, []) + + var items = [ + { + src: "https://upload.wikimedia.org/wikipedia/en/9/90/The_DuckDuckGo_Duck.png", + action: "equip", + name: "Avatar um", + description: "Descrição | Descrição" + } + ]; + for (let i = 0; i < 6; i++) + items = items.concat(items); return ( - <Container style={{paddingTop : "2em", backgroundColor : "purple"}}> + <Container style={{paddingTop : "2em", backgroundColor : "#f4f4f4"}}> <Grid container direction="row" justify="space-around" @@ -67,19 +78,19 @@ export default function ItemStoreContainer (props) { </Grid> <StoreSection> Bordas de avatar - <ItemCarousel items={avatar_frames}/> + <ItemCarousel items={items}/> </StoreSection> <StoreSection> Insígnias - <ItemCarousel items={badges}/> + <ItemCarousel items={items}/> </StoreSection> <StoreSection> Bordas de card - <ItemCarousel items={card_frames}/> + <ItemCarousel items={items}/> </StoreSection> <StoreSection> Bordas de capa de perfil - <ItemCarousel items={cover_frames}/> + <ItemCarousel items={items}/> </StoreSection> </Container> ) -- GitLab From 60a8d27b9e3542e1440c3020fa2bc9e34a2866bc Mon Sep 17 00:00:00 2001 From: Raul Almeida <haltsimog@gmail.com> Date: Fri, 17 Apr 2020 11:53:41 -0300 Subject: [PATCH 14/16] WIP Item Store: finish item card carousel It's a circular linked list --- src/Components/ItemCarousel.js | 24 +++++++++++++++++------- src/Pages/ItemStore.js | 19 ++++++++++++------- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/src/Components/ItemCarousel.js b/src/Components/ItemCarousel.js index 260a26c5..a3e03e8e 100644 --- a/src/Components/ItemCarousel.js +++ b/src/Components/ItemCarousel.js @@ -22,6 +22,9 @@ import Card from '@material-ui/core/Card'; import CardActions from '@material-ui/core/CardActions'; import CardContent from '@material-ui/core/CardContent'; import ItemCard from './ItemCard.js'; +import ArrowBackIcon from '@material-ui/icons/ArrowBack'; +import ArrowForwardIcon from '@material-ui/icons/ArrowForward'; +import IconButton from '@material-ui/core/IconButton'; //url/user_items/index?q={"item_type": umdaqueles, "op": "none", "unlock_rule": "purchase"} export default function ItemCarousel (props) { @@ -29,13 +32,13 @@ export default function ItemCarousel (props) { const [right, setRight] = useState(5); const goLeft = () => { - setLeft(left-1); - setRight(right-1); + setRight(right == 0 ? props.items.length-1 : right-1); + setLeft(left == 0 ? props.items.length-1 : left-1); } const goRight = () => { - setRight(right+1); - setLeft(left+1); + setRight(right == props.items.length-1 ? 0 : right+1); + setLeft(left == props.items.length-1 ? 0 : left+1); } return ( @@ -47,15 +50,22 @@ export default function ItemCarousel (props) { xs={12} spacing={3} > - <p onClick={goLeft}>ESQUERDA</p> - <p onClick={goRight}>DIREITA</p> - {props.items.slice(left, right).map((i) => { + <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 <ItemCard src={i.src} action={i.action} name={i.name} description={i.description}/> })} + <IconButton onClick={goRight}> + <ArrowForwardIcon/> + </IconButton> </Grid> ) } diff --git a/src/Pages/ItemStore.js b/src/Pages/ItemStore.js index 76cd9658..92d38657 100644 --- a/src/Pages/ItemStore.js +++ b/src/Pages/ItemStore.js @@ -28,9 +28,14 @@ import StoreGuide from '../Components/StoreGuide.js'; import ItemCarousel from '../Components/ItemCarousel.js'; import {apiUrl} from '../env'; -const StoreSection = styled.h2` +const SectionTitle = styled.h3` font-weight: 100; ` +const StoreSection = styled.div` + font-size: 1.5em; + margin-top: 20px; + margin-bottom: 20px; +` export default function ItemStoreContainer (props) { const [avatar_frames, setAvatarFrames] = useState([]); @@ -59,8 +64,8 @@ export default function ItemStoreContainer (props) { description: "Descrição | Descrição" } ]; - for (let i = 0; i < 6; i++) - items = items.concat(items); + for (let i = 0; i < 10; i++) + items = items.concat(items[0]); return ( <Container style={{paddingTop : "2em", backgroundColor : "#f4f4f4"}}> @@ -77,19 +82,19 @@ export default function ItemStoreContainer (props) { <StoreGuide/> </Grid> <StoreSection> - Bordas de avatar + <SectionTitle>Bordas de avatar</SectionTitle> <ItemCarousel items={items}/> </StoreSection> <StoreSection> - Insígnias + <SectionTitle>Insígnias</SectionTitle> <ItemCarousel items={items}/> </StoreSection> <StoreSection> - Bordas de card + <SectionTitle>Bordas de card</SectionTitle> <ItemCarousel items={items}/> </StoreSection> <StoreSection> - Bordas de capa de perfil + <SectionTitle>Bordas de capa de perfil</SectionTitle> <ItemCarousel items={items}/> </StoreSection> </Container> -- GitLab From 49545645427b2870a20047982947ab9ba6318d49 Mon Sep 17 00:00:00 2001 From: Raul Almeida <haltsimog@gmail.com> Date: Wed, 6 May 2020 11:22:23 -0300 Subject: [PATCH 15/16] WIP item store (multiple changes) - Add interface functionality (undo equip/unequip item) - Fix some axios calls - Add other axios calls - Improve visuals - Add store guide text etc --- src/Components/ItemCardAction.js | 98 ++++++++++++++++--- src/Components/StoreGuide.js | 37 +++++-- .../TabPanels/TabPanelStatusEConquistas.js | 2 +- src/Pages/ItemStore.js | 27 +++-- 4 files changed, 132 insertions(+), 32 deletions(-) diff --git a/src/Components/ItemCardAction.js b/src/Components/ItemCardAction.js index c02455ea..e323fd88 100644 --- a/src/Components/ItemCardAction.js +++ b/src/Components/ItemCardAction.js @@ -24,6 +24,14 @@ import Snackbar from '@material-ui/core/Snackbar'; import MuiAlert from '@material-ui/lab/Alert'; import Button from '@material-ui/core/Button'; import gem from '../img/gamification/gem.svg'; +import SnackbarContent from '@material-ui/core/SnackbarContent'; +import Dialog from '@material-ui/core/Dialog'; +import DialogActions from '@material-ui/core/DialogActions'; +import DialogContent from '@material-ui/core/DialogContent'; +import DialogContentText from '@material-ui/core/DialogContentText'; +import DialogTitle from '@material-ui/core/DialogTitle'; +import axios from 'axios' +import {apiUrl} from '../../env'; function Alert(props) { return <MuiAlert elevation={6} variant="filled" {...props} />; @@ -47,11 +55,21 @@ const GemImg = styled.img` top: 8px; padding-right: 5px; ` + +const GemSpan = styled.span` + color: red; +` + export default function ItemCardAction (props) { const [success, setSuccess] = useState(false); const [failure, setFailure] = useState(false); - const [message, setMessage] = useState("beerarea"); + const [message, setMessage] = useState(""); const [info, setInfo] = useState(false); + const [item_id, setItemID] = useState(0); + const [last_operation, setLastOperation] = useState(); + const [open_dialog, setOpenDialog] = useState(false); + const nonPurchaseMessage = <span>Item {last_operation == 'equip' ? 'retirado' : 'equipado'}. <a onClick={revertLastOperation}>Desfazer</a></span>; + const handleClose = (snackbar) => { if (snackbar == 'success') @@ -62,23 +80,46 @@ export default function ItemCardAction (props) { setFailure(false); } + const revertLastOperation = () => { + manageItemAndShowSnackbar(last_operation == 'equip' ? 'unequip' : 'equip', + setInfo, + nonPurchaseMessage; + 'Erro'); + } + + const manageItemAndShowSnackbar = (operation, setSnackbar, successMessage, failureMessage) => { + axios.patch(apiUrl + '/users/' + operation + '_item?id=' + item_id).then( + response => { + if (response.status == 200) { + setSnackbar(true); + setMessage(successMessage); + } else { + setFailure(true); + setMessage(failureMessage); + } + } + ); + setLastOperation(operation == 'purchase' ? last_operation : (operation == 'equip' ? 'unequip' : 'equip')); + } + + const handleClickBuyItem = () => { + setOpenDialog(false); + manageItemAndShowSnackbar('purchase', setSuccess, <span>Item comprado.</span>, + <span>Compra falhou. Tente novamente</span>); + } + + const handleDialogClose = () => { + setOpenDialog(false); + } + const handleClick = () => { // this will become an axios get - if (props.operation == 'unequip') { - setInfo(true); - setMessage("Item retirado"); - } - else if (props.operation == 'equip') { - setInfo(true); - setMessage("Item equipado"); - } + if (props.operation == 'unequip') + manageItemAndShowSnackbar('unequip', setInfo, nonPurchaseMessage, 'Erro'); + else if (props.operation == 'equip') + manageItemAndShowSnackbar('equip', setInfo, nonPurchaseMessage, 'Erro'); else if (props.operation == 'buy') { - setSuccess(true); - setMessage("Item comprado"); - } - else { - setFailure(true); - setMessage("Compra falhou"); + setOpenDialog(true); } } @@ -104,6 +145,33 @@ export default function ItemCardAction (props) { {props.operation == 'buy' ? "COMPRAR" : props.operation == 'equip' ? "USAR" : "TIRAR"} </span> + <Dialog + open={open_dialog} + onClose={handleClose} + aria-labelledby="alert-dialog-title" + aria-describedby="alert-dialog-description" + > + <DialogTitle id="alert-dialog-title">{"Deseja realmente comprar este item?"}</DialogTitle> + <DialogContent> + <DialogContentText id="alert-dialog-description"> + <strong>Esta compra não envolve nenhum dinheiro real.</strong> + + <br/><br/>O item que você deseja comprar, <strong>NOME DO ITEM</strong>, custa + <GemImg src={gem}/><GemSpan>PREÇO</GemSpan> gemas. Você possui + <GemImg src={gem}/><GemSpan><strong>GEMAS</strong></GemSpan> gemas. + + <br/><br/>Comprar este item lhe deixará com <GemImg src={gem}/><GemSpan><strong>TANTAS</strong></GemSpan> gemas. + </DialogContentText> + </DialogContent> + <DialogActions> + <Button onClick={handleDialogClose} color="primary"> + Cancelar + </Button> + <Button onClick={handleClickBuyItem} color="primary" autoFocus> + Comprar + </Button> + </DialogActions> + </Dialog> </div> ) } diff --git a/src/Components/StoreGuide.js b/src/Components/StoreGuide.js index 03bcf8a2..a4b0f509 100644 --- a/src/Components/StoreGuide.js +++ b/src/Components/StoreGuide.js @@ -47,21 +47,38 @@ export default function ItemStoreContainer (props) { O que são "gemas"? </StoreTopic> <StoreBody> - Aqui eu explico muito bem o que são "gemas" + Gemas são moedas virtuais que você ganha usando a plataforma MEC RED (publicando recursos, avaliando recursos, criando conexões, etc) e pode usar para adquirir itens cosméticos para seu perfil, como insígnias e bordas de avatar. </StoreBody> <StoreTopic> - Regras + Posso usar dinheiro real para comprar gemas? </StoreTopic> <StoreBody> - 1st RULE: You do not talk about FIGHT CLUB. - 2nd RULE: You DO NOT talk about FIGHT CLUB. - 3rd RULE: If someone says "stop" or goes limp, taps out the fight is over. - 4th RULE: Only two guys to a fight. - 5th RULE: One fight at a time. - 6th RULE: No shirts, no shoes. - 7th RULE: Fights will go on as long as they have to. - 8th RULE: If this is your first night at FIGHT CLUB, you HAVE to fight. + <strong>Não.</strong> Gemas são adquiridas exclusivamente através do uso da plataforma. </StoreBody> + <StoreTopic> + Qual a vantagem de usar itens? + </StoreTopic> + <StoreBody> + Os itens são uma maneira de mostrar quem você é, quais os seus interesses e quais foram suas contribuições mais importantes. Nenhum item oferece funcionalidade a mais, de maneira que novos usuários não sofram desvantagem. + </StoreBody> + <StoreTopic> + Como usar + </StoreTopic> + <StoreBody> + As seções da loja dividem os itens por <strong>categoria</strong>. + <ul> + <li> + Itens adquiridos <strong>somente por conquistas</strong> não aparecem + na loja (exceto pelos que você já tem); + </li> + <li> + Outros itens podem ser comprados (usando gemas), usados (usar uma borda de avatar, por exemplo) ou tirados (se estiverem sendo usados). + </li> + </ul> + </StoreBody> + <h4> + Boas compras! + </h4> </CardContent> </Card> </Grid> diff --git a/src/Components/TabPanels/TabPanelStatusEConquistas.js b/src/Components/TabPanels/TabPanelStatusEConquistas.js index 9b41ad4f..67eeaa52 100644 --- a/src/Components/TabPanels/TabPanelStatusEConquistas.js +++ b/src/Components/TabPanels/TabPanelStatusEConquistas.js @@ -27,7 +27,7 @@ export default function TabPanelStatusEConquistas (props) { axios.all( ['xp_to_next_lvl', 'percent_to_next_level', 'points', 'xp', 'get_level', 'completed_achievements'].map((r) => { - return axios.get(apiUrl + '/' + r + '/' + state.currentUser.id); + return axios.get(apiUrl + '/' r + '?id=' + state.currentUser.id); })).then(axios.spread((xp_to_next_lvl, percent_to_next_level, points, xp, level, completed_achievements) => { this.setXpToNextLevel(xp_to_next_lvl); diff --git a/src/Pages/ItemStore.js b/src/Pages/ItemStore.js index 92d38657..0487644e 100644 --- a/src/Pages/ItemStore.js +++ b/src/Pages/ItemStore.js @@ -30,10 +30,17 @@ import {apiUrl} from '../env'; const SectionTitle = styled.h3` font-weight: 100; + margin-bottom: 0; ` + +const StoreDivider = styled.hr` + width: 50px; + margin-left: 0; +` + const StoreSection = styled.div` font-size: 1.5em; - margin-top: 20px; + margin-top: 60px; margin-bottom: 20px; ` @@ -49,17 +56,18 @@ export default function ItemStoreContainer (props) { return axios.get(apiUrl + '/' + 'user_items/index?q={"item_type":' + r + ', "op": "none", "unlock_rule": "purchase"}'); })).then(axios.spread((avatar, card, cover, badge) => { - setAvatarFrames(avatar); - setCardFrames(card); - setCoverFrames(cover); - setBadges(badge); + console.log([avatar, card, cover, badge]); + //setAvatarFrames(avatar); + //setCardFrames(card); + //setCoverFrames(cover); + //setBadges(badge); })); }, []) var items = [ { src: "https://upload.wikimedia.org/wikipedia/en/9/90/The_DuckDuckGo_Duck.png", - action: "equip", + action: "buy", name: "Avatar um", description: "Descrição | Descrição" } @@ -83,18 +91,25 @@ export default function ItemStoreContainer (props) { </Grid> <StoreSection> <SectionTitle>Bordas de avatar</SectionTitle> + <StoreDivider/> <ItemCarousel items={items}/> </StoreSection> + <StoreSection> <SectionTitle>Insígnias</SectionTitle> + <StoreDivider/> <ItemCarousel items={items}/> </StoreSection> + <StoreSection> <SectionTitle>Bordas de card</SectionTitle> + <StoreDivider/> <ItemCarousel items={items}/> </StoreSection> + <StoreSection> <SectionTitle>Bordas de capa de perfil</SectionTitle> + <StoreDivider/> <ItemCarousel items={items}/> </StoreSection> </Container> -- GitLab From 1b51bb8756f2a30cc4f1ad6d9306202ec6344cbc Mon Sep 17 00:00:00 2001 From: Raul Almeida <haltsimog@gmail.com> Date: Fri, 8 May 2020 10:26:56 -0300 Subject: [PATCH 16/16] WIP more adjustments to item store Detailed information on reports --- src/Components/ItemCardAction.js | 4 +-- src/Components/MenuBar.js | 2 +- .../TabPanels/TabPanelStatusEConquistas.js | 2 +- src/Pages/ItemStore.js | 33 ++++++------------- 4 files changed, 14 insertions(+), 27 deletions(-) diff --git a/src/Components/ItemCardAction.js b/src/Components/ItemCardAction.js index e323fd88..c5e9f41d 100644 --- a/src/Components/ItemCardAction.js +++ b/src/Components/ItemCardAction.js @@ -31,7 +31,7 @@ import DialogContent from '@material-ui/core/DialogContent'; import DialogContentText from '@material-ui/core/DialogContentText'; import DialogTitle from '@material-ui/core/DialogTitle'; import axios from 'axios' -import {apiUrl} from '../../env'; +import {apiUrl} from '../env'; function Alert(props) { return <MuiAlert elevation={6} variant="filled" {...props} />; @@ -83,7 +83,7 @@ export default function ItemCardAction (props) { const revertLastOperation = () => { manageItemAndShowSnackbar(last_operation == 'equip' ? 'unequip' : 'equip', setInfo, - nonPurchaseMessage; + nonPurchaseMessage, 'Erro'); } diff --git a/src/Components/MenuBar.js b/src/Components/MenuBar.js index cb2ab092..d7787a8c 100644 --- a/src/Components/MenuBar.js +++ b/src/Components/MenuBar.js @@ -127,7 +127,7 @@ export default function MenuBar(props){ <a href="http://educacaoconectada.mec.gov.br/" rel="noopener noreferrer" target="_blank" > <ButtonStyled >Educação Conectada</ButtonStyled> </a> - <a href="/store"> + <a href="/loja"> <ButtonStyled>Lojinha</ButtonStyled> </a> <ButtonStyled onClick={props.openSearchBar} ><IconSearchStyled />Buscar</ButtonStyled> diff --git a/src/Components/TabPanels/TabPanelStatusEConquistas.js b/src/Components/TabPanels/TabPanelStatusEConquistas.js index 67eeaa52..1c5b1986 100644 --- a/src/Components/TabPanels/TabPanelStatusEConquistas.js +++ b/src/Components/TabPanels/TabPanelStatusEConquistas.js @@ -27,7 +27,7 @@ export default function TabPanelStatusEConquistas (props) { axios.all( ['xp_to_next_lvl', 'percent_to_next_level', 'points', 'xp', 'get_level', 'completed_achievements'].map((r) => { - return axios.get(apiUrl + '/' r + '?id=' + state.currentUser.id); + return axios.get(apiUrl + '/' + r + '?id=' + state.currentUser.id); })).then(axios.spread((xp_to_next_lvl, percent_to_next_level, points, xp, level, completed_achievements) => { this.setXpToNextLevel(xp_to_next_lvl); diff --git a/src/Pages/ItemStore.js b/src/Pages/ItemStore.js index 0487644e..ce8855c0 100644 --- a/src/Pages/ItemStore.js +++ b/src/Pages/ItemStore.js @@ -53,30 +53,17 @@ export default function ItemStoreContainer (props) { useEffect(() => { axios.all( ['avatar_frame', 'card_frame', 'cover_frame', 'badge'].map((r) => { - return axios.get(apiUrl + '/' + 'user_items/index?q={"item_type":' - + r + ', "op": "none", "unlock_rule": "purchase"}'); + return axios.get(apiUrl+'/' + 'user_items/index?item_type='+r+'&unlock_rule=purchase'); })).then(axios.spread((avatar, card, cover, badge) => { - console.log([avatar, card, cover, badge]); - //setAvatarFrames(avatar); - //setCardFrames(card); - //setCoverFrames(cover); - //setBadges(badge); + setAvatarFrames(avatar); + setCardFrames(card); + setCoverFrames(cover); + setBadges(badge); })); }, []) - - var items = [ - { - src: "https://upload.wikimedia.org/wikipedia/en/9/90/The_DuckDuckGo_Duck.png", - action: "buy", - name: "Avatar um", - description: "Descrição | Descrição" - } - ]; - for (let i = 0; i < 10; i++) - items = items.concat(items[0]); return ( - <Container style={{paddingTop : "2em", backgroundColor : "#f4f4f4"}}> + <Container style={{paddingTop : "2em", backgroundColor : "#f4f4f4", width: '100%'}}> <Grid container direction="row" justify="space-around" @@ -92,25 +79,25 @@ export default function ItemStoreContainer (props) { <StoreSection> <SectionTitle>Bordas de avatar</SectionTitle> <StoreDivider/> - <ItemCarousel items={items}/> + <ItemCarousel items={avatar_frames}/> </StoreSection> <StoreSection> <SectionTitle>Insígnias</SectionTitle> <StoreDivider/> - <ItemCarousel items={items}/> + <ItemCarousel items={badges}/> </StoreSection> <StoreSection> <SectionTitle>Bordas de card</SectionTitle> <StoreDivider/> - <ItemCarousel items={items}/> + <ItemCarousel items={card_frames}/> </StoreSection> <StoreSection> <SectionTitle>Bordas de capa de perfil</SectionTitle> <StoreDivider/> - <ItemCarousel items={items}/> + <ItemCarousel items={cover_frames}/> </StoreSection> </Container> ) -- GitLab