feat: complete UI/UX overhaul - dashboard unification, calendar UX, mobile optimization

- Dashboard redesign as command center with filters, quick actions, inline approve/reject
- Reusable components: BookingRow, BookingFilters, ActionMenu, BookingPreviewModal, BookingEditModal
- Calendar: drag & drop reschedule, eventClick preview modal, grid/list toggle
- Mobile: segmented control bookings/calendar toggle, compact pills, responsive layout
- Collapsible filters with active count badge
- Smart menu positioning with Teleport
- Calendar/list bidirectional data sync
- Navigation: unified History page, removed AdminPending
- Google Calendar OAuth integration
- Dark mode contrast improvements, breadcrumb navigation
- useLocalStorage composable for state persistence

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Claude Agent
2026-02-12 15:34:47 +00:00
parent a4d3f862d2
commit d245c72757
36 changed files with 5275 additions and 1569 deletions

View File

@@ -0,0 +1,21 @@
import { ref, watch, type Ref } from 'vue'
export function useLocalStorage<T>(key: string, defaultValue: T): Ref<T> {
let initial = defaultValue
try {
const stored = localStorage.getItem(key)
if (stored !== null) {
initial = JSON.parse(stored)
}
} catch {
// Invalid JSON in storage, use default
}
const value = ref<T>(initial) as Ref<T>
watch(value, (newVal) => {
localStorage.setItem(key, JSON.stringify(newVal))
}, { deep: true })
return value
}

View File

@@ -0,0 +1,28 @@
import { ref, onMounted, onUnmounted } from 'vue'
export function useMediaQuery(query: string) {
const matches = ref(false)
let mediaQuery: MediaQueryList | null = null
const update = () => {
if (mediaQuery) {
matches.value = mediaQuery.matches
}
}
onMounted(() => {
mediaQuery = window.matchMedia(query)
matches.value = mediaQuery.matches
mediaQuery.addEventListener('change', update)
})
onUnmounted(() => {
mediaQuery?.removeEventListener('change', update)
})
return matches
}
export function useIsMobile() {
return useMediaQuery('(max-width: 768px)')
}