Add real-time booking collaboration via WebSocket

- Backend: /ws relay endpoint (@fastify/websocket)
- Frontend: useHotelSocket hook with lock/unlock/booking events
- Calendar: lock overlay with diagonal stripes shows other manager editing

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-17 18:05:09 +03:00
parent 1d24e5a4c4
commit 3506105fc1
7 changed files with 1919 additions and 9 deletions

40
backend/src/routes/ws.ts Normal file
View File

@@ -0,0 +1,40 @@
import { FastifyPluginAsync } from 'fastify'
import fastifyWebsocket from '@fastify/websocket'
import type { WebSocket } from 'ws'
// hotel slug → set of connected clients
const hotelRooms = new Map<string, Set<WebSocket>>()
const ws: FastifyPluginAsync = async (fastify) => {
await fastify.register(fastifyWebsocket)
fastify.get<{ Querystring: { hotel?: string; token?: string } }>(
'/ws',
{ websocket: true },
(socket, request) => {
const hotel = request.query.hotel ?? ''
if (!hotel) { socket.close(4001, 'hotel required'); return }
if (!hotelRooms.has(hotel)) hotelRooms.set(hotel, new Set())
hotelRooms.get(hotel)!.add(socket)
socket.on('message', (raw) => {
const data = raw.toString()
const peers = hotelRooms.get(hotel)
if (!peers) return
peers.forEach(client => {
if (client !== socket && client.readyState === 1) {
client.send(data)
}
})
})
socket.on('close', () => {
hotelRooms.get(hotel)?.delete(socket)
if (hotelRooms.get(hotel)?.size === 0) hotelRooms.delete(hotel)
})
},
)
}
export default ws