diff --git a/src/components/Home/DonorDashboard/index.tsx b/src/components/Home/DonorDashboard/index.tsx index 0b85633..0170d2a 100644 --- a/src/components/Home/DonorDashboard/index.tsx +++ b/src/components/Home/DonorDashboard/index.tsx @@ -1,43 +1,93 @@ import { Box, Typography } from '@mui/material'; -import { filter, lowerCase, some } from 'es-toolkit/compat'; -import { useState } from 'react'; +import { useState, useMemo } from 'react'; import OrganizationCard from './OrganizationCard'; import { useOrganizationStore } from '@/stores'; -import { SearchBar } from '@/components/common'; +import { SearchBar, Filters } from '@/components/common'; const DonorDashboard = () => { const [searchQuery, setSearchQuery] = useState(''); + const [needsQuery, setNeedsQuery] = useState(''); + const [descriptionQuery, setDescriptionQuery] = useState(''); + const [locationQuery, setLocationQuery] = useState(''); const organizationProfiles = useOrganizationStore( (state) => state.organizationProfiles ); - // Filtered organizations based on search query - const filteredOrganizations = filter(organizationProfiles, (org) => { - if (!org.name) return false; - const searchTerm = lowerCase(searchQuery); - return ( - lowerCase(org.name).includes(searchTerm) || - lowerCase(org.location).includes(searchTerm) || - some(org.needs, (need) => lowerCase(need).includes(searchTerm)) - ); - }); + const filteredOrganizations = useMemo(() => { + return organizationProfiles.filter((org) => { + const matchesSearch = searchQuery + ? org.name.toLowerCase().includes(searchQuery.toLowerCase()) || + org.location.toLowerCase().includes(searchQuery.toLowerCase()) || + (org.needs || []).some((need) => + need.itemName.toLowerCase().includes(searchQuery.toLowerCase()) + ) + : true; + + const matchesNeeds = needsQuery + ? (org.needs || []).some((need) => + need.itemName.toLowerCase().includes(needsQuery.toLowerCase()) + ) + : true; + + const matchesDescription = descriptionQuery + ? org.description + ?.toLowerCase() + .includes(descriptionQuery.toLowerCase()) + : true; + + const matchesLocation = locationQuery + ? org.location.toLowerCase().includes(locationQuery.toLowerCase()) + : true; + + return ( + matchesSearch && matchesNeeds && matchesDescription && matchesLocation + ); + }); + }, [ + organizationProfiles, + searchQuery, + needsQuery, + descriptionQuery, + locationQuery, + ]); return organizationProfiles.length > 0 ? ( -
- - - {filteredOrganizations.map((org) => ( - - ))} + + + + -
+ + {filteredOrganizations.map((org) => ( + + ))} + ) : ( void; + descriptionQuery: string; + setDescriptionQuery: (query: string) => void; + locationQuery: string; + setLocationQuery: (query: string) => void; +} + +const Filters = ({ + needsQuery, + setNeedsQuery, + descriptionQuery, + setDescriptionQuery, + locationQuery, + setLocationQuery, +}: FiltersProps) => { + const organizationProfiles = useOrganizationStore( + (state) => state.organizationProfiles + ); + + const [anchorElement, setAnchorElement] = useState(null); + + const handleClose = () => { + setAnchorElement(null); + }; + + const open = Boolean(anchorElement); + const id = open ? 'filters-popover' : undefined; + + const needsOptions = [ + ...new Set( + organizationProfiles.flatMap( + (org) => org.needs?.flatMap((need) => need.itemName) || [] + ) + ), + ].filter(Boolean); + + return ( + + + + + {/* Needs dropdown */} + + Filter by Needs + + + + {/* Description text field */} + setDescriptionQuery(event_.target.value)} + /> + + {/* Location text field */} + setLocationQuery(event_.target.value)} + /> + + + + ); +}; + +export default Filters; diff --git a/src/components/common/SearchBar.tsx b/src/components/common/SearchBar.tsx index 1f07e2d..0a7b74c 100644 --- a/src/components/common/SearchBar.tsx +++ b/src/components/common/SearchBar.tsx @@ -1,6 +1,6 @@ import type { ChangeEvent } from 'react'; import { useCallback, useMemo, useEffect, useState } from 'react'; -import { TextField, Box, Button } from '@mui/material'; +import { TextField } from '@mui/material'; import { useSearchParams } from 'react-router-dom'; import { debounce } from 'es-toolkit/compat'; @@ -42,22 +42,14 @@ const SearchBar = ({ onSearchChange }: SearchBarProps) => { }, [searchParams, onSearchChange]); return ( - - - - + ); }; diff --git a/src/components/common/index.tsx b/src/components/common/index.tsx index 28914be..91b687e 100644 --- a/src/components/common/index.tsx +++ b/src/components/common/index.tsx @@ -5,3 +5,4 @@ export { default as ProtectedRoute } from './ProtectedRoute'; export { default as CustomDialog } from './CustomDialog'; export { default as RoleSelectionModal } from './RoleSelectionModal'; export { default as Layout } from './Layout'; +export { default as Filters } from './Filters';