@@ -20,22 +20,27 @@ import { cn } from '@/lib/utils'
2020import { Badge } from '@/components/ui/badge'
2121import { CreateManualEventDialog } from '@/components/calendar/create-manual-event-dialog'
2222import { DayEventsDialog } from '@/components/calendar/day-events-dialog'
23- import { CalendarHeader } from '@/components/calendar/calendar-header'
2423import { AnimatePresence , motion } from 'framer-motion'
2524import slotifyClient from '@/hooks/fetch'
2625import { CalendarEvent } from '@/types/types'
2726import { errorToast } from '@/hooks/use-toast'
27+ import { ChevronLeft , ChevronRight , Loader2 , Sparkles } from 'lucide-react'
28+ import { Button } from '@/components/ui/button'
29+ import { CreateEvent } from './create-event'
2830
2931export function DisplayCalendar ( ) {
3032 const [ calendar , setCalendar ] = useState < Array < CalendarEvent > > ( [ ] )
3133 const [ currentMonth , setCurrentMonth ] = useState ( new Date ( ) )
3234 const [ selectedDate , setSelectedDate ] = useState < Date | null > ( null )
3335 const [ selectedEvent , setSelectedEvent ] = useState < CalendarEvent | null > ( null )
34- const [ isCreateEventDialogOpen , setIsCreateEventDialogOpen ] = useState ( false )
36+ const [ isManualCreateEventOpen , setisManualCreateEventOpen ] = useState ( false )
37+ const [ isCreateEventOpen , setIsCreateEventOpen ] = useState ( false )
3538 const [ isDayEventsDialogOpen , setIsDayEventsDialogOpen ] = useState ( false )
39+ const [ isLoading , setIsLoading ] = useState ( false )
3640
3741 useEffect ( ( ) => {
3842 const fetchCalendar = async ( ) => {
43+ setIsLoading ( true )
3944 const end = new Date ( currentMonth )
4045 end . setMonth ( currentMonth . getMonth ( ) + 1 )
4146
@@ -50,6 +55,7 @@ export function DisplayCalendar() {
5055 } ,
5156 } )
5257 setCalendar ( calendarData )
58+ setIsLoading ( false )
5359 } catch ( error ) {
5460 console . error ( error )
5561 errorToast ( error )
@@ -81,15 +87,53 @@ export function DisplayCalendar() {
8187 setCurrentMonth ( prev => ( isValid ( prev ) ? addMonths ( prev , 1 ) : new Date ( ) ) )
8288 const handleToday = ( ) => setCurrentMonth ( new Date ( ) )
8389
90+ const formattedMonth = isValid ( currentMonth )
91+ ? format ( currentMonth , 'MMMM yyyy' )
92+ : 'Invalid Date'
93+
94+ function handleManualCreateEvent ( date : Date ) {
95+ setSelectedDate ( date )
96+ setisManualCreateEventOpen ( true )
97+ }
98+
8499 return (
85100 < div >
86- < CalendarHeader
87- currentMonth = { currentMonth }
88- onPreviousMonthAction = { handlePreviousMonth }
89- onNextMonthAction = { handleNextMonth }
90- onTodayAction = { handleToday }
91- onCreateEventAction = { ( ) => setIsCreateEventDialogOpen ( true ) }
92- />
101+ < header className = 'border-b mb-4' >
102+ < div className = 'flex items-center justify-between h-16' >
103+ < div className = 'flex items-center' >
104+ < div className = 'text-lg font-semibold' > { formattedMonth } </ div >
105+ </ div >
106+ < div className = 'flex items-center gap-2' >
107+ < Button
108+ onClick = { ( ) => {
109+ setIsCreateEventOpen ( ! isCreateEventOpen )
110+ console . log ( 'Create super event: ' , isCreateEventOpen )
111+ } }
112+ className = 'bg-focusColor hover:bg-focusColor/90'
113+ >
114+ < Sparkles className = 'h-4 w-4 mr-2' />
115+ Create super event
116+ </ Button >
117+
118+ < Button variant = 'outline' onClick = { handleToday } >
119+ Today
120+ </ Button >
121+ < div className = 'flex items-center gap-1' >
122+ < Button
123+ variant = 'outline'
124+ size = 'icon'
125+ onClick = { handlePreviousMonth }
126+ >
127+ < ChevronLeft className = 'h-4 w-4' />
128+ </ Button >
129+ < Button variant = 'outline' size = 'icon' onClick = { handleNextMonth } >
130+ < ChevronRight className = 'h-4 w-4' />
131+ </ Button >
132+ </ div >
133+ </ div >
134+ </ div >
135+ </ header >
136+
93137 < AnimatePresence mode = 'wait' >
94138 < motion . div
95139 key = { currentMonth . toISOString ( ) }
@@ -98,81 +142,103 @@ export function DisplayCalendar() {
98142 exit = { { opacity : 0 , y : - 20 } }
99143 transition = { { duration : 0.2 } }
100144 >
101- < div className = 'grid grid-cols-7 gap-px bg-muted rounded-lg overflow-hidden' >
102- { [ 'Sun' , 'Mon' , 'Tue' , 'Wed' , 'Thu' , 'Fri' , 'Sat' ] . map ( day => (
103- < div
104- key = { day }
105- className = 'bg-muted-foreground/5 p-3 text-center text-sm font-medium'
106- >
107- { day }
108- </ div >
109- ) ) }
110- { days . map ( day => {
111- const dayEvents = getEventsForDay ( day )
112- return (
145+ { isLoading ? (
146+ < div className = 'flex items-center justify-center h-[66vh] space-x-2' >
147+ < Loader2 className = 'h-6 w-6 animate-spin' />
148+ < span > Loading...</ span >
149+ </ div >
150+ ) : (
151+ < div className = 'grid grid-cols-7 gap-px bg-muted rounded-lg overflow-hidden' >
152+ { [ 'Sun' , 'Mon' , 'Tue' , 'Wed' , 'Thu' , 'Fri' , 'Sat' ] . map ( day => (
113153 < div
114- key = { day . toString ( ) }
115- className = { cn (
116- 'min-h-[120px] bg-card p-2 relative' ,
117- ! isSameMonth ( day , currentMonth ) && 'bg-muted-foreground/5' ,
118- 'hover:bg-accent cursor-pointer' ,
119- ) }
120- onClick = { ( ) => {
121- setSelectedDate ( day )
122- setSelectedEvent ( null )
123- setIsDayEventsDialogOpen ( true )
124- } }
154+ key = { day }
155+ className = 'bg-muted-foreground/5 p-3 text-center text-sm font-medium'
125156 >
126- < time
127- dateTime = { format ( day , 'yyyy-MM-dd' ) }
157+ { day }
158+ </ div >
159+ ) ) }
160+ { days . map ( day => {
161+ const dayEvents = getEventsForDay ( day )
162+ return (
163+ < div
164+ key = { day . toString ( ) }
128165 className = { cn (
129- 'font-medium' ,
130- isToday ( day ) &&
131- 'bg-focusColor text-primary-foreground rounded-full w-6 h-6 flex items-center justify-center' ,
166+ 'min-h-[120px] bg-card p-2 relative' ,
167+ ! isSameMonth ( day , currentMonth ) &&
168+ 'bg-muted-foreground/5' ,
169+ 'hover:bg-accent cursor-pointer' ,
132170 ) }
171+ onClick = { ( ) => {
172+ setSelectedDate ( day )
173+ setSelectedEvent ( null )
174+ setIsDayEventsDialogOpen ( true )
175+ } }
133176 >
134- { format ( day , 'd' ) }
135- </ time >
136- < div className = 'mt-2 space-y-1' >
137- { dayEvents . slice ( 0 , 2 ) . map ( event => (
138- < Badge
139- key = { event . id }
140- variant = 'secondary'
141- className = 'block truncate text-xs cursor-pointer'
142- onClick = { e => {
143- e . stopPropagation ( )
144- setSelectedDate ( day )
145- setSelectedEvent ( event )
146- setIsDayEventsDialogOpen ( true )
147- } }
148- >
149- { event . startTime &&
150- format ( parseISO ( event . startTime ) , 'HH:mm' ) } { ' ' }
151- { event . subject ? event . subject : '(No Name)' }
152- </ Badge >
153- ) ) }
154- { dayEvents . length > 2 && (
155- < Badge
156- variant = 'outline'
157- className = 'block truncate text-xs'
158- >
159- +{ dayEvents . length - 2 } more
160- </ Badge >
161- ) }
177+ < time
178+ dateTime = { format ( day , 'yyyy-MM-dd' ) }
179+ className = { cn (
180+ 'font-medium' ,
181+ isToday ( day ) &&
182+ 'bg-focusColor text-primary-foreground rounded-full w-6 h-6 flex items-center justify-center' ,
183+ ) }
184+ >
185+ { format ( day , 'd' ) }
186+ </ time >
187+ < div className = 'mt-2 space-y-1' >
188+ { dayEvents . slice ( 0 , 2 ) . map ( event => (
189+ < Badge
190+ key = { event . id }
191+ variant = 'secondary'
192+ className = 'block truncate text-xs cursor-pointer'
193+ onClick = { e => {
194+ e . stopPropagation ( )
195+ setSelectedDate ( day )
196+ setSelectedEvent ( event )
197+ setIsDayEventsDialogOpen ( true )
198+ } }
199+ >
200+ { event . startTime &&
201+ format ( parseISO ( event . startTime ) , 'HH:mm' ) } { ' ' }
202+ { event . subject ? event . subject : '(No Name)' }
203+ </ Badge >
204+ ) ) }
205+ { dayEvents . length > 2 && (
206+ < Badge
207+ variant = 'outline'
208+ className = 'block truncate text-xs'
209+ >
210+ +{ dayEvents . length - 2 } more
211+ </ Badge >
212+ ) }
213+ </ div >
162214 </ div >
163- </ div >
164- )
165- } ) }
166- </ div >
215+ )
216+ } ) }
217+ </ div >
218+ ) }
167219 </ motion . div >
168220 </ AnimatePresence >
169221
170222 < CreateManualEventDialog
171- open = { isCreateEventDialogOpen }
172- onOpenChangeAction = { setIsCreateEventDialogOpen }
223+ open = { isManualCreateEventOpen }
224+ onOpenChangeAction = { setisManualCreateEventOpen }
173225 selectedDate = { selectedDate }
174226 />
175227
228+ < CreateEvent
229+ open = { isCreateEventOpen }
230+ onOpenChangeAction = { setIsCreateEventOpen }
231+ closeCreateEventDialogOpen = { ( ) => setIsCreateEventOpen ( false ) }
232+ initialTitle = { '' }
233+ initialDuration = { 60 }
234+ initialParticipants = { [ ] }
235+ initialSelectedRange = { null }
236+ inputsDisabled = { false }
237+ isRescheduleAccepted = { false }
238+ isComplete = { false }
239+ handleManualCreateEvent = { handleManualCreateEvent }
240+ />
241+
176242 < DayEventsDialog
177243 open = { isDayEventsDialogOpen }
178244 onOpenChangeAction = { setIsDayEventsDialogOpen }
0 commit comments