134 lines
4.8 KiB
JavaScript
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 }
|
|
})
|
|
}
|