From 3e13fb9c6c85f44c9f385c38e8eaea60e4d410ac Mon Sep 17 00:00:00 2001 From: franco sanchez Date: Thu, 21 Dec 2023 22:08:21 -0300 Subject: [PATCH] feat: authentication and profiling are being implemented --- src/components/nav/DesktopNav.tsx | 97 +++++++++++++----- src/hooks/querys.ts | 10 ++ src/pages/profile/Profile.tsx | 157 ++++++++++++------------------ src/services/api.ts | 11 ++- src/services/firebase/auth.tsx | 70 +++++++++++++ src/services/firebase/config.ts | 26 +++++ 6 files changed, 247 insertions(+), 124 deletions(-) create mode 100644 src/services/firebase/auth.tsx create mode 100644 src/services/firebase/config.ts diff --git a/src/components/nav/DesktopNav.tsx b/src/components/nav/DesktopNav.tsx index a48df9e..0c6d740 100644 --- a/src/components/nav/DesktopNav.tsx +++ b/src/components/nav/DesktopNav.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useState, useRef } from 'react'; -import { NavLink } from 'react-router-dom'; +import { NavLink, useNavigate } from 'react-router-dom'; import { BsSun } from 'react-icons/bs'; import { RiMoonLine } from 'react-icons/ri'; import { @@ -12,42 +12,85 @@ import { useColorMode, useColorModeValue, useDisclosure, + Menu, + MenuButton, + MenuList, + MenuItem, + MenuGroup, + MenuDivider, + Image, } from '@chakra-ui/react'; +import { FaRegUserCircle } from 'react-icons/fa'; +import { FaPowerOff } from 'react-icons/fa6'; import { navLink, accountLinks } from '../../data/links'; import { InputSearch } from '../forms/filters/InputSearch'; import { ModalFilter } from '../forms/filters/ModalFilter'; +import { useAuth } from '../../store/AuthContext'; +import { handleSignOut } from '../../services/firebase/auth'; export function DesktopNav() { + const { currentUser } = useAuth(); + const navigate = useNavigate(); const { isOpen, onOpen, onClose } = useDisclosure(); const { colorMode, toggleColorMode } = useColorMode(); const bgNavColor = useColorModeValue('#ffffff8b', '#12121244'); + let profileMenu; - // let user = false; - // const [user, setUser] = useState(null); - // console.log(user); - - // useEffect(() => { - // fetch('http://localhost:9090/auth/login/check-user', { - // method: 'GET', - // // credentials: 'include', - // headers: { - // Accept: 'application/json', - // 'Content-Type': 'application/json', - // // 'Access-Control-Allow-Credentials': true, - // }, - // }) - // .then((response) => { - // if (response.status === 200) return response.json(); - // throw new Error('authentication has been failed!'); - // }) - // .then((resObject) => { - // // setUser(resObject.user); - // }) - // .catch((err) => { - // console.log(err); - // }); - // }, []); + if (currentUser) { + profileMenu = ( + + + + + } + _hover={{ textDecoration: 'none' }} + > + Perfil + + + + + } + onClick={() => { + handleSignOut(); + navigate('/'); + }} + > + Cerrar Sessión + + + + + ); + } return ( <> @@ -138,6 +181,7 @@ export function DesktopNav() { + {profileMenu} diff --git a/src/hooks/querys.ts b/src/hooks/querys.ts index 0379b0d..27b1a5b 100644 --- a/src/hooks/querys.ts +++ b/src/hooks/querys.ts @@ -16,6 +16,7 @@ import { getMoreBooks, getRelatedBooks, getMoreBooksAuthors, + getUserAndBooks, postBook, } from '../services/api'; import { keys } from '../utils/utils'; @@ -144,6 +145,14 @@ function useBook(pathUrl: string | undefined) { }); } +function useProfile(id: string | undefined) { + return useSuspenseQuery({ + queryKey: ['profile', id], + queryFn: () => getUserAndBooks(id), + gcTime: 3000, + }); +} + export { useMutatePost, useAllFilterOptions, @@ -155,4 +164,5 @@ export { useMoreBooks, useRelatedBooks, useMoreBooksAuthors, + useProfile, }; diff --git a/src/pages/profile/Profile.tsx b/src/pages/profile/Profile.tsx index 64df29b..183de87 100644 --- a/src/pages/profile/Profile.tsx +++ b/src/pages/profile/Profile.tsx @@ -1,109 +1,72 @@ import React from 'react'; import { useParams } from 'react-router-dom'; -import { Box, Container, Flex } from '@chakra-ui/react'; +import { Box, Flex, Image } from '@chakra-ui/react'; + +import { MySimpleGrid } from '../../components/MySimpleGrid'; +import { Card } from '../../components/cards/Card'; +import { Aside } from '../../components/Aside'; +import { MainHead } from '../../components/Head'; +import ResultLength from '../../components/ResultLength'; +import { useAuth } from '../../store/AuthContext'; +import { useProfile } from '../../hooks/querys'; export default function Profile() { - const { user } = useParams(); + const { userId } = useParams(); + const { data } = useProfile(userId); + const { currentUser } = useAuth(); return ( <> - - - {user} + + + + + {currentUser?.displayName} - - - - Opciones - - - - - - - - - - - - - - - + + + + {data.books.map( + ({ + id, + category, + language, + title, + authors, + synopsis, + sourceLink, + pathUrl, + image, + }) => ( + + + + ), + )} + ); diff --git a/src/services/api.ts b/src/services/api.ts index e596305..d45527c 100644 --- a/src/services/api.ts +++ b/src/services/api.ts @@ -68,7 +68,7 @@ async function getAllFilterOptions() { return data; } -async function deleteBook(id: any) { +async function deleteBook(id: string | undefined) { const data = await fetchData(`${API_URL}/book/delete/${id}`, { method: 'DELETE', }); @@ -76,6 +76,14 @@ async function deleteBook(id: any) { return data; } +// Usuarios + +async function getUserAndBooks(id: string | undefined) { + const data = await fetchData(`${API_URL}/my-books/${id}`); + + return data; +} + export { getAllBooks, getAllSearchBooks, @@ -88,4 +96,5 @@ export { getMoreBooksAuthors, postBook, deleteBook, + getUserAndBooks, }; diff --git a/src/services/firebase/auth.tsx b/src/services/firebase/auth.tsx new file mode 100644 index 0000000..7d6f3d1 --- /dev/null +++ b/src/services/firebase/auth.tsx @@ -0,0 +1,70 @@ +import React from 'react'; +import { useNavigate } from 'react-router-dom'; +import { Button, useColorModeValue } from '@chakra-ui/react'; +import { GrGoogle } from 'react-icons/gr'; +import { GoogleAuthProvider, signInWithPopup, signOut } from 'firebase/auth'; + +import { logIn, logOut } from './config'; + +const provider = new GoogleAuthProvider(); + +provider.setCustomParameters({ prompt: 'select_account ' }); + +function SignIn() { + const navigate = useNavigate(); + + async function signInWithGoogle() { + try { + const result = await signInWithPopup(logIn, provider); + const token = await result.user.getIdToken(); + + // Enviar el token al backend + fetch('http://localhost:9090/api/register', { + method: 'POST', + headers: { + Authorization: `Bearer ${token}`, + 'content-type': 'application/json', + }, + }); + + navigate(`/profile/${result.user.uid}`); + } catch (error) { + console.error(error); + } + } + return ( + <> + + + ); +} + +// async function login() { +// try { +// const result = await signInWithPopup(logIn, provider); +// const token = await result.user.getIdToken(); +// console.log(result); +// } catch (error) { +// console.log(error); +// } +// } + +function handleSignOut() { + logOut(); +} + +export { SignIn, handleSignOut }; diff --git a/src/services/firebase/config.ts b/src/services/firebase/config.ts new file mode 100644 index 0000000..ab806bb --- /dev/null +++ b/src/services/firebase/config.ts @@ -0,0 +1,26 @@ +import { initializeApp } from 'firebase/app'; +// import { getAnalytics } from 'firebase/analytics'; +import { getAuth, signOut } from 'firebase/auth'; + +const firebaseConfig = { + apiKey: import.meta.env.VITE_API_KEY, + authDomain: import.meta.env.VITE_AUTH_DOMAIN, + projectId: import.meta.env.VITE_PROJECT_ID, + storageBucket: import.meta.env.VITE_STORAGE_BUCKET, + messagingSenderId: import.meta.env.VITE_MESS_SENDER_ID, + appId: import.meta.env.VITE_APP_ID, +}; + +const app = initializeApp(firebaseConfig); + +// const analytics = getAnalytics(app); + +export const logIn = getAuth(app); + +export async function logOut() { + try { + await signOut(logIn); + } catch (error) { + console.error('Error al cerrar sesión:', error); + } +}