@@ -10,6 +10,8 @@ import {
1010 MenuItem ,
1111 TextField ,
1212 Typography ,
13+ FormControlLabel ,
14+ Checkbox ,
1315} from '@mui/material'
1416import { useEffect , useMemo , useState } from 'react'
1517import { Event , Speaker } from '../../../types'
@@ -32,29 +34,43 @@ export const EventSpeakers = ({ event }: EventSpeakersProps) => {
3234 const [ speakersStatsOpen , setSpeakersStatsOpen ] = useState ( false )
3335 const [ displayedSpeakers , setDisplayedSpeakers ] = useState < Speaker [ ] > ( [ ] )
3436 const [ search , setSearch ] = useState < string > ( '' )
37+ const [ showOnlyWithoutSessions , setShowOnlyWithoutSessions ] = useState ( false )
3538 const [ exportAnchorEl , setExportAnchorEl ] = useState < null | HTMLElement > ( null )
3639 const isExportMenuOpen = Boolean ( exportAnchorEl )
3740 const { createNotification } = useNotification ( )
3841
3942 const speakersData = useMemo ( ( ) => speakers . data || [ ] , [ speakers . data ] )
43+ const sessionsData = useMemo ( ( ) => sessions . data || [ ] , [ sessions . data ] )
4044 const isFiltered = displayedSpeakers . length !== speakersData . length
4145
4246 useEffect ( ( ) => {
4347 const searchFiltered = search . toLowerCase ( ) . trim ( )
4448 setDisplayedSpeakers (
4549 speakersData . filter ( ( s ) => {
46- if ( s . name . toLowerCase ( ) . includes ( searchFiltered ) ) {
47- return true
48- }
49- if ( s . note && s . note . toLowerCase ( ) . includes ( searchFiltered ) ) {
50- return true
51- }
52- if ( s . company && s . company . toLowerCase ( ) . includes ( searchFiltered ) ) {
53- return true
50+ // Filter by search term
51+ const matchesSearch =
52+ ! searchFiltered ||
53+ s . name . toLowerCase ( ) . includes ( searchFiltered ) ||
54+ ( s . note && s . note . toLowerCase ( ) . includes ( searchFiltered ) ) ||
55+ ( s . company && s . company . toLowerCase ( ) . includes ( searchFiltered ) )
56+
57+ // Filter by session status
58+ if ( showOnlyWithoutSessions ) {
59+ const hasSessions = sessionsData . some (
60+ ( session ) => session . speakers && session . speakers . includes ( s . id )
61+ )
62+ return matchesSearch && ! hasSessions
5463 }
64+
65+ return matchesSearch
5566 } )
5667 )
57- } , [ speakersData , search ] )
68+ } , [ speakersData , search , showOnlyWithoutSessions , sessionsData ] )
69+
70+ const clearFilters = ( ) => {
71+ setSearch ( '' )
72+ setShowOnlyWithoutSessions ( false )
73+ }
5874
5975 const closeExportMenu = ( type : SpeakersExportType | null ) => ( ) => {
6076 setExportAnchorEl ( null )
@@ -113,16 +129,22 @@ export const EventSpeakers = ({ event }: EventSpeakersProps) => {
113129 InputProps = { {
114130 endAdornment : isFiltered ? (
115131 < InputAdornment position = "start" >
116- < IconButton
117- aria-label = "Clear filters"
118- onClick = { ( ) => setDisplayedSpeakers ( speakersData ) }
119- edge = "end" >
132+ < IconButton aria-label = "Clear filters" onClick = { clearFilters } edge = "end" >
120133 < Clear />
121134 </ IconButton >
122135 </ InputAdornment >
123136 ) : null ,
124137 } }
125138 />
139+ < FormControlLabel
140+ control = {
141+ < Checkbox
142+ checked = { showOnlyWithoutSessions }
143+ onChange = { ( e ) => setShowOnlyWithoutSessions ( e . target . checked ) }
144+ />
145+ }
146+ label = "Show only speakers without sessions"
147+ />
126148 </ Grid >
127149 </ Grid >
128150
0 commit comments