diff --git a/src/components/aside/AboutCategories.tsx b/src/components/aside/AboutCategories.tsx index 3358f08..3efb64f 100644 --- a/src/components/aside/AboutCategories.tsx +++ b/src/components/aside/AboutCategories.tsx @@ -19,11 +19,11 @@ export function AboutCategories({ category }: any) { mt='2' fontSize='sm' maxH='250px' - overflow='auto' + overflowY='scroll' pr='1' sx={{ '&::-webkit-scrollbar': { - width: '7px', + width: '5px', }, '&::-webkit-scrollbar-thumb': { background: '#a2aab3', diff --git a/src/components/filters/AsideFilter.tsx b/src/components/filters/AsideFilter.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/filters/FilterAccordion.tsx b/src/components/filters/FilterAccordion.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/FilterDrawer.tsx b/src/components/filters/FilterDrawer.tsx similarity index 100% rename from src/components/FilterDrawer.tsx rename to src/components/filters/FilterDrawer.tsx diff --git a/src/components/filters/FilterNumberPages.tsx b/src/components/filters/FilterNumberPages.tsx new file mode 100644 index 0000000..3117599 --- /dev/null +++ b/src/components/filters/FilterNumberPages.tsx @@ -0,0 +1,49 @@ +import React from 'react'; +import { Flex, Input, useColorModeValue } from '@chakra-ui/react'; + +interface FilterNumberTypes { + min: string | undefined; + max: string | undefined; + setMin: React.ChangeEventHandler; + setMax: React.ChangeEventHandler; +} + +export function FilterNumberPages({ min, max, setMin, setMax }: FilterNumberTypes) { + const bgInput = useColorModeValue('gray.100', 'black'); + const colorInput = useColorModeValue('gray.900', 'gray.100'); + + return ( + <> + + + + + + ); +} diff --git a/src/components/ui/MyContainer.tsx b/src/components/ui/MyContainer.tsx index 476f4eb..eacd7cc 100644 --- a/src/components/ui/MyContainer.tsx +++ b/src/components/ui/MyContainer.tsx @@ -6,6 +6,7 @@ export function MyContainer({ children }: { children: React.ReactNode }) { <> - N° paginas: + N° páginas: {bookObject.numberPages} diff --git a/src/pages/Search.tsx b/src/pages/FilteredData.tsx similarity index 55% rename from src/pages/Search.tsx rename to src/pages/FilteredData.tsx index 4dfe529..d7c9b87 100644 --- a/src/pages/Search.tsx +++ b/src/pages/FilteredData.tsx @@ -16,6 +16,11 @@ import { Alert, AlertIcon, AlertTitle, + Accordion, + AccordionItem, + AccordionButton, + AccordionIcon, + AccordionPanel, } from '@chakra-ui/react'; import { Card } from '@components/cards/Card'; @@ -27,31 +32,45 @@ import { MySimpleGrid } from '@components/ui/MySimpleGrid'; import { MainHead } from '@components/layout/Head'; import { Aside } from '@components/aside/Aside'; import { MySliderCategories } from '@components/ui/MySliderCategories'; -import { FilterDrawer } from '@components/FilterDrawer'; +import { FilterDrawer } from '@components/filters/FilterDrawer'; import { ResultLength } from '@components/aside/ResultLength'; import { AboutCategories } from '@components/aside/AboutCategories'; import { Lost } from '@assets/assets'; import { aboutCategories } from '../constant/constants'; import { SkeletonAllBooks } from '@components/skeletons/SkeletonABooks'; import { MyContainer } from '@components/ui/MyContainer'; +import { FilterNumberPages } from '@components/filters/FilterNumberPages'; +import { capitalizeWords } from '@utils/utils'; -export default function Search() { +export default function FilteredData() { const { ref, inView } = useInView(); const location = useLocation(); const { isOpen, onToggle, onClose } = useDisclosure(); const grayColor = useColorModeValue('#E2E8F0', '#2D3748'); const [languages, setLanguages] = useState([]); - const [selectedLanguage, setSelectedLanguage] = useState(''); + const [authors, setAuthors] = useState([]); const [years, setYears] = useState([]); + const [selectedLanguage, setSelectedLanguage] = useState(''); const [selectedYear, setSelectedYear] = useState(''); + const [selectedAuthor, setSelectedAuthor] = useState(''); + const [selectedMinPages, setSelectedMinPages] = useState(''); + const [selectedMaxPages, setSelectedMaxPages] = 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. + // Verificar si los radios estan activos o no. + const isFiltering = + !!selectedLanguage || + !!selectedYear || + !!selectedAuthor || + (selectedMinPages && selectedMaxPages) || // Solo cuando ambos están definidos + !!selectedMinPages || + !!selectedMaxPages; const hasMultipleLanguages = languages.length > 1; const hasMultipleYears = years.length > 1; + const hasMultipleAuthors = authors.length > 1; const { data: dataPaginated, @@ -63,29 +82,6 @@ export default function Search() { 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(); useScrollYRestoration(isPendingPaginated); // Restablece la posición del scroll al volver de la vista del libro useEffect(() => { @@ -104,12 +100,67 @@ export default function Search() { if (dataFilter) { const languageCounts = dataFilter?.languageCounts || []; const yearCounts = dataFilter?.yearCounts || []; + const authorsCounts = dataFilter?.authorsCounts || []; setLanguages(Array.isArray(languageCounts) ? languageCounts : []); setYears(Array.isArray(yearCounts) ? yearCounts : []); + setAuthors(Array.isArray(authorsCounts) ? authorsCounts : []); } }, [dataFilter]); + // Restablecer los valores de los radios(filtros) cuando cambie la ruta + useEffect(() => { + setSelectedLanguage(''); + setSelectedYear(''); + setSelectedAuthor(''); + setSelectedMinPages(''); + setSelectedMaxPages(''); + }, [location.pathname]); + + // 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, authors, numberPages }) => { + // Filtrar por idioma + const languageMatch = selectedLanguage + ? language === selectedLanguage + : true; + + // Filtrar por año + const yearMatch = selectedYear ? String(year) === selectedYear : true; + + // Filtrar por autor + const authorMatch = selectedAuthor + ? authors[0].toLowerCase() === selectedAuthor + : true; + + // Filtrar por número de páginas + const minPages = selectedMinPages ? Number(selectedMinPages) : null; + const maxPages = selectedMaxPages ? Number(selectedMaxPages) : null; + + let pagesMatch = true; + + if (minPages !== null && maxPages !== null) { + pagesMatch = numberPages >= minPages && numberPages <= maxPages; + } else if (minPages !== null) { + pagesMatch = numberPages >= minPages; + } else if (maxPages !== null) { + pagesMatch = numberPages <= maxPages; + } + + // Devuelve el resultado solo si cumple con todos los filtros + return languageMatch && yearMatch && authorMatch && pagesMatch; + }) || [] + ); + } + // Combina todos los resultados de las páginas + return dataPaginated?.pages.flatMap((page) => page?.results) || []; + } + + const results = getNormalizedResults(); + function handleLanguageChange(languages: string) { setSelectedLanguage(languages); } @@ -118,13 +169,19 @@ export default function Search() { setSelectedYear(year); } - // Restablecer los valores de los radios(filtros) cuando cambie la ruta - useEffect(() => { - setSelectedLanguage(''); - setSelectedYear(''); - }, [location.pathname]); + function handleAuthorChange(author: string) { + setSelectedAuthor(author); + } + + function handleMinChange(e: React.ChangeEvent) { + setSelectedMinPages(e.target.value); + } + + function handleMaxChange(e: React.ChangeEvent) { + setSelectedMaxPages(e.target.value); + } - if (hasMultipleLanguages || hasMultipleYears) { + if (hasMultipleLanguages || hasMultipleYears || hasMultipleAuthors) { asideFilter = ( Filtrar por: - - - Idioma - - - Todos los Idiomas - {Array.isArray(languages) && - languages.map(({ language, count }: any) => ( - - {language} - - ({count}) + + +

+ + + N° de páginas - - ))} - - - - - Año - - - Todos los Años - {Array.isArray(years) && - years.map(({ year, count }: any) => ( - - {year} - - ({count}) + + +

+ + + +
+ +

+ + + 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}) + + + ))} + + + +
+ +

+ + + Autor + + + +

+ + + + Todos los Autores + {Array.isArray(authors) && + authors.map(({ authors, count }: any) => ( + + {capitalizeWords(authors)} + + ({count}) + + + ))} + + + +
+
+
); diff --git a/src/routes.tsx b/src/routes.tsx index 6052714..aaae6cc 100644 --- a/src/routes.tsx +++ b/src/routes.tsx @@ -19,7 +19,7 @@ const PrivacyPolicies = lazy(() => import('@pages/PrivacyPolicies')); const Explore = lazy(() => import('@pages/Explore')); const MostViewed = lazy(() => import('@pages/MostViewed')); const Book = lazy(() => import('@pages/Book')); -const Search = lazy(() => import('@pages/Search')); +const FilteredData = lazy(() => import('@pages/FilteredData')); const NewBook = lazy(() => import('@pages/NewBook')); const Favorites = lazy(() => import('@pages/Favorites')); @@ -81,7 +81,7 @@ export const routes = createBrowserRouter([ path: ':query/:param', element: ( }> - + ), }, diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 444417c..57bf46d 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -84,6 +84,18 @@ function sortArrayByLabel(array: T[]): T[] { return array.slice().sort((a, b) => a.label.localeCompare(b.label)); } +function capitalizeWords(str: string) { + return str + .split(' ') // Dividir la cadena por espacios + .map((word) => + word + .split('.') // Dividir cada palabra por puntos + .map((part) => part.charAt(0).toUpperCase() + part.slice(1)) // Capitalizar cada parte después de un punto + .join('.'), + ) // Unir las partes capitalizadas con un punto + .join(' '); // Unir las palabras capitalizadas con espacios +} + export { keys, handleImageLoad, @@ -92,4 +104,5 @@ export { isSpanish, parseDate, sortArrayByLabel, + capitalizeWords, };