Skip to content

Commit 463bb17

Browse files
authored
Reschedule feature (#20)
* send reschedule requests on events rescheduling in progress update shared pointer attempting to use hashmap approach * implement new reschuling check on dashboard * change confidence value to int * fetch live rescheduling requests linting update shared accept button in progress * update dashboard layout * split reschedule requests into 2 columns create event dialog * working accepted/declined requests remove console.logs * pending accept -> opens disabled create event update shared pointer * rebase alterations * fix GetAPIRescheduleRequestsMe request * fix create event button * updated generated file linting changes fix reschedule names prettier changes
1 parent 645f968 commit 463bb17

12 files changed

Lines changed: 644 additions & 235 deletions

File tree

public/swagger/swagger.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2427,6 +2427,7 @@
24272427
},
24282428
"attendees": {
24292429
"type": "array",
2430+
"nullable": true,
24302431
"items": {
24312432
"type": "integer",
24322433
"format": "uint32",

shared

src/app/dashboard/page.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -122,10 +122,10 @@ export default function Dashboard() {
122122
}
123123

124124
return (
125-
<div className='flex flex-col justify-start items-center mt-10 h-[90vh] w-screen overflow-x-hidden'>
125+
<div className='flex flex-col justify-start items-center pt-10 h-[90vh] w-screen'>
126126
<User />
127-
<div className='flex flex-row justify-start ml-[10vw] w-screen gap-6 mt-10'>
128-
<div className='w-[60vw]'>
127+
<div className='flex flex-row justify-center w-screen gap-10 mt-5'>
128+
<div className='w-[45vw]'>
129129
<div className='mb-8'>
130130
<EventsForToday events={calendar} />
131131
</div>
@@ -222,7 +222,7 @@ export default function Dashboard() {
222222
)}
223223
</div>
224224
</div>
225-
<div className='w-[30vw]'>
225+
<div className='w-[45vw]'>
226226
<RescheduleRequests />
227227
</div>
228228
</div>

src/components/calendar-overview.tsx

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use client'
22

3-
import { useCallback, useEffect, useRef, useState } from 'react'
3+
import { useEffect, useRef, useState } from 'react'
44
import {
55
format,
66
startOfWeek,
@@ -70,10 +70,6 @@ export function CalendarOverview() {
7070

7171
const viewportRef = useRef<HTMLDivElement>(null)
7272

73-
const closeCreateEventDialogOpen = useCallback(() => {
74-
setIsCreateEventOpen(false)
75-
}, [setIsCreateEventOpen])
76-
7773
useEffect(() => {
7874
if (viewportRef.current) {
7975
const el = viewportRef.current
@@ -155,6 +151,22 @@ export function CalendarOverview() {
155151
return (doc.body.textContent || '').trim()
156152
}
157153

154+
const handleReschedule = async (selectedEventID: string) => {
155+
if (!selectedEventID) return
156+
try {
157+
await slotifyClient.PostAPIRescheduleRequestSingle({
158+
msftMeetingID: selectedEventID,
159+
})
160+
toast({
161+
title: 'Reschedule sent',
162+
description: 'Sent reschedule request to the organizer',
163+
})
164+
} catch (error) {
165+
console.error(error)
166+
errorToast(error)
167+
}
168+
}
169+
158170
return (
159171
<div>
160172
<Card>
@@ -391,7 +403,12 @@ export function CalendarOverview() {
391403
<CreateEvent
392404
open={isCreateEventOpen}
393405
onOpenChangeAction={setIsCreateEventOpen}
394-
closeCreateEventDialogOpenAction={closeCreateEventDialogOpen}
406+
closeCreateEventDialogOpen={() => setIsCreateEventOpen(false)}
407+
initialTitle={''}
408+
initialDuration={'1hr'}
409+
initialParticipants={[]}
410+
initialSelectedRange={null}
411+
inputsDisabled={false}
395412
/>
396413

397414
<Dialog
@@ -492,10 +509,8 @@ export function CalendarOverview() {
492509
<Button
493510
variant='destructive'
494511
onClick={() => {
495-
toast({
496-
title: 'Reschedule sent',
497-
description: 'Sent reschedule request to the organizer',
498-
})
512+
console.log('Reschedule event: ', selectedEvent.id)
513+
handleReschedule(selectedEvent.id!.toString())
499514
setIsDayEventsDialogOpen(false)
500515
}}
501516
>

src/components/calendar/create-event.tsx

Lines changed: 80 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,12 @@ import { UserSearch } from '@/components/user-search-bar'
2727
interface CreateEventProps {
2828
open: boolean
2929
onOpenChangeAction: (open: boolean) => void
30-
closeCreateEventDialogOpenAction: () => void
30+
closeCreateEventDialogOpen: () => void
31+
initialTitle?: string
32+
initialDuration?: string
33+
initialParticipants?: User[]
34+
initialSelectedRange?: { start: Date; end: Date } | null
35+
inputsDisabled?: boolean
3136
}
3237

3338
// Mapping from dropdown option to minutes
@@ -40,22 +45,25 @@ const durationMapping: { [key: string]: number } = {
4045
export function CreateEvent({
4146
open,
4247
onOpenChangeAction,
43-
closeCreateEventDialogOpenAction,
48+
closeCreateEventDialogOpen,
49+
initialTitle = '',
50+
initialDuration = '1hr',
51+
initialParticipants = [],
52+
initialSelectedRange = null,
53+
inputsDisabled = false,
4454
}: CreateEventProps) {
4555
const [myEvents, setMyEvents] = useState<CalendarEvent[]>([])
46-
const [title, setTitle] = useState('')
56+
const [title, setTitle] = useState(initialTitle)
4757
const [location, setLocation] = useState('')
48-
const [duration, setDuration] = useState('1hr')
58+
const [duration, setDuration] = useState(initialDuration)
4959

5060
// const [userSearchQuery, setUserSearchQuery] = useState('')
5161
// const [searchResults, setSearchResults] = useState<User[]>([])
52-
const [selectedParticipants, setSelectedParticipants] = useState<User[]>([])
62+
const [selectedParticipants, setSelectedParticipants] =
63+
useState<User[]>(initialParticipants)
5364

5465
const [selectedDate, setSelectedDate] = useState<Date | null>(null)
55-
const [selectedRange, setSelectedRange] = useState<{
56-
start: Date
57-
end: Date
58-
} | null>(null)
66+
const [selectedRange, setSelectedRange] = useState(initialSelectedRange)
5967
const [availabilityData, setAvailabilityData] =
6068
useState<SchedulingSlotsSuccessResponse | null>(null)
6169

@@ -68,7 +76,6 @@ export function CreateEvent({
6876
const fetchCurrentUser = async () => {
6977
try {
7078
const user = await slotifyClient.GetAPIUsersMe()
71-
console.log('Current user:', user)
7279
setCurrentUser(user)
7380
} catch (error) {
7481
console.error('Error fetching current user:', error)
@@ -77,6 +84,21 @@ export function CreateEvent({
7784
fetchCurrentUser()
7885
}, [])
7986

87+
useEffect(() => {
88+
if (open) {
89+
setTitle(initialTitle)
90+
setDuration(initialDuration)
91+
setSelectedParticipants(initialParticipants)
92+
setSelectedRange(initialSelectedRange)
93+
}
94+
}, [
95+
open,
96+
initialTitle,
97+
initialDuration,
98+
initialParticipants,
99+
initialSelectedRange,
100+
])
101+
80102
// Ref to store the last fetched range (optional)
81103
const lastFetchedRangeRef = useRef<{ start: number; end: number } | null>(
82104
null,
@@ -94,15 +116,44 @@ export function CreateEvent({
94116
selectedRange.start.getTime() !== range.start.getTime() ||
95117
selectedRange.end.getTime() !== range.end.getTime())
96118
) {
97-
console.log('Range selected (updating):', range)
98119
setSelectedRange(range)
99-
} else {
100-
console.log('Range selected is identical or null; no update.')
101120
}
102121
},
103122
[selectedRange],
104123
)
105124

125+
// useEffect(() => {
126+
// const searchUsers = async () => {
127+
// if (!userSearchQuery) {
128+
// setSearchResults([])
129+
// return
130+
// }
131+
// try {
132+
// let response
133+
// if (userSearchQuery.includes('@')) {
134+
// // Search by email
135+
// response = await slotifyClient.GetAPIUsers({
136+
// queries: { email: userSearchQuery },
137+
// })
138+
// } else {
139+
// // Search by name
140+
// response = await slotifyClient.GetAPIUsers({
141+
// queries: { name: userSearchQuery },
142+
// })
143+
// }
144+
// setSearchResults(response)
145+
// } catch (error) {
146+
// console.error('Error searching users:', error)
147+
// toast({
148+
// title: 'Error',
149+
// description: 'Failed to search users.',
150+
// variant: 'destructive',
151+
// })
152+
// }
153+
// }
154+
// searchUsers()
155+
// }, [userSearchQuery])
156+
106157
// Add a user from search results to selected participants
107158
const handleAddParticipant = (user: User) => {
108159
if (
@@ -135,11 +186,8 @@ export function CreateEvent({
135186
end: memoizedRange?.end?.toISOString() || new Date().toISOString(),
136187
},
137188
})
138-
console.log("User's own events:", myEventsResponse)
139189
setMyEvents(myEventsResponse)
140190

141-
console.log('Check Availability button clicked.')
142-
143191
// Validate required fields
144192
if (selectedParticipants.length === 0 || !memoizedRange) {
145193
toast({
@@ -156,16 +204,11 @@ export function CreateEvent({
156204
memoizedRange &&
157205
lastFetchedRangeRef.current.start === memoizedRange.start.getTime() &&
158206
lastFetchedRangeRef.current.end === memoizedRange.end.getTime()
159-
) {
160-
console.log(
161-
'Range unchanged from last fetch; re-fetching due to manual trigger.',
162-
)
163-
}
164-
165-
lastFetchedRangeRef.current = {
166-
start: memoizedRange.start.getTime(),
167-
end: memoizedRange.end.getTime(),
168-
}
207+
)
208+
lastFetchedRangeRef.current = {
209+
start: memoizedRange.start.getTime(),
210+
end: memoizedRange.end.getTime(),
211+
}
169212

170213
setIsLoading(true)
171214
try {
@@ -183,20 +226,8 @@ export function CreateEvent({
183226
})
184227
}
185228

186-
console.log('Attendees:', attendees)
187-
188229
const durationInMinutes = durationMapping[duration] || 60
189230
const meetingDuration = `PT${durationInMinutes}M`
190-
console.log('Meeting duration:', meetingDuration)
191-
192-
console.log('Sending scheduling API call with details:', {
193-
meetingName: title || 'New Meeting',
194-
meetingDuration,
195-
timeSlot: {
196-
start: memoizedRange.start.toISOString(),
197-
end: memoizedRange.end.toISOString(),
198-
},
199-
})
200231

201232
// Fetch scheduling suggestions
202233
const response = await slotifyClient.PostAPISchedulingSlots({
@@ -218,7 +249,6 @@ export function CreateEvent({
218249
},
219250
})
220251

221-
console.log('Scheduling API response received:', response)
222252
setAvailabilityData(response)
223253

224254
// Now fetch each selected participant's calendar events for conflicts
@@ -233,7 +263,7 @@ export function CreateEvent({
233263
)
234264
const conflictResults = await Promise.all(conflictPromises)
235265
const allConflictEvents = conflictResults.flat()
236-
console.log('Conflict events fetched:', allConflictEvents)
266+
237267
setConflictEvents(allConflictEvents)
238268
} catch (error) {
239269
console.error('Error fetching availability:', error)
@@ -244,12 +274,10 @@ export function CreateEvent({
244274
})
245275
} finally {
246276
setIsLoading(false)
247-
console.log('Finished API call for availability.')
248277
}
249278
}
250279

251280
const handleCreateManually = () => {
252-
console.log('Manual event creation triggered')
253281
onOpenChangeAction(false)
254282
}
255283

@@ -275,9 +303,9 @@ export function CreateEvent({
275303
placeholder='My New Meeting'
276304
value={title}
277305
onChange={e => {
278-
console.log('Title changed:', e.target.value)
279306
setTitle(e.target.value)
280307
}}
308+
disabled={inputsDisabled}
281309
/>
282310
</div>
283311

@@ -288,9 +316,9 @@ export function CreateEvent({
288316
placeholder='None'
289317
value={location}
290318
onChange={e => {
291-
console.log('Location changed:', e.target.value)
292319
setLocation(e.target.value)
293320
}}
321+
disabled={inputsDisabled}
294322
/>
295323
</div>
296324

@@ -300,10 +328,10 @@ export function CreateEvent({
300328
id='duration'
301329
value={duration}
302330
onChange={e => {
303-
console.log('Duration changed:', e.target.value)
304331
setDuration(e.target.value)
305332
}}
306333
className='block w-full rounded-md border border-gray-300 p-2'
334+
disabled={inputsDisabled}
307335
>
308336
<option value='30 minutes'>30 minutes</option>
309337
<option value='1hr'>1hr</option>
@@ -321,11 +349,14 @@ export function CreateEvent({
321349
<Label>Event Range</Label>
322350
<EventRangePicker
323351
selectedDate={selectedDate}
352+
selectedRange={selectedRange}
324353
onDateSelect={date => {
325-
console.log('Date selected:', date)
326-
setSelectedDate(date)
354+
if (!inputsDisabled) setSelectedDate(date)
355+
}}
356+
onRangeSelect={range => {
357+
if (!inputsDisabled) handleRangeSelect(range)
327358
}}
328-
onRangeSelect={handleRangeSelect}
359+
disabled={inputsDisabled}
329360
/>
330361
</div>
331362

@@ -368,7 +399,7 @@ export function CreateEvent({
368399
participants={selectedParticipants}
369400
location={''} //TODO fix this
370401
eventTitle={title}
371-
closeCreateEventDialogOpen={closeCreateEventDialogOpenAction}
402+
closeCreateEventDialogOpen={closeCreateEventDialogOpen}
372403
/>
373404
</div>
374405
</div>

0 commit comments

Comments
 (0)