feat: task problem/solution split + maintenance icons on rooms/calendar
- TechnicalPage: redesign task cards with separate "Задача" and "Решение" sections - "Задача": problem description + problem photos (editable before done) - "Решение": technician resolution comment + resolution photos (green section) - Resolution comment in CompletionModal now saves to resolution_notes field - Resolution photos save to resolution_photos (no longer mixed with problem photos) - RoomModal history tab: maintenance entries show separate problem/resolution sections - Backend: add resolution_notes, resolution_photos to PATCH allowed fields - Migration 029: resolution_notes TEXT + resolution_photos TEXT[] columns - RoomsPage: load active maintenance tasks, show 🔧 неисправность badge on room cards - CalendarPage: load active maintenance tasks, show 🔧 неиспр. label in calendar row - BookingCalendar: activeMaintenance prop, WS handler updates maintenance set on task changes - CalendarPage WS: handle housekeeping_task_created to update activeMaintenance set Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -27,6 +27,8 @@ export function CalendarPage() {
|
||||
const [priceOverrides, setPriceOverrides] = useState<Record<string, Record<string, number>>>({})
|
||||
// roomId → assigneeName for "убирается" tooltip
|
||||
const [cleaningAssignees, setCleaningAssignees] = useState<Record<string, string>>({})
|
||||
// Set of room IDs with active maintenance tasks
|
||||
const [activeMaintenance, setActiveMaintenance] = useState<Set<string>>(new Set())
|
||||
|
||||
useEffect(() => {
|
||||
if (!slug) return
|
||||
@@ -55,6 +57,17 @@ export function CalendarPage() {
|
||||
}
|
||||
}).catch(console.error)
|
||||
|
||||
// Fetch active maintenance tasks
|
||||
api.housekeeping.list(slug, { status: 'active', category: 'maintenance' })
|
||||
.then(tasks => {
|
||||
const ids = new Set(tasks.map(t => {
|
||||
const tAny = t as unknown as Record<string, string>
|
||||
return tAny.roomId ?? tAny.room_id ?? ''
|
||||
}).filter(Boolean))
|
||||
setActiveMaintenance(ids)
|
||||
})
|
||||
.catch(() => {})
|
||||
|
||||
// Fetch active HK tasks to build "who is cleaning" tooltip map
|
||||
api.housekeeping.list(slug, { status: 'active', category: 'housekeeping' })
|
||||
.then(tasks => {
|
||||
@@ -90,8 +103,23 @@ export function CalendarPage() {
|
||||
if (msg.roomStatus !== 'cleaning') {
|
||||
setCleaningAssignees(prev => { const n = { ...prev }; delete n[msg.roomId]; return n })
|
||||
}
|
||||
} else if (msg.type === 'housekeeping_task_created') {
|
||||
const t = msg.task as Record<string, string>
|
||||
const roomId = t.roomId ?? t.room_id
|
||||
if (t.category === 'maintenance' && roomId) {
|
||||
setActiveMaintenance(prev => new Set([...prev, roomId]))
|
||||
}
|
||||
} else if (msg.type === 'housekeeping_updated') {
|
||||
const t = msg.task as Record<string, string>
|
||||
const roomId = t.roomId ?? t.room_id
|
||||
// Track maintenance tasks
|
||||
if (t.category === 'maintenance' && roomId) {
|
||||
if (t.status === 'done' || t.status === 'cancelled') {
|
||||
setActiveMaintenance(prev => { const n = new Set(prev); n.delete(roomId); return n })
|
||||
} else {
|
||||
setActiveMaintenance(prev => new Set([...prev, roomId]))
|
||||
}
|
||||
}
|
||||
if (t.roomId) {
|
||||
if (t.status === 'in_progress' && t.assigneeName) {
|
||||
setCleaningAssignees(prev => ({ ...prev, [t.roomId]: t.assigneeName }))
|
||||
@@ -258,6 +286,7 @@ export function CalendarPage() {
|
||||
onRoomUpdate={handleRoomUpdate}
|
||||
onMaintenanceTaskCreate={handleMaintenanceTaskCreate}
|
||||
cleaningAssignees={cleaningAssignees}
|
||||
activeMaintenance={activeMaintenance}
|
||||
fadingBookingIds={fadingBookings}
|
||||
rentalObjects={isRentalActive ? rentalObjects as unknown as import('../data/rentalData').RentalObject[] : undefined}
|
||||
rentalBookings={isRentalActive ? rentalBookings as unknown as RentalBooking[] : undefined}
|
||||
|
||||
Reference in New Issue
Block a user