Skip to content

Commit

Permalink
Fix Mentor Filtration sef-global#223: Add filters and sorting
Browse files Browse the repository at this point in the history
  • Loading branch information
rdwaynedehoedt committed Nov 28, 2024
1 parent 10d34a5 commit 9a9eb71
Showing 1 changed file with 218 additions and 54 deletions.
272 changes: 218 additions & 54 deletions src/pages/Mentors/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,17 @@ import { usePublicMentors } from '../../hooks/usePublicMentors';
import { type Mentor, type Category } from '../../types';
import MentorCard from '../../components/MentorCard/MentorCard.component';
import Loading from '../../assets/svg/Loading';
import { ApplicationStatus } from '../../enums';

const Mentors = () => {
const [selectedCategory, setSelectedCategory] = useState<string | null>(null);
const [selectedCountries, setSelectedCountries] = useState<string[]>([]);
const [selectedAvailableSlots, setSelectedAvailableSlots] = useState<number[]>([]);
const [sortedMentors, setSortedMentors] = useState<Mentor[]>([]);
const [uniqueCountries, setUniqueCountries] = useState<string[]>([]);
const [uniqueAvailableSlots, setUniqueAvailableSlots] = useState<number[]>([]);
const [isCountryDropdownOpen, setIsCountryDropdownOpen] = useState(false);
const [isSlotsDropdownOpen, setIsSlotsDropdownOpen] = useState(false);
const pageSize = 10;

const { ref, inView } = useInView();
Expand All @@ -31,13 +38,62 @@ const Mentors = () => {
useEffect(() => {
if (data) {
const allMentors = data.pages.flatMap((page) => page.items);
setSortedMentors(allMentors);

const countries = allMentors
.map((mentor) => mentor.application?.country)
.filter((country): country is string => !!country);
setUniqueCountries([...new Set(countries)]);

const availableSlots = allMentors
.map((mentor) => {
const approvedMenteesCount = mentor?.mentees
? mentor.mentees.filter(
(mentee) => mentee.state === ApplicationStatus.APPROVED
).length
: 0;
const availableSlots = mentor?.application.noOfMentees
? Math.max(0, mentor.application.noOfMentees - approvedMenteesCount)
: 0;
return availableSlots;
})
.filter((slots, index, self) => self.indexOf(slots) === index);
setUniqueAvailableSlots(availableSlots);
}
}, [data]);

useEffect(() => {
if (data) {
let allMentors = data.pages.flatMap((page) => page.items);

if (selectedCountries.length > 0) {
allMentors = allMentors.filter((mentor) =>
selectedCountries.includes(mentor.application.country)
);
}

if (selectedAvailableSlots.length > 0) {
allMentors = allMentors.filter((mentor) => {
const approvedMenteesCount = mentor?.mentees
? mentor.mentees.filter(
(mentee) => mentee.state === ApplicationStatus.APPROVED
).length
: 0;
const availableSlots = mentor?.application.noOfMentees
? Math.max(0, mentor.application.noOfMentees - approvedMenteesCount)
: 0;
return selectedAvailableSlots.includes(availableSlots);
});
}

setSortedMentors(allMentors);
}
}, [data, selectedCountries, selectedAvailableSlots]);

const handleSortAZ = () => {
const sorted = [...sortedMentors].sort((a, b) =>
a.application.firstName.localeCompare(b.application.firstName)
(a.application?.firstName || '').localeCompare(
b.application?.firstName || ''
)
);
setSortedMentors(sorted);
};
Expand All @@ -46,6 +102,34 @@ const Mentors = () => {
setSelectedCategory(category);
};

const handleCountryChange = (country: string) => {
setSelectedCountries((prevCountries) => {
if (prevCountries.includes(country)) {
return prevCountries.filter((c) => c !== country);
} else {
return [...prevCountries, country];
}
});
};

const handleAvailableSlotsChange = (slots: number) => {
setSelectedAvailableSlots((prevSlots) => {
if (prevSlots.includes(slots)) {
return prevSlots.filter((s) => s !== slots);
} else {
return [...prevSlots, slots];
}
});
};

const toggleCountryDropdown = () => {
setIsCountryDropdownOpen(!isCountryDropdownOpen);
};

const toggleSlotsDropdown = () => {
setIsSlotsDropdownOpen(!isSlotsDropdownOpen);
};

if (status === 'pending' || categoriesLoading) {
return (
<div className="flex items-center justify-center h-screen">
Expand All @@ -59,69 +143,149 @@ const Mentors = () => {
}

return (
<div className="w-full">
<div>
<div className="mb-4 w-full flex items-center justify-between">
<p className="text-2xl font-semibold">Mentors</p>
</div>
<hr className="mb-8" />
<div className="min-h-screen flex flex-col items-center p-6 bg-white">
<div className="w-full max-w-7xl flex flex-col lg:flex-row gap-8">
<div className="w-full lg:w-1/4 bg-white rounded-lg p-6 self-start">
<p className="text-xl font-semibold mb-4 text-gray-800">Filters</p>

<div className="mb-4 w-full flex items-center justify-between">
<div className="flex flex-wrap gap-3 items-center text-sm">
<button
onClick={() => {
handleCategoryChange(null);
}}
className={`bg-blue text-black px-4 py-1 rounded-full border border-blue-500 ${
selectedCategory === null ? 'bg-blue-500 text-white' : ''
}`}
>
All
</button>
{allCategories.map((category: Category) => (
<div className="mb-6">
<p className="font-medium mb-2 text-gray-700">Categories</p>
<div className="flex flex-col gap-3 text-sm">
<label className="flex items-center space-x-2">
<input
type="checkbox"
checked={selectedCategory === null}
onChange={() => handleCategoryChange(null)}
className="form-checkbox h-4 w-4 text-blue-500"
/>
<span className="text-gray-700">All</span>
</label>

{allCategories.map((category: Category) => (
<label
key={category.uuid}
className="flex items-center space-x-2"
>
<input
type="checkbox"
checked={selectedCategory === category.uuid}
onChange={() => handleCategoryChange(category.uuid)}
className="form-checkbox h-4 w-4 text-blue-500"
/>
<span className="text-gray-700">{category.category}</span>
</label>
))}
</div>
</div>

<div className="mb-6">
<p className="font-medium mb-2 text-gray-700 flex items-center">
<button
key={category.uuid}
onClick={() => {
handleCategoryChange(category.uuid);
}}
className={`bg-blue text-black px-4 py-1 rounded-full border border-blue-500 ${
selectedCategory === category.uuid
? 'bg-blue-500 text-white'
: ''
}`}
className=" text-gray-700 hover:text-blue-500"
onClick={toggleCountryDropdown}
>
{category.category}
Countries {isCountryDropdownOpen ? '-' : ' +'}
</button>
))}
</p>

{isCountryDropdownOpen && (
<div className="flex flex-col gap-3 text-sm">
<label className="flex items-center space-x-2">
<input
type="checkbox"
checked={selectedCountries.length === 0}
onChange={() => setSelectedCountries([])}
className="form-checkbox h-4 w-4 text-blue-500"
/>
<span className="text-gray-700">All</span>
</label>
{uniqueCountries.map((country) => (
<label key={country} className="flex items-center space-x-2">
<input
type="checkbox"
checked={selectedCountries.includes(country)}
onChange={() => handleCountryChange(country)}
className="form-checkbox h-4 w-4 text-blue-500"
/>
<span className="text-gray-700">{country}</span>
</label>
))}
</div>
)}
</div>
</div>

<div className="mb-4 w-full flex justify-end">
<button
onClick={handleSortAZ}
className="bg-blue-500 text-white px-2 py-1 rounded border border-blue-500 text-xs mr-6"
>
Sort A-Z
</button>
</div>
<div className="mb-6">
<p className="font-medium mb-2 text-gray-700 flex items-center">
<button
className=" text-gray-700 hover:text-blue-500"
onClick={toggleSlotsDropdown}
>
Available Slots {isSlotsDropdownOpen ? '-' : ' +'}
</button>
</p>

{sortedMentors.length > 0 ? (
<div className="flex-grow grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-5 xl:grid-cols-6 gap-8 items-start">
{sortedMentors.map((mentor) => (
<MentorCard key={mentor.uuid} mentor={mentor} />
))}
{isSlotsDropdownOpen && (
<div className="flex flex-col gap-3 text-sm">
<label className="flex items-center space-x-2">
<input
type="checkbox"
checked={selectedAvailableSlots.length === 0}
onChange={() => setSelectedAvailableSlots([])}
className="form-checkbox h-4 w-4 text-blue-500"
/>
<span className="text-gray-700">All</span>
</label>
{uniqueAvailableSlots.map((slots) => (
<label key={slots} className="flex items-center space-x-2">
<input
type="checkbox"
checked={selectedAvailableSlots.includes(slots)}
onChange={() => handleAvailableSlotsChange(slots)}
className="form-checkbox h-4 w-4 text-blue-500"
/>
<span className="text-gray-700">
{slots} Slots Available
</span>
</label>
))}
</div>
)}
</div>
) : (
<p>No mentors found for this category.</p>
)}

{isFetchingNextPage && (
<div className="flex justify-center mt-4">
<Loading />
<div>
<button
onClick={handleSortAZ}
className="bg-blue-500 text-white px-2 py-1 rounded border border-blue-500 text-xs mr-6"
>
Sort A-Z
</button>
</div>
)}
</div>

<div ref={ref} style={{ height: '20px' }} />
<div className="w-full flex-grow bg-white rounded-lg p-6">
<div>
<p className="text-2xl font-semibold mb-4">Mentors</p>
<hr className="mb-6" />

{sortedMentors.length > 0 ? (
<div className="grid grid-cols-1 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
{sortedMentors.map((mentor) => (
<MentorCard key={mentor.uuid} mentor={mentor} />
))}
</div>
) : (
<p>No mentors found for this filter.</p>
)}

{isFetchingNextPage && (
<div className="flex justify-center mt-6">
<Loading />
</div>
)}

<div ref={ref} style={{ height: '20px' }} />
</div>
</div>
</div>
</div>
);
Expand Down

0 comments on commit 9a9eb71

Please sign in to comment.