diff --git a/src/Components/BadgesModal.js b/src/Components/BadgesModal.js index e42706bb37173c83c0ecd9c6072ebbcb658ca2b8..cbc2e77aca1dfa6f5918c079a0b52f4e2fcae9d1 100644 --- a/src/Components/BadgesModal.js +++ b/src/Components/BadgesModal.js @@ -15,7 +15,7 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with Plataforma Integrada MEC. If not, see <http://www.gnu.org/licenses/>.*/ -import React from 'react'; +import React, { useEffect, useState } from 'react'; import { makeStyles } from '@material-ui/core/styles'; import Dialog from '@material-ui/core/Dialog'; import AppBar from '@material-ui/core/AppBar'; @@ -24,183 +24,292 @@ import IconButton from '@material-ui/core/IconButton'; import Typography from '@material-ui/core/Typography'; import CloseIcon from '@material-ui/icons/Close'; import Slide from '@material-ui/core/Slide'; -import Grid from '@material-ui/core/Grid'; -import Accordion from '@material-ui/core/Accordion'; -import AccordionSummary from '@material-ui/core/AccordionSummary'; -import AccordionDetails from '@material-ui/core/AccordionDetails'; -import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; - -import BadgeCard from './BadgeCard'; +import { getRequest } from './HelperFunctions/getAxiosConfig' +import styled from 'styled-components' +import UserItemsCarousel from './UserItemsCarousel' +import ContactCard from './ContactCard' +import { apiDomain } from '../env' +import Grid from '@material-ui/core/Grid' const useStyles = makeStyles((theme) => ({ - appBar: { - position: 'relative', - }, - title: { - marginLeft: theme.spacing(2), - flex: 1, - }, - root: { - width: '100%', - }, + appBar: { + position: 'relative', + }, + title: { + marginLeft: theme.spacing(2), + flex: 1, + }, + root: { + width: '100%', + }, })); +const SectionTitle = styled.h3` + font-weight: 500; + margin-bottom: 0; +` + +const ErrorTextCenter = styled.h3` + font-weight: bold; + margin-bottom: 0; + text-align: center; +` + +const StoreDivider = styled.hr` + width: 50px; + margin-left: 0; +` + +const StoreSection = styled.div` + font-size: 1.5em; + margin-top: 60px; + margin-bottom: 20px; +` + +const Content = styled.div` + width: 95%; + margin: 50px auto; +` +const ExplicationTitle = styled.h2` + font-weight: lighter +` + const Transition = React.forwardRef(function Transition(props, ref) { - return <Slide direction="up" ref={ref} {...props} />; + return <Slide direction="up" ref={ref} {...props} />; }); export default function FullScreenDialog(props) { - const classes = useStyles(); - const myBadgets = [ - { - title: "Shrimp and Chorizo Paella", - time: "September 14, 2016", - description: "This impressive paella is a perfect party dish and a fun meal to cook together with your guests.Add 1 cup of frozen peas along with the mussels, if you like.", - avatar: "https://futhead.cursecdn.com/static/img/17/items/badges/6000255.png" - }, - { - title: "Shrimp and Chorizo Paella", - time: "September 14, 2016", - description: "This impressive paella is a perfect party dish and a fun meal to cook together with your guests.Add 1 cup of frozen peas along with the mussels, if you like.", - avatar: "https://futhead.cursecdn.com/static/img/17/items/badges/6000255.png" - }, - { - title: "Shrimp and Chorizo Paella", - time: "September 14, 2016", - description: "This impressive paella is a perfect party dish and a fun meal to cook together with your guests.Add 1 cup of frozen peas along with the mussels, if you like.", - avatar: "https://futhead.cursecdn.com/static/img/17/items/badges/6000255.png" - }, - { - title: "Shrimp and Chorizo Paella", - time: "September 14, 2016", - description: "This impressive paella is a perfect party dish and a fun meal to cook together with your guests.Add 1 cup of frozen peas along with the mussels, if you like.", - avatar: "https://futhead.cursecdn.com/static/img/17/items/badges/6000255.png" - }, - { - title: "Shrimp and Chorizo Paella", - time: "September 14, 2016", - description: "This impressive paella is a perfect party dish and a fun meal to cook together with your guests.Add 1 cup of frozen peas along with the mussels, if you like.", - avatar: "https://futhead.cursecdn.com/static/img/17/items/badges/6000255.png" - }, - { - title: "Shrimp and Chorizo Paella", - time: "September 14, 2016", - description: "This impressive paella is a perfect party dish and a fun meal to cook together with your guests.Add 1 cup of frozen peas along with the mussels, if you like.", - avatar: "https://futhead.cursecdn.com/static/img/17/items/badges/6000255.png" - } - ] - - const myAvatares = [ - { - title: "Shrimp and Chorizo Paella", - time: "September 14, 2016", - description: "This impressive paella is a perfect party dish and a fun meal to cook together with your guests.Add 1 cup of frozen peas along with the mussels, if you like.", - avatar: "https://styles.redditmedia.com/t5_tpk2m/styles/profileIcon_snoo5272646d-0efc-4e69-a737-47637e80bb66-headshot.png?width=256&height=256&crop=256:256,smart&s=4f7a7996efd782f55ec9f10b23545043cd61d3b4" - }, - { - title: "Shrimp and Chorizo Paella", - time: "September 14, 2016", - description: "This impressive paella is a perfect party dish and a fun meal to cook together with your guests.Add 1 cup of frozen peas along with the mussels, if you like.", - avatar: "https://styles.redditmedia.com/t5_tpk2m/styles/profileIcon_snoo5272646d-0efc-4e69-a737-47637e80bb66-headshot.png?width=256&height=256&crop=256:256,smart&s=4f7a7996efd782f55ec9f10b23545043cd61d3b4" - }, - { - title: "Shrimp and Chorizo Paella", - time: "September 14, 2016", - description: "This impressive paella is a perfect party dish and a fun meal to cook together with your guests.Add 1 cup of frozen peas along with the mussels, if you like.", - avatar: "https://styles.redditmedia.com/t5_tpk2m/styles/profileIcon_snoo5272646d-0efc-4e69-a737-47637e80bb66-headshot.png?width=256&height=256&crop=256:256,smart&s=4f7a7996efd782f55ec9f10b23545043cd61d3b4" - }, - { - title: "Shrimp and Chorizo Paella", - time: "September 14, 2016", - description: "This impressive paella is a perfect party dish and a fun meal to cook together with your guests.Add 1 cup of frozen peas along with the mussels, if you like.", - avatar: "https://styles.redditmedia.com/t5_tpk2m/styles/profileIcon_snoo5272646d-0efc-4e69-a737-47637e80bb66-headshot.png?width=256&height=256&crop=256:256,smart&s=4f7a7996efd782f55ec9f10b23545043cd61d3b4" - }, - { - title: "Shrimp and Chorizo Paella", - time: "September 14, 2016", - description: "This impressive paella is a perfect party dish and a fun meal to cook together with your guests.Add 1 cup of frozen peas along with the mussels, if you like.", - avatar: "https://styles.redditmedia.com/t5_tpk2m/styles/profileIcon_snoo5272646d-0efc-4e69-a737-47637e80bb66-headshot.png?width=256&height=256&crop=256:256,smart&s=4f7a7996efd782f55ec9f10b23545043cd61d3b4" - }, - { - title: "Shrimp and Chorizo Paella", - time: "September 14, 2016", - description: "This impressive paella is a perfect party dish and a fun meal to cook together with your guests.Add 1 cup of frozen peas along with the mussels, if you like.", - avatar: "https://styles.redditmedia.com/t5_tpk2m/styles/profileIcon_snoo5272646d-0efc-4e69-a737-47637e80bb66-headshot.png?width=256&height=256&crop=256:256,smart&s=4f7a7996efd782f55ec9f10b23545043cd61d3b4" - } - ] - - // - - return ( - <div> - <Dialog fullScreen open={props.open} onClose={props.handleClose} TransitionComponent={Transition}> - <AppBar className={classes.appBar}> - <Toolbar> - <IconButton edge="start" color="inherit" onClick={props.handleClose} aria-label="close"> - <CloseIcon /> - </IconButton> - <Typography variant="h6" className={classes.title}> - Seus Badges - </Typography> - </Toolbar> - </AppBar> - - <Accordion> - <AccordionSummary - expandIcon={<ExpandMoreIcon />} - aria-controls="panel1a-content" - id="panel1a-header" - > - <Typography variant="h6">Badgets</Typography> - </AccordionSummary> - <AccordionDetails> - <Grid container direction="row" alignItems="center" justify="center" spacing={4} xs={12}> - { - myBadgets.map((badge, index) => { - return ( - <Grid item alignContent="center" key={index}> - <BadgeCard - title={badge.title} - time={badge.time} - description={badge.description} - avatar={badge.avatar} - /> - </Grid> - ) - }) - } - </Grid> - </AccordionDetails> - </Accordion> - - <Accordion> - <AccordionSummary - expandIcon={<ExpandMoreIcon />} - aria-controls="panel1a-content" - id="panel1a-header" - > - <Typography variant="h6">Avatares</Typography> - </AccordionSummary> - <AccordionDetails> - <Grid container direction="row" alignItems="center" justify="center" spacing={4} xs={12}> - { - myAvatares.map((badge, index) => { - return ( - <Grid item alignContent="center" key={index}> - <BadgeCard - title={badge.title} - time={badge.time} - description={badge.description} - avatar={badge.avatar} - /> - </Grid> - ) - }) - } - </Grid> - </AccordionDetails> - </Accordion> - </Dialog> - </div> - ); + const classes = useStyles(); + + const [badges, setBadges] = useState([]); + const [avatar_frames, setAvatarFrames] = useState([]); + const [card_frames, setCardFrames] = useState([]); + const [cover_frames, setCoverFrames] = useState([]); + + const [totalBadges, setTotalBadges] = useState(0) + const [totalAvatarFrame, setTotalAvatarFrame] = useState(0) + const [totalCoverFrame, setTotalCoverFrame] = useState(0) + const [totalCardFrame, setTotalCardFrame] = useState(0) + + const [errInBadge, setErrInBadge] = useState(false) + const [errInAvatarFrame, setErrInAvatarFrame] = useState(false) + const [errInCoverFrame, setErrInCoverFrame] = useState(false) + const [errInCardFrame, setErrInCardFrame] = useState(false) + + const [disabledBadges, setDisabledBadges] = useState(false) + const [disabledAvatarFrame, setDisabledAvatarFrame] = useState(false) + const [disabledCoverFrame, setDisabledCoverFrame] = useState(false) + const [disabledCardFrame, setDisabledCardFrame] = useState(false) + + const [stopLoadingBadges, setStopLoadingBadges] = useState(false) + const [stopLoadingAvatarFrame, setStopLoadingAvatarFrame] = useState(false) + const [stopLoadingCoverFrame, setStopLoadingCoverFrame] = useState(false) + const [stopLoadingCardFrame, setStopLoadingCardFrame] = useState(false) + + const [currBadgePage, setCurrBadgePage] = useState(0) + const [currAvatarFramePage, setCurrAvatarFramePage] = useState(0) + const [currCoverFramePage, setCurrCoverFramePage] = useState(0) + const [currCardFramePage, setCurrCardFramePage] = useState(0) + + const buildUrl = (objType, page) => { + return `/user_items?filter={"state" : "active"}&item_type=${objType}&page=${page}&range=[0,9]&results_per_page=10&sort=["id","DESC"]` + } + + useEffect(() => { + setDisabledBadges(true) + getRequest( + buildUrl("badge", currBadgePage), + (data, header) => { + if (data.length === 0) + setStopLoadingBadges(true) + if (header.has('X-Total-Count')) + setTotalBadges(header.get('X-Total-Count')) + setBadges((previous) => previous.concat(data)) + setDisabledBadges(false) + }, + (error) => { + setErrInBadge(true) + setDisabledBadges(false) + } + ) + }, [currBadgePage]) + + useEffect(() => { + setDisabledAvatarFrame(true) + getRequest( + buildUrl("avatar_frame", currAvatarFramePage), + (data, header) => { + if (data.length === 0) + setStopLoadingAvatarFrame(true) + if (header.has('X-Total-Count')) + setTotalAvatarFrame(header.get('X-Total-Count')) + setAvatarFrames((previous) => previous.concat(data)) + setDisabledAvatarFrame(false) + }, + (error) => { + setErrInAvatarFrame(true) + setDisabledAvatarFrame(false) + } + ) + }, [currAvatarFramePage]) + + useEffect(() => { + setDisabledCoverFrame(true) + getRequest( + buildUrl("cover_frame", currCoverFramePage), + (data, header) => { + if (data.length === 0) + setStopLoadingCoverFrame(true) + if (header.has('X-Total-Count')) + setTotalCoverFrame(header.get('X-Total-Count')) + setCoverFrames((previous) => previous.concat(data)) + setDisabledCoverFrame(false) + }, + (error) => { + setErrInCoverFrame(true) + setDisabledCoverFrame(false) + } + ) + }, [currCoverFramePage]) + + useEffect(() => { + setDisabledCardFrame(true) + getRequest( + buildUrl("card_frame", currCardFramePage), + (data, header) => { + if (data.length === 0) + setStopLoadingCardFrame(true) + if (header.has('X-Total-Count')) + setTotalCardFrame(header.get('X-Total-Count')) + setCardFrames((previous) => previous.concat(data)) + setDisabledCardFrame(false) + }, + (error) => { + setErrInCardFrame(true) + setDisabledCardFrame(false) + } + ) + }, [currCardFramePage]) + + + return ( + <div> + <Dialog fullScreen open={props.open} onClose={props.handleClose} TransitionComponent={Transition}> + <AppBar className={classes.appBar}> + <Toolbar> + <IconButton edge="start" color="inherit" onClick={props.handleClose} aria-label="close"> + <CloseIcon /> + </IconButton> + <Typography variant="h6" className={classes.title}> + Personalize o seu card de usuário + </Typography> + </Toolbar> + </AppBar> + <Content> + <Grid container direction='column' justify='center' alignItems='center'> + <Grid item> + <ExplicationTitle> + Os outros usuários verão o seu card de usuário desse jeito... + </ExplicationTitle> + </Grid> + <Grid item> + <ContactCard + name={props.currUser.name} + avatar={props.currUser.avatar ? apiDomain + props.currUser.avatar : null} + cover={props.currUser.cover ? apiDomain + props.currUser.cover : null} + numCollections={props.currUser.collections_count} + numLearningObjects={props.currUser.learning_objects_count} + follow_count={props.currUser.follows_count} + points={props.currUserPoints} + // followed={props.currUser.followed || null} + // followerID={props.currUser.follower.id} + href={'/usuario-publico/' + props.currUser.id} + /> + </Grid> + </Grid> + + { + errInBadge ? + <StoreSection> + <ErrorTextCenter> + Erro ao carregar as insígnias + </ErrorTextCenter> + </StoreSection> + : + <StoreSection> + <SectionTitle>Suas insígnias ({totalBadges})</SectionTitle> + <StoreDivider /> + <UserItemsCarousel + items={badges} + setCurrPage={() => { setCurrBadgePage(currBadgePage + 1) }} + disabled={disabledBadges} + stop={stopLoadingBadges} + /> + </StoreSection> + } + + { + errInCardFrame ? + <StoreSection> + <ErrorTextCenter> + Erro ao carregar as Molduras de card de usuário + </ErrorTextCenter> + </StoreSection> + : + <StoreSection> + <SectionTitle>Suas molduras de card de usuário ({totalCardFrame})</SectionTitle> + <StoreDivider /> + <UserItemsCarousel + items={card_frames} + setCurrPage={() => { setCurrCardFramePage(currCardFramePage + 1) }} + disabled={disabledCardFrame} + stop={stopLoadingCardFrame} + /> + </StoreSection> + } + + { + errInAvatarFrame ? + <StoreSection> + <ErrorTextCenter> + Erro ao carregar as Molduras de avatar + </ErrorTextCenter> + </StoreSection> + : + <StoreSection> + <SectionTitle>Suas molduras de avatar ({totalAvatarFrame})</SectionTitle> + <StoreDivider /> + <UserItemsCarousel + items={avatar_frames} + setCurrPage={() => { setCurrAvatarFramePage(currAvatarFramePage + 1) }} + disabled={disabledAvatarFrame} + stop={stopLoadingAvatarFrame} + /> + </StoreSection> + } + + { + errInCoverFrame ? + <StoreSection> + <ErrorTextCenter> + Erro ao carregar as Molduras de capa + </ErrorTextCenter> + </StoreSection> + : + <StoreSection> + <SectionTitle>Suas molduras de capa ({totalCoverFrame})</SectionTitle> + <StoreDivider /> + <UserItemsCarousel + items={cover_frames} + setCurrPage={() => { setCurrCoverFramePage(currCoverFramePage + 1) }} + disabled={disabledCoverFrame} + stop={stopLoadingCoverFrame} + /> + </StoreSection> + } + </Content> + </Dialog> + </div> + ); } + diff --git a/src/Components/LevelDescriptionCard.js b/src/Components/LevelDescriptionCard.js index 66e737b1e22cfdcef375d778b3b2b6c4a2882f6e..f87ccd0b28161a1ae2acdbc12003bd9535debad7 100644 --- a/src/Components/LevelDescriptionCard.js +++ b/src/Components/LevelDescriptionCard.js @@ -22,7 +22,7 @@ export default function LevelDescriptionCard(props) { return ( <LevelDescDiv> - <BadgesModal handleClose={handleClose} open={open} /> + <BadgesModal handleClose={handleClose} open={open} currUser={props.currUser} /> <Grid container alignItems="center" justify={WINDOW_WIDTH <= 500 ? 'center' : 'space-between'} direction='row'> <Grid item> <Grid container alignItems="center" justify='center' direction='row'> diff --git a/src/Components/TabPanels/TabPanelStatusEConquistas.js b/src/Components/TabPanels/TabPanelStatusEConquistas.js index 23417d7d15f412f33d8a292b8ffe46d8c5fc33a2..dbad571da9aed0a847aa8620065671600fa43217 100644 --- a/src/Components/TabPanels/TabPanelStatusEConquistas.js +++ b/src/Components/TabPanels/TabPanelStatusEConquistas.js @@ -26,18 +26,20 @@ import { getRequest } from '../HelperFunctions/getAxiosConfig' import AchievementsCarosel from './AchivementsCarrosel' import ProgressCarosel from './ProgressCarrosel' -export default function TabPanelStatusEConquistas({ id, level, levelXP, points, experience }) { +export default function TabPanelStatusEConquistas({ id, level, levelXP, points, experience, currUser }) { 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 [errorInAchievements, setErrorInAchievements] = 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 [errorInProgress, setErrorInProgress] = useState(false) const buildUrl = (page, type) => { return `/${type}?page=${page}&range=[0,9]&results_per_page=10&sort=["id","DESC"]` @@ -56,6 +58,7 @@ export default function TabPanelStatusEConquistas({ id, level, levelXP, points, setDisableAchievements(false) }, (error) => { + setErrorInAchievements(true) setDisableAchievements(false) } ) @@ -74,6 +77,7 @@ export default function TabPanelStatusEConquistas({ id, level, levelXP, points, setDisableProgress(false) }, (error) => { + setErrorInProgress(true) setDisableProgress(false) } ) @@ -84,6 +88,7 @@ export default function TabPanelStatusEConquistas({ id, level, levelXP, points, <UserProfileContainer> <Paper elevation={3}> <LevelDescriptionCard + currUser={currUser} xp_to_next_lvl={levelXP - experience} bar_size={(experience / levelXP) * 100} coins={points} @@ -95,30 +100,48 @@ export default function TabPanelStatusEConquistas({ id, level, levelXP, points, <UserProfileContainer> <Paper elevation={3} style={{ padding: '1em' }}> <AchievementsList> - <AchievementsSectionTitle> - Últimas conquistas ({totalAchievements}) - </AchievementsSectionTitle> - <AchievementsCarosel - items={achievements} - setCurrPage={() => { setCurrPageAchievements(currPageAchievements + 1) }} - disabled={disableAchievements} - stop={stopAchievements} - /> + { + errorInAchievements ? + <AchievementsSectionTitle> + Erro ao buscar suas conquistas + </AchievementsSectionTitle> + : + <> + <AchievementsSectionTitle> + Ú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> - <ProgressCarosel - items={progress} - setCurrPage={() => { setCurrPageProgress(currPageProgress + 1) }} - disabled={disableProgress} - stop={stopProgress} - /> + { + errorInProgress ? + <AchievementsSectionTitle> + Error ao buscar o seu progresso + </AchievementsSectionTitle> + : + <> + <AchievementsSectionTitle> + Progressos ({totalProgress}) + </AchievementsSectionTitle> + <ProgressCarosel + items={progress} + setCurrPage={() => { setCurrPageProgress(currPageProgress + 1) }} + disabled={disableProgress} + stop={stopProgress} + /> + </> + } </AchievementsList> </Paper> </UserProfileContainer> @@ -129,13 +152,7 @@ export default function TabPanelStatusEConquistas({ id, level, levelXP, points, const AchievementsSectionTitle = styled.h1` font-weight: 400; ` -const AchievementsContainer = styled.div` - max-width : 1140px; - margin-bottom: 30px; - margin-top: 70px; - margin-left : auto; - margin-right : auto; -` + const AchievementsList = styled.div` display: flex; flex-direction: column diff --git a/src/Components/UserItemCard.js b/src/Components/UserItemCard.js new file mode 100644 index 0000000000000000000000000000000000000000..097e1c448dd59442ba099f8b1b0c210276ac1e43 --- /dev/null +++ b/src/Components/UserItemCard.js @@ -0,0 +1,71 @@ +/*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 UserItemCardAction from './UserItemCardAction'; +import { apiDomain } from '../env' + +const ItemImage = styled.img` + border-radius: 150; + max-width: 100%; +` + +const ItemName = styled.h3` + display: -webkit-box; + -webkit-line-clamp: 3; + -webkit-box-orient: vertical; + overflow: hidden; + font-size: 0.8em; + font-weight: lighter; + color: #666666; + width: 100%; + word-break: break-word; +` + +const ItemDescription = styled.p` + display: -webkit-box; + -webkit-line-clamp: 3; + -webkit-box-orient: vertical; + overflow: hidden; + font-size: 0.5em; + color: #666666; +` + +export default function ItemCard(props) { + return ( + <Grid item xs={11} sm={3} md={2} > + <Card style={{ textAlign: 'center' }}> + <CardContent> + <ItemImage src={apiDomain + props.src} /> + <ItemName>{props.name}</ItemName> + <ItemDescription>{props.description}</ItemDescription> + <UserItemCardAction + itemId={props.itemId} + name={props.name} + totalPrice={props.price - props.discount} + myQntOfPoints={props.myQntOfPoints} + onFinishPurchase={props.onFinishPurchase} + /> + </CardContent> + </Card> + </Grid> + ) +} diff --git a/src/Components/UserItemCardAction.js b/src/Components/UserItemCardAction.js new file mode 100644 index 0000000000000000000000000000000000000000..b35f374b4f430db5eddbad46a0fb9462ac0943c2 --- /dev/null +++ b/src/Components/UserItemCardAction.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, { useState, useContext } from 'react'; +import Snackbar from '@material-ui/core/Snackbar'; +import MuiAlert from '@material-ui/lab/Alert'; +import { Store } from '../Store' +import { postRequest } from './HelperFunctions/getAxiosConfig' + +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', + color: '#666666', + } + return stl; +} + +export default function ItemCardAction(props) { + const { state } = useContext(Store) + const [snack, setSnack] = useState({ + open: false, + message: "", + icon: "", + }) + + const handleSnackbar = (open, message, icon) => { + setSnack({ + open: open, + message: message, + icon: icon + }) + } + + const manageItemAndShowSnackbar = () => { + postRequest( + "/users/equip_item", + { "item_id": props.itemId }, + (data, header) => { + handleSnackbar(true, 'Item equipado com sucesso', 'success') + }, + (error) => { + handleSnackbar(true, 'Ocorreu algum erro', 'error') + } + ) + } + + const manageItemAndShowSnackbar2 = () => { + postRequest( + "/users/unequip_item", + { "item_id": props.itemId }, + (data, header) => { + handleSnackbar(true, 'Item desequipado com sucesso', 'success') + }, + (error) => { + handleSnackbar(true, 'Ocorreu algum erro', 'error') + } + ) + } + + const handleClick = () => { + if (state.currentUser.id) + manageItemAndShowSnackbar(); + else + handleSnackbar(true, 'Você precisa estar logado para fazer uma compra na nossa loja', 'warning') + } + + const handleClick2 = () => { + if (state.currentUser.id) + manageItemAndShowSnackbar2(); + else + handleSnackbar(true, 'Você precisa estar logado para fazer uma compra na nossa loja', 'warning') + } + + + return ( + <div> + <Snackbar open={snack.open} autoHideDuration={6000} onClose={handleSnackbar.bind(null, false, '', '')}> + <Alert onClose={handleSnackbar.bind(null, false, '', '')} severity={snack.icon}> + {snack.message} + </Alert> + </Snackbar> + <span style={actionStyle(props.operation)} onClick={handleClick}> + Equipar + </span> + <span style={actionStyle(props.operation)} onClick={handleClick2}> + Desequipar + </span> + </div> + ) +} diff --git a/src/Components/UserItemsCarousel.js b/src/Components/UserItemsCarousel.js new file mode 100644 index 0000000000000000000000000000000000000000..a4ff08d8abbf8fd53ceab28c96be4fa620ceff2d --- /dev/null +++ b/src/Components/UserItemsCarousel.js @@ -0,0 +1,86 @@ +/*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 UserItemCard from './UserItemCard.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) { + 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 <UserItemCard + key={new Date().toISOString + i.id} + itemId={i.id} + src={i.image} + name={i.name} + description={i.description} + /> + })} + <IconButton onClick={goRight} disabled={props.disabled}> + <ArrowForwardIcon /> + </IconButton> + </Grid> + ) +} diff --git a/src/Pages/UserPage.js b/src/Pages/UserPage.js index 5a6b1d3a180f0fafd9e98e575826ae5f05a3f1ef..bacd96327a6a54fff96e29771c940012b5f34087 100644 --- a/src/Pages/UserPage.js +++ b/src/Pages/UserPage.js @@ -58,6 +58,7 @@ export default function UserPage(props) { const [levelXP, setLevelXP] = useState(0); const [points, setPoints] = useState(0); const [experience, setExperience] = useState(0); + const [currUser, setCurrUser] = useState({}); // const [following, setFollowing] = useState(0); @@ -77,12 +78,11 @@ export default function UserPage(props) { }; function handleSuccessfulGet(data) { - console.log(data); dispatch({ type: "GET_USER", user: data, }); - + setCurrUser(data) setFollows(data.follows_count); setLevel(data.level) setLevelXP(data.level_xp) @@ -245,6 +245,7 @@ export default function UserPage(props) { {tabValue === 1 && <TabPanelStatusEConquistas id={id} + currUser={currUser} level={level} levelXP={levelXP} points={points}