From b8b0058e848ed24cac481734c0f9add630d1b36b Mon Sep 17 00:00:00 2001 From: Luis Felipe Risch <lfr20@inf.ufpr.br> Date: Thu, 22 Apr 2021 12:18:50 -0300 Subject: [PATCH] building gamefication --- src/Components/ContactCard.js | 118 ++++++++++++++++++++++---------- src/Components/ItemCard.js | 39 +++++++---- src/Components/ItemCarousel.js | 96 +++++++++++++++----------- src/Pages/ItemStore.js | 119 +++++++++++++++++++++++++++------ 4 files changed, 262 insertions(+), 110 deletions(-) diff --git a/src/Components/ContactCard.js b/src/Components/ContactCard.js index 2e0513cc..468fa8ec 100644 --- a/src/Components/ContactCard.js +++ b/src/Components/ContactCard.js @@ -27,14 +27,20 @@ import FollowButton from "./ContactButtons/FollowButton.js"; import FollowingButton from "./ContactButtons/FollowingButton.js"; import FollowersCountButton from "./ContactButtons/FollowersCountButton.js"; import { Link } from "react-router-dom"; -import Badge from "./Badge.js"; +import Badge from "./Badge.js"; +import Rubi from '../img/gamification/gem.svg'; export default function ImgMediaCard(props) { - const [followedBoolean, setFollowedBoolean] = useState(props.followed); const toggleFollowed = () => { setFollowedBoolean(!followedBoolean); }; + + function isOnStore() { + return (window.location.href.includes("loja")) + } + + return ( <StyledCard> <CardDiv> @@ -84,45 +90,57 @@ export default function ImgMediaCard(props) { </span> </Link> - <div style={{ display: "flex", justifyContent: "center" }}> - { - followedBoolean ? - ( - <React.Fragment> - <FollowingButton - followedID={props.followerID ? props.followerID : props.followedID} - toggleFollowed={toggleFollowed} /> - - <Options - followableID={props.followerID ? props.followerID : props.followedID} - followed={followedBoolean} - toggleFollowed={toggleFollowed} /> - </React.Fragment> - ) - : - ( - <React.Fragment> - <FollowButton - followerID={props.followedID ? props.followedID : props.followerID} - toggleFollowed={toggleFollowed} /> - - <Options - followableID={props.followedID ? props.followedID : props.followerID} - followed={followedBoolean} - toggleFollowed={toggleFollowed} /> - </React.Fragment> - ) - } + { + !isOnStore() ? + <div style={{ display: "flex", justifyContent: "center" }}> + { + followedBoolean ? + ( + <React.Fragment> + <FollowingButton + followedID={props.followerID ? props.followerID : props.followedID} + toggleFollowed={toggleFollowed} /> - </div> + <Options + followableID={props.followerID ? props.followerID : props.followedID} + followed={followedBoolean} + toggleFollowed={toggleFollowed} /> + </React.Fragment> + ) + : + ( + <React.Fragment> + <FollowButton + followerID={props.followedID ? props.followedID : props.followerID} + toggleFollowed={toggleFollowed} /> + + <Options + followableID={props.followedID ? props.followedID : props.followerID} + followed={followedBoolean} + toggleFollowed={toggleFollowed} /> + </React.Fragment> + ) + } + </div> + : + <StatusInfoDiv> + <CoinsInfoDiv> + <GemImg src={Rubi} /> + <CoinsSpan>{props.points} </CoinsSpan> + </CoinsInfoDiv> + </StatusInfoDiv> + } </UserInfo> </CardContent> </CardAreaDiv> </CardDiv> - </StyledCard> + </StyledCard > ); } + + + /*Controls top part of Card*/ const Header = styled.div` display: flex; @@ -136,10 +154,10 @@ export const CardAreaDiv = styled(Card)` flex-direction: column; margin: 0 auto; background-color: red; - height: 95%; - width: 92%; + height: 92%; + width: 94%; margin: 8px 0; - align: center; + /* align-items: center; */ `; export const CardDiv = styled.div` text-align: start; @@ -229,3 +247,31 @@ const BadgesDiv = styled.div` flex-direction: row; justify-content: space-around; `; + +const StatusInfoDiv = styled.div` + margin-top: 0.5em; + display: flex; + justify-content: center; + align-items: center; + width: 100%; + flex-wrap: wrap; +`; + +const CoinsInfoDiv = styled.div` + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + flex: 1; +`; + +const CoinsSpan = styled.span` + color: red; + font-size: 16px; + margin-left: 5px; +`; + +const GemImg = styled.img` + height: 23px; +`; + diff --git a/src/Components/ItemCard.js b/src/Components/ItemCard.js index dea4bd2a..f181cb9b 100644 --- a/src/Components/ItemCard.js +++ b/src/Components/ItemCard.js @@ -21,6 +21,7 @@ import Grid from '@material-ui/core/Grid'; import Card from '@material-ui/core/Card'; import CardContent from '@material-ui/core/CardContent'; import ItemCardAction from './ItemCardAction.js'; +import { apiDomain } from '../env' const ItemImage = styled.img` border-radius: 150; @@ -28,28 +29,38 @@ const ItemImage = styled.img` ` 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` - font-size: 0.5em; + 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={9} sm={2}> - <Card style={{textAlign: 'center'}}> - <CardContent> - <ItemImage src={props.src}/> - <ItemName>{props.name}</ItemName> - <ItemDescription>{props.description}</ItemDescription> - <ItemCardAction operation={props.action}/> - </CardContent> - </Card> - </Grid> - ) +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> + <ItemCardAction operation={props.action} /> + </CardContent> + </Card> + </Grid> + ) } diff --git a/src/Components/ItemCarousel.js b/src/Components/ItemCarousel.js index a790b4f1..625966e9 100644 --- a/src/Components/ItemCarousel.js +++ b/src/Components/ItemCarousel.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, {useState} from 'react'; +import React, { useState } from 'react'; import Grid from '@material-ui/core/Grid'; import ItemCard from './ItemCard.js'; import ArrowBackIcon from '@material-ui/icons/ArrowBack'; @@ -23,45 +23,61 @@ 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(5); +export default function ItemCarousel(props) { + const [left, setLeft] = useState(0); + const [right, setRight] = useState(objectsPerPage()); - const goLeft = () => { - setRight(right === 0 ? props.items.length-1 : right-1); - setLeft(left === 0 ? props.items.length-1 : left-1); - } - - const goRight = () => { - setRight(right === props.items.length-1 ? 0 : right+1); - setLeft(left === props.items.length-1 ? 0 : left+1); - } + function objectsPerPage() { + var pageWidth = window.innerWidth + if (pageWidth >= 1000) { + return 5 + } + else { + if (pageWidth > 766) { + return 3 + } + else { + return 1 + } + } + } - return ( - <Grid - item container - direction="row" - justify="center" - alignItems="center" - xs={12} - 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 <ItemCard - src={i.src} - action={i.action} - name={i.name} - description={i.description}/> - })} - <IconButton onClick={goRight}> - <ArrowForwardIcon/> - </IconButton> - </Grid> - ) + 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) + 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 <ItemCard + src={i.image} + action={i.action} + name={i.name} + description={i.description} /> + })} + <IconButton onClick={goRight} disabled={props.disabled}> + <ArrowForwardIcon /> + </IconButton> + </Grid> + ) } diff --git a/src/Pages/ItemStore.js b/src/Pages/ItemStore.js index ac2a67a9..8c4d9120 100644 --- a/src/Pages/ItemStore.js +++ b/src/Pages/ItemStore.js @@ -21,16 +21,16 @@ import axios from 'axios'; import Grid from '@material-ui/core/Grid'; import Container from '@material-ui/core/Container'; import CircularProgress from '@material-ui/core/CircularProgress'; - import StoreGuide from '../Components/StoreGuide.js'; import ItemCarousel from '../Components/ItemCarousel.js'; import ContactCard from '../Components/ContactCard.js'; import { apiUrl } from '../env'; import { Store } from '../Store'; import { apiDomain } from '../env'; +import { getRequest } from '../Components/HelperFunctions/getAxiosConfig' const SectionTitle = styled.h3` - font-weight: 100; + font-weight: 100; margin-bottom: 0; ` @@ -46,28 +46,24 @@ const StoreSection = styled.div` ` export default function ItemStoreContainer(props) { - const { state, dispatch } = useContext(Store); - console.log(state); + const { state } = useContext(Store); const [avatar_frames, setAvatarFrames] = useState([]); const [card_frames, setCardFrames] = useState([]); const [cover_frames, setCoverFrames] = useState([]); const [badges, setBadges] = useState([]); + const [disabled, setDisabled] = useState(false) const [currUser, setCurrUser] = useState({}); - const [isLoading, setIsLoading] = useState(true); - - // useEffect(() => { - // axios.all( - // ['avatar_frame', 'card_frame', 'cover_frame', 'badge'].map((r) => { - // return axios.get(apiUrl+'/' + 'user_items/index?item_type='+r+'&unlock_rule=purchase'); - // })).then(axios.spread((avatar, card, cover, badge) => { - // setAvatarFrames(avatar); - // setCardFrames(card); - // setCoverFrames(cover); - // setBadges(badge); - // })); - // }, []) + const [isLoading, setIsLoading] = useState(true); + 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 `/items?item_type=${objType}&page=${page}&range=[0,9]&results_per_page=10&sort=["id","DESC"]` + } useEffect(() => { axios.get((`${apiUrl}/users/` + state.currentUser.id)) @@ -82,6 +78,60 @@ export default function ItemStoreContainer(props) { ) }, [state.currentUser.id]) + useEffect(() => { + setDisabled(true) + getRequest( + buildUrl("badge", currBadgePage), + (data, header) => { + setBadges((previous) => previous.concat(data)) + setDisabled(false) + }, + (error) => { + + } + ) + }, [currBadgePage]) + + useEffect(() => { + setDisabled(true) + getRequest( + buildUrl("avatar_frame", currBadgePage), + (data, header) => { + setAvatarFrames((previous) => previous.concat(data)) + setDisabled(false) + }, + (error) => { + + } + ) + }, [currAvatarFramePage]) + + useEffect(() => { + setDisabled(true) + getRequest( + buildUrl("cover_frame", currBadgePage), + (data, header) => { + setCoverFrames((previous) => previous.concat(data)) + setDisabled(false) + }, + (error) => { + } + ) + }, [currCoverFramePage]) + + useEffect(() => { + setDisabled(true) + getRequest( + buildUrl("card_frame", currBadgePage), + (data, header) => { + setCardFrames((previous) => previous.concat(data)) + setDisabled(false) + }, + (error) => { + } + ) + }, [currCardFramePage]) + return ( <Container maxWidth="false" style={{ marginBottom: "-20px", paddingTop: "2em", backgroundColor: "#f4f4f4" }}> @@ -103,6 +153,7 @@ export default function ItemStoreContainer(props) { numCollections={currUser.collections_count} numLearningObjects={currUser.learning_objects_count} follow_count={currUser.follows_count} + points={currUser.points} // followed={currUser.followed || null} // followerID={currUser.follower.id} href={'/usuario-publico/' + currUser.id} @@ -114,13 +165,41 @@ export default function ItemStoreContainer(props) { <StoreSection> <SectionTitle>Insígnias</SectionTitle> <StoreDivider /> - <ItemCarousel items={badges} /> + <ItemCarousel + items={badges} + setCurrPage={() => { setCurrBadgePage(currBadgePage + 1) }} + disabled={disabled} + /> + </StoreSection> + + <StoreSection> + <SectionTitle>Moldura de card de usuário</SectionTitle> + <StoreDivider /> + <ItemCarousel + items={card_frames} + setCurrPage={() => { setCurrCardFramePage(currCardFramePage + 1) }} + disabled={disabled} + /> + </StoreSection> + + <StoreSection> + <SectionTitle>Moldura de avatar</SectionTitle> + <StoreDivider /> + <ItemCarousel + items={avatar_frames} + setCurrPage={() => { setCurrAvatarFramePage(currAvatarFramePage + 1) }} + disabled={disabled} + /> </StoreSection> <StoreSection> - <SectionTitle>Bordas de perfil</SectionTitle> + <SectionTitle>Moldura de capa</SectionTitle> <StoreDivider /> - <ItemCarousel items={card_frames} /> + <ItemCarousel + items={cover_frames} + setCurrPage={() => { setCurrCoverFramePage(currCoverFramePage + 1) }} + disabled={disabled} + /> </StoreSection> </Container> -- GitLab