feat(dashboard): redesign with active bookings, calendar, and compact stats

Major Dashboard improvements focusing on active reservations and calendar view:

Frontend changes:
- Add ActiveBookings component showing in-progress bookings with progress bars
- Add DashboardCalendar component with read-only calendar view of all user bookings
- Refactor Dashboard layout: active bookings → stats grid → calendar → activity
- Remove redundant Quick Actions and Available Spaces sections
- Make Quick Stats compact (36px icons, 20px font) and clickable (router-link)
- Add datetime utility functions (isBookingActive, getBookingProgress, formatRemainingTime)
- Fix MyBookings to read status query parameter from URL
- Auto-refresh active bookings every 60s with proper cleanup

Backend changes:
- Add GET /api/bookings/my/calendar endpoint with date range filtering
- Fix Google Calendar sync in reschedule_booking and admin_update_booking
- Add Google OAuth environment variables to .env.example

Design:
- Dark mode compatible with CSS variables throughout
- Mobile responsive (768px breakpoint, 2-column stats grid)
- CollapsibleSection pattern for all dashboard sections
- Progress bars with accent colors for active bookings

Performance:
- Optimized API calls (calendar uses date range filtering)
- Remove duplicate calendar data loading on mount
- Computed property caching for stats and filtered bookings
- Memory leak prevention (setInterval cleanup on unmount)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Claude Agent
2026-02-12 10:21:32 +00:00
parent 72f46b1062
commit 28685d8254
8 changed files with 560 additions and 251 deletions

View File

@@ -190,6 +190,13 @@ export const bookingsApi = {
createRecurring: async (data: RecurringBookingCreate): Promise<RecurringBookingResult> => {
const response = await api.post<RecurringBookingResult>('/bookings/recurring', data)
return response.data
},
getMyCalendar: async (start: string, end: string): Promise<Booking[]> => {
const response = await api.get<Booking[]>('/bookings/my/calendar', {
params: { start, end }
})
return response.data
}
}