@@ -9,72 +9,31 @@ import { teacherIdsFromCourseInfo, uniqueTeachersFromCourseInfo, getAllPickedSlo
9
9
import { Button } from '../../../ui/button'
10
10
import ProfessorItem from './ProfessorItem'
11
11
import { DropdownMenu , DropdownMenuContent , DropdownMenuGroup , DropdownMenuItem , DropdownMenuPortal , DropdownMenuSeparator , DropdownMenuSub , DropdownMenuSubContent , DropdownMenuSubTrigger , DropdownMenuTrigger } from '../../../ui/dropdown-menu'
12
+ import ClassSelectorDropdownController from './ClassSelectorDropdownController'
12
13
13
14
type Props = {
14
15
course : CourseInfo
15
16
}
16
17
17
- const buildTeacherFilters = ( teachers , filteredTeachers ) => {
18
- if ( ! filteredTeachers ) return [ ] ;
19
-
20
- return teachers . map ( ( teacher ) => {
21
- return {
22
- ...teacher ,
23
- isFiltered : filteredTeachers . includes ( teacher . id )
24
- }
25
- } )
26
- }
27
-
28
18
//TODO: Check this code, not too good
29
19
const ClassSelector = ( { course } : Props ) => {
30
20
const classSelectorTriggerRef = useRef ( null )
31
21
const classSelectorContentRef = useRef ( null )
32
22
const [ isDropdownOpen , setIsDropdownOpen ] = useState ( false )
33
23
34
24
const { multipleOptions, setMultipleOptions, selectedOption } = useContext ( MultipleOptionsContext )
35
- const { pickedCourses, choosingNewCourse } = useContext ( CourseContext )
36
25
37
26
const [ selectedClassId , setSelectedClassId ] = useState < number | null > ( null ) ;
38
27
39
28
const courseOption : CourseOption = multipleOptions [ selectedOption ] . course_options . find ( ( opt ) => opt . course_id === course . id )
40
29
if ( courseOption )
41
30
courseOption . filteredTeachers = [ ...teacherIdsFromCourseInfo ( course ) ] ;
42
31
43
- /**
44
- * This is used to retrieve the teachers from a course and to populate the filter of the teachers
45
- * which is the dropdown menu that appears by clicking on "Professores" on the class selector dropdown
46
- */
47
- const teachers = useMemo ( ( ) => {
48
- if ( ! course . classes ) return [ ]
49
-
50
- return uniqueTeachersFromCourseInfo ( course ) ;
51
- } , [ course . classes ] )
52
-
53
- // This is used to store the ids of the teachers so it is easy to verify if a teacher is filtered or not
54
- const [ filteredTeachers , setFilteredTeachers ] = useState ( teacherIdsFromCourseInfo ( course ) ) ;
55
-
56
- useEffect ( ( ) => {
57
- setFilteredTeachers ( teacherIdsFromCourseInfo ( course ) ) ;
58
- } , [ pickedCourses ] )
59
-
60
- // This is used as an object with the teacher properties in order for us to being able
61
- // to show teacher information on the filter dropdown menu
62
- const [ teacherFilters , setTeacherFilters ] = useState ( ( ) => {
63
- return buildTeacherFilters ( teachers , filteredTeachers ) ;
64
- } ) ;
65
-
66
32
const [ locked , setLocked ] = useState ( courseOption ?. locked )
67
33
68
34
const [ preview , setPreview ] = useState < number | null > ( null )
69
35
const [ display , setDisplay ] = useState ( courseOption ?. picked_class_id )
70
36
71
- const deleteOption = ( ) => {
72
- const multipleOptionsEntry = multipleOptions [ selectedOption ] . course_options . find ( ( option ) => option . picked_class_id === selectedClassId ) ;
73
- multipleOptionsEntry . picked_class_id = null ;
74
- setSelectedClassId ( null ) ;
75
- setMultipleOptions ( [ ...multipleOptions ] ) ;
76
- }
77
-
78
37
useEffect ( ( ) => {
79
38
const course_options = multipleOptions [ selectedOption ] . course_options ;
80
39
const option = course_options . filter ( ( option ) => option . course_id === course . id && option . picked_class_id !== null )
@@ -88,21 +47,6 @@ const ClassSelector = ({ course }: Props) => {
88
47
setDisplay ( option [ 0 ] . picked_class_id ) ;
89
48
} , [ selectedOption , multipleOptions , course . id ] ) ;
90
49
91
- useEffect ( ( ) => {
92
- setTeacherFilters ( ( ) => {
93
- return buildTeacherFilters ( teachers , filteredTeachers ) ;
94
- } ) ;
95
- } , [ filteredTeachers ] )
96
-
97
- /**
98
- * This useEffect is used to make the dropdown content width match the trigger width
99
- */
100
- useEffect ( ( ) => {
101
- if ( classSelectorTriggerRef . current && classSelectorContentRef . current ) {
102
- classSelectorContentRef . current . style . width = `${ classSelectorTriggerRef . current . offsetWidth } px`
103
- }
104
- } , [ isDropdownOpen ] )
105
-
106
50
const toggleLocker = ( ) => {
107
51
const newMultipleOptions = [ ...multipleOptions ] ;
108
52
const courseOptions = newMultipleOptions [ selectedOption ] . course_options . map ( opt => {
@@ -120,44 +64,6 @@ const ClassSelector = ({ course }: Props) => {
120
64
setLocked ( courseOption ?. locked )
121
65
} , [ selectedOption ] ) ;
122
66
123
- //(thePeras): Classes options should be a new state
124
- /**
125
- * Return the classes options filtered by the selected teachers
126
- * Classes with at least one of its teachers selected will be returned
127
- */
128
- const getOptions = ( ) : Array < ClassInfo > => {
129
- return course . classes ?. filter ( ( c ) => {
130
- return c . slots . some ( ( slot ) => slot . professors . filter ( ( prof ) => filteredTeachers ?. includes ( prof . id ) ) . length > 0 )
131
- } )
132
- }
133
-
134
- useEffect ( ( ) => {
135
- setFilteredTeachers ( courseOption ?. filteredTeachers ) ;
136
- } , [ choosingNewCourse ] )
137
-
138
- // Checks if any of the selected classes have time conflicts with the classInfo
139
- // This is used to display a warning icon in each class of the dropdown in case of conflicts
140
- const timesCollideWithSelected = ( classInfo : ClassInfo ) => {
141
- const pickedSlots = getAllPickedSlots ( pickedCourses , multipleOptions [ selectedOption ] )
142
- return pickedSlots . some ( ( slot ) => classInfo . slots . some ( ( currentSlot ) => schedulesConflict ( slot , currentSlot ) ) )
143
- }
144
-
145
- // Puts inside the preview the actual selected class so we can then restore it later after the user stops
146
- // previewing
147
- const showPreview = ( classInfo : ClassInfo ) => {
148
- const newMultipleOptions = [ ...multipleOptions ] ;
149
- const newCourseOptions : CourseOption [ ] = newMultipleOptions [ selectedOption ] . course_options . map ( ( c : CourseOption ) => {
150
- if ( c . course_id === course . id ) {
151
- setPreview ( classInfo . id )
152
- c . picked_class_id = classInfo . id
153
- }
154
-
155
- return c ;
156
- } ) ;
157
-
158
- newMultipleOptions [ selectedOption ] . course_options = newCourseOptions ;
159
- setMultipleOptions ( newMultipleOptions )
160
- }
161
67
162
68
// Restores into multiple options the picked_class_id prior to when the user started previewing
163
69
const removePreview = ( ) => {
@@ -177,24 +83,8 @@ const ClassSelector = ({ course }: Props) => {
177
83
setPreview ( null ) ;
178
84
}
179
85
180
- function toggleTeacher ( id : number ) {
181
- if ( filteredTeachers . includes ( id ) ) {
182
- setFilteredTeachers ( filteredTeachers . filter ( ( t ) => t !== id ) )
183
- } else {
184
- setFilteredTeachers ( [ ...filteredTeachers , id ] )
185
- }
186
- }
187
-
188
- function toggleAllTeachers ( teachers : ProfessorInfo [ ] ) {
189
- if ( filteredTeachers . length > 0 ) {
190
- setFilteredTeachers ( [ ] )
191
- } else {
192
- setFilteredTeachers ( teachers . flatMap ( ( t ) => t . id ) )
193
- }
194
- }
195
-
196
86
return (
197
- < div className = "relative text-sm" key = { `course-option-${ course . acronym } ` } >
87
+ < div className = "text-sm" key = { `course-option-${ course . acronym } ` } >
198
88
{ /* Header */ }
199
89
< p className = "mb-0.5 flex text-xs" >
200
90
< strong > { course . acronym } </ strong >
@@ -209,87 +99,32 @@ const ClassSelector = ({ course }: Props) => {
209
99
removePreview ( ) ;
210
100
}
211
101
} } >
212
- < DropdownMenuTrigger asChild disabled = { courseOption ?. locked } ref = { classSelectorTriggerRef } >
213
- < Button
214
- variant = "outline"
215
- size = "sm"
216
- className = "w-full justify-between truncate bg-lightish text-xs font-normal tracking-tighter hover:bg-primary/75 hover:text-white dark:bg-darkish"
102
+ < div className = "w-full" >
103
+ < DropdownMenuTrigger asChild disabled = { courseOption ?. locked } ref = { classSelectorTriggerRef } >
104
+ < Button
105
+ variant = "outline"
106
+ size = "sm"
107
+ className = "w-full justify-between truncate bg-lightish text-xs font-normal tracking-tighter hover:bg-primary/75 hover:text-white dark:bg-darkish"
108
+ >
109
+ < span className = { `${ selectedClassId === null ? "opacity-50" : "" } ` } > { getClassDisplayText ( course , selectedClassId ) } </ span >
110
+ { ! courseOption ?. locked && < ChevronUpDownIcon className = "text-blackish h-6 w-6 dark:text-lightish" /> }
111
+ </ Button >
112
+ </ DropdownMenuTrigger >
113
+ < DropdownMenuContent
114
+ className = "bg-lightish text-darkish dark:bg-darkish dark:text-lightish"
115
+ ref = { classSelectorContentRef }
217
116
>
218
- < span className = { `${ selectedClassId === null ? "opacity-50" : "" } ` } > { getClassDisplayText ( course , selectedClassId ) } </ span >
219
- { ! courseOption ?. locked && < ChevronUpDownIcon className = "text-blackish h-6 w-6 dark:text-lightish" /> }
220
- </ Button >
221
- </ DropdownMenuTrigger >
222
- < DropdownMenuContent
223
- className = "bg-lightish text-darkish dark:bg-darkish dark:text-lightish"
224
- ref = { classSelectorContentRef }
225
- >
226
- { course . classes === null ? (
227
- < p className = "w-100 select-none p-2 text-center" > A carregar as aulas...</ p >
228
- ) : (
229
- < >
230
- < DropdownMenuGroup >
231
- < DropdownMenuSub >
232
- < DropdownMenuSubTrigger >
233
- < User className = "mr-2 h-4 w-4" />
234
- < span > Professores</ span >
235
- </ DropdownMenuSubTrigger >
236
- < DropdownMenuPortal >
237
- < DropdownMenuSubContent className = "w-80 bg-lightish text-darkish dark:bg-darkish dark:text-lightish" >
238
- < DropdownMenuItem
239
- onClick = { ( e ) => {
240
- e . preventDefault ( )
241
- toggleAllTeachers ( teachers )
242
- } }
243
- >
244
- < span className = "block truncate dark:text-white" >
245
- { filteredTeachers ?. length > 0 ? 'Apagar todos' : 'Selecionar Todos' }
246
- </ span >
247
- </ DropdownMenuItem >
248
- < DropdownMenuSeparator />
249
- { teacherFilters . map ( ( option ) => {
250
- return (
251
- < ProfessorItem
252
- key = { `${ course . acronym } -teacher-${ option . acronym } ` }
253
- professorInformation = { option }
254
- filtered = { option . isFiltered }
255
- onSelect = { ( e ) => {
256
- e . preventDefault ( )
257
- toggleTeacher ( option . id )
258
- } }
259
- />
260
- )
261
- } ) }
262
- </ DropdownMenuSubContent >
263
- </ DropdownMenuPortal >
264
- </ DropdownMenuSub >
265
- </ DropdownMenuGroup >
266
- < DropdownMenuSeparator />
267
- < DropdownMenuGroup className = "max-h-96 overflow-y-auto" >
268
- < DropdownMenuItem onSelect = { ( ) => deleteOption ( ) } >
269
- < span className = "text-sm tracking-tighter" > Remover Seleção</ span >
270
- </ DropdownMenuItem >
271
- { course . classes &&
272
- getOptions ( ) . map ( ( classInfo ) => (
273
- < ClassItem
274
- key = { `schedule-${ classInfo . name } ` }
275
- course_id = { course . id }
276
- classInfo = { classInfo }
277
- displayed = { display === classInfo . id }
278
- checked = { selectedOption === classInfo . id }
279
- preview = { preview }
280
- conflict = { timesCollideWithSelected ( classInfo ) }
281
- onSelect = { ( ) => {
282
- setSelectedClassId ( classInfo . id )
283
- setPreview ( null )
284
- } }
285
- onMouseEnter = { ( ) => showPreview ( classInfo ) }
286
- onMouseLeave = { ( ) => removePreview ( ) }
287
- />
288
- ) ) }
289
- </ DropdownMenuGroup >
290
- </ >
291
- ) }
292
- </ DropdownMenuContent >
117
+ < ClassSelectorDropdownController
118
+ course = { course }
119
+ selectedClassIdHook = { [ selectedClassId , setSelectedClassId ] }
120
+ previewHook = { [ preview , setPreview ] }
121
+ display = { display }
122
+ removePreview = { removePreview }
123
+ contentRef = { classSelectorContentRef }
124
+ triggerRef = { classSelectorTriggerRef }
125
+ />
126
+ </ DropdownMenuContent >
127
+ </ div >
293
128
</ DropdownMenu >
294
129
295
130
{ /* Lock Button */ }
0 commit comments