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:
@@ -131,3 +131,39 @@ export const isoToLocalDateTime = (isoDateTime: string, timezone: string = 'UTC'
|
||||
// Format as YYYY-MM-DDTHH:mm for datetime-local input
|
||||
return `${year}-${month}-${day}T${hour.padStart(2, '0')}:${minute.padStart(2, '0')}`
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a booking is currently active (in progress).
|
||||
*/
|
||||
export const isBookingActive = (startDatetime: string, endDatetime: string): boolean => {
|
||||
const now = new Date()
|
||||
const start = new Date(ensureUTC(startDatetime))
|
||||
const end = new Date(ensureUTC(endDatetime))
|
||||
return start <= now && end >= now
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate progress percentage for an active booking.
|
||||
*/
|
||||
export const getBookingProgress = (startDatetime: string, endDatetime: string): number => {
|
||||
const now = new Date()
|
||||
const start = new Date(ensureUTC(startDatetime))
|
||||
const end = new Date(ensureUTC(endDatetime))
|
||||
const total = end.getTime() - start.getTime()
|
||||
const elapsed = now.getTime() - start.getTime()
|
||||
return Math.min(100, Math.max(0, (elapsed / total) * 100))
|
||||
}
|
||||
|
||||
/**
|
||||
* Format remaining time for an active booking.
|
||||
*/
|
||||
export const formatRemainingTime = (endDatetime: string): string => {
|
||||
const now = new Date()
|
||||
const end = new Date(ensureUTC(endDatetime))
|
||||
const remaining = end.getTime() - now.getTime()
|
||||
if (remaining <= 0) return 'Ended'
|
||||
const hours = Math.floor(remaining / 3600000)
|
||||
const minutes = Math.floor((remaining % 3600000) / 60000)
|
||||
if (hours > 0) return `${hours}h ${minutes}m remaining`
|
||||
return `${minutes}m remaining`
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user