diff --git a/.env.development b/.env.development index cf99636a..eb58e232 100644 --- a/.env.development +++ b/.env.development @@ -2,3 +2,4 @@ EXPO_PUBLIC_API_URL=http://localhost EXPO_PUBLIC_API_USUARIO_PORT=3001 EXPO_PUBLIC_API_FORUM_PORT=3002 EXPO_PUBLIC_API_SAUDE_PORT=3003 +EXPO_PUBLIC_JWT_TOKEN_SECRET=f57d8cc37a35a8051aa97b5ec8506a2ac479e81f82aed9de975a0cb90b903044 diff --git a/.env.production b/.env.production index 26d7f342..a01e8933 100644 --- a/.env.production +++ b/.env.production @@ -2,3 +2,4 @@ EXPO_PUBLIC_API_URL=http://3.80.226.110 EXPO_PUBLIC_API_USUARIO_PORT=3001 EXPO_PUBLIC_API_FORUM_PORT=3002 EXPO_PUBLIC_API_SAUDE_PORT=3003 +EXPO_PUBLIC_JWT_TOKEN_SECRET=f57d8cc37a35a8051aa97b5ec8506a2ac479e81f82aed9de975a0cb90b903044 diff --git a/src/app/components/BackButton.tsx b/src/app/components/BackButton.tsx index ef65be6a..46b26d54 100644 --- a/src/app/components/BackButton.tsx +++ b/src/app/components/BackButton.tsx @@ -5,10 +5,18 @@ import { router } from "expo-router"; interface Props { canGoBack?: boolean; + route?: string; } -export default function BackButton({ canGoBack = true }: Readonly) { +export default function BackButton({ + canGoBack = true, + route, +}: Readonly) { const goBack = () => { + if (route) { + router.push(route); + } + canGoBack && router.canGoBack() ? router.back() : false; }; diff --git a/src/app/components/ModalConfirmation.tsx b/src/app/components/ModalConfirmation.tsx index 20d98371..a91208b7 100644 --- a/src/app/components/ModalConfirmation.tsx +++ b/src/app/components/ModalConfirmation.tsx @@ -1,4 +1,4 @@ -import React, { useState } from "react"; +import React from "react"; import { Modal, StyleSheet, Text, Pressable, View } from "react-native"; interface IProps { @@ -14,11 +14,7 @@ export default function ModalConfirmation({ }: IProps) { return ( - + @@ -50,7 +46,7 @@ const styles = StyleSheet.create({ flex: 1, justifyContent: "center", alignItems: "center", - marginTop: 22, + backgroundColor: "#00000098", }, modalView: { margin: 20, @@ -90,7 +86,7 @@ const styles = StyleSheet.create({ textAlign: "center", }, modalText: { - marginBottom: 15, + marginBottom: 35, textAlign: "center", fontWeight: "bold", }, diff --git a/src/app/private/pages/editarPerfil.tsx b/src/app/private/pages/editarPerfil.tsx index 563d5622..988a4cd0 100644 --- a/src/app/private/pages/editarPerfil.tsx +++ b/src/app/private/pages/editarPerfil.tsx @@ -1,61 +1,30 @@ import React, { useEffect, useState } from "react"; import { Pressable, StyleSheet, Text, View } from "react-native"; -import BackButton from "../../components/BackButton"; import Toast from "react-native-toast-message"; import Icon from "react-native-vector-icons/MaterialCommunityIcons"; import { TextInput } from "react-native"; import AsyncStorage from "@react-native-async-storage/async-storage"; -import { - deleteUserById, - getUserById, - updateUser, -} from "../../services/user.service"; -import { router } from "expo-router"; +import { deleteUserById, updateUser } from "../../services/user.service"; +import { router, useLocalSearchParams } from "expo-router"; import ErrorMessage from "../../components/ErrorMessage"; import CustomButton from "../../components/CustomButton"; import { IUser } from "../../interfaces/user.interface"; import UploadImage from "../../components/UploadImage"; import ModalConfirmation from "../../components/ModalConfirmation"; +import BackButton from "../../components/BackButton"; interface IErrors { nome?: string; } export default function EditarPerfil() { - const [foto, setFoto] = useState(null); - const [nome, setNome] = useState(""); - const [token, setToken] = useState(""); + const user = useLocalSearchParams() as unknown as IUser; + const [foto, setFoto] = useState(user.foto); + const [nome, setNome] = useState(user.nome); const [erros, setErros] = useState({}); - const [user, setUser] = useState(null); const [showErrors, setShowErrors] = useState(false); const [modalVisible, setModalVisible] = useState(false); - const getUser = async () => { - if (token) return; - - const payloadToken = (await AsyncStorage.getItem("token")) as string; - const userInfo = JSON.parse(atob(payloadToken.split(".")[1])) as IUser; - setToken(payloadToken as string); - - try { - const response = await getUserById(userInfo.id, payloadToken); - const responseUser = response.data as IUser & { - foto: { data: Uint8Array }; - }; - - setUser(responseUser); - setNome(responseUser.nome); - setFoto(responseUser.foto); - } catch (err) { - const error = err as { message: string }; - Toast.show({ - type: "error", - text1: "Erro!", - text2: error.message, - }); - } - }; - const salvar = async () => { if (Object.keys(erros).length > 0) { setShowErrors(true); @@ -66,12 +35,7 @@ export default function EditarPerfil() { const token = await AsyncStorage.getItem("token"); try { - const id = user?.id as number; - const response = await updateUser(id, body, token as string); - const responseUser = response.data as IUser; - setUser(responseUser); - setNome(responseUser.nome); - setFoto(responseUser.foto ?? ""); + const response = await updateUser(user.id, body, token as string); Toast.show({ type: "success", @@ -90,12 +54,10 @@ export default function EditarPerfil() { }; const apagarConta = async () => { - // TODO fazer modal de confirmação const token = await AsyncStorage.getItem("token"); try { - const id = user?.id as number; - const response = await deleteUserById(id, token as string); + const response = await deleteUserById(user.id, token as string); Toast.show({ type: "success", @@ -137,14 +99,9 @@ export default function EditarPerfil() { setErros(erros); }; - getUser(); - return ( - - {router.replace("/private/tabs/perfil")}}> - - + {foto && } {!foto && } @@ -165,7 +122,7 @@ export default function EditarPerfil() { - {user?.email} + {user.email} @@ -176,6 +133,7 @@ export default function EditarPerfil() { Apagar Conta + (undefined); + + const logout = () => { + AsyncStorage.removeItem("token").then(() => router.replace("/")); + }; + + const navigate = () => { + router.push({ pathname: "/private/pages/editarPerfil", params: user }); + }; + + const getUser = (id: number, token: string) => { + getUserById(id, token) + .then((response) => { + const responseUser = response.data as IUser & { + foto: { data: Uint8Array }; + }; + console.log(responseUser); + setUser(responseUser); + }) + .catch((err) => { + const error = err as { message: string }; + Toast.show({ + type: "error", + text1: "Erro!", + text2: error.message, + }); + }); + }; + + const handleUser = () => { + AsyncStorage.getItem("token").then((token) => { + const key = process.env.EXPO_PUBLIC_JWT_TOKEN_SECRET as string; + const userInfo = JWT.decode(token as string, key) as unknown as IUser; + getUser(userInfo.id, token as string); + }); + }; + + useEffect(() => handleUser(), []); + + const hasFoto = (foto: string | null | undefined) => { + if (!foto) return false; + + const raw = foto.split("data:image/png;base64,")[1]; + return raw.length > 0; + }; + + const getFoto = (foto: string | null | undefined) => { + if (hasFoto(foto)) { + return ( + + ); + } + + return ( + + + + ); + }; -export default function Perfil({ nome }: Props) { return ( - - - Maria Betânia + + {getFoto(user?.foto)} + Olá, {user?.nome}! + + + + + + + + Perfil + Edite seu perfil + + + + + + + + Logout + Sair da sua conta + + - - - - - - - Perfil - Edite seu perfil - - - - - - - - - - Sair - - - ); } const styles = StyleSheet.create({ - nameBar: { + header: { backgroundColor: "#2CCDB5", width: "100%", - height: 150, + padding: 10, flexDirection: "row", alignItems: "center", - justifyContent: "center", - position: "relative", }, - imagem: { - height: 80, - width: 80, - borderRadius: 50, - zIndex: 1, - position: "absolute", - top: "50%", - left: "50%", - transform: [{ translateX: -40 }, { translateY: -40 }], + fotoPerfil: { + width: 60, + aspectRatio: 1, + borderRadius: 100, }, - imagemidosobotao: { + semFoto: { position: "relative", backgroundColor: "#EFEFF0" }, + semFotoIcon: { position: "absolute", - width: 40, - height: 40, - top: 20, - marginLeft: 20, // Adicione margem à direita para separar a imagem do texto + right: "38%", + bottom: "38%", + opacity: 0.4, + margin: "auto", + alignSelf: "center", + zIndex: 1, }, - name: { + nomeUsuario: { color: "#FFFFFF", fontWeight: "bold", - fontSize: 13, - alignSelf: "center", - textAlign: "center", - marginTop: 108, + fontSize: 16, + marginLeft: 20, }, - textContainer: { + options: { flexDirection: "column", - justifyContent: "center", // Centralizar verticalmente - marginLeft: 70, - top: 12, + width: "100%", + height: "100%", + alignItems: "center", }, - buttonContainer: { - height: 70, + option: { flexDirection: "row", - }, - - button: { - width: "80%", - alignSelf: "center", - marginTop: 34, - height: 80, + width: "90%", + marginTop: 25, text: "#000", backgroundColor: "#FFF", borderRadius: 16, - elevation: 3, + padding: 20, }, - buttonIOS: { - width: "80%", - alignSelf: "center", - marginTop: 34, - height: 74, - text: "#000", - backgroundColor: "#FFF", - borderRadius: 12, - }, - icon: { - color: "#A5A5A5", - opacity: 0.8, + optionText: { + flexDirection: "column", + marginVertical: "auto", marginLeft: 15, - marginTop: 18, - marginBottom: 17, - width: "15%", }, - iconChevron: { - marginVertical: 15, - marginLeft: 280, - }, - buttonTextLogout: { - fontWeight: "bold", - fontSize: 18, - position: "absolute", - alignItems: "center", - left: 65, - marginVertical: 25, - }, - buttonTextEdit: { - fontWeight: "bold", - bottom: 10, - fontSize: 18, - marginBottom: 5, // Adicione margem inferior + optionTextTitle: { + color: "#000", + fontWeight: "700", + fontSize: 20, }, - buttonSubText: { - fontSize: 14, - bottom: 12, - color: "#808080", + optionTextSubTitle: { + color: "#989898", + fontWeight: "500", }, });