feat: chat — search, notifications room, settings

- Migration 071: nullable sender_id, is_system flag, notifications room type
- Backend: notifications room auto-created per hotel, search messages endpoint,
  notify endpoint (manager/admin posts system messages), read-only enforcement
- API: ChatSearchResult type, chat.search(), chat.notify(), updated ChatMessage type
- Frontend ChatWidget: search view (people + messages tabs), settings panel
  (notifications visibility toggle, sound toggle), notifications room (bell icon,
  read-only banner, amber styling for system messages), new-chat button

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-14 11:25:40 +03:00
parent 291d45622b
commit 3c4c40da44
4 changed files with 594 additions and 88 deletions

View File

@@ -340,7 +340,11 @@ export const api = {
markRead: (slug: string, roomId: string) =>
req<{ ok: boolean }>('PATCH', `/api/hotels/${slug}/chat/rooms/${roomId}/read`),
openDirect: (slug: string, otherUserId: string) =>
req<{ room_id: string }>('POST', `/api/hotels/${slug}/chat/direct/${otherUserId}`),
req<{ roomId: string }>('POST', `/api/hotels/${slug}/chat/direct/${otherUserId}`),
search: (slug: string, q: string) =>
req<ChatSearchResult[]>('GET', `/api/hotels/${slug}/chat/search?q=${encodeURIComponent(q)}`),
notify: (slug: string, text: string, systemName?: string) =>
req<ChatMessage>('POST', `/api/hotels/${slug}/chat/notify`, { text, system_name: systemName }),
},
// ── Workstations ──────────────────────────────────────────────────────────
@@ -1302,7 +1306,7 @@ export interface LoyaltyTransaction {
export interface ChatRoom {
id: string
type: 'general' | 'direct'
type: 'general' | 'direct' | 'notifications'
name: string | null
unreadCount: number
lastMessage: string | null
@@ -1315,11 +1319,24 @@ export interface ChatRoom {
export interface ChatMessage {
id: string
roomId: string
senderId: string
senderId: string | null
senderName: string
senderRole: string
text: string
createdAt: string
isSystem: boolean
systemName: string | null
}
export interface ChatSearchResult {
id: string
roomId: string
text: string
createdAt: string
senderName: string
roomType: 'general' | 'direct' | 'notifications'
roomName: string | null
otherUserName: string | null
}
export interface WorkstationDevice {