import { NOTIFICATION_EVENTS } from '../../../shared/constants/notification-events.js' import { prisma } from '../lib/prisma.js' export async function registerUserMessageRoutes(fastify) { fastify.get('/api/me/orders/:id/messages', { preHandler: [fastify.authenticate] }, async (request, reply) => { const userId = request.user.sub const { id } = request.params const order = await prisma.order.findFirst({ where: { id, userId } }) if (!order) return reply.code(404).send({ error: 'Заказ не найден' }) const items = await prisma.orderMessage.findMany({ where: { orderId: id }, orderBy: { createdAt: 'asc' }, }) return { items } }) fastify.post('/api/me/orders/:id/messages', { preHandler: [fastify.authenticate] }, async (request, reply) => { const userId = request.user.sub const { id } = request.params const order = await prisma.order.findFirst({ where: { id, userId } }) if (!order) return reply.code(404).send({ error: 'Заказ не найден' }) const text = String(request.body?.text || '').trim() if (!text) return reply.code(400).send({ error: 'Сообщение пустое' }) if (text.length > 2000) return reply.code(400).send({ error: 'Сообщение слишком длинное' }) const msg = await prisma.orderMessage.create({ data: { orderId: id, authorType: 'user', text }, }) request.server.eventBus.emit(NOTIFICATION_EVENTS.ORDER_MESSAGE_SENT, { orderId: id, authorType: 'user', messageId: msg.id, preview: text, }) return reply.code(201).send({ item: msg }) }) fastify.get('/api/me/messages/unread-count', { preHandler: [fastify.authenticate] }, async (request) => { const userId = request.user.sub const orders = await prisma.order.findMany({ where: { userId }, select: { id: true }, }) if (orders.length === 0) return { count: 0 } const orderIds = orders.map((o) => o.id) const readStates = await prisma.userOrderMessageReadState.findMany({ where: { userId }, }) const lastReadByOrder = new Map(readStates.map((r) => [r.orderId, r.lastReadAt])) const adminMessages = await prisma.orderMessage.findMany({ where: { orderId: { in: orderIds }, authorType: 'admin' }, select: { orderId: true, createdAt: true }, }) let count = 0 for (const msg of adminMessages) { const lastRead = lastReadByOrder.get(msg.orderId) ?? new Date(0) if (msg.createdAt > lastRead) count++ } return { count } }) fastify.get('/api/me/conversations', { preHandler: [fastify.authenticate] }, async (request) => { const userId = request.user.sub const orders = await prisma.order.findMany({ where: { userId, messages: { some: {} } }, select: { id: true, status: true, deliveryType: true, messages: { orderBy: { createdAt: 'desc' }, take: 1, select: { text: true, createdAt: true }, }, }, orderBy: { updatedAt: 'desc' }, }) const readStates = await prisma.userOrderMessageReadState.findMany({ where: { userId }, }) const lastReadByOrder = new Map(readStates.map((r) => [r.orderId, r.lastReadAt])) const orderIds = orders.map((o) => o.id) const unreadCounts = new Map() if (orderIds.length > 0) { const adminMessages = await prisma.orderMessage.findMany({ where: { orderId: { in: orderIds }, authorType: 'admin' }, select: { orderId: true, createdAt: true }, }) for (const msg of adminMessages) { const lastRead = lastReadByOrder.get(msg.orderId) ?? new Date(0) if (msg.createdAt > lastRead) { unreadCounts.set(msg.orderId, (unreadCounts.get(msg.orderId) ?? 0) + 1) } } } const items = [] for (const o of orders) { const lastMsg = o.messages[0] if (!lastMsg) continue items.push({ orderId: o.id, status: o.status, deliveryType: o.deliveryType, lastMessageAt: lastMsg.createdAt, preview: lastMsg.text.length > 280 ? `${lastMsg.text.slice(0, 277)}…` : lastMsg.text, unreadCount: unreadCounts.get(o.id) ?? 0, }) } return { items } }) fastify.post('/api/me/orders/:id/messages/read', { preHandler: [fastify.authenticate] }, async (request, reply) => { const userId = request.user.sub const { id } = request.params const order = await prisma.order.findFirst({ where: { id, userId } }) if (!order) return reply.code(404).send({ error: 'Заказ не найден' }) const now = new Date() await prisma.userOrderMessageReadState.upsert({ where: { userId_orderId: { userId, orderId: id } }, create: { userId, orderId: id, lastReadAt: now }, update: { lastReadAt: now }, }) return { ok: true } }) }