From fd438c0bb8c767f6c87fd872b2211db422b576cb Mon Sep 17 00:00:00 2001 From: Lucas Schoenfelder <les17@inf.ufpr.br> Date: Wed, 5 Feb 2020 19:19:17 -0300 Subject: [PATCH] adicionado localStorage e requisicoes ao backend para algumas das abas --- src/Components/LoginContainerFunction.js | 364 +++++++++++++++++++++++ src/Components/LoginModal.js | 14 +- src/Components/MenuList.js | 1 + src/Components/ModalAlterarAvatar.js | 119 ++++++++ src/Components/SignUpContainer.js | 4 +- src/Components/SignUpModal.js | 5 + src/Components/TabPanelAtividades.js | 32 +- src/Components/TabPanelMeusRecursos.js | 4 +- src/Pages/UserPage.js | 40 ++- src/Store.js | 14 +- 10 files changed, 585 insertions(+), 12 deletions(-) create mode 100644 src/Components/LoginContainerFunction.js create mode 100644 src/Components/ModalAlterarAvatar.js diff --git a/src/Components/LoginContainerFunction.js b/src/Components/LoginContainerFunction.js new file mode 100644 index 00000000..d1a5451b --- /dev/null +++ b/src/Components/LoginContainerFunction.js @@ -0,0 +1,364 @@ +/*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 GoogleLogin from 'react-google-login' +import { Button } from '@material-ui/core'; +//import FacebookLogin from 'react-facebook-login'; +import CloseIcon from '@material-ui/icons/Close'; +import styled from 'styled-components' +import {device} from './device.js' +import LabeledCheckbox from './Checkbox.js' +import FormInput from "./FormInput.js" +import GoogleLogo from "../img/logo_google.svg" + +function validateUserInput(type, input) { + let flag = false + + if (type === 'email') { + if(input.split("").filter(x => x === "@").length !== 1) { + flag = true + } + } + else if (type === 'senha') { + if(input.length < 1) { + flag = true + } + } + + return flag +} + +export default function LoginContainer (props) { + const [formEmail, setEmail] = useState( + { + dict : { + key : false, + value : "" + } + } + ) + + const [formSenha, setSenha] = useState( + { + dict : { + key : false, + value : "" + } + } + ) + + const [checkboxControl, handleCheckbox] = useState(false) + + const switchModal = (e) => { + e.preventDefault() + props.handleClose() + props.openSignUp() + } + + const handleChange = (e, type) => { + const userInput = e.target.value + const flag = validateUserInput(type, userInput) + + if(type === 'email') { + setEmail({...formEmail, dict : { + key : flag, + value : userInput + }}) + console.log(formEmail) + } + else if(type === 'senha') { + setSenha({...formSenha, dict : { + key : flag, + value : userInput + }}) + console.log(formSenha) + } + } + + const limpaCamposForm = () => { + setEmail({...formEmail, dict : { + key : false, + value : '' + }}); + + setSenha({...formSenha, dict : { + key : false, + value : '' + }}) + } + + const onSubmit = (e) => { + e.preventDefault() + const login = {email : formEmail.dict.value, senha : formSenha.dict.value} + + if (!(formEmail.dict.key && formSenha.dict.key)) { + props.handleLoginInfo(login) + limpaCamposForm() + } + + {/*if (checkboxControl) { + props.lembrarMe() + }*/} + } + + //arrumar isso + const responseGoogle = (response) => { + console.log(response); + } + + return ( + + <ContainerStyled > + <DialogHeaderStyled> + <span style={{width:"32px"}}/> + <H2Styled> Entrar + </H2Styled> + <StyledCloseModalButton onClick={props.handleClose}> + <CloseIcon/> + </StyledCloseModalButton> + </DialogHeaderStyled> + + <DialogContentDiv> + <SocialConnectDiv> + <StyledGoogleLoginButton + clientId="658977310896-knrl3gka66fldh83dao2rhgbblmd4un9.apps.googleusercontent.com" + onSuccess={responseGoogle} + onFailure={responseGoogle} + cookiePolicy={'single_host_origin'} + > + <span style={{textTransform:"none", fontSize:"13px", color : "#666"}}>Usando o Google</span> + </StyledGoogleLoginButton> + </SocialConnectDiv> + + <H3Div> + <H3Styled> + <RightSideStrikedH3/> + <span style={{verticalAlign:"middle"}}>ou</span> + <LeftSideStrikedH3/> + </H3Styled> + </H3Div> + + <form ref="form" onSubmit={e => onSubmit(e)}> + <FormInput + inputType={"text"} + name={"email"} + value={formEmail} + placeholder={"E-mail"} + handleChange={e => handleChange(e, 'email')} + required={true} + /> + <br/> + <FormInput + inputType={"password"} + name={"senha"} + value={formSenha} + placeholder={"Senha"} + handleChange={e => handleChange(e, 'senha')} + required={true} + /> + <br/> + + <RememberRecover> + <LabeledCheckbox label={<StyledLabel><StyledSpan>Lembrar-me</StyledSpan></StyledLabel>} onchange={() => {handleCheckbox(!checkboxControl)}} disabledCheckbox={checkboxControl}/> + <UserForgotTheirPasswordSpan>Esqueceu a senha? <a href="recuperar-senha" style={{textAlign: "right", color:"#4cd0e1"}}>Clique aqui!</a></UserForgotTheirPasswordSpan> + </RememberRecover> + + <ConfirmContainerStyled> + <StyledLoginButton onClick={e => onSubmit(e)} variant="contained"> + <span style={{borderRadius:"3px", boxSizing:"border-box", fontFamily:"Roboto, sans serif", fontWeight:"500", color:"#fff"}}>ENTRAR</span> + </StyledLoginButton> + </ConfirmContainerStyled> + </form> + + <DialogFooterStyled> + <span style={{textAlign:"center", fontSize: "14px", color:"rgb(102, 102, 102)"}}>Ainda não tem cadastro? <StyledAnchor href="" onClick={e => switchModal(e)}>CADASTRE-SE</StyledAnchor></span> + </DialogFooterStyled> + </DialogContentDiv> + </ContainerStyled> + + ) +} + + + const ContainerStyled = styled.div` + box-sizing : border-box; + background-color : white; + max-width : none; + display : flex; + flex-direction : column; + min-width : 440px; + + align : center; + padding : 10px; + border-radius: 4px; + line-height : 20px; + font-size : 14px; + @media ${device.mobileM} { + width : 100%; + height : 100%; + } + ` + + export const DialogHeaderStyled = styled.div` + text-align : center; + display : flex; + flex-direction : row; + justify-content : space-between; + padding : 10px 26px 0 26px; + height : 64px; + ` + const H2Styled = styled.h2` + align-self : center; + color : #666; + font-size : 26px; + font-weight : 100; + font-family: 'Roboto', sans serif, 'Helvetica Neue', Helvetica, Arial, sans-serif !important; + justify-content: space-between; + text-align: center; + letter-spacing: .005em; + ` + + export const StyledCloseModalButton = styled(Button)` + display : inline-block; + position : relative; + float : right !important; + margin-right : -8px !important; + background : transparent !important; + min-width: 0 !important; + width : 40px; + ` + export const DialogContentDiv = styled.div` + padding : 20px 30px; + overflow : visible !important; + ` + + export const SocialConnectDiv = styled.div` + margin-top : 0; + display : flex; + flex-direction : row; + ` + export const StyledGoogleLoginButton = styled(GoogleLogin)` + background-color : #fff !important; + color : #666 !important; + border : 1px solid rgb(66, 133, 244); + box-shadow: 0 0 0 1px #4285f4 !important; + :hover { + background-color: #f4f4f4 !important; + } + ` + + const DialogFooterStyled = styled.div` + box-sizing : border-box; + font-family : 'Roboto', sans serif; + margin : 20px -20px; + padding-top : 20px; + border-top : 1px #e5e5e5 solid; + justify-content : center; + text-align : center; + line-height : 1.42857143 + ` + + + const RightSideStrikedH3 = styled.div` + display : inline-block; + border-bottom: 1px dotted #666; + vertical-align : middle; + font-weight : 500; + margin-right : 5px; + width : 45%; + ` + + const LeftSideStrikedH3 = styled.div` + display : inline-block; + border-bottom: 1px dotted #666; + vertical-align : middle; + font-weight : 500; + margin-left : 5px; + width : 45%; + ` + + export const H3Div = styled.div` + margin-top : 0; + margin-bottom : 10px; + ` + + const H3Styled = styled.h3` + overflow : hidden; + text-align : center; + font-size : 14px; + color : #666; + margin : 10px 0; + ` + + const StyledAnchor = styled.a` + color : #00bcd4; + text-decoration : none; + ` + const ConfirmContainerStyled = styled.div` + display : flex; + margin-top : 10px; + align-items : center; + justify-content : center; + ` + const StyledLoginButton = styled(Button)` + background-color : #00bcd4 !important; + box-shadow : none !important; + outline: none !important; + border : 0 !important; + overflow : hidden !important; + width : 35% !important; + display : inline-block !important; + font-family : 'Roboto', sans serif !important; + font-size: 14px !important; + height : 36px !important; + align-items : center !important; + border-radius: 3px !important; + align-self : 50% !important; + :hover { + background-color : #00acc1 !important; + } + ` + + + const RememberRecover = styled.div` + display : flex; + justify-content : space-between; + font-size: 12px; + font-weight : 400; + ` + + const StyledLabel = styled.div` + box-sizing : border-box; + position : relative; + vertical-align : middle !important; + color : #666; + ` + + const UserForgotTheirPasswordSpan = styled.span` + margin-top : 1em; + font-size : 12px; + font-weight : 400; + text-align : right; + color : #666; + ` + + const StyledSpan = styled.span` + font-size : 12px; + font-weight : 400; + padding-top : 2px; + ` diff --git a/src/Components/LoginModal.js b/src/Components/LoginModal.js index 65ff4e34..26607d36 100644 --- a/src/Components/LoginModal.js +++ b/src/Components/LoginModal.js @@ -22,7 +22,7 @@ import Modal from '@material-ui/core/Modal'; import Backdrop from '@material-ui/core/Backdrop'; import Zoom from '@material-ui/core/Fade'; import styled from 'styled-components' -import LoginContainer from './LoginContainer' +import LoginContainer from './LoginContainer.js' import {Store} from '../Store.js' import axios from 'axios' import {apiUrl} from '../env'; @@ -45,7 +45,8 @@ function Alert(props) { } export default function LoginModal (props){ - const {state, dispatch} = useContext(Store) + const {state, dispatch} = useContext(Store) + const [snackbarOpened, handleSnackbar] = useState(false) const handleCloseSnackbar = (event, reason) => { @@ -77,6 +78,15 @@ export default function LoginModal (props){ } } ) + // console.log(response.headers) + // console.log(response.data) + // console.log(response.data.data.name) + // console.log(response.data.data.uid) + localStorage.setItem('@portalmec/accessToken', response.headers['access-token']) + localStorage.setItem('@portalmec/clientToken', response.headers.client,) + localStorage.setItem('@portalmec/id', response.data.data.id) + localStorage.setItem('@portalmec/username', response.data.data.name) + localStorage.setItem('@portalmec/uid', response.data.data.uid) props.handleClose(); props.openSnackbar(); }, (error) => { diff --git a/src/Components/MenuList.js b/src/Components/MenuList.js index 0402b7e2..910af9cf 100644 --- a/src/Components/MenuList.js +++ b/src/Components/MenuList.js @@ -55,6 +55,7 @@ export default function MenuList(props) { }; const handleLogout = () => { + localStorage.removeItem('@portalmec/username'); dispatch( { type: 'USER_LOGGED_OUT', userLoggedOut: !state.userIsLoggedIn, diff --git a/src/Components/ModalAlterarAvatar.js b/src/Components/ModalAlterarAvatar.js new file mode 100644 index 00000000..f770ebf1 --- /dev/null +++ b/src/Components/ModalAlterarAvatar.js @@ -0,0 +1,119 @@ +/*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, {useContext, useState} from 'react'; +import { Button } from '@material-ui/core'; +import Modal from '@material-ui/core/Modal'; +import Backdrop from '@material-ui/core/Backdrop'; +import Zoom from '@material-ui/core/Fade'; +import styled from 'styled-components' +import {Store} from '../Store.js' +import axios from 'axios' +import {apiUrl} from '../env'; +import CloseIcon from '@material-ui/icons/Close'; + +const StyledModal = styled(Modal)` + display : flex; + flex-direction : column; + border-radius : 4px; + background-color : #fff; + min-width : 560px; +` + +export default function ModarAlterarAvatar (props){ + const {state, dispatch} = useContext(Store) + + const handleLoginInfo = (login) => { + axios.post(`${apiUrl}`, + { + } + ).then( (response) => { + dispatch ({ + + }, (error) => { + + } + ) + } + + + return ( + <> + <StyledModal + aria-labelledby="transition-modal-title" + aria-describedby="transition-modal-description" + open={props.open} + animation={true} + centered={true} + onClose={props.handleClose} + closeAfterTransition + BackdropComponent={Backdrop} + BackdropProps={{ + timeout: 500, + }} + > + <Zoom in={props.open} style={{ transitionDelay :"0.4ms"}}> + <HeaderDiv> + <span style={{width:"32px"}}/> + <StyledH2>Editar Foto</StyledH2> + <StyledCloseModalButton onClick={this.props.handleClose}> + <CloseIcon/> + </StyledCloseModalButton> + </HeaderDiv> + <DialogDiv> + </DialogDiv> + </Zoom> + </StyledModal> + </> + ) +} + +const DialogDiv = styled.div` + padding : 20px 30px; + overflow : visible !important; +` + +const HeaderDiv = styled.div` + display : flex; + flex-direction : row; + align-items : center; + align-content : center; + max-width : 100%; +` +const StyledH2 = styled.h2` + font-size : 26px; + font-weight : lighter; + margin-top : 20px; + margin-bottom : 10px; + font-family: inherit; + line-height: 1.1; + color: inherit; +` +const StyledCloseModalButton = styled(Button)` + display : inline-block; + position : relative; + float : right !important; + margin-right : -8px !important; + background : transparent !important; + min-width: 0 !important; + width : 40px; + border-radius : 50%; + padding : 8px; + height : 40px; + margin : 0 6px; +` diff --git a/src/Components/SignUpContainer.js b/src/Components/SignUpContainer.js index c41f3655..21652735 100644 --- a/src/Components/SignUpContainer.js +++ b/src/Components/SignUpContainer.js @@ -90,7 +90,7 @@ class SignUpContainer extends Component { const { name, email, password } = this.state; const errors = validateUserInfo(name, email, password) console.log(this.state) - if ( errors.length < 0) { + if ( errors.length < 1) { //pass user info to Store.js and clear all text fields this.props.handleLoginInfo(this.state) this.setState({ @@ -211,7 +211,7 @@ const ContainerStyled = styled.div` display : flex; flex-direction : column; min-width : 450px; - min-height : 690px; + max-height : none; position : relative; padding : 10px; diff --git a/src/Components/SignUpModal.js b/src/Components/SignUpModal.js index 8a9ffb20..cf38fc14 100644 --- a/src/Components/SignUpModal.js +++ b/src/Components/SignUpModal.js @@ -88,6 +88,11 @@ export default function SignUpModal (props) { } } ) + localStorage.setItem('@portalmec/accessToken', response.headers['access-token']) + localStorage.setItem('@portalmec/clientToken', response.headers.client,) + localStorage.setItem('@portalmec/id', response.data.data.id) + localStorage.setItem('@portalmec/username', response.data.data.name) + localStorage.setItem('@portalmec/uid', response.data.data.uid) console.log(state.currentUser) props.handleClose() }, (error) => { diff --git a/src/Components/TabPanelAtividades.js b/src/Components/TabPanelAtividades.js index f65115ca..e26988af 100644 --- a/src/Components/TabPanelAtividades.js +++ b/src/Components/TabPanelAtividades.js @@ -1,10 +1,40 @@ -import React, {useContext} from 'react' +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 axios from 'axios' +import {apiUrl} from '../env'; export default function TabPanelAtividades (props) { + const [notifications, setNotifications] = useState([]); + const [notificatonsLength, setLength] = useState(0); + + const config = { + headers : { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Access-Token': localStorage.getItem('@portalmec/accessToken'), + 'Client': localStorage.getItem('@portalmec/clientToken'), + 'Uid': localStorage.getItem('@portalmec/uid'), + 'Host': 'api.portalmec.c3sl.ufpr.br', + 'Cookie': '' + } + } + + useEffect( () => { + axios.get(`${apiUrl}/feed`, config) + .then( (response) => { + // console.log(response) + setNotifications(response) + setLength(response.length) + }, + (error) => { + console.log('error while running getNotifications') + } + ) + }, []) + return ( <ContainerDivStyled> <Paper elevation={3}> diff --git a/src/Components/TabPanelMeusRecursos.js b/src/Components/TabPanelMeusRecursos.js index 44e30ab1..d43f9643 100644 --- a/src/Components/TabPanelMeusRecursos.js +++ b/src/Components/TabPanelMeusRecursos.js @@ -1,8 +1,10 @@ -import React, {useContext} from 'react' +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 axios from 'axios' +import {apiUrl} from '../env'; export default function TabPanelAtividades (props) { return ( diff --git a/src/Pages/UserPage.js b/src/Pages/UserPage.js index f6bd664c..d8fef866 100644 --- a/src/Pages/UserPage.js +++ b/src/Pages/UserPage.js @@ -16,7 +16,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, useContext} from 'react'; +import React, {useState, useContext, useEffect} from 'react'; import styled from 'styled-components' import { Container } from 'react-grid-system' import Button from '@material-ui/core/Button'; @@ -37,16 +37,50 @@ import TabPanelMeusRecursos from '../Components/TabPanelMeusRecursos.js' import TabPanelFavoritos from '../Components/TabPanelFavoritos.js' import TabPanelColecoes from '../Components/TabPanelColecoes.js' import TabPanelRede from '../Components/TabPanelRede.js' +import axios from 'axios' +import {apiUrl} from '../env'; export default function UserPage (props){ const {state, dispatch} = useContext(Store) const [hoverAlterarFoto, handleAlterarFoto] = React.useState(false) const [value, setValue] = useState(0); + const user = localStorage.getItem('@portalmec/username') + const id = localStorage.getItem('@portalmec/id') const handleHoverAlterarFoto = () => { handleAlterarFoto(!hoverAlterarFoto) } + useEffect( () => { + axios.get( (`${apiUrl}/users/` + id), { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Host': 'api.portalmec.c3sl.ufpr.br', + 'Cookie': '' + }) + .then( (response) => { + console.log(response) + dispatch ({ + type : 'USER_ACCESSED_USER_PAGE', + set: { + id : response.data.id, + email : response.data.email, + username : response.data.name, + education : response.data.education, + userAvatar : response.data.avatar, + userCover : response.data.cover, + followCount : response.data.follow_count, + collectionsCount: response.data.collections_count, + } + }) + console.log(state.currentUser) + }, + (error) => { + console.log('error while running ComponentDidMout') + } + ) + }, []) + const redirect = () => { props.history.push('/') } @@ -102,7 +136,7 @@ export default function UserPage (props){ </ChangeAvatarDiv> </ProfileAvatarDiv> <UserProfileInfoDiv> - <p style={{fontSize:"28px", color:"#fff", marginBottom:"2px", fontWeight:"500"}}>{state.currentUser.username}</p> + <p style={{fontSize:"28px", color:"#fff", marginBottom:"2px", fontWeight:"500"}}>{user}</p> <div style={{fontSize:"14px", color:"#fff", marginBottom:"2px"}}> <p>{state.currentUser.education}</p> </div> @@ -116,7 +150,7 @@ export default function UserPage (props){ <CheckTeacherDiv> <> { - state.isCollaborativeTeacher ? + state.currentUser.isCollaborativeTeacher ? ( [ <> diff --git a/src/Store.js b/src/Store.js index 6c19780f..8fc1382a 100644 --- a/src/Store.js +++ b/src/Store.js @@ -22,7 +22,7 @@ export const Store = React.createContext() const initialState = { searchOpen: false, - userIsLoggedIn : true, + userIsLoggedIn : false, userAgreedToPublicationTerms: false, userAgreedToPublicationPermissions: false, modalColaborarPlataformaOpen : false, @@ -36,14 +36,17 @@ const initialState = { }, currentUser: { id : '', - username : 'Horstmann', + username : '', email : '', accessToken : '', clientToken : '', education : '', isCollaborativeTeacher : false, userAvatar : '', - userCover : '' + userCover : '', + uid : '', + followCount : 0, + collectionsCount : 0 } } @@ -92,6 +95,11 @@ function reducer(state, action) { ...state, userAgreedToPublicationPermissions : action.userAgreement } + case 'USER_ACCESSED_USER_PAGE': + return { + ...state, + currentUser : action.set + } default: return state } -- GitLab