From d4d65893b0b029f048880a7d19156be43aff0663 Mon Sep 17 00:00:00 2001 From: franco sanchez Date: Thu, 22 Aug 2024 10:50:16 -0300 Subject: [PATCH] feat: now shows which category is selected and other changes --- .eslintrc.json | 2 +- src/components/AllBooks.tsx | 10 +- src/components/BooksSection.tsx | 6 +- src/components/Categories.tsx | 37 ++++- src/components/FilterDrawer.tsx | 5 +- src/components/cards/MoreBooksAuthors.tsx | 27 ++-- src/components/cards/RelatedCard.tsx | 7 +- src/components/forms/FormEdit.tsx | 4 +- src/components/forms/NewBook.tsx | 4 +- src/components/layout/Footer.tsx | 4 +- src/components/modals/ModalConfirmation.tsx | 7 +- src/components/modals/ModalOptions.tsx | 1 - src/components/modals/ModalShare.tsx | 14 +- src/components/nav/MobileNav.tsx | 19 +-- src/components/nav/menu/MenuProfile.tsx | 12 +- src/components/types.d.ts | 7 +- src/components/ui/MyPopover.tsx | 14 +- src/components/ui/MySliderCategories.tsx | 3 +- src/contexts/categoryStore.ts | 28 ++++ src/data/links.ts | 9 +- src/hooks/queries.ts | 11 +- src/main.tsx | 9 +- src/pages/Book.tsx | 20 +-- src/pages/Home.tsx | 25 ++-- src/pages/PrivacyPolicies.tsx | 38 +++-- src/pages/Search.tsx | 151 ++++++++++---------- src/pages/profile/Profile.tsx | 27 ++-- src/routes.tsx | 4 +- src/services/api.ts | 9 +- 29 files changed, 219 insertions(+), 295 deletions(-) create mode 100644 src/contexts/categoryStore.ts diff --git a/.eslintrc.json b/.eslintrc.json index 171565f..1c74457 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -51,7 +51,7 @@ "trailingComma": "all", "tabWidth": 2, "singleQuote": true, - "printWidth": 80, + "printWidth": 85, "jsxSingleQuote": true, "bracketSameLine": false, "endOfLine": "auto" diff --git a/src/components/AllBooks.tsx b/src/components/AllBooks.tsx index c952956..5c31c37 100644 --- a/src/components/AllBooks.tsx +++ b/src/components/AllBooks.tsx @@ -67,11 +67,7 @@ export function AllBooks() { if (isFetchingNextPage) { fetchingNextPageUI = ( - + ); } @@ -91,8 +87,8 @@ export function AllBooks() { - Explora todos los libros publicados y encuentra tu próxima - lectura favorita. + Explora todos los libros publicados y encuentra tu próxima lectura + favorita. "Un libro es un sueño que sostienes en tus manos" -{' '} diff --git a/src/components/BooksSection.tsx b/src/components/BooksSection.tsx index 57a85f2..62c5f2f 100644 --- a/src/components/BooksSection.tsx +++ b/src/components/BooksSection.tsx @@ -3,11 +3,7 @@ import { Box, Center, Flex, Divider, Spinner } from '@chakra-ui/react'; import { BooksSectionType } from '@components/types'; -export function BooksSection({ - title, - data, - booksComponent, -}: BooksSectionType) { +export function BooksSection({ title, data, booksComponent }: BooksSectionType) { return ( <> diff --git a/src/components/Categories.tsx b/src/components/Categories.tsx index 26ae990..afe813a 100644 --- a/src/components/Categories.tsx +++ b/src/components/Categories.tsx @@ -1,13 +1,41 @@ -import React from 'react'; -import { NavLink } from 'react-router-dom'; +import React, { useEffect } from 'react'; +import { NavLink, useLocation } from 'react-router-dom'; import { Link } from '@chakra-ui/react'; import { BsTag } from 'react-icons/bs'; import { MyTag } from '@components/ui/MyTag'; import { useAllFilterOptions } from '@hooks/queries'; +import { useCategoryStore } from '@contexts/categoryStore'; export default function Categories() { const { data } = useAllFilterOptions(); + const location = useLocation(); + const selectedCategory = useCategoryStore((state) => state.selectedCategory); + const setSelectedCategory = useCategoryStore((state) => state.setSelectedCategory); + const isCategoryActive = useCategoryStore((state) => state.isCategoryActive); + + // Verifica si la categoría debe estar activa en la ruta actual + const isActive = isCategoryActive(location as any); + + function handleCategoryClick(category: string) { + const disabledRoutes = ['/explore', '/most-viewed']; + const isDisabled = disabledRoutes.some((route) => + location.pathname.startsWith(route), + ); + + if (isActive || isDisabled) { + setSelectedCategory(category); + } else { + console.log('Las categorías están deshabilitadas en esta ruta.'); + } + } + + // Eliminar la categoría seleccionada si la ruta actual está deshabilitada + useEffect(() => { + if (!isActive && selectedCategory) { + setSelectedCategory(null); + } + }, [location, isCategoryActive, setSelectedCategory]); return ( <> @@ -20,10 +48,11 @@ export default function Categories() { to={`/books/filter/category/${category}`} tabIndex={-1} _hover={{ outline: 'none' }} + onClick={() => handleCategoryClick(category)} > ))} - handleAllRadioChange('language')} - > + handleAllRadioChange('language')}> Todos los Idiomas diff --git a/src/components/cards/MoreBooksAuthors.tsx b/src/components/cards/MoreBooksAuthors.tsx index 09f2268..65aa894 100644 --- a/src/components/cards/MoreBooksAuthors.tsx +++ b/src/components/cards/MoreBooksAuthors.tsx @@ -7,27 +7,22 @@ import { CardType, RelatedBooksType } from '@components/types'; import { useMoreBooksAuthors } from '@hooks/queries'; import { useRefetchLocation } from '@hooks/useRefetchLocation'; -export default function MoreBooksAuthors({ - currentBookId, - id, -}: RelatedBooksType) { +export default function MoreBooksAuthors({ currentBookId, id }: RelatedBooksType) { const { data, refetch } = useMoreBooksAuthors(id); const moreBooksAuthors = useRefetchLocation({ currentBookId, data, refetch }); let uiCard; if (moreBooksAuthors.length > 0) { - uiCard = moreBooksAuthors.map( - ({ id, title, authors, pathUrl }: CardType) => ( - - - - ), - ); + uiCard = moreBooksAuthors.map(({ id, title, authors, pathUrl }: CardType) => ( + + + + )); } else { uiCard = ( diff --git a/src/components/cards/RelatedCard.tsx b/src/components/cards/RelatedCard.tsx index 8fc7c2e..1d8167e 100644 --- a/src/components/cards/RelatedCard.tsx +++ b/src/components/cards/RelatedCard.tsx @@ -6,12 +6,7 @@ import { FiArrowRight } from 'react-icons/fi'; import { CardType } from '@components/types'; import { useHandleEnterKey } from '@utils/utils'; -export function RelatedCard({ - title, - authors, - pathUrl, - refetchQueries, -}: CardType) { +export function RelatedCard({ title, authors, pathUrl, refetchQueries }: CardType) { const handleEnterKey = useHandleEnterKey(pathUrl); const borderCard = useColorModeValue('gray.200', 'gray.600'); const colorAuthorCard = useColorModeValue('gray.600', 'gray.300'); diff --git a/src/components/forms/FormEdit.tsx b/src/components/forms/FormEdit.tsx index 4a36ee4..2bcdbc5 100644 --- a/src/components/forms/FormEdit.tsx +++ b/src/components/forms/FormEdit.tsx @@ -142,9 +142,7 @@ export function FormEdit({ justify='center' > - - Aquí verás una vista previa de la imagen recortada. - + Aquí verás una vista previa de la imagen recortada. Solo se aceptan formatos PNG, JPG y WebP con un máximo de 2 MB. diff --git a/src/components/forms/NewBook.tsx b/src/components/forms/NewBook.tsx index a528a66..0817b0a 100644 --- a/src/components/forms/NewBook.tsx +++ b/src/components/forms/NewBook.tsx @@ -137,9 +137,7 @@ export function FormNewBook() { justify='center' > - - Aquí verás una vista previa de la imagen recortada. - + Aquí verás una vista previa de la imagen recortada. Solo se aceptan formatos PNG, JPG y WebP con un máximo de 2 MB. diff --git a/src/components/layout/Footer.tsx b/src/components/layout/Footer.tsx index 2dede35..eaa6968 100644 --- a/src/components/layout/Footer.tsx +++ b/src/components/layout/Footer.tsx @@ -49,9 +49,7 @@ export function Footer() { }, [networkState, prevNetworkState, myToast]); if (networkState === 'online') { - connectionState = ( - - ); + connectionState = ; } if (networkState === 'offline') { diff --git a/src/components/modals/ModalConfirmation.tsx b/src/components/modals/ModalConfirmation.tsx index 879e891..fc7500e 100644 --- a/src/components/modals/ModalConfirmation.tsx +++ b/src/components/modals/ModalConfirmation.tsx @@ -43,12 +43,7 @@ export function ModalConfirmation({ rounded='lg' fontSize={{ base: 'xs', md: 'sm' }} > - + {warningText} diff --git a/src/components/modals/ModalOptions.tsx b/src/components/modals/ModalOptions.tsx index 2865ef0..7e94621 100644 --- a/src/components/modals/ModalOptions.tsx +++ b/src/components/modals/ModalOptions.tsx @@ -1,5 +1,4 @@ import React from 'react'; -// import { NavLink } from 'react-router-dom'; import { Modal, ModalOverlay, diff --git a/src/components/modals/ModalShare.tsx b/src/components/modals/ModalShare.tsx index e5450c2..37ce4b5 100644 --- a/src/components/modals/ModalShare.tsx +++ b/src/components/modals/ModalShare.tsx @@ -109,11 +109,7 @@ export function ModalShare({ shareUrl, data, isOpen, onClose }: ModalType) { - + X @@ -138,13 +134,7 @@ export function ModalShare({ shareUrl, data, isOpen, onClose }: ModalType) { boxSize={{ base: 10, md: 12 }} rounded='3xl' /> - + Correo electrónico diff --git a/src/components/nav/MobileNav.tsx b/src/components/nav/MobileNav.tsx index d8ce499..ae6925b 100644 --- a/src/components/nav/MobileNav.tsx +++ b/src/components/nav/MobileNav.tsx @@ -129,11 +129,7 @@ export function MobileNav() { _hover={{ bg: 'none', color: 'green.500' }} _active={{ bg: 'none' }} > - {isOpenMenu ? ( - - ) : ( - - )} + {isOpenMenu ? : } - {colorMode === 'dark' ? ( - - ) : ( - - )} + {colorMode === 'dark' ? : } {profileMenu} @@ -186,12 +178,7 @@ export function MobileNav() { - + - + Perfil - + Crear Publicación { +interface RelatedBooksType extends Omit { data?: any; currentBookId?: string | undefined; refetch?: () => void; @@ -142,9 +141,7 @@ interface SkeletonType { showTags?: boolean; } -interface ModalOptionsAndConfirType - extends Omit>, - DisclosureType { +interface ModalOptionsAndConfirType extends Omit>, DisclosureType { onDeleteBook?: () => any | void; onEditBook?: () => any | void; isPending?: boolean; diff --git a/src/components/ui/MyPopover.tsx b/src/components/ui/MyPopover.tsx index e539499..5726b2a 100644 --- a/src/components/ui/MyPopover.tsx +++ b/src/components/ui/MyPopover.tsx @@ -21,21 +21,11 @@ export function MyPopover({ textBody, textFooter }: Props) { <> - - + {textBody} {textFooter ? {textFooter} : null} diff --git a/src/components/ui/MySliderCategories.tsx b/src/components/ui/MySliderCategories.tsx index 01a187b..1df2747 100644 --- a/src/components/ui/MySliderCategories.tsx +++ b/src/components/ui/MySliderCategories.tsx @@ -3,6 +3,7 @@ import { Box, Button, Flex, useColorModeValue } from '@chakra-ui/react'; import { MdChevronLeft, MdChevronRight } from 'react-icons/md'; import { SkeletonTags } from '@components/skeletons/SkeletonTags'; + const Categories = lazy(() => import('@components/Categories')); export function MySliderCategories() { @@ -15,7 +16,7 @@ export function MySliderCategories() { const container = containerRef.current as any; let isHovered = false; - function handleScroll(event) { + function handleScroll(event: WheelEvent) { if (isHovered) { container.scrollLeft += event.deltaY; event.preventDefault(); diff --git a/src/contexts/categoryStore.ts b/src/contexts/categoryStore.ts new file mode 100644 index 0000000..6d2d45c --- /dev/null +++ b/src/contexts/categoryStore.ts @@ -0,0 +1,28 @@ +import { create } from 'zustand'; +import { persist, createJSONStorage } from 'zustand/middleware'; + +interface CategoryType { + selectedCategory: string | null; + setSelectedCategory: (category: string | null) => void; + isCategoryActive: (location: Location) => boolean; +} + +const disabledRoutes = ['/explore', '/most-viewed']; + +export const useCategoryStore = create( + persist( + (set) => ({ + selectedCategory: null, + setSelectedCategory: (category: string | null) => { + set({ selectedCategory: category }); + }, + isCategoryActive: (location) => { + return !disabledRoutes.some((route) => location.pathname.startsWith(route)); + }, + }), + { + name: 'category', + storage: createJSONStorage(() => sessionStorage), + }, + ), +); diff --git a/src/data/links.ts b/src/data/links.ts index 6c416c5..9f537ed 100644 --- a/src/data/links.ts +++ b/src/data/links.ts @@ -359,11 +359,4 @@ const aboutCategories: Array = [ }, ]; -export { - navLink, - accountLinks, - languages, - categories, - aboutCategories, - formats, -}; +export { navLink, accountLinks, languages, categories, aboutCategories, formats }; diff --git a/src/hooks/queries.ts b/src/hooks/queries.ts index b895308..3a0fc41 100644 --- a/src/hooks/queries.ts +++ b/src/hooks/queries.ts @@ -109,14 +109,10 @@ function useBooksPaginate() { }); } -function useFilterPaginated( - query: string | undefined, - param: string | undefined, -) { +function useFilterPaginated(query: string | undefined, param: string | undefined) { return useInfiniteQuery({ queryKey: [keys.filterPaginated, query, param], - queryFn: ({ pageParam }) => - getBooksFilterPaginated(query, param, pageParam), + queryFn: ({ pageParam }) => getBooksFilterPaginated(query, param, pageParam), initialPageParam: 0, getNextPageParam: (lastPage) => { if (lastPage.info.nextPage === null) return; @@ -236,8 +232,7 @@ function useProfile( ) { return useInfiniteQuery({ queryKey: [keys.profile, username, userId], - queryFn: ({ pageParam }) => - getUserAndBooks(username, userId, token, pageParam), + queryFn: ({ pageParam }) => getUserAndBooks(username, userId, token, pageParam), initialPageParam: 0, getNextPageParam: (lastPage) => { if (lastPage.info.nextPage === null) return; diff --git a/src/main.tsx b/src/main.tsx index 64a4866..cdfd8f6 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -16,10 +16,7 @@ const queryClient = new QueryClient(); Sentry.init({ dsn: import.meta.env.VITE_SENTRY_DNS, - integrations: [ - Sentry.browserTracingIntegration(), - Sentry.replayIntegration(), - ], + integrations: [Sentry.browserTracingIntegration(), Sentry.replayIntegration()], tracesSampleRate: 1.0, tracePropagationTargets: [ API_URL, @@ -44,6 +41,4 @@ const html = ( ); -ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( - html, -); +ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(html); diff --git a/src/pages/Book.tsx b/src/pages/Book.tsx index c0ab8fb..14f2b14 100644 --- a/src/pages/Book.tsx +++ b/src/pages/Book.tsx @@ -41,9 +41,7 @@ import { useAuth } from '@contexts/AuthContext'; import { useMyToast } from '@hooks/useMyToast'; const Categories = lazy(() => import('@components/Categories')); -const MoreBooksAuthors = lazy( - () => import('@components/cards/MoreBooksAuthors'), -); +const MoreBooksAuthors = lazy(() => import('@components/cards/MoreBooksAuthors')); const RelatedBooks = lazy(() => import('@components/cards/RelatedBooks')); const MoreBooks = lazy(() => import('@components/cards/MoreBooks')); @@ -271,10 +269,7 @@ export default function Book() { mb='2' > - + - } + booksComponent={} /> - + @@ -162,21 +160,20 @@ export function Home() { XBuniverse es una plataforma en línea que permite a los usuarios compartir y descubrir libros de su elección. Cualquier persona puede - crear una cuenta y comenzar a compartir sus libros favoritos con - otros usuarios de la comunidad. + crear una cuenta y comenzar a compartir sus libros favoritos con otros + usuarios de la comunidad. - Además de compartir libros, también puedes explorar una amplia - selección de títulos disponibles y descubrir nuevas lecturas - interesantes. + Además de compartir libros, también puedes explorar una amplia selección + de títulos disponibles y descubrir nuevas lecturas interesantes. - La plataforma es muy fácil de usar, lo que significa que puedes - comenzar a compartir y explorar libros en cuestión de minutos. + La plataforma es muy fácil de usar, lo que significa que puedes comenzar + a compartir y explorar libros en cuestión de minutos. - ¡Regístrate ahora en XBuniverse y únete a esta comunidad de amantes - de la lectura! + ¡Regístrate ahora en XBuniverse y únete a esta comunidad de amantes de la + lectura! @@ -212,8 +209,8 @@ export function Home() { emocionantes, conocimientos fascinantes y aventuras inolvidables. - Ya sea que estés buscando un libro para acompañarte en tu próximo - viaje o simplemente para disfrutar en tu tiempo libre. + Ya sea que estés buscando un libro para acompañarte en tu próximo viaje o + simplemente para disfrutar en tu tiempo libre. diff --git a/src/pages/PrivacyPolicies.tsx b/src/pages/PrivacyPolicies.tsx index 39b611d..908d707 100644 --- a/src/pages/PrivacyPolicies.tsx +++ b/src/pages/PrivacyPolicies.tsx @@ -14,10 +14,10 @@ export default function PrivacyPolicies() { Política de Privacidad de XBuniverse - XBuniverse se compromete a proteger tu privacidad y a mantener seguros - tus datos personales. Esta Política de Privacidad describe cómo - recopilamos, utilizamos y protegemos la información que recopilamos de - nuestros usuarios. + XBuniverse se compromete a proteger tu privacidad y a mantener seguros tus + datos personales. Esta Política de Privacidad describe cómo recopilamos, + utilizamos y protegemos la información que recopilamos de nuestros + usuarios. Recopilación de información @@ -26,50 +26,48 @@ export default function PrivacyPolicies() { Recopilamos información personal como tu nombre, dirección de correo electrónico y otra información relevante para proporcionar nuestros servicios. También podemos recopilar información no personal como la - dirección IP, el tipo de navegador, el proveedor de servicios de - Internet, las páginas que visitas y la hora y fecha de tu visita. + dirección IP, el tipo de navegador, el proveedor de servicios de Internet, + las páginas que visitas y la hora y fecha de tu visita. Uso de la información La información que recopilamos se utiliza para proporcionar nuestros - servicios, para mejorar nuestro sitio web y para enviar información - sobre nuestros productos y servicios. No compartimos tu información - personal con terceros, excepto cuando sea necesario para proporcionar - nuestros servicios o cuando lo requiere la ley. + servicios, para mejorar nuestro sitio web y para enviar información sobre + nuestros productos y servicios. No compartimos tu información personal con + terceros, excepto cuando sea necesario para proporcionar nuestros servicios + o cuando lo requiere la ley. Cookies Utilizamos cookies y otras tecnologías similares para mejorar tu - experiencia en nuestro sitio web y para recopilar información sobre - tus visitas. Puedes controlar el uso de cookies en tu navegador. + experiencia en nuestro sitio web y para recopilar información sobre tus + visitas. Puedes controlar el uso de cookies en tu navegador. Seguridad - Tomamos medidas para proteger la información que recopilamos, - incluyendo la utilización de medidas de seguridad físicas, - electrónicas y procedimentales para garantizar la seguridad de la - información. + Tomamos medidas para proteger la información que recopilamos, incluyendo la + utilización de medidas de seguridad físicas, electrónicas y procedimentales + para garantizar la seguridad de la información. Cambios en esta política Podemos actualizar esta Política de Privacidad de vez en cuando. Te - notificaremos cualquier cambio en nuestra Política de Privacidad - publicando la nueva Política de Privacidad en nuestro sitio web. + notificaremos cualquier cambio en nuestra Política de Privacidad publicando + la nueva Política de Privacidad en nuestro sitio web. Contacto - Si tienes preguntas sobre nuestra Política de Privacidad, contáctanos - en{' '} + Si tienes preguntas sobre nuestra Política de Privacidad, contáctanos en{' '} ; - } - if (errorPaginated) { return ( - + ); } @@ -272,78 +264,81 @@ export default function Search() { handleLanguageChange={handleLanguageChange} handleYearChange={handleYearChange} /> - - - {results.length > 0 ? ( - - {results.map( - ({ - id, - title, - synopsis, - authors, - category, - language, - sourceLink, - image, - pathUrl, - }: CardType) => ( - - - - ), - )} - - ) : ( + {isPendingPaginated ? ( + + ) : ( + <> - - ¡Ups! - - - - No se encontraron libros que cumplan con los filtros seleccionados - + + {results.length > 0 ? ( + + {results.map( + ({ + id, + title, + synopsis, + authors, + category, + language, + sourceLink, + image, + pathUrl, + }: CardType) => ( + + + + ), + )} + + ) : ( + + + ¡Ups! + + + + No se encontraron libros que cumplan con los filtros seleccionados + + + )} - )} - + + )} {!isFiltering && {fetchingNextPageUI}} ); diff --git a/src/pages/profile/Profile.tsx b/src/pages/profile/Profile.tsx index 6b26878..59f5154 100644 --- a/src/pages/profile/Profile.tsx +++ b/src/pages/profile/Profile.tsx @@ -38,8 +38,11 @@ export function Profile() { const { currentUser } = useAuth(); const uid = currentUser?.uid; const { username } = useParams(); - const { data, isPending, error, fetchNextPage, isFetchingNextPage } = - useProfile(username, uid, getToken); + const { data, isPending, error, fetchNextPage, isFetchingNextPage } = useProfile( + username, + uid, + getToken, + ); const createdAt = data?.pages[0].user.createdAt; let asideAndCardsUI; let fetchingNextPageUI; @@ -141,12 +144,7 @@ export function Profile() { > Bienvenido a XBuniverse - + - + ); } @@ -208,12 +202,7 @@ export function Profile() { referrerPolicy='no-referrer' borderRadius='full' /> - + {data?.pages[0].user.name} } - > + }> ), diff --git a/src/services/api.ts b/src/services/api.ts index 07e45f5..9675766 100644 --- a/src/services/api.ts +++ b/src/services/api.ts @@ -32,15 +32,10 @@ async function getBooksFilterPaginated( param: string | undefined, page: number | undefined, ) { - return await fetchData( - `${API_URL}/books?${query}=${param}&limit=10&page=${page}`, - ); + return await fetchData(`${API_URL}/books?${query}=${param}&limit=10&page=${page}`); } -async function getBooksFilter( - query: string | undefined, - param: string | undefined, -) { +async function getBooksFilter(query: string | undefined, param: string | undefined) { return await fetchData(`${API_URL}/books?${query}=${param}`); }