feat: chat pagination — infinite scroll / load older messages

- Backend: cursor-based pagination via ?before=<ISO timestamp>
- Frontend: auto-load when scrolling to top (<60px), spinner + manual 'Загрузить ещё' button
- Poll merge: preserves older history when new messages arrive from polling
- hasMoreMsgs flag: shown only when exactly 50 msgs returned (more may exist)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-14 16:35:38 +03:00
parent ef1fd4246e
commit e7ad9862ba
3 changed files with 77 additions and 22 deletions

View File

@@ -333,8 +333,10 @@ export const api = {
chat: {
listRooms: (slug: string) =>
req<ChatRoom[]>('GET', `/api/hotels/${slug}/chat/rooms`),
getMessages: (slug: string, roomId: string, limit = 50) =>
req<ChatMessage[]>('GET', `/api/hotels/${slug}/chat/rooms/${roomId}/messages?limit=${limit}`),
getMessages: (slug: string, roomId: string, limit = 50, before?: string) => {
const qs = before ? `?limit=${limit}&before=${encodeURIComponent(before)}` : `?limit=${limit}`
return req<ChatMessage[]>('GET', `/api/hotels/${slug}/chat/rooms/${roomId}/messages${qs}`)
},
sendMessage: (slug: string, roomId: string, text: string, attachmentUrl?: string) =>
req<ChatMessage>('POST', `/api/hotels/${slug}/chat/rooms/${roomId}/messages`, { text, ...(attachmentUrl ? { attachment_url: attachmentUrl } : {}) }),
uploadImage: async (file: File): Promise<{ url: string }> => {