Files
shop-server/server/src/routes/user-messages.js
T
2026-05-21 14:22:03 +05:00

134 lines
4.8 KiB
JavaScript

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 }
})
}