Files
halobestie-clone/backend/src/routes/public/mitra.chat.routes.js
ramadhan sjamsani 4158fb9432 Phase 3.2 docs + Phase 3.1 testing fixes
- Add phase3.2.md requirement: overlay UX, mitra activity log
- Add phase3.2-plan.md implementation plan
- Fix stale request validation: add GET /:sessionId/status endpoint
- Fix notification tap flow: setIncomingFromNotification + onChatRequestTapped
- IncomingRequestSheet shows stale message instead of auto-dismiss
- Home screen validates on resume, shows immediately on fresh WS

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 22:09:25 +08:00

83 lines
3.7 KiB
JavaScript

import { authenticate } from '../../plugins/auth.js'
import { getMitraByFirebaseUid } from '../../services/mitra.service.js'
import { acceptPairingRequest, declinePairingRequest, getSessionStatus } from '../../services/pairing.service.js'
import { getActiveSessionsByMitra, getActiveSessionsByMitraWithUnread, endSession, getMitraHistory } from '../../services/session.service.js'
import { respondToExtension } from '../../services/extension.service.js'
import { EndedBy } from '../../constants.js'
const resolveMitra = async (request, reply) => {
const mitra = await getMitraByFirebaseUid(request.firebaseUser.uid)
if (!mitra) {
return reply.code(404).send({
success: false,
error: { code: 'ACCOUNT_NOT_FOUND', message: 'Mitra account not found' },
})
}
if (!mitra.is_active) {
return reply.code(403).send({
success: false,
error: { code: 'ACCOUNT_INACTIVE', message: 'Account is inactive' },
})
}
request.mitra = mitra
}
export const mitraChatRoutes = async (app) => {
// Check if a session is still pending acceptance (for notification validation)
app.get('/:sessionId/status', { preHandler: [authenticate, resolveMitra] }, async (request, reply) => {
const session = await getSessionStatus(request.params.sessionId)
if (!session) {
return reply.code(404).send({ success: false, error: { code: 'NOT_FOUND', message: 'Session not found' } })
}
return reply.send({ success: true, data: { status: session.status } })
})
app.post('/:sessionId/accept', { preHandler: [authenticate, resolveMitra] }, async (request, reply) => {
const session = await acceptPairingRequest(request.params.sessionId, request.mitra.id)
return reply.send({ success: true, data: session })
})
app.post('/:sessionId/decline', { preHandler: [authenticate, resolveMitra] }, async (request, reply) => {
await declinePairingRequest(request.params.sessionId, request.mitra.id)
return reply.send({ success: true })
})
app.get('/sessions/active', { preHandler: [authenticate, resolveMitra] }, async (request, reply) => {
const sessions = await getActiveSessionsByMitra(request.mitra.id)
return reply.send({ success: true, data: sessions })
})
app.get('/sessions/active-with-unread', { preHandler: [authenticate, resolveMitra] }, async (request, reply) => {
const sessions = await getActiveSessionsByMitraWithUnread(request.mitra.id)
return reply.send({ success: true, data: sessions })
})
app.post('/sessions/:sessionId/end', { preHandler: [authenticate, resolveMitra] }, async (request, reply) => {
const session = await endSession(request.params.sessionId, EndedBy.MITRA, request.mitra.id)
return reply.send({ success: true, data: session })
})
// Respond to extension request
app.post('/sessions/:sessionId/extend-response', { preHandler: [authenticate, resolveMitra] }, async (request, reply) => {
const { extension_id, accepted } = request.body || {}
if (!extension_id || accepted === undefined) {
return reply.code(400).send({
success: false,
error: { code: 'BAD_REQUEST', message: 'extension_id and accepted are required' },
})
}
const extension = await respondToExtension(extension_id, request.params.sessionId, request.mitra.id, accepted)
return reply.send({ success: true, data: extension })
})
// Chat history
app.get('/history', { preHandler: [authenticate, resolveMitra] }, async (request, reply) => {
const { page, limit } = request.query
const history = await getMitraHistory(request.mitra.id, {
page: page ? parseInt(page) : 1,
limit: limit ? parseInt(limit) : 20,
})
return reply.send({ success: true, data: history })
})
}