Skip to content

Commit acddf4c

Browse files
committed
fix buttons on calendar pages
lint changes remove redundant meetings from navbar better today's events formatting add loading indicator for weekly calendar more loading indicators fading animations for navbar more loading indicators fetch slots for all days + loading indicator prettier changes remove transparency on slots
1 parent 2681280 commit acddf4c

File tree

9 files changed

+766
-643
lines changed

9 files changed

+766
-643
lines changed

src/app/dashboard/page.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,11 @@ import { format } from 'date-fns'
2222
export default function Dashboard() {
2323
const [calendar, setCalendar] = useState<CalendarEvent[]>([])
2424
const [invites, setInvites] = useState<InvitesMe[]>([])
25+
const [isLoading, setIsLoading] = useState<boolean>(false)
2526

2627
useEffect(() => {
2728
const fetchCalendar = async () => {
29+
setIsLoading(true)
2830
const now = new Date()
2931
const endOfDay = new Date(now)
3032
endOfDay.setHours(23, 59, 59, 999)
@@ -46,6 +48,7 @@ export default function Dashboard() {
4648
} catch (error) {
4749
console.log('calendar me error', error)
4850
}
51+
setIsLoading(false)
4952
}
5053

5154
fetchCalendar()
@@ -130,7 +133,7 @@ export default function Dashboard() {
130133
<div className='flex flex-row justify-center w-screen gap-10 mt-5'>
131134
<div className='w-[45vw]'>
132135
<div className='mb-8'>
133-
<EventsForToday events={calendar} />
136+
<EventsForToday events={calendar} isLoading={isLoading} />
134137
</div>
135138
<div className='mb-8'>
136139
<h2 className='text-2xl font-bold mb-4'>Group Invites</h2>

src/components/calendar-overview.tsx

Lines changed: 192 additions & 168 deletions
Large diffs are not rendered by default.

src/components/calendar/calendar-header.tsx

Lines changed: 0 additions & 55 deletions
This file was deleted.

src/components/calendar/calendar.tsx

Lines changed: 137 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -20,22 +20,27 @@ import { cn } from '@/lib/utils'
2020
import { Badge } from '@/components/ui/badge'
2121
import { CreateManualEventDialog } from '@/components/calendar/create-manual-event-dialog'
2222
import { DayEventsDialog } from '@/components/calendar/day-events-dialog'
23-
import { CalendarHeader } from '@/components/calendar/calendar-header'
2423
import { AnimatePresence, motion } from 'framer-motion'
2524
import slotifyClient from '@/hooks/fetch'
2625
import { CalendarEvent } from '@/types/types'
2726
import { 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

2931
export 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

Comments
 (0)