feat(admin): implement full day-by-day schedule editor with live preview
## Features ### Admin Schedule Page (`packages/app/src/pages/admin/schedule.vue`) - Interactive date-based slot editor for managing daily schedules - Real-time slot editing: start/end times, capacity adjustments - Slot deletion with conflict warnings when bookings exist - Add new slots with modal dialog - Live booking status display (booked count, people names) - Publish/Save changes with sync feedback - Revert unsaved changes with confirmation - Skeleton loading states and empty state handling - Responsive design with optimized mobile UX ### Backend Enhancements - **New DTO** (`PublishDaySlotsDto`): Structured slot publishing with validation - Date string validation - Slot array with existing slot IDs for updates - Time and capacity validation per slot - **Schedule Preview API** (`getSchedulePreview`): - Check for existing published slots - Fallback to active WeekTemplates for unpublished dates - Unified response format with isPublished flag - **Publish Slots API** (`publishDaySlots`): - Atomic transaction for consistency - Update existing slots with new times/capacity - Create new slots from template data - Delete unpublished slots or set to CLOSED if bookings exist - Prevent capacity reduction below existing bookings - Returns all published slots for feedback ### State Management - Enhanced admin store with schedule state - Support for pending/unsaved slot changes - Optimistic UI updates with server sync ### Documentation - Comprehensive scheduling system architecture docs - Quick reference for admin workflows - Flow diagrams and state transitions - Implementation guide for future maintenance ## Breaking Changes None ## Testing Recommendations - Create slots for future dates via schedule editor - Verify booking prevention for locked/full slots - Test capacity adjustments with existing bookings - Confirm template-based schedule generation - Verify transaction rollback on publish failures Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -13,6 +13,8 @@ import type {
|
||||
TimeSlot,
|
||||
CreateManualSlotDto,
|
||||
PaginatedData,
|
||||
ScheduleSlotPreview,
|
||||
PublishDaySlotsDto,
|
||||
} from '@mp-pilates/shared'
|
||||
|
||||
export interface AdminStats {
|
||||
@@ -42,7 +44,7 @@ export const useAdminStore = defineStore('admin', () => {
|
||||
}
|
||||
|
||||
async function saveWeekTemplates(templates: WeekTemplateInput[]): Promise<WeekTemplate[]> {
|
||||
const data = await put<WeekTemplate[]>('/admin/week-template', templates)
|
||||
const data = await put<WeekTemplate[]>('/admin/week-template', { templates })
|
||||
weekTemplates.value = data
|
||||
return data
|
||||
}
|
||||
@@ -132,6 +134,26 @@ export const useAdminStore = defineStore('admin', () => {
|
||||
return post<{ count: number }>('/admin/generate-slots', { startDate, endDate })
|
||||
}
|
||||
|
||||
// ── Schedule management ─────────────────────────────────────────
|
||||
const schedulePreview = ref<ScheduleSlotPreview[]>([])
|
||||
const scheduleLoading = ref(false)
|
||||
|
||||
async function fetchSchedulePreview(date: string): Promise<ScheduleSlotPreview[]> {
|
||||
scheduleLoading.value = true
|
||||
try {
|
||||
const data = await get<ScheduleSlotPreview[]>('/admin/schedule/preview', { date })
|
||||
schedulePreview.value = data
|
||||
return data
|
||||
} finally {
|
||||
scheduleLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function publishDaySlots(dto: PublishDaySlotsDto): Promise<void> {
|
||||
await post('/admin/schedule/publish', dto as unknown as Record<string, unknown>)
|
||||
await fetchSchedulePreview(dto.date)
|
||||
}
|
||||
|
||||
// ── Dashboard stats ──────────────────────────────────────────────
|
||||
async function fetchDashboardStats(): Promise<AdminStats> {
|
||||
return get<AdminStats>('/admin/stats')
|
||||
@@ -142,6 +164,8 @@ export const useAdminStore = defineStore('admin', () => {
|
||||
weekTemplates,
|
||||
cardTypes,
|
||||
studioConfig,
|
||||
schedulePreview,
|
||||
scheduleLoading,
|
||||
// Week templates
|
||||
fetchWeekTemplates,
|
||||
saveWeekTemplates,
|
||||
@@ -164,6 +188,9 @@ export const useAdminStore = defineStore('admin', () => {
|
||||
createManualSlot,
|
||||
closeSlot,
|
||||
generateSlots,
|
||||
// Schedule
|
||||
fetchSchedulePreview,
|
||||
publishDaySlots,
|
||||
// Stats
|
||||
fetchDashboardStats,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user