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:
@@ -26,6 +26,26 @@
|
||||
:style="{ width: getProgress(booking.start_datetime, booking.end_datetime) + '%' }"
|
||||
/>
|
||||
</div>
|
||||
<div class="active-actions">
|
||||
<router-link :to="`/history`" class="action-btn action-btn-view" title="View bookings">
|
||||
<Eye :size="16" />
|
||||
</router-link>
|
||||
<button
|
||||
v-if="booking.status === 'pending'"
|
||||
class="action-btn action-btn-edit"
|
||||
title="Edit booking"
|
||||
@click="$emit('refresh')"
|
||||
>
|
||||
<Pencil :size="16" />
|
||||
</button>
|
||||
<button
|
||||
class="action-btn action-btn-cancel"
|
||||
title="Cancel booking"
|
||||
@click="$emit('cancel', booking)"
|
||||
>
|
||||
<X :size="16" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -33,7 +53,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, onMounted, onUnmounted } from 'vue'
|
||||
import { Zap } from 'lucide-vue-next'
|
||||
import { Zap, Eye, Pencil, X } from 'lucide-vue-next'
|
||||
import { isBookingActive, getBookingProgress, formatRemainingTime } from '@/utils/datetime'
|
||||
import { formatTime as formatTimeUtil } from '@/utils/datetime'
|
||||
import { useAuthStore } from '@/stores/auth'
|
||||
@@ -43,6 +63,11 @@ const props = defineProps<{
|
||||
bookings: Booking[]
|
||||
}>()
|
||||
|
||||
defineEmits<{
|
||||
cancel: [booking: Booking]
|
||||
refresh: []
|
||||
}>()
|
||||
|
||||
const authStore = useAuthStore()
|
||||
const userTimezone = computed(() => authStore.user?.timezone || 'UTC')
|
||||
|
||||
@@ -175,6 +200,50 @@ onUnmounted(() => {
|
||||
transition: width 1s ease;
|
||||
}
|
||||
|
||||
.active-actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.action-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: var(--radius-sm);
|
||||
border: 1px solid var(--color-border);
|
||||
background: var(--color-surface);
|
||||
color: var(--color-text-secondary);
|
||||
cursor: pointer;
|
||||
transition: all var(--transition-fast);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.action-btn:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
|
||||
.action-btn-view:hover {
|
||||
color: var(--color-info);
|
||||
border-color: var(--color-info);
|
||||
background: color-mix(in srgb, var(--color-info) 10%, transparent);
|
||||
}
|
||||
|
||||
.action-btn-edit:hover {
|
||||
color: var(--color-warning);
|
||||
border-color: var(--color-warning);
|
||||
background: color-mix(in srgb, var(--color-warning) 10%, transparent);
|
||||
}
|
||||
|
||||
.action-btn-cancel:hover {
|
||||
color: var(--color-danger);
|
||||
border-color: var(--color-danger);
|
||||
background: color-mix(in srgb, var(--color-danger) 10%, transparent);
|
||||
}
|
||||
|
||||
/* Mobile responsive */
|
||||
@media (max-width: 768px) {
|
||||
.active-card-top {
|
||||
|
||||
Reference in New Issue
Block a user