Página de perfil mostra dados do banco de dados do usuário autenticado
This commit is contained in:
@@ -29,7 +29,7 @@ import '@ionic/react/css/display.css';
|
|||||||
|
|
||||||
/* Theme variables */
|
/* Theme variables */
|
||||||
import './theme/variables.css';
|
import './theme/variables.css';
|
||||||
// import Tabs from './components/Tabs';
|
import Perfil from './pages/Perfil';
|
||||||
|
|
||||||
setupIonicReact();
|
setupIonicReact();
|
||||||
|
|
||||||
@@ -41,6 +41,8 @@ const App: React.FC = () => (
|
|||||||
<Route exact path="/mainpages" component={MainPages}></Route>
|
<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/edit" component={Perfil}></Route> TODO */}
|
||||||
<Route exact path="/">
|
<Route exact path="/">
|
||||||
<Redirect to="/cadastro" />
|
<Redirect to="/cadastro" />
|
||||||
</Route>
|
</Route>
|
||||||
|
|||||||
@@ -2,16 +2,22 @@ const tokenId = 'token';
|
|||||||
const productDetails = '@productDetails';
|
const productDetails = '@productDetails';
|
||||||
|
|
||||||
const LocalStorage = {
|
const LocalStorage = {
|
||||||
getToken: (): string | null => {
|
getToken: (): string => {
|
||||||
return localStorage.getItem(tokenId)
|
const tokenId = localStorage.getItem('tokenId')
|
||||||
|
|
||||||
|
if (!tokenId) {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
return tokenId
|
||||||
},
|
},
|
||||||
|
|
||||||
setToken: (token: string) => {
|
setToken: (token: string) => {
|
||||||
localStorage.setItem(tokenId, token)
|
localStorage.setItem('tokenId', token)
|
||||||
},
|
},
|
||||||
|
|
||||||
clearToken: () => {
|
clearToken: () => {
|
||||||
localStorage.setItem(tokenId, '');
|
localStorage.removeItem('tokenId')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
11
src/constants/routes/usersRoutes.ts
Normal file
11
src/constants/routes/usersRoutes.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
const usersRoutesDefault = '/users';
|
||||||
|
const usersRoutes = {
|
||||||
|
create: {
|
||||||
|
url: `${usersRoutesDefault}/create`
|
||||||
|
},
|
||||||
|
get: {
|
||||||
|
url: `${usersRoutesDefault}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default usersRoutes;
|
||||||
@@ -7,15 +7,12 @@ import {
|
|||||||
} from "@ionic/react";
|
} from "@ionic/react";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { IonGrid, IonRow, IonCol, IonToast } from "@ionic/react";
|
import { IonGrid, IonRow, IonCol, IonToast } from "@ionic/react";
|
||||||
import { personCircle } from "ionicons/icons";
|
|
||||||
import { useHistory } from "react-router-dom";
|
import { useHistory } from "react-router-dom";
|
||||||
import {
|
import {
|
||||||
IonItem,
|
IonItem,
|
||||||
IonLabel,
|
IonLabel,
|
||||||
IonInput,
|
IonInput,
|
||||||
IonButton,
|
IonButton,
|
||||||
IonIcon,
|
|
||||||
IonAlert,
|
|
||||||
} from "@ionic/react";
|
} from "@ionic/react";
|
||||||
|
|
||||||
import * as sessionRoutes from '../services/session';
|
import * as sessionRoutes from '../services/session';
|
||||||
@@ -29,11 +26,10 @@ const Page: React.FC = () => {
|
|||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
const [email, setEmail] = useState<string>("matheusalb3213@gmail.com");
|
const [email, setEmail] = useState<string>("matheusalb3213@gmail.com");
|
||||||
const [password, setPassword] = useState<string>("123456");
|
const [password, setPassword] = useState<string>("123456");
|
||||||
const [isError, setIsError] = useState<boolean>(false);
|
|
||||||
const [message, setMessage] = useState<string>("");
|
|
||||||
|
|
||||||
function validateEmail(email: string) {
|
function validateEmail(email: string) {
|
||||||
const re =
|
const re =
|
||||||
|
// eslint-disable-next-line no-control-regex
|
||||||
/^((?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\]))$/;
|
/^((?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\]))$/;
|
||||||
return re.test(String(email).toLowerCase());
|
return re.test(String(email).toLowerCase());
|
||||||
}
|
}
|
||||||
@@ -107,15 +103,6 @@ const Page: React.FC = () => {
|
|||||||
</IonToolbar>
|
</IonToolbar>
|
||||||
</IonHeader>
|
</IonHeader>
|
||||||
|
|
||||||
<IonRow>
|
|
||||||
<IonCol>
|
|
||||||
<IonIcon
|
|
||||||
style={{ fontSize: "70px", color: "#0040ff" }}
|
|
||||||
icon={personCircle}
|
|
||||||
/>
|
|
||||||
</IonCol>
|
|
||||||
</IonRow>
|
|
||||||
|
|
||||||
<IonContent fullscreen>
|
<IonContent fullscreen>
|
||||||
<IonHeader collapse="condense">
|
<IonHeader collapse="condense">
|
||||||
<IonToolbar>
|
<IonToolbar>
|
||||||
@@ -124,19 +111,6 @@ const Page: React.FC = () => {
|
|||||||
</IonHeader>
|
</IonHeader>
|
||||||
|
|
||||||
<IonGrid>
|
<IonGrid>
|
||||||
<IonRow>
|
|
||||||
<IonCol>
|
|
||||||
<IonAlert
|
|
||||||
isOpen={isError}
|
|
||||||
onDidDismiss={() => setIsError(false)}
|
|
||||||
cssClass="my-custom-class"
|
|
||||||
header={"Error!"}
|
|
||||||
message={message}
|
|
||||||
buttons={["Dismiss"]}
|
|
||||||
/>
|
|
||||||
</IonCol>
|
|
||||||
</IonRow>
|
|
||||||
|
|
||||||
<IonRow>
|
<IonRow>
|
||||||
<IonCol>
|
<IonCol>
|
||||||
<IonItem>
|
<IonItem>
|
||||||
@@ -165,10 +139,6 @@ const Page: React.FC = () => {
|
|||||||
|
|
||||||
<IonRow>
|
<IonRow>
|
||||||
<IonCol>
|
<IonCol>
|
||||||
<p style={{ fontSize: "small" }}>
|
|
||||||
Clicando no botão de "Login", você concorda com a nossa{" "}
|
|
||||||
<a href="#">política de termos e serviços</a>
|
|
||||||
</p>
|
|
||||||
<IonButton expand="block" onClick={handleLogin}>
|
<IonButton expand="block" onClick={handleLogin}>
|
||||||
Login
|
Login
|
||||||
</IonButton>
|
</IonButton>
|
||||||
|
|||||||
3
src/pages/Perfil.css
Normal file
3
src/pages/Perfil.css
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
#avatar {
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
151
src/pages/Perfil.tsx
Normal file
151
src/pages/Perfil.tsx
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
import {
|
||||||
|
IonCard,
|
||||||
|
IonCardContent,
|
||||||
|
IonCardHeader,
|
||||||
|
IonCardTitle,
|
||||||
|
IonContent,
|
||||||
|
IonFab,
|
||||||
|
IonFabButton,
|
||||||
|
IonHeader,
|
||||||
|
IonIcon,
|
||||||
|
IonPage,
|
||||||
|
IonTitle,
|
||||||
|
IonToast,
|
||||||
|
IonToolbar,
|
||||||
|
} from "@ionic/react";
|
||||||
|
import { useHistory } from "react-router-dom";
|
||||||
|
import React, { useState, useEffect, useReducer } from "react";
|
||||||
|
import { IonRow, IonCol } from "@ionic/react";
|
||||||
|
import { createOutline } from "ionicons/icons";
|
||||||
|
|
||||||
|
import * as sessionRoutes from '../services/session';
|
||||||
|
import * as usersRoutes from '../services/users';
|
||||||
|
|
||||||
|
import './Perfil.css'
|
||||||
|
import LocalStorage from "../LocalStorage";
|
||||||
|
|
||||||
|
const Perfil: React.FC = () => {
|
||||||
|
const [showToast, setShowToast] = useState(false);
|
||||||
|
const [messageToast, setMessageToast ] = useState('');
|
||||||
|
|
||||||
|
const [inputValues, setInputValues] = useReducer(
|
||||||
|
(state: any, newState: any) => ({ ...state, ...newState }),
|
||||||
|
{
|
||||||
|
fullname: '',
|
||||||
|
bio: ''
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const history = useHistory();
|
||||||
|
|
||||||
|
const loadUserData = async () => {
|
||||||
|
let userId = ''
|
||||||
|
|
||||||
|
await sessionRoutes.refresh().then(response => {
|
||||||
|
if (response.status === 'error') {
|
||||||
|
setMessageToast(response.message);
|
||||||
|
setShowToast(true);
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
userId = response.userId
|
||||||
|
}).catch(error => {
|
||||||
|
console.dir('Houve um erro: ', { error })
|
||||||
|
alert('Houve um erro')
|
||||||
|
})
|
||||||
|
|
||||||
|
await usersRoutes.getById(userId).then(response => {
|
||||||
|
if (response.status === 'error') {
|
||||||
|
setMessageToast(response.message.data)
|
||||||
|
setShowToast(true);
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const userData = response.data
|
||||||
|
|
||||||
|
setInputValues({'fullname': userData.name, 'bio': userData.bio});
|
||||||
|
}).catch(error => {
|
||||||
|
console.dir('Houve um erro: ', { error })
|
||||||
|
alert('Houve um erro')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const userToken = LocalStorage.getToken()
|
||||||
|
|
||||||
|
if (!userToken) {
|
||||||
|
// TODO, não impede o usuário de retornar a página de login
|
||||||
|
history.push({ pathname: '/login' });
|
||||||
|
setMessageToast("Por favor, autentique-se!");
|
||||||
|
setShowToast(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// const refreshResponse = refreshSession()
|
||||||
|
loadUserData()
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleEditProfile = () => {
|
||||||
|
alert('oi')
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<IonPage>
|
||||||
|
<IonHeader>
|
||||||
|
<IonToolbar>
|
||||||
|
<IonTitle>Seu perfil</IonTitle>
|
||||||
|
</IonToolbar>
|
||||||
|
</IonHeader>
|
||||||
|
|
||||||
|
<IonContent fullscreen>
|
||||||
|
<IonHeader collapse="condense">
|
||||||
|
<IonToolbar>
|
||||||
|
<IonTitle size="large">Seu perfil</IonTitle>
|
||||||
|
</IonToolbar>
|
||||||
|
</IonHeader>
|
||||||
|
|
||||||
|
<IonCard>
|
||||||
|
<IonCardContent>
|
||||||
|
<IonRow>
|
||||||
|
<IonCol></IonCol>
|
||||||
|
<IonCol>
|
||||||
|
<img src="https://static.generated.photos/vue-static/home/feed/adult.png" alt="avatar" className='avatar' id='avatar'/>
|
||||||
|
</IonCol>
|
||||||
|
<IonCol></IonCol>
|
||||||
|
</IonRow>
|
||||||
|
|
||||||
|
<IonCardHeader>
|
||||||
|
<IonCardTitle class="ion-text-center">{inputValues.fullname}</IonCardTitle>
|
||||||
|
</IonCardHeader>
|
||||||
|
</IonCardContent>
|
||||||
|
</IonCard>
|
||||||
|
|
||||||
|
<IonCard>
|
||||||
|
<IonCardHeader>
|
||||||
|
<IonCardTitle>Biografia</IonCardTitle>
|
||||||
|
</IonCardHeader>
|
||||||
|
<IonCardContent>
|
||||||
|
{inputValues.bio ? inputValues.bio : 'Sem biografia.'}
|
||||||
|
</IonCardContent>
|
||||||
|
</IonCard>
|
||||||
|
|
||||||
|
<IonFab vertical="bottom" horizontal="end" slot="fixed" onClick={handleEditProfile}>
|
||||||
|
<IonFabButton>
|
||||||
|
<IonIcon icon={createOutline} />
|
||||||
|
</IonFabButton>
|
||||||
|
</IonFab>
|
||||||
|
|
||||||
|
<IonToast
|
||||||
|
color='danger'
|
||||||
|
isOpen={showToast}
|
||||||
|
onDidDismiss={() => setShowToast(false)}
|
||||||
|
message={messageToast}
|
||||||
|
duration={2500}
|
||||||
|
/>
|
||||||
|
</IonContent>
|
||||||
|
</IonPage>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Perfil;
|
||||||
66
src/pages/PerfilEditar.tsx
Normal file
66
src/pages/PerfilEditar.tsx
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
import {
|
||||||
|
IonCard,
|
||||||
|
IonCardContent,
|
||||||
|
IonCardHeader,
|
||||||
|
IonCardTitle,
|
||||||
|
IonContent,
|
||||||
|
IonFab,
|
||||||
|
IonFabButton,
|
||||||
|
IonGrid,
|
||||||
|
IonHeader,
|
||||||
|
IonIcon,
|
||||||
|
IonInput,
|
||||||
|
IonItem,
|
||||||
|
IonLabel,
|
||||||
|
IonPage,
|
||||||
|
IonTitle,
|
||||||
|
IonToolbar
|
||||||
|
} from "@ionic/react";
|
||||||
|
import React, { useState } from "react";
|
||||||
|
import { IonRow, IonCol } from "@ionic/react";
|
||||||
|
import { createOutline } from "ionicons/icons";
|
||||||
|
|
||||||
|
import './Perfil.css'
|
||||||
|
|
||||||
|
const Perfil: React.FC = () => {
|
||||||
|
const [email, setEmail] = useState<string>("matheusalb3213@gmail.com");
|
||||||
|
|
||||||
|
const handleEditProfile = () => {
|
||||||
|
alert('oi')
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<IonPage>
|
||||||
|
<IonHeader>
|
||||||
|
<IonToolbar>
|
||||||
|
<IonTitle>Editar perfil</IonTitle>
|
||||||
|
</IonToolbar>
|
||||||
|
</IonHeader>
|
||||||
|
|
||||||
|
<IonContent fullscreen>
|
||||||
|
<IonHeader collapse="condense">
|
||||||
|
<IonToolbar>
|
||||||
|
<IonTitle size="large">Editar perfil</IonTitle>
|
||||||
|
</IonToolbar>
|
||||||
|
</IonHeader>
|
||||||
|
|
||||||
|
<IonGrid>
|
||||||
|
<IonRow>
|
||||||
|
<IonCol>
|
||||||
|
<IonItem>
|
||||||
|
<IonLabel position="floating"> Email</IonLabel>
|
||||||
|
<IonInput
|
||||||
|
type="email"
|
||||||
|
value={email}
|
||||||
|
onIonChange={(e) => setEmail(e.detail.value!)}
|
||||||
|
></IonInput>
|
||||||
|
</IonItem>
|
||||||
|
</IonCol>
|
||||||
|
</IonRow>
|
||||||
|
</IonGrid>
|
||||||
|
</IonContent>
|
||||||
|
</IonPage>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Perfil;
|
||||||
@@ -14,8 +14,8 @@ interface createData {
|
|||||||
function updateHeader() {
|
function updateHeader() {
|
||||||
token = LocalStorage.getToken();
|
token = LocalStorage.getToken();
|
||||||
header = {
|
header = {
|
||||||
Accept: 'application/json',
|
"Accept": 'application/json',
|
||||||
'Content-Type': 'application/json',
|
"Content-Type": 'application/json',
|
||||||
"Authorization": 'Bearer ' + token
|
"Authorization": 'Bearer ' + token
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,21 @@
|
|||||||
import instance from '../services/api';
|
import instance from '../services/api';
|
||||||
// import LocalStorage from '../LocalStorage';
|
// import LocalStorage from '../LocalStorage';
|
||||||
|
|
||||||
let token:string;
|
import userRoutes from '../constants/routes/usersRoutes';
|
||||||
let header:string;
|
import { AxiosRequestHeaders } from 'axios';
|
||||||
|
import LocalStorage from '../LocalStorage';
|
||||||
|
|
||||||
|
let token: string;
|
||||||
|
let header: AxiosRequestHeaders;
|
||||||
|
|
||||||
function updateHeader() {
|
function updateHeader() {
|
||||||
// token = LocalStorage.getToken();
|
token = LocalStorage.getToken();
|
||||||
header = `{
|
|
||||||
|
header = {
|
||||||
"Accept": 'application/json',
|
"Accept": 'application/json',
|
||||||
"Content-Type": 'application/json',
|
"Content-Type": 'application/json',
|
||||||
"Authorization": 'Bearer ' + token
|
"Authorization": 'Bearer ' + token
|
||||||
}`
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CadastroResponse {
|
export interface CadastroResponse {
|
||||||
@@ -40,6 +45,13 @@ export interface CadastroRequest {
|
|||||||
export async function create(CadastroRequest: any) {
|
export async function create(CadastroRequest: any) {
|
||||||
updateHeader();
|
updateHeader();
|
||||||
|
|
||||||
const response = await instance.post("http://localhost:3333/users/", CadastroRequest);
|
const response = await instance.post(userRoutes.create.url, CadastroRequest);
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getById(userId: string) {
|
||||||
|
updateHeader();
|
||||||
|
|
||||||
|
const response = await instance.get(userRoutes.get.url + `/${userId}`, { headers: header });
|
||||||
return response.data;
|
return response.data;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user