1- import { useGetTimetableQuery } from "@/api/timetableApiSlice" ;
1+ import { useGetTimetableQuery , useGetTimetablesQuery } from "@/api/timetableApiSlice" ;
22import { Button } from "@/components/ui/button" ;
33import { Timetable , TimetableEvents } from "@/utils/type-utils" ;
44import { useEffect , useState } from "react" ;
55import { Link , useSearchParams } from "react-router-dom" ;
66import Calendar from "../TimetableBuilder/Calendar" ;
77import { useGetEventsQuery } from "@/api/eventsApiSlice" ;
88import { Spinner } from "@/components/ui/spinner" ;
9+ import { zodResolver } from "@hookform/resolvers/zod" ;
10+ import { useForm } from "react-hook-form" ;
11+ import { z } from "zod" ;
12+ import { CompareFormSchema } from "../Home/TimetableCompareButton" ;
13+ import { format } from "path" ;
14+ import { Form , FormControl , FormField , FormItem , FormLabel , FormMessage } from "@/components/ui/form" ;
15+ import { Select , SelectContent , SelectItem , SelectTrigger , SelectValue } from "@/components/ui/select" ;
16+ import { SemesterIcon } from "@/components/semester-icon" ;
17+ import { GitCompareArrows } from "lucide-react" ;
918
1019export const CompareTimetables = ( ) => {
11- const [ queryParams ] = useSearchParams ( ) ;
12- const validParams = queryParams . has ( "id1" ) && queryParams . has ( "id2" ) ;
1320
14- if ( ! validParams ) {
15- return (
16- < div className = "w-full text-red-500 text-center mt-10" >
17- You have not selected two timetables to compare. Please try again.
18- </ div >
19- ) ;
20- }
21- const timetableId1 = parseInt ( queryParams . get ( "id1" ) || "0" ) ;
22- const timetableId2 = parseInt ( queryParams . get ( "id2" ) || "0" ) ;
21+ const [ timetable1 , setTimetable1 ] = useState < Timetable > ( ) ;
22+ const [ timetable2 , setTimetable2 ] = useState < Timetable > ( ) ;
23+ const [ offeringIds1 , setOfferingIds1 ] = useState < number [ ] > ( ) ;
24+ const [ offeringIds2 , setOfferingIds2 ] = useState < number [ ] > ( ) ;
25+ const [ queryParams ] = useSearchParams ( ) ;
2326
24- const { data : data1 } = useGetTimetableQuery ( timetableId1 ) as {
25- data : Timetable [ ] ;
26- } ;
27- const { data : data2 } = useGetTimetableQuery ( timetableId2 ) as {
28- data : Timetable [ ] ;
27+ const compareForm = useForm < z . infer < typeof CompareFormSchema > > ( {
28+ resolver : zodResolver ( CompareFormSchema ) ,
29+ } ) ;
30+
31+ const onSubmit = ( values : z . infer < typeof CompareFormSchema > ) => {
32+ console . log ( "Compare Form submitted:" , values ) ;
33+ const timetableId1 = compareForm . getValues ( "timetable1" ) ;
34+ const timetableId2 = compareForm . getValues ( "timetable2" ) ;
35+ setTimetable1 ( timetables . find ( t => t . id === timetableId1 ) )
36+ refetchEvents1 ( )
37+ setTimetable2 ( timetables . find ( t => t . id === timetableId2 ) )
38+ refetchEvents2 ( )
2939 } ;
3040
31- const { data : timetableEventsData1 } = useGetEventsQuery ( timetableId1 ) as {
41+ const { data : timetables , isLoading, refetch } = useGetTimetablesQuery ( ) as {
42+ data : Timetable [ ] ;
43+ isLoading : boolean ;
44+ refetch : ( ) => void ;
45+ } ;
46+
47+ const { data : timetableEventsData1 , refetch : refetchEvents1 } = useGetEventsQuery (
48+ compareForm . getValues ( "timetable1" ) ?? undefined ,
49+ {
50+ skip : compareForm . getValues ( "timetable1" ) === undefined
51+ }
52+ ) as {
3253 data : TimetableEvents ;
54+ refetch : ( ) => void ;
3355 } ;
34- const { data : timetableEventsData2 } = useGetEventsQuery ( timetableId2 ) as {
56+ const { data : timetableEventsData2 , refetch : refetchEvents2 } = useGetEventsQuery (
57+ compareForm . getValues ( "timetable2" ) ,
58+ {
59+ skip : compareForm . getValues ( "timetable2" ) === undefined
60+ }
61+ ) as {
3562 data : TimetableEvents ;
63+ refetch : ( ) => void ;
3664 } ;
3765
38- const [ timetable1 , setTimetable1 ] = useState < Timetable | null > ( null ) ;
39- const [ timetable2 , setTimetable2 ] = useState < Timetable | null > ( null ) ;
40- const [ offeringIds1 , setOfferingIds1 ] = useState < number [ ] > ( [ ] ) ;
41- const [ offeringIds2 , setOfferingIds2 ] = useState < number [ ] > ( [ ] ) ;
42-
4366 useEffect ( ( ) => {
44- if ( data1 ) {
45- setTimetable1 ( data1 [ 0 ] ) ;
67+ if ( queryParams . has ( "id1" ) && timetables ) {
68+ const id = parseInt ( queryParams . get ( "id1" ) || "0" ) ;
69+ compareForm . setValue ( "timetable1" , id ) ;
70+ setTimetable1 ( timetables . find ( t => t . id === id ) ) ;
4671 }
47- } , [ data1 ] ) ;
72+ } , [ timetables ] ) ;
73+
4874 useEffect ( ( ) => {
49- if ( data2 ) {
50- setTimetable2 ( data2 [ 0 ] ) ;
75+ if ( queryParams . has ( "id2" ) && timetables ) {
76+ const id = parseInt ( queryParams . get ( "id2" ) || "0" ) ;
77+ compareForm . setValue ( "timetable2" , id ) ;
78+ setTimetable2 ( timetables . find ( t => t . id === id ) ) ;
5179 }
52- } , [ data2 ] ) ;
80+ } , [ timetables ] ) ;
5381
5482 // get unique offeringIds for calendar
5583 useEffect ( ( ) => {
@@ -77,14 +105,93 @@ export const CompareTimetables = () => {
77105 return (
78106 < >
79107 < div className = "w-full" >
80- < div className = "mb-4 p-8" >
81- < div className = "mb-2 flex flex-row justify-between" >
108+ < div className = "mb-2 p-8 pt-4 " >
109+ < div className = "mb-2 flex flex-row items-center justify-between" >
82110 < div >
83- < h1 className = "text-2xl font-medium tracking-tight mb-4 " >
111+ < h1 className = "text-2xl font-medium tracking-tight" >
84112 Comparing Timetables
85113 </ h1 >
86114 </ div >
87- < div className = "flex gap-2 " >
115+ < Form { ...compareForm } >
116+ < form
117+ onSubmit = { compareForm . handleSubmit ( onSubmit ) }
118+ className = "flex flex-row gap-4 items-center"
119+ >
120+ < FormField
121+ control = { compareForm . control }
122+ name = "timetable1"
123+ render = { ( { field } ) => (
124+ < FormItem >
125+ < Select
126+ onValueChange = { ( value ) => field . onChange ( Number ( value ) ) }
127+ >
128+ < FormControl >
129+ < SelectTrigger >
130+ < SelectValue placeholder = "Select a timetable" />
131+ </ SelectTrigger >
132+ </ FormControl >
133+ < SelectContent >
134+ { timetables && timetables . map ( ( timetable ) => (
135+ < SelectItem
136+ key = { timetable . id }
137+ value = { timetable . id . toString ( ) }
138+ >
139+ < div className = "flex items-center gap-2" >
140+ < SemesterIcon
141+ semester = { timetable . semester }
142+ size = { 18 }
143+ />
144+ < span > { timetable . timetable_title } </ span >
145+ </ div >
146+ </ SelectItem >
147+ ) ) }
148+ </ SelectContent >
149+ </ Select >
150+ < FormMessage />
151+ </ FormItem >
152+ ) }
153+ />
154+ < Button size = "sm" className = "px-5" >
155+ Compare
156+ < GitCompareArrows />
157+ </ Button >
158+ < FormField
159+ control = { compareForm . control }
160+ name = "timetable2"
161+ render = { ( { field } ) => (
162+ < FormItem >
163+ < Select
164+ onValueChange = { ( value ) => field . onChange ( Number ( value ) ) }
165+ >
166+ < FormControl >
167+ < SelectTrigger >
168+ < SelectValue placeholder = "Select a timetable" />
169+ </ SelectTrigger >
170+ </ FormControl >
171+ < SelectContent >
172+ { timetables && timetables . map ( ( timetable ) => (
173+ < SelectItem
174+ key = { timetable . id }
175+ value = { timetable . id . toString ( ) }
176+ >
177+ < div className = "flex items-center gap-2" >
178+ < SemesterIcon
179+ semester = { timetable . semester }
180+ size = { 18 }
181+ />
182+ < span > { timetable . timetable_title } </ span >
183+ </ div >
184+ </ SelectItem >
185+ ) ) }
186+ </ SelectContent >
187+ </ Select >
188+ < FormMessage />
189+ </ FormItem >
190+ ) }
191+ />
192+ </ form >
193+ </ Form >
194+ < div className = "flex gap-2 ml-[7rem]" >
88195 < Link to = "/dashboard/home" >
89196 < Button size = "sm" variant = "outline" onClick = { ( ) => { } } >
90197 Back to Home
@@ -95,8 +202,10 @@ export const CompareTimetables = () => {
95202 < hr className = "mb-4" />
96203 < div className = "flex gap-4" >
97204 < div className = "w-1/2" >
98- { offeringIds1 . length === 0 ? (
99- < Spinner />
205+ { ! offeringIds1 ? (
206+ < >
207+ { queryParams . has ( "id1" ) ? < Spinner /> : < div className = "w-full text-center py-[8rem] text-sm bg-gray-100/50 rounded" > Select a timetable to compare</ div > }
208+ </ >
100209 ) : (
101210 < Calendar
102211 setShowLoadingPage = { ( ) => { } }
@@ -110,8 +219,10 @@ export const CompareTimetables = () => {
110219 ) }
111220 </ div >
112221 < div className = "w-1/2" >
113- { offeringIds2 . length === 0 ? (
114- < Spinner />
222+ { ! offeringIds2 ? (
223+ < >
224+ { queryParams . has ( "id2" ) ? < Spinner /> : < div className = "w-full text-center py-[8rem] text-sm bg-gray-100/50 rounded" > Select a timetable to compare</ div > }
225+ </ >
115226 ) : (
116227 < Calendar
117228 setShowLoadingPage = { ( ) => { } }
0 commit comments