Merge pull request #3 from CloudAlb/feature/perfil

Feature/perfil
This commit is contained in:
CloudAlb
2022-05-28 12:52:38 -03:00
committed by GitHub
11 changed files with 249 additions and 61 deletions

View File

@@ -1,12 +1,16 @@
import { Redirect, Route } from 'react-router-dom'; import { Redirect, Route } from 'react-router-dom';
import { import {
IonApp, IonApp,
IonIcon,
IonLabel,
IonRouterOutlet, IonRouterOutlet,
IonTabBar,
IonTabButton,
IonTabs,
setupIonicReact setupIonicReact
} from '@ionic/react'; } from '@ionic/react';
import { IonReactRouter } from '@ionic/react-router'; import { IonReactRouter } from '@ionic/react-router';
import Cadastro from './pages/Cadastro/Cadastro'; import Cadastro from './pages/Cadastro/Cadastro';
import MainPages from './pages/MainPages';
// importação das páginas // importação das páginas
import Login from './pages/Login'; import Login from './pages/Login';
@@ -31,15 +35,14 @@ import '@ionic/react/css/display.css';
import './theme/variables.css'; import './theme/variables.css';
import Perfil from './pages/Perfil'; import Perfil from './pages/Perfil';
import PerfilEditar from './pages/PerfilEditar'; import PerfilEditar from './pages/PerfilEditar';
import { search, home, person } from 'ionicons/icons';
import { useState, useContext, useEffect } from 'react';
import React from 'react';
setupIonicReact(); setupIonicReact();
const App: React.FC = () => ( const routes = (
<IonApp> <>
<IonReactRouter>
<IonRouterOutlet>
<Route exact path="/mainpages" component={MainPages}></Route>
<Route exact path="/cadastro" component={Cadastro}></Route> <Route exact path="/cadastro" component={Cadastro}></Route>
<Route exact path="/login" component={Login}></Route> <Route exact path="/login" component={Login}></Route>
<Route exact path="/perfil" component={Perfil}></Route> <Route exact path="/perfil" component={Perfil}></Route>
@@ -47,10 +50,63 @@ const App: React.FC = () => (
<Route exact path="/"> <Route exact path="/">
<Redirect to="/cadastro" /> <Redirect to="/cadastro" />
</Route> </Route>
</IonRouterOutlet> </>)
interface IUserManager {
setIsLoggedIn: Function;
}
const user: IUserManager = {
setIsLoggedIn: () => {}
};
export const UserContext = React.createContext<IUserManager>(user);
const IonicApp: React.FC = () => {
const [isLoggedIn, setIsLoggedIn] = useState(false);
const user = useContext(UserContext);
user.setIsLoggedIn = setIsLoggedIn;
useEffect(() => {
// TODO, verifica se usuário está logado
// fazer com serviço externo (evita duplicações)
})
return(
<IonApp>
<IonReactRouter>
{isLoggedIn ? (
<IonTabs>
<IonRouterOutlet>{routes}</IonRouterOutlet>
<IonTabBar slot="bottom">
<IonTabButton tab="buscar" href="/buscar">
<IonIcon icon={search} />
<IonLabel>Buscar</IonLabel>
</IonTabButton>
<IonTabButton tab="home" href="/home">
<IonIcon icon={home} />
<IonLabel>Home</IonLabel>
</IonTabButton>
<IonTabButton tab="perfil" href="/perfil">
<IonIcon icon={person} />
<IonLabel>Perfil</IonLabel>
</IonTabButton>
</IonTabBar>
</IonTabs>
) : (<IonRouterOutlet>{routes}</IonRouterOutlet>)}
</IonReactRouter> </IonReactRouter>
</IonApp> </IonApp>
)
}
const App: React.FC = () => {
return (
<UserContext.Provider value={user}>
<IonicApp />
</UserContext.Provider>
); );
};
export default App; export default App;

View File

@@ -1,7 +1,7 @@
const usersRoutesDefault = '/users'; const usersRoutesDefault = '/users';
const usersRoutes = { const usersRoutes = {
create: { create: {
url: `${usersRoutesDefault}/create` url: `${usersRoutesDefault}`
}, },
get: { get: {
url: `${usersRoutesDefault}` url: `${usersRoutesDefault}`

View File

@@ -5,7 +5,7 @@ import { useEffect, useState } from 'react';
import { useHistory, useParams } from 'react-router'; import { useHistory, useParams } from 'react-router';
import './Cadastro.css'; import './Cadastro.css';
import ModalExample from '../../components/Email'; import ModalExample from '../../components/Email';
import * as UsersService from '../../services/users' import * as UsersService from '../../services/api/users'
const Cadastro: React.FC = () => { const Cadastro: React.FC = () => {
const history = useHistory(); const history = useHistory();
@@ -70,7 +70,8 @@ const Cadastro: React.FC = () => {
if(name != '' && email != '' && birthDate != '' && password != '' && confirmPassword != '') { if(name != '' && email != '' && birthDate != '' && password != '' && confirmPassword != '') {
if(password === confirmPassword){ if(password === confirmPassword){
const signUpForm = { const signUpForm = {
name: firstName +' '+ lastName, name: firstName,
lastname: lastName,
email: email, email: email,
birth_date: birthDate, birth_date: birthDate,
password: password password: password
@@ -113,7 +114,7 @@ const Cadastro: React.FC = () => {
<IonHeader> <IonHeader>
<IonToolbar> <IonToolbar>
<IonButtons slot="start"> <IonButtons slot="start">
<IonBackButton text={''} icon={arrowBack} defaultHref='mainpages' /> <IonBackButton text={''} icon={arrowBack} defaultHref='login' />
</IonButtons> </IonButtons>
</IonToolbar> </IonToolbar>
</IonHeader> </IonHeader>

View File

@@ -5,7 +5,7 @@ import {
IonTitle, IonTitle,
IonToolbar IonToolbar
} from "@ionic/react"; } from "@ionic/react";
import React, { useState } from "react"; import React, { useContext, useState } from "react";
import { IonGrid, IonRow, IonCol, IonToast } from "@ionic/react"; import { IonGrid, IonRow, IonCol, IonToast } from "@ionic/react";
import { useHistory } from "react-router-dom"; import { useHistory } from "react-router-dom";
import { import {
@@ -15,9 +15,10 @@ import {
IonButton, IonButton,
} from "@ionic/react"; } from "@ionic/react";
import * as sessionRoutes from '../services/session'; import * as sessionRoutes from '../services/api/session';
import LocalStorage from '../LocalStorage'; import LocalStorage from '../LocalStorage';
import { Action } from "../components/Action"; import { Action } from "../components/Action";
import { UserContext } from "../App";
const Page: React.FC = () => { const Page: React.FC = () => {
const [showToast, setShowToast] = useState(false); const [showToast, setShowToast] = useState(false);
@@ -27,6 +28,8 @@ const Page: React.FC = () => {
const [email, setEmail] = useState<string>("matheusalb3213@gmail.com"); const [email, setEmail] = useState<string>("matheusalb3213@gmail.com");
const [password, setPassword] = useState<string>("12345678"); const [password, setPassword] = useState<string>("12345678");
const user = useContext(UserContext);
function validateEmail(email: string) { function validateEmail(email: string) {
const re = const re =
// eslint-disable-next-line no-control-regex // eslint-disable-next-line no-control-regex
@@ -84,6 +87,8 @@ const Page: React.FC = () => {
LocalStorage.setToken(token); LocalStorage.setToken(token);
user.setIsLoggedIn(true);
history.push({ pathname: '/home' }); history.push({ pathname: '/home' });
}).catch(error => { }).catch(error => {
// if (!error.response) return // if (!error.response) return

View File

@@ -1,3 +1,9 @@
#avatar { #avatar {
border-radius: 50%; border-radius: 50%;
width: 64px;
height: 64px;
}
IonIcon {
color: blue;
} }

View File

@@ -3,11 +3,17 @@ import {
IonCardContent, IonCardContent,
IonCardHeader, IonCardHeader,
IonCardTitle, IonCardTitle,
IonChip,
IonContent, IonContent,
IonFab, IonFab,
IonFabButton, IonFabButton,
IonGrid,
IonHeader, IonHeader,
IonIcon, IonIcon,
IonItem,
IonLabel,
IonList,
IonListHeader,
IonPage, IonPage,
IonTitle, IonTitle,
IonToast, IonToast,
@@ -18,11 +24,12 @@ import React, { useState, useEffect, useReducer } from "react";
import { IonRow, IonCol } from "@ionic/react"; import { IonRow, IonCol } from "@ionic/react";
import { createOutline } from "ionicons/icons"; import { createOutline } from "ionicons/icons";
import * as sessionRoutes from '../services/session'; import * as sessionRoutes from '../services/api/session';
import * as usersRoutes from '../services/users'; import * as usersRoutes from '../services/api/users';
import './Perfil.css' import './Perfil.css'
import LocalStorage from "../LocalStorage"; import LocalStorage from "../LocalStorage";
import { refreshSession } from "../services/refreshSession";
const Perfil: React.FC = () => { const Perfil: React.FC = () => {
const [showToast, setShowToast] = useState(false); const [showToast, setShowToast] = useState(false);
@@ -32,8 +39,10 @@ const Perfil: React.FC = () => {
(state: any, newState: any) => ({ ...state, ...newState }), (state: any, newState: any) => ({ ...state, ...newState }),
{ {
name: '', name: '',
lastname: '',
email: '',
birth_date: '',
bio: '', bio: '',
email: ''
} }
); );
@@ -50,19 +59,14 @@ const Perfil: React.FC = () => {
const loadUserData = async () => { const loadUserData = async () => {
let userId = '' let userId = ''
await sessionRoutes.refresh().then(response => { // verify if user is authenticated
if (response.status === 'error') { const refreshedSession = await refreshSession()
setMessageToast(response.message);
setShowToast(true);
if (refreshedSession.error) {
redirectUserToLogin()
return return
} }
userId = response.userId
}).catch(() => {
redirectUserToLogin()
})
await usersRoutes.getById(userId).then(response => { await usersRoutes.getById(userId).then(response => {
if (response.status === 'error') { if (response.status === 'error') {
setMessageToast(response.message.data) setMessageToast(response.message.data)
@@ -73,7 +77,13 @@ const Perfil: React.FC = () => {
const userData = response.data const userData = response.data
setInputValues({'name': userData.name, 'bio': userData.bio, 'email': userData.email}); setInputValues({
'name': userData.name,
'lastname': userData.lastname,
'email': userData.email,
'birth_date': userData.birth_date,
'bio': userData.bio
});
}).catch(() => { }).catch(() => {
redirectUserToLogin() redirectUserToLogin()
}) })
@@ -115,7 +125,7 @@ const Perfil: React.FC = () => {
</IonRow> </IonRow>
<IonCardHeader> <IonCardHeader>
<IonCardTitle class="ion-text-center">{inputValues.name}</IonCardTitle> <IonCardTitle class="ion-text-center">{inputValues.name} {inputValues.lastname}</IonCardTitle>
</IonCardHeader> </IonCardHeader>
</IonCardContent> </IonCardContent>
</IonCard> </IonCard>
@@ -129,6 +139,32 @@ const Perfil: React.FC = () => {
</IonCardContent> </IonCardContent>
</IonCard> </IonCard>
<IonCard>
<IonCardContent>
<IonLabel>Status do perfil</IonLabel>
<IonChip>
<IonLabel color="primary">Passageiro</IonLabel>
</IonChip>
</IonCardContent>
</IonCard>
<IonList>
<IonListHeader>Dashboard</IonListHeader>
<IonItem>
<IonIcon></IonIcon>
<IonLabel>Confirmar perfil</IonLabel>
</IonItem>
<IonItem>
<IonLabel>Cadastrar Van</IonLabel>
</IonItem>
<IonItem>
<IonLabel>Pagamentos</IonLabel>
</IonItem>
<IonItem>
<IonLabel>Avaliações</IonLabel>
</IonItem>
</IonList>
<IonFab vertical="bottom" horizontal="end" slot="fixed"> <IonFab vertical="bottom" horizontal="end" slot="fixed">
<IonFabButton onClick={() => history.push({ pathname: '/perfil/editar', state: { userData: inputValues } })}> <IonFabButton onClick={() => history.push({ pathname: '/perfil/editar', state: { userData: inputValues } })}>
<IonIcon icon={createOutline} /> <IonIcon icon={createOutline} />

View File

@@ -25,12 +25,16 @@ import { saveOutline } from "ionicons/icons";
import isEqual from 'lodash.isequal'; import isEqual from 'lodash.isequal';
import * as usersRoutes from '../services/users'; import * as usersRoutes from '../services/api/users';
import './Cadastro/Cadastro.css'
interface userData { interface userData {
name: string; name: string;
bio: string; lastname: string;
email: string; email: string;
birth_date: string;
bio: string;
} }
interface LocationState { interface LocationState {
@@ -46,22 +50,34 @@ const PerfilEditar: React.FC = () => {
const [userData, setUserData] = useState({ const [userData, setUserData] = useState({
name: '', name: '',
lastname: '',
email: '',
birth_date: '',
bio: '', bio: '',
email: ''
}); });
const [inputValues, setInputValues] = useReducer( const [inputValues, setInputValues] = useReducer(
(state: any, newState: any) => ({ ...state, ...newState }), (state: any, newState: any) => ({ ...state, ...newState }),
{ {
name: '', name: '',
lastname: '',
email: '',
birth_date: '',
bio: '', bio: '',
email: ''
} }
); );
useEffect(() => { useEffect(() => {
let userData = location.state.userData
setUserData(location.state.userData) setUserData(location.state.userData)
setInputValues({'name': userData.name, 'email': userData.email, 'bio': userData.bio}); setInputValues({
'name': userData.name,
'lastname': userData.lastname,
'email': userData.email,
'birth_date': userData.birth_date,
'bio': userData.bio
});
}, [userData]); }, [userData]);
const handleUpdateUserData = () => { const handleUpdateUserData = () => {
@@ -90,7 +106,7 @@ const PerfilEditar: React.FC = () => {
<IonToolbar> <IonToolbar>
<IonTitle>Editar perfil</IonTitle> <IonTitle>Editar perfil</IonTitle>
<IonButtons slot="start"> <IonButtons slot="start">
<IonBackButton defaultHref="perfil" /> <IonBackButton defaultHref="/perfil" />
</IonButtons> </IonButtons>
</IonToolbar> </IonToolbar>
</IonHeader> </IonHeader>
@@ -104,15 +120,27 @@ const PerfilEditar: React.FC = () => {
<IonGrid> <IonGrid>
<IonRow> <IonRow>
<IonCol> <IonCol size="12">
<div id='nome-sobrenome'>
<IonItem> <IonItem>
<IonLabel position="stacked"> Nome completo</IonLabel> <IonLabel position="stacked"> Nome</IonLabel>
<IonInput <IonInput
type="text" type="text"
value={inputValues.name} value={inputValues.name}
onIonChange={(e) => setInputValues({'name': e.detail.value!})} onIonChange={(e) => setInputValues({'name': e.detail.value!})}
></IonInput> ></IonInput>
</IonItem> </IonItem>
<IonItem>
<IonLabel position="stacked"> Sobrenome</IonLabel>
<IonInput
type="text"
value={inputValues.lastname}
onIonChange={(e) => setInputValues({'lastname': e.detail.value!})}
></IonInput>
</IonItem>
</div>
<IonItem> <IonItem>
<IonLabel position="stacked"> Email</IonLabel> <IonLabel position="stacked"> Email</IonLabel>
<IonInput <IonInput
@@ -121,6 +149,17 @@ const PerfilEditar: React.FC = () => {
onIonChange={(e) => setInputValues({'email': e.detail.value!})} onIonChange={(e) => setInputValues({'email': e.detail.value!})}
></IonInput> ></IonInput>
</IonItem> </IonItem>
<IonItem>
<IonLabel position='stacked'>Data de nascimento</IonLabel>
<IonInput
type='date'
value={inputValues.birth_date}
onIonInput={(e: any) => setInputValues({'birth_date': e.detail.value!})}
>
</IonInput>
</IonItem>
<IonItem> <IonItem>
<IonLabel position="stacked"> Biografia</IonLabel> <IonLabel position="stacked"> Biografia</IonLabel>
<IonTextarea <IonTextarea

View File

@@ -1,5 +1,5 @@
import axios from 'axios'; import axios from 'axios';
import apiConfig from '../config/api.config'; import apiConfig from '../../config/api.config';
const instance = axios.create({ const instance = axios.create({
baseURL: apiConfig.getBaseUrl(), baseURL: apiConfig.getBaseUrl(),

View File

@@ -1,6 +1,6 @@
import instance from '../services/api'; import instance from './api';
import sessionRoutes from '../constants/routes/sessionRoutes'; import sessionRoutes from '../../constants/routes/sessionRoutes';
import LocalStorage from '../LocalStorage'; import LocalStorage from '../../LocalStorage';
import { AxiosRequestHeaders } from 'axios'; import { AxiosRequestHeaders } from 'axios';
let token: string | null; let token: string | null;

View File

@@ -1,9 +1,9 @@
import instance from '../services/api'; import instance from './api';
// import LocalStorage from '../LocalStorage'; // import LocalStorage from '../LocalStorage';
import userRoutes from '../constants/routes/usersRoutes'; import userRoutes from '../../constants/routes/usersRoutes';
import { AxiosRequestHeaders } from 'axios'; import { AxiosRequestHeaders } from 'axios';
import LocalStorage from '../LocalStorage'; import LocalStorage from '../../LocalStorage';
let token: string; let token: string;
let header: AxiosRequestHeaders; let header: AxiosRequestHeaders;
@@ -30,6 +30,7 @@ export interface CadastroResponse {
export interface CadastroRequest { export interface CadastroRequest {
name: string; name: string;
lastname: string;
email: string; email: string;
birth_date: string; birth_date: string;
password: string; password: string;

View File

@@ -0,0 +1,44 @@
import * as sessionRoutes from "../services/api/session";
interface refreshSessionReturn {
userId?: string;
error?: boolean;
errorMessage?: string;
}
interface refreshSessionResponse {
status?: string;
message?: string;
userId?: string;
}
export const refreshSession = async (): Promise<refreshSessionReturn> => {
try {
let res: refreshSessionResponse = await sessionRoutes.refresh()
if (res.status === "error") {
return {
error: true,
errorMessage: res.message,
};
}
return {
userId: res.userId,
};
} catch(err) {
return {
error: true,
errorMessage: "Por favor, autentique-se.",
};
}
// catch (err: any) {
// if (err.response) {
// // The client was given an error response (5xx, 4xx)
// } else if (err.request) {
// // The client never received a response, and the request was never left
// } else {
// // Anything else
// }
// }
};