diff --git a/.github/workflows/links.yml b/.github/workflows/links.yml new file mode 100644 index 0000000..2765c9f --- /dev/null +++ b/.github/workflows/links.yml @@ -0,0 +1,16 @@ +name: Links (Fail Fast) + +on: + push: + pull_request: + +jobs: + linkChecker: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Link Checker + uses: lycheeverse/lychee-action@v1.8.0 + with: + fail: true diff --git a/src/components/RelatedPost.tsx b/src/components/RelatedPost.tsx deleted file mode 100644 index 2379f15..0000000 --- a/src/components/RelatedPost.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import React from 'react'; -import { Flex, useColorModeValue } from '@chakra-ui/react'; - -import { RelatedCard } from '../components/cards/RelatedCard'; -import { CardType, ReleatedBooksType } from '../components/types'; -import { useMoreBooks } from '../hooks/querys'; - -export default function RelatedPost({ currentBookId }: ReleatedBooksType) { - const colorCard = useColorModeValue('gray.900', 'gray.100'); - const { data, refetch } = useMoreBooks(); - - // Filtrar el ID que coincide con el libro que se esta viendo para evitar ver el mismo en los relacionados, - // si eso pasa se hace un refetch() a la api para mostrar otros libros, - // si no hay coincidencias no se hace una actualizaciĆ³n. - - const relatedBooks = data.filter((book: any) => { - if (book.pathUrl === currentBookId) { - refetch(); - } - - return book.pathUrl !== currentBookId; - }); - - return ( - <> - - {relatedBooks.map( - ({ id, title, synopsis, authors, category, pathUrl }: CardType) => ( - - - - ), - )} - - - ); -} diff --git a/src/components/cards/Card.tsx b/src/components/cards/Card.tsx index b5e41f6..5dcb416 100644 --- a/src/components/cards/Card.tsx +++ b/src/components/cards/Card.tsx @@ -66,7 +66,7 @@ export function Card({ bg='green.50' color='green.900' icon={BsTag} - name={category[0]} + name={category && category[0]} size='md' isFocused={false} tabIndex={-1} diff --git a/src/components/cards/ContainerRCard.tsx b/src/components/cards/ContainerRCard.tsx new file mode 100644 index 0000000..ddef073 --- /dev/null +++ b/src/components/cards/ContainerRCard.tsx @@ -0,0 +1,14 @@ +import React from 'react'; +import { Flex, useColorModeValue } from '@chakra-ui/react'; + +export function ContainerRCard({ children }: { children: React.ReactNode }) { + const colorCard = useColorModeValue('gray.900', 'gray.100'); + + return ( + <> + + {children} + + + ); +} diff --git a/src/components/cards/MoreBooks.tsx b/src/components/cards/MoreBooks.tsx new file mode 100644 index 0000000..53c654b --- /dev/null +++ b/src/components/cards/MoreBooks.tsx @@ -0,0 +1,38 @@ +import React from 'react'; + +import { RelatedCard } from './RelatedCard'; +import { ContainerRCard } from './ContainerRCard'; +import { CardType, ReleatedBooksType } from '../types'; +import { useMoreBooks } from '../../hooks/querys'; +import { useRefetchLocation } from '../../hooks/useRefetchLocation'; + +export default function MoreBooks({ currentBookId }: ReleatedBooksType) { + const { data, refetch } = useMoreBooks(); + const moreBooks = useRefetchLocation(currentBookId, data, refetch); + + // const moreBooks = data.filter((book: any) => { + // if (book.pathUrl === currentBookId) { + // refetch(); + // } + + // return book.pathUrl !== currentBookId; + // }); + + return ( + <> + + {moreBooks.map(({ id, title, authors, pathUrl }: CardType) => ( + + + + ))} + + + ); +} diff --git a/src/components/cards/RelatedBooks.tsx b/src/components/cards/RelatedBooks.tsx new file mode 100644 index 0000000..45e9331 --- /dev/null +++ b/src/components/cards/RelatedBooks.tsx @@ -0,0 +1,30 @@ +import React from 'react'; + +import { RelatedCard } from './RelatedCard'; +import { ContainerRCard } from './ContainerRCard'; +import { CardType, ReleatedBooksType } from '../types'; +import { useRelatedBooks } from '../../hooks/querys'; +import { useRefetchLocation } from '../../hooks/useRefetchLocation'; + +export default function RelatedBooks({ currentBookId, id }: ReleatedBooksType) { + const { data, refetch } = useRelatedBooks(id); + const relatedBooks = useRefetchLocation(currentBookId, data, refetch); + + return ( + <> + + {relatedBooks.map(({ id, title, authors, pathUrl }: CardType) => ( + + + + ))} + + + ); +} diff --git a/src/components/types.d.ts b/src/components/types.d.ts index 2d52ba6..7c75dc7 100644 --- a/src/components/types.d.ts +++ b/src/components/types.d.ts @@ -24,7 +24,7 @@ interface CardType { title: string; synopsis?: string; authors: string[]; - category: string[]; + category?: string[]; year?: number; language?: number; sourceLink?: string; @@ -92,7 +92,8 @@ interface ModalType extends DisclosureType { } interface ReleatedBooksType { - currentBookId: string | undefined; + id?: string; + currentBookId?: string | undefined; } interface SelectType extends Omit { diff --git a/src/hooks/querys.ts b/src/hooks/querys.ts index 0b12e9c..8f6b4c2 100644 --- a/src/hooks/querys.ts +++ b/src/hooks/querys.ts @@ -13,6 +13,7 @@ import { getBook, getBooksFilter, getMoreBooks, + getRelatedBooks, postBook, } from '../services/api'; import { keys } from '../utils/utils'; @@ -113,6 +114,17 @@ function useMoreBooks() { }); } +function useRelatedBooks(id: string | undefined) { + return useQuery({ + queryKey: [keys.relatedBooks], + queryFn: () => getRelatedBooks(id), + suspense: true, + refetchOnWindowFocus: false, + cacheTime: 3000, + staleTime: 60000, + }); +} + function useBook(pathUrl: string | undefined) { return useQuery({ queryKey: [keys.one, pathUrl], @@ -132,4 +144,5 @@ export { useBook, useFilter, useMoreBooks, + useRelatedBooks, }; diff --git a/src/hooks/useRefetchLocation.tsx b/src/hooks/useRefetchLocation.tsx new file mode 100644 index 0000000..013a4ff --- /dev/null +++ b/src/hooks/useRefetchLocation.tsx @@ -0,0 +1,23 @@ +import { useState, useEffect } from 'react'; +import { useLocation } from 'react-router-dom'; + +export function useRefetchLocation(currentBookId, data, refetch) { + const location = useLocation(); + const [previousPathname, setPreviousPathname] = useState(location.pathname); + const [relatedBooks, setRelatedBooks] = useState([]); + + useEffect(() => { + const filteredBooks = data.filter((book) => { + return book.pathUrl !== currentBookId; + }); + + setRelatedBooks(filteredBooks); + + if (location.pathname !== previousPathname) { + refetch(); + setPreviousPathname(location.pathname); + } + }, [data, currentBookId, location.pathname, refetch, previousPathname]); + + return relatedBooks; +} diff --git a/src/pages/Book.tsx b/src/pages/Book.tsx index c9030f1..971f1ac 100644 --- a/src/pages/Book.tsx +++ b/src/pages/Book.tsx @@ -25,7 +25,8 @@ import { ModalShare } from '../components/ModalShare'; import { MyLink } from '../components/MyLink'; const Categories = lazy(() => import('../components/Categories')); -const RelatedPost = lazy(() => import('../components/RelatedPost')); +const RelatedBooks = lazy(() => import('../components/cards/RelatedBooks')); +const MoreBooks = lazy(() => import('../components/cards/MoreBooks')); export default function Book() { const shareUrl = window.location.href; @@ -114,7 +115,7 @@ export default function Book() { w='full' maxW='1300px' m='auto' - mb='25' + mb={{ base: 25, md: 32 }} align='flex-start' direction={{ base: 'column', lg: 'row-reverse' }} > @@ -314,6 +315,34 @@ export default function Book() { + + + Libros relacionados con{' '} + + {data.category[0]} + + + + + + } + > + + + + + + + + - + diff --git a/src/services/api.ts b/src/services/api.ts index 536a21b..4f3cbd2 100644 --- a/src/services/api.ts +++ b/src/services/api.ts @@ -50,6 +50,12 @@ async function getMoreBooks() { return data; } +async function getRelatedBooks(id: string | undefined) { + const data = await fetchData(`${API_URL}/books/related-books/${id}`); + + return data; +} + async function getAllFilterOptions() { const data = await fetchData(`${API_URL}/books/options`); @@ -72,6 +78,7 @@ export { getBooksFilter, getAllFilterOptions, getMoreBooks, + getRelatedBooks, postBook, deleteBook, }; diff --git a/src/utils/utils.ts b/src/utils/utils.ts index c576625..76238c4 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -11,6 +11,7 @@ const keys = { paginate: 'BookPaginate', filter: 'BooksFilter', random: 'BooksRandom', + relatedBooks: 'RelatedBooks', }; function handleImageLoad(e: React.SyntheticEvent) {