From e17376f06a12065340ffbb7eea0bc9d3c815794b Mon Sep 17 00:00:00 2001 From: franco sanchez Date: Wed, 7 Aug 2024 13:16:06 -0300 Subject: [PATCH] feat: improved the way it filters in Search.tsx now via API --- src/components/FilterDrawer.tsx | 14 +- src/components/types.d.ts | 2 - src/hooks/queries.ts | 32 ++- src/pages/Search.tsx | 408 ++++++++++++++++---------------- src/services/api.ts | 10 +- src/utils/utils.ts | 1 + 6 files changed, 235 insertions(+), 232 deletions(-) diff --git a/src/components/FilterDrawer.tsx b/src/components/FilterDrawer.tsx index 1c57c90..b0c5401 100644 --- a/src/components/FilterDrawer.tsx +++ b/src/components/FilterDrawer.tsx @@ -22,9 +22,7 @@ export function FilterDrawer({ onClose, handleLanguageChange, language, - languagesMap, year, - yearsMap, handleYearChange, }: DrawerType) { const bgContentCheckbox = useColorModeValue('white', 'transparent'); @@ -80,8 +78,8 @@ export function FilterDrawer({ direction='column-reverse' gap='5' > - {language && - language.map((language) => ( + {Array.isArray(language) && + language?.map(({ language, count }: any) => ( {language} - ({languagesMap && languagesMap[language]}) + ({count}) ))} @@ -116,8 +114,8 @@ export function FilterDrawer({ direction='column-reverse' gap='5' > - {year && - year.map((year) => ( + {Array.isArray(year) && + year?.map(({ year, count }: any) => ( {year} - ({yearsMap && yearsMap[year]}) + ({count}) ))} diff --git a/src/components/types.d.ts b/src/components/types.d.ts index 98485c8..d050fc7 100644 --- a/src/components/types.d.ts +++ b/src/components/types.d.ts @@ -112,9 +112,7 @@ type languagesYMapType = { [key: string]: number } | undefined; interface LanguageAndYearType { language: languageYType; - languagesMap: languagesYMapType; year: languageYType; - yearsMap: languagesYMapType; } interface DrawerType extends DisclosureType, LanguageAndYearType { diff --git a/src/hooks/queries.ts b/src/hooks/queries.ts index 2e4336b..a1f3da8 100644 --- a/src/hooks/queries.ts +++ b/src/hooks/queries.ts @@ -24,6 +24,7 @@ import { updateBook, deleteBook, deleteAccount, + getBooksFilterPaginated, } from '@services/api'; import { useAccountActions } from '@hooks/useAccountActions'; import { keys } from '@utils/utils'; @@ -108,17 +109,14 @@ function useBooksPaginate() { }); } -function useFilter(query: string | undefined, param: string | undefined) { - // return useSuspenseQuery({ - // queryKey: [keys.filter, query, param], - // queryFn: () => getBooksFilter(query, param, page), - // gcTime: 3000, - // retry: 1, - // }); - +function useFilterPaginated( + query: string | undefined, + param: string | undefined, +) { return useInfiniteQuery({ - queryKey: [keys.filter, query, param], - queryFn: ({ pageParam }) => getBooksFilter(query, param, pageParam), + queryKey: [keys.filterPaginated, query, param], + queryFn: ({ pageParam }) => + getBooksFilterPaginated(query, param, pageParam), initialPageParam: 0, getNextPageParam: (lastPage) => { if (lastPage.info.nextPage === null) return; @@ -126,7 +124,18 @@ function useFilter(query: string | undefined, param: string | undefined) { return lastPage.info.nextPage; }, gcTime: 3000, - retry: 1, + retry: false, + refetchOnWindowFocus: false, + }); +} + +function useFilter(query: string | undefined, param: string | undefined) { + return useQuery({ + queryKey: [keys.filter, query, param], + queryFn: () => getBooksFilter(query, param), + gcTime: 3000, + retry: false, + refetchOnWindowFocus: false, }); } @@ -279,6 +288,7 @@ export { useAllSearchBooks, useBooksPaginate, useBook, + useFilterPaginated, useFilter, useMoreBooks, useMostViewedBooks, diff --git a/src/pages/Search.tsx b/src/pages/Search.tsx index cbeb872..ff1ad09 100644 --- a/src/pages/Search.tsx +++ b/src/pages/Search.tsx @@ -19,8 +19,8 @@ import { } from '@chakra-ui/react'; import { Card } from '@components/cards/Card'; -import { CardType, LanguageAndYearType } from '@components/types'; -import { useFilter } from '@hooks/queries'; +import { CardType } from '@components/types'; +import { useFilter, useFilterPaginated } from '@hooks/queries'; import { ContainerTitle } from '@components/ContainerTitle'; import { MySimpleGrid } from '@components/MySimpleGrid'; import { MainHead } from '@components/Head'; @@ -35,167 +35,157 @@ import { SkeletonAllBooks } from '@components/skeletons/SkeletonABooks'; export default function Search() { const { ref, inView } = useInView(); - // const location = useLocation(); - // const { isOpen, onToggle, onClose } = useDisclosure(); + const location = useLocation(); + const { isOpen, onToggle, onClose } = useDisclosure(); const grayColor = useColorModeValue('#E2E8F0', '#2D3748'); - // const [languages, setLanguages] = useState([]); - // const [selectedLanguage, setSelectedLanguage] = useState(''); - // const [years, setYears] = useState([]); - // const [selectedYear, setSelectedYear] = useState(''); + const [languages, setLanguages] = useState([]); + const [selectedLanguage, setSelectedLanguage] = useState(''); + const [years, setYears] = useState([]); + const [selectedYear, setSelectedYear] = useState(''); const { query, param } = useParams(); let asideFilter; let aboutCategoriesUI; let buttonFilter; let fetchingNextPageUI; + const isFiltering = !!selectedLanguage || !!selectedYear; // Verificar si los radios estan activos o no. - const { data, isPending, error, fetchNextPage, isFetchingNextPage } = - useFilter(query, param); + const { + data: dataPaginated, + isPending: isPendingPaginated, + error: errorPaginated, + fetchNextPage, + isFetchingNextPage, + } = useFilterPaginated(query, param); + + const { data: dataFilter } = useFilter(query, param); + + // Esta función ejecuta la petición de paginación por defecto + // y si se aplican los filtros ejecuta la petición "dataFilter". + function getNormalizedResults() { + if (isFiltering) { + return ( + dataFilter?.results?.filter(({ language, year }) => { + // Filtrar por idioma + const languageMatch = selectedLanguage + ? language === selectedLanguage + : true; + + // Filtrar por año + const yearMatch = selectedYear ? String(year) === selectedYear : true; + + return languageMatch && yearMatch; + }) || [] + ); + } + // Combina todos los resultados de las páginas + return dataPaginated?.pages.flatMap((page) => page?.results) || []; + } + + const results = getNormalizedResults(); useEffect(() => { let isMounted = true; - if (inView && isMounted) { + if (inView && isMounted && !isPendingPaginated) { fetchNextPage(); } return () => { isMounted = false; }; - }, [inView, fetchNextPage]); - - // function getLanguagesAndYears( - // data: Array | undefined, - // ): LanguageAndYearType | null { - // if (!data) { - // return null; - // } - - // const languagesMap = data.reduce((acc, book) => { - // const language = book.language; - - // if (language) { - // acc[language] = (acc[language] || 0) + 1; - // } - - // return acc; - // }, {}); - - // const yearsMap = data.reduce((acc, book) => { - // const year = book.year; - - // if (year) { - // acc[year] = (acc[year] || 0) + 1; - // } - - // return acc; - // }, {}); - - // const language = Object.keys(languagesMap); - // const year = Object.keys(yearsMap); - - // if (language.length === 1 && year.length === 1) return null; + }, [inView, fetchNextPage, isPendingPaginated]); - // return { language, languagesMap, year, yearsMap }; - // } - - // const languagesAndYearData = getLanguagesAndYears(data?.pages[0]?.results); - - // const filteredBooks = data?.pages.filter(({ language, year }) => { - // return ( - // (languages.length === 0 || languages.includes(language)) && - // (years.length === 0 || years.includes(year)) - // ); - // }); + useEffect(() => { + if (dataFilter) { + const languageCounts = dataFilter?.languageCounts || []; + const yearCounts = dataFilter?.yearCounts || []; - // function handleLanguageChange(languages) { - // setLanguages(languages); - // setSelectedLanguage(languages); - // } + setLanguages(Array.isArray(languageCounts) ? languageCounts : []); + setYears(Array.isArray(yearCounts) ? yearCounts : []); + } + }, [dataFilter]); - // function handleYearChange(year) { - // setYears(year); - // setSelectedYear(year); - // } + function handleLanguageChange(languages: string) { + setSelectedLanguage(languages); + } - // // Restablecer los valores de los radios(filtros) cuando cambie la ruta - // useEffect(() => { - // setSelectedLanguage(''); - // setLanguages([]); - // setSelectedYear(''); - // setYears([]); - // }, [location.pathname]); + function handleYearChange(year: string) { + setSelectedYear(year); + } - // if (languagesAndYearData) { - // const { language, languagesMap, year, yearsMap } = languagesAndYearData; + // Restablecer los valores de los radios(filtros) cuando cambie la ruta + useEffect(() => { + setSelectedLanguage(''); + setSelectedYear(''); + }, [location.pathname]); - // asideFilter = ( - // - // - // - // Filtrar por: - // - // - // - // {language && - // language.map((language) => ( - // - // {language} - // - // ({languagesMap && languagesMap[language]}) - // - // - // ))} - // Todos los Idiomas - // - // Idioma - // - // - // - // - // - // {year && - // year.map((year) => ( - // - // {year} - // - // ({yearsMap && yearsMap[year]}) - // - // - // ))} - // Todos los Años - // - // Año - // - // - // - // - // ); + asideFilter = ( + + + + Filtrar por: + + + + Idioma + + + Todos los Idiomas + {Array.isArray(languages) && + languages.map(({ language, count }: any) => ( + + {language} + + ({count}) + + + ))} + + + + + Año + + + Todos los Años + {Array.isArray(years) && + years.map(({ year, count }: any) => ( + + {year} + + ({count}) + + + ))} + + + + ); - // buttonFilter = ( - // - // ); - // } + buttonFilter = ( + + ); // Verifica si los 3 campos de aboutCategories esten con info o no const categoryCheck = aboutCategories.find((item) => { @@ -212,11 +202,11 @@ export default function Search() { } } - if (isPending) { + if (isPendingPaginated) { return ; } - if (error) { + if (errorPaginated) { return ( - + {buttonFilter} - {/* */} + /> - - {data?.pages.map((page, index) => ( - - {page?.results.map( - ({ - id, - title, - synopsis, - authors, - category, - language, - sourceLink, - image, - pathUrl, - }: CardType) => ( - - - - ), - )} - {/* - - ¡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 + + + )} - {fetchingNextPageUI} + {!isFiltering && {fetchingNextPageUI}} ); } diff --git a/src/services/api.ts b/src/services/api.ts index f43250d..375cd09 100644 --- a/src/services/api.ts +++ b/src/services/api.ts @@ -17,7 +17,7 @@ async function getBook(pathUrl: string | undefined) { return await fetchData(`${API_URL}/books/path/${pathUrl}`); } -async function getBooksFilter( +async function getBooksFilterPaginated( query: string | undefined, param: string | undefined, page: number | undefined, @@ -27,6 +27,13 @@ async function getBooksFilter( ); } +async function getBooksFilter( + query: string | undefined, + param: string | undefined, +) { + return await fetchData(`${API_URL}/books?${query}=${param}`); +} + async function getMoreBooks() { return await fetchData(`${API_URL}/books/more-books`); } @@ -115,6 +122,7 @@ export { getAllSearchBooks, getBooksPaginate, getBook, + getBooksFilterPaginated, getBooksFilter, getAllFilterOptions, getMoreBooks, diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 9054c7a..cc9d988 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -9,6 +9,7 @@ const keys = { one: 'BookOne', filtersOptions: 'BookFiltersOptions', paginate: 'BookPaginate', + filterPaginated: 'BooksFilterPaginated', filter: 'BooksFilter', random: 'BooksRandom', relatedBooks: 'RelatedBooks',