@@ -14,12 +14,15 @@ import { DatePicker } from "@mui/x-date-pickers/DatePicker";
1414import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider" ;
1515import { TimePicker } from "@mui/x-date-pickers/TimePicker" ;
1616import { format } from "date-fns" ;
17- import { useEffect , useState } from "react" ;
17+ import { useCallback , useEffect , useState } from "react" ;
1818
1919import { RoomsHeatmap } from "@/components/studyrooms/heatmap/rooms-heatmap" ;
2020import { fetchStudyRooms } from "@/lib/rooms/get-rooms" ;
21+ import { getDefaultWindow , toLocalStr } from "@/lib/rooms/utils" ;
2122import type { StudyRooms } from "@/lib/types/studyrooms" ;
2223
24+ const MAX_FALLBACK_DAYS = 7 ;
25+
2326const LOCATION_OPTIONS = [
2427 "Plaza Verde" ,
2528 "Langson Library" ,
@@ -29,29 +32,28 @@ const LOCATION_OPTIONS = [
2932 "Ayala Science Library" ,
3033] ;
3134
32- const toLocalStr = ( d : Date ) => {
33- const h = d . getHours ( ) ;
34- const m = d . getMinutes ( ) ;
35- return `${ h % 12 || 12 } :${ m . toString ( ) . padStart ( 2 , "0" ) } ${ h >= 12 ? "pm" : "am" } ` ;
36- } ;
37-
3835export default function Page ( ) {
39- const defaultStart = new Date ( ) ;
40- defaultStart . setHours ( 11 , 0 , 0 , 0 ) ;
41- const defaultEnd = new Date ( ) ;
42- defaultEnd . setHours ( 17 , 0 , 0 , 0 ) ;
43-
44- const tomorrow = new Date ( ) ;
45- tomorrow . setDate ( tomorrow . getDate ( ) + 1 ) ;
46-
47- const [ date , setDate ] = useState < Date | null > ( tomorrow ) ;
36+ const [ { defaultDate, defaultStart, defaultEnd } ] = useState ( ( ) => {
37+ const { start, end } = getDefaultWindow ( ) ;
38+ return {
39+ defaultStart : start ,
40+ defaultEnd : end ,
41+ defaultDate : new Date (
42+ start . getFullYear ( ) ,
43+ start . getMonth ( ) ,
44+ start . getDate ( ) ,
45+ ) ,
46+ } ;
47+ } ) ;
48+ const [ date , setDate ] = useState < Date | null > ( defaultDate ) ;
4849 const [ startTime , setStartTime ] = useState < Date | null > ( defaultStart ) ;
4950 const [ endTime , setEndTime ] = useState < Date | null > ( defaultEnd ) ;
5051 const [ committedStart , setCommittedStart ] = useState < Date | null > (
5152 defaultStart ,
5253 ) ;
5354 const [ committedEnd , setCommittedEnd ] = useState < Date | null > ( defaultEnd ) ;
54- const [ committedDate , setCommittedDate ] = useState < Date | null > ( tomorrow ) ;
55+ const [ committedDate , setCommittedDate ] = useState < Date | null > ( defaultDate ) ;
56+ const [ fallbackNotice , setFallbackNotice ] = useState < string | null > ( null ) ;
5557 const [ location , setLocation ] = useState < string | null > ( null ) ;
5658 const [ capacityMin , setCapacityMin ] = useState ( "" ) ;
5759 const [ capacityMax , setCapacityMax ] = useState ( "" ) ;
@@ -88,10 +90,95 @@ export default function Page() {
8890 if ( key === "techEnhanced" ) setIsTechEnhanced ( false ) ;
8991 } ;
9092
91- async function handleSubmit ( e : React . FormEvent ) {
93+ const searchWithFallback = useCallback (
94+ async ( {
95+ baseDate,
96+ startTime : slotStart ,
97+ endTime : slotEnd ,
98+ fallbackStart = slotStart ,
99+ fallbackEnd = slotEnd ,
100+ filters = { } ,
101+ updateFormState = false ,
102+ } : {
103+ baseDate : Date ;
104+ startTime : Date ;
105+ endTime : Date ;
106+ fallbackStart ?: Date ;
107+ fallbackEnd ?: Date ;
108+ filters ?: {
109+ location ?: string | null ;
110+ capacityMin ?: string ;
111+ capacityMax ?: string ;
112+ isTechEnhanced ?: boolean ;
113+ } ;
114+ updateFormState ?: boolean ;
115+ } ) => {
116+ for ( let offset = 0 ; offset < MAX_FALLBACK_DAYS ; offset ++ ) {
117+ const tryDate = new Date ( baseDate ) ;
118+ tryDate . setDate ( tryDate . getDate ( ) + offset ) ;
119+ const isFallback = offset > 0 ;
120+ const start = isFallback ? fallbackStart : slotStart ;
121+ const end = isFallback ? fallbackEnd : slotEnd ;
122+
123+ try {
124+ const { data } = await fetchStudyRooms ( {
125+ date : format ( tryDate , "yyyy-MM-dd" ) ,
126+ timeRange : `${ toLocalStr ( start ) } -${ toLocalStr ( end ) } ` ,
127+ location : filters . location || undefined ,
128+ capacityMin : filters . capacityMin
129+ ? Number ( filters . capacityMin )
130+ : undefined ,
131+ capacityMax : filters . capacityMax
132+ ? Number ( filters . capacityMax )
133+ : undefined ,
134+ isTechEnhanced : filters . isTechEnhanced || undefined ,
135+ } ) ;
136+
137+ if ( data . length > 0 ) {
138+ const committedStartForDay = new Date ( tryDate ) ;
139+ committedStartForDay . setHours (
140+ start . getHours ( ) ,
141+ start . getMinutes ( ) ,
142+ 0 ,
143+ 0 ,
144+ ) ;
145+ const committedEndForDay = new Date ( tryDate ) ;
146+ committedEndForDay . setHours ( end . getHours ( ) , end . getMinutes ( ) , 0 , 0 ) ;
147+ setRooms ( data ) ;
148+ setCommittedDate ( tryDate ) ;
149+ setCommittedStart ( committedStartForDay ) ;
150+ setCommittedEnd ( committedEndForDay ) ;
151+ if ( updateFormState ) {
152+ setDate ( tryDate ) ;
153+ setStartTime ( committedStartForDay ) ;
154+ setEndTime ( committedEndForDay ) ;
155+ }
156+ if ( isFallback ) {
157+ setFallbackNotice (
158+ `No rooms available for ${ format ( baseDate , "EEEE, MMM d" ) } . Showing results for ${ format ( tryDate , "EEEE, MMM d" ) } instead.` ,
159+ ) ;
160+ }
161+ return ;
162+ }
163+ } catch ( err ) {
164+ setError ( err instanceof Error ? err . message : "API call failed" ) ;
165+ return ;
166+ }
167+ }
168+ setRooms ( [ ] ) ;
169+ setCommittedDate ( null ) ;
170+ setCommittedStart ( null ) ;
171+ setCommittedEnd ( null ) ;
172+ setError ( `No rooms available in the next ${ MAX_FALLBACK_DAYS } days.` ) ;
173+ } ,
174+ [ ] ,
175+ ) ;
176+
177+ const handleSubmit = async ( e : React . FormEvent ) => {
92178 e . preventDefault ( ) ;
93179 setError ( null ) ;
94180 setRooms ( null ) ;
181+ setFallbackNotice ( null ) ;
95182
96183 if ( ! date || ! startTime || ! endTime ) {
97184 setError ( "Please select a date and time range." ) ;
@@ -119,47 +206,30 @@ export default function Page() {
119206 return ;
120207 }
121208
122- const tr = `${ toLocalStr ( startTime ) } -${ toLocalStr ( endTime ) } ` ;
123-
124- try {
125- const { data } = await fetchStudyRooms ( {
126- date : format ( date , "yyyy-MM-dd" ) ,
127- timeRange : tr ,
128- location : location || undefined ,
129- capacityMin : capacityMin ? Number ( capacityMin ) : undefined ,
130- capacityMax : capacityMax ? Number ( capacityMax ) : undefined ,
131- isTechEnhanced : isTechEnhanced || undefined ,
132- } ) ;
133-
134- setRooms ( data ) ;
135- setCommittedDate ( date ) ;
136- setCommittedStart ( startTime ) ;
137- setCommittedEnd ( endTime ) ;
138- } catch ( err ) {
139- setError ( err instanceof Error ? err . message : "API call failed" ) ;
140- }
141- }
209+ const baseDate = new Date ( date ) ;
210+ baseDate . setHours ( 0 , 0 , 0 , 0 ) ;
211+ await searchWithFallback ( {
212+ baseDate,
213+ startTime,
214+ endTime,
215+ filters : { location, capacityMin, capacityMax, isTechEnhanced } ,
216+ } ) ;
217+ } ;
142218
143219 useEffect ( ( ) => {
144- const tmrw = new Date ( ) ;
145- tmrw . setDate ( tmrw . getDate ( ) + 1 ) ;
146- const today = format ( tmrw , "yyyy-MM-dd" ) ;
147- const defaultTr = "11:00am-5:00pm" ;
148- const initialCommittedStart = new Date ( ) ;
149- initialCommittedStart . setHours ( 11 , 0 , 0 , 0 ) ;
150- const initialCommittedEnd = new Date ( ) ;
151- initialCommittedEnd . setHours ( 17 , 0 , 0 , 0 ) ;
152- fetchStudyRooms ( { date : today , timeRange : defaultTr } )
153- . then ( ( { data } ) => {
154- setRooms ( data ) ;
155- setCommittedDate ( tmrw ) ;
156- setCommittedStart ( initialCommittedStart ) ;
157- setCommittedEnd ( initialCommittedEnd ) ;
158- } )
159- . catch ( ( err ) =>
160- setError ( err instanceof Error ? err . message : "API call failed" ) ,
161- ) ;
162- } , [ ] ) ;
220+ const fallbackStart = new Date ( defaultDate ) ;
221+ fallbackStart . setHours ( 11 , 0 , 0 , 0 ) ;
222+ const fallbackEnd = new Date ( defaultDate ) ;
223+ fallbackEnd . setHours ( 17 , 0 , 0 , 0 ) ;
224+ searchWithFallback ( {
225+ baseDate : defaultDate ,
226+ startTime : defaultStart ,
227+ endTime : defaultEnd ,
228+ fallbackStart,
229+ fallbackEnd,
230+ updateFormState : true ,
231+ } ) ;
232+ } , [ searchWithFallback , defaultDate , defaultStart , defaultEnd ] ) ;
163233
164234 return (
165235 < LocalizationProvider dateAdapter = { AdapterDateFns } >
@@ -263,6 +333,12 @@ export default function Page() {
263333 </ Button >
264334 </ Box >
265335
336+ { fallbackNotice && (
337+ < Typography variant = "body2" color = "info.main" sx = { { mt : 2 } } >
338+ { fallbackNotice }
339+ </ Typography >
340+ ) }
341+
266342 { rooms && committedDate && committedStart && committedEnd && (
267343 < RoomsHeatmap
268344 rooms = { rooms }
@@ -271,14 +347,6 @@ export default function Page() {
271347 endTime = { committedEnd }
272348 />
273349 ) }
274-
275- { /*rooms && committedStart && committedEnd && (
276- <RoomResults
277- rooms={rooms}
278- startTime={committedStart}
279- endTime={committedEnd}
280- />
281- )*/ }
282350 </ LocalizationProvider >
283351 ) ;
284352}
0 commit comments