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:
@@ -111,7 +111,7 @@ const chatRoutes: FastifyPluginAsync = async (fastify) => {
|
||||
|
||||
// ── GET messages ──────────────────────────────────────────────────────────
|
||||
|
||||
fastify.get<RoomParam & { Querystring: { limit?: string } }>(
|
||||
fastify.get<RoomParam & { Querystring: { limit?: string; before?: string } }>(
|
||||
'/api/hotels/:slug/chat/rooms/:roomId/messages',
|
||||
{ onRequest: [fastify.authenticate] },
|
||||
async (request, reply) => {
|
||||
@@ -122,8 +122,13 @@ const chatRoutes: FastifyPluginAsync = async (fastify) => {
|
||||
if (!hotelId) return reply.code(404).send({ error: 'Hotel not found' })
|
||||
|
||||
const limit = Math.min(Number(request.query.limit ?? 50), 100)
|
||||
const before = request.query.before // ISO timestamp cursor
|
||||
const userId = request.user.sub
|
||||
|
||||
const params: unknown[] = [roomId, hotelId, userId, limit]
|
||||
const beforeClause = before ? `AND m.created_at < $5` : ''
|
||||
if (before) params.push(before)
|
||||
|
||||
const { rows } = await db.query(
|
||||
`SELECT m.id, m.room_id, m.sender_id, m.text, m.created_at,
|
||||
m.is_system, m.system_name, m.attachment_url, m.edited_at, m.deleted_at,
|
||||
@@ -142,17 +147,20 @@ const chatRoutes: FastifyPluginAsync = async (fastify) => {
|
||||
) AS reactions
|
||||
FROM chat_messages m
|
||||
LEFT JOIN users u ON u.id = m.sender_id
|
||||
WHERE m.room_id = $1 AND m.hotel_id = $2
|
||||
WHERE m.room_id = $1 AND m.hotel_id = $2 ${beforeClause}
|
||||
ORDER BY m.created_at DESC
|
||||
LIMIT $4`,
|
||||
[roomId, hotelId, userId, limit],
|
||||
params,
|
||||
)
|
||||
|
||||
await db.query(
|
||||
`INSERT INTO chat_read_status (room_id, user_id, last_read) VALUES ($1, $2, NOW())
|
||||
ON CONFLICT (room_id, user_id) DO UPDATE SET last_read = NOW()`,
|
||||
[roomId, userId],
|
||||
)
|
||||
// Only mark read on initial load (no before cursor)
|
||||
if (!before) {
|
||||
await db.query(
|
||||
`INSERT INTO chat_read_status (room_id, user_id, last_read) VALUES ($1, $2, NOW())
|
||||
ON CONFLICT (room_id, user_id) DO UPDATE SET last_read = NOW()`,
|
||||
[roomId, userId],
|
||||
)
|
||||
}
|
||||
return rows.reverse()
|
||||
},
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user