feat: add category field to housekeeping tasks + TechnicalPage for maintenance tasks

- Add migration 025 to add `category` column (housekeeping/maintenance) to housekeeping_tasks
- Backend: filter by ?category= in GET, store category in POST, allow patching category
- API client: HkPayload + housekeeping.list() now support category param
- HousekeepingPage: filters by category=housekeeping so maintenance tasks don't appear
- RoomContextMenu: priority sub-form for dirty/cleaning status, tech task creation inline form
- BookingCalendar: accepts onMaintenanceTaskCreate prop, passes priority to onRoomUpdate
- CalendarPage: handleRoomUpdate creates task for dirty+cleaning (with priority), new handleMaintenanceTaskCreate for category=maintenance tasks
- TechnicalPage: new page for viewing/creating/updating maintenance tasks
- App.tsx: /technical route added
- Sidebar: Тех. задачи nav item added under Управление

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-23 23:28:42 +03:00
parent 9be51e5d07
commit 3bb7262b59
10 changed files with 508 additions and 48 deletions

View File

@@ -11,6 +11,7 @@ import { BookingModal } from '../bookings/BookingModal'
import { BookingDetailPanel } from '../bookings/BookingDetailPanel'
import { RentalBookingModal } from '../rental/RentalBookingModal'
import { RoomContextMenu } from '../rooms/RoomContextMenu'
import type { HkPriority } from '../rooms/RoomContextMenu'
const CELL_WIDTH = 52
const ROW_HEIGHT = 56
@@ -27,7 +28,8 @@ interface BookingCalendarProps {
onBookingCreate: (b: Partial<Booking>) => void
onBookingUpdate: (id: string, b: Partial<Booking>) => void
onBookingBulkUpdate?: (updates: Array<{ id: string; data: Partial<Booking> }>) => void
onRoomUpdate?: (roomId: string, patch: Partial<Room>) => void
onRoomUpdate?: (roomId: string, patch: Partial<Room>, priority?: HkPriority) => void
onMaintenanceTaskCreate?: (roomId: string, description: string, priority: HkPriority) => void
fadingBookingIds?: Set<string>
rentalObjects?: RentalObject[]
rentalBookings?: RentalBooking[]
@@ -61,7 +63,7 @@ function getRoomTypeColor(type: string): string {
return map[type] ?? 'bg-slate-100 text-slate-600 dark:bg-slate-700 dark:text-slate-300'
}
export function BookingCalendar({ rooms, bookings, slug, onBookingCreate, onBookingUpdate, onBookingBulkUpdate, onRoomUpdate, fadingBookingIds, rentalObjects, rentalBookings, onRentalBookingCreate, locks = new Map(), onDraftStart, onDraftCancel, wsConnected, priceOverrides }: BookingCalendarProps) {
export function BookingCalendar({ rooms, bookings, slug, onBookingCreate, onBookingUpdate, onBookingBulkUpdate, onRoomUpdate, onMaintenanceTaskCreate, fadingBookingIds, rentalObjects, rentalBookings, onRentalBookingCreate, locks = new Map(), onDraftStart, onDraftCancel, wsConnected, priceOverrides }: BookingCalendarProps) {
const [startDate, setStartDate] = useState(() => startOfDay(new Date()))
const [visibleDays, setVisibleDays] = useState(DAYS_VISIBLE)
@@ -82,8 +84,12 @@ export function BookingCalendar({ rooms, bookings, slug, onBookingCreate, onBook
onRoomUpdate?.(roomId, { status, maintenanceFrom: from, maintenanceTo: to })
}
const handleCtxHkChange = (roomId: string, status: HousekeepingStatus) => {
onRoomUpdate?.(roomId, { housekeepingStatus: status })
const handleCtxHkChange = (roomId: string, status: HousekeepingStatus, priority?: HkPriority) => {
onRoomUpdate?.(roomId, { housekeepingStatus: status }, priority)
}
const handleCtxMaintenanceTask = (roomId: string, description: string, priority: HkPriority) => {
onMaintenanceTaskCreate?.(roomId, description, priority)
}
// Cell hover price tooltip
@@ -957,6 +963,7 @@ export function BookingCalendar({ rooms, bookings, slug, onBookingCreate, onBook
onClose={() => setCtxMenu(null)}
onStatusChange={handleCtxStatusChange}
onHkStatusChange={handleCtxHkChange}
onMaintenanceTask={handleCtxMaintenanceTask}
/>
)}