From da0e0f2be86fe869dbb8d674a34905a968cc5c5e Mon Sep 17 00:00:00 2001 From: Chris Parsons <438676+chrisparsons83@users.noreply.github.com> Date: Mon, 2 Mar 2026 00:29:54 -0800 Subject: [PATCH] feat: convert sport filter to multi-select with mobile bottom sheet (#51) Replaces the single-sport native onSportFilterChange(e.target.value)} - className="flex-1 min-w-[120px] px-3 py-2 border rounded-md text-base md:text-sm bg-background text-foreground" - > - - {uniqueSports.map((sport) => ( - - ))} - + {/* Sport Filter Multi-Select */} +
+ {/* Mobile: bottom sheet */} +
+ + + + + + Filter by sport +
+ {uniqueSports.map((sport) => { + const checkboxId = `sheet-sport-filter-${sport.replace(/\s+/g, "-").toLowerCase()}`; + return ( + + ); + })} +
+ + {sportFilters.length > 0 && ( + + )} + + + + +
+
+
+ + {/* Desktop: popover */} +
+ + + + + + {sportFilters.length > 0 && ( +
+ +
+ )} +
+ {uniqueSports.map((sport) => { + const checkboxId = `popover-sport-filter-${sport.replace(/\s+/g, "-").toLowerCase()}`; + return ( + + ); + })} +
+
+
+
+
{/* Show/Hide Drafted Toggle */} )} + diff --git a/app/routes/leagues/$leagueId.draft.$seasonId.tsx b/app/routes/leagues/$leagueId.draft.$seasonId.tsx index 90767c5..158e07c 100644 --- a/app/routes/leagues/$leagueId.draft.$seasonId.tsx +++ b/app/routes/leagues/$leagueId.draft.$seasonId.tsx @@ -434,7 +434,7 @@ export default function DraftRoom() { const [hideDrafted, setHideDrafted] = useState(true); const [hideIneligible, setHideIneligible] = useState(true); const [hideCompletedSports, setHideCompletedSports] = useState(false); - const [sportFilter, setSportFilter] = useState("all"); + const [sportFilters, setSportFilters] = useState([]); const [queue, setQueue] = useState(userQueue); const [isPaused, setIsPaused] = useState(season.draftPaused || false); const [isDraftComplete, setIsDraftComplete] = useState( @@ -1275,45 +1275,44 @@ export default function DraftRoom() { ); // Filter participants based on search, sport, drafted status, and eligibility - const filteredParticipants = useMemo( - () => - availableParticipants.filter((participant: any) => { - // Drafted filter - hide drafted participants by default - if (hideDrafted && draftedParticipantIds.has(participant.id)) { + const filteredParticipants = useMemo(() => { + const sportFilterSet = new Set(sportFilters); + return availableParticipants.filter((participant: any) => { + // Drafted filter - hide drafted participants by default + if (hideDrafted && draftedParticipantIds.has(participant.id)) { + return false; + } + // Eligibility filter - hide ineligible participants by default (if user has a team) + if (hideIneligible && eligibility) { + const isEligible = eligibility.eligibleSportIds.has(participant.sport.id); + if (!isEligible) { return false; } - // Eligibility filter - hide ineligible participants by default (if user has a team) - if (hideIneligible && eligibility) { - const isEligible = eligibility.eligibleSportIds.has(participant.sport.id); - if (!isEligible) { - return false; - } - } - // Hide completed sports filter - hide participants from sports already drafted by user's team - if (hideCompletedSports && userDraftedSportIds.has(participant.sport.id)) { - return false; - } - // Search filter - if ( - searchQuery && - !participant.name.toLowerCase().includes(searchQuery.toLowerCase()) - ) { - return false; - } - // Sport filter - if (sportFilter !== "all" && participant.sport.name !== sportFilter) { - return false; - } - return true; - }), - [availableParticipants, hideDrafted, hideIneligible, hideCompletedSports, eligibility, draftedParticipantIds, userDraftedSportIds, searchQuery, sportFilter] - ); + } + // Hide completed sports filter - hide participants from sports already drafted by user's team + if (hideCompletedSports && userDraftedSportIds.has(participant.sport.id)) { + return false; + } + // Search filter + if ( + searchQuery && + !participant.name.toLowerCase().includes(searchQuery.toLowerCase()) + ) { + return false; + } + // Sport filter + if (sportFilterSet.size > 0 && !sportFilterSet.has(participant.sport.name)) { + return false; + } + return true; + }); + }, [availableParticipants, hideDrafted, hideIneligible, hideCompletedSports, eligibility, draftedParticipantIds, userDraftedSportIds, searchQuery, sportFilters]); // Shared component props — defined once to avoid duplication between desktop and mobile layouts const availableParticipantsSectionProps = { participants: filteredParticipants, searchQuery, - sportFilter, + sportFilters, hideDrafted, hideIneligible, uniqueSports, @@ -1323,7 +1322,7 @@ export default function DraftRoom() { canPick, hasTeam: !!userTeam, onSearchChange: setSearchQuery, - onSportFilterChange: setSportFilter, + onSportFiltersChange: setSportFilters, onHideDraftedChange: setHideDrafted, onHideIneligibleChange: setHideIneligible, hideCompletedSports,