import { Router } from 'express'; import { authenticate } from '../../../middleware/auth.middleware'; import { requireRole } from '../../../middleware/rbac.middleware'; import { smsConversationsService } from './sms-conversations.service'; const router = Router(); router.use(authenticate, requireRole('SUPER_ADMIN', 'INFLUENCE_ADMIN')); // GET /api/sms/conversations — list conversations router.get('/', async (req, res, next) => { try { const page = Math.max(1, Number(req.query.page) || 1); const limit = Math.min(100, Math.max(1, Number(req.query.limit) || 50)); const result = await smsConversationsService.findAll({ page, limit, search: req.query.search as string | undefined, status: req.query.status as string | undefined, campaignId: req.query.campaignId as string | undefined, unreadOnly: req.query.unreadOnly === 'true', }); res.json(result); } catch (err) { next(err); } }); // GET /api/sms/conversations/contact-search — search contacts for new conversation router.get('/contact-search', async (req, res, next) => { try { const q = (req.query.q as string || '').trim(); if (q.length < 2) { res.json({ results: [] }); return; } const results = await smsConversationsService.searchContacts(q); res.json({ results }); } catch (err) { next(err); } }); // POST /api/sms/conversations — start new conversation router.post('/', async (req, res, next) => { try { const { phone, message, contactName, contactId } = req.body as { phone?: string; message?: string; contactName?: string; contactId?: string; }; if (!phone || typeof phone !== 'string' || phone.replace(/\D/g, '').length < 7) { res.status(400).json({ error: 'Valid phone number is required (min 7 digits)' }); return; } if (!message || typeof message !== 'string' || message.trim().length === 0) { res.status(400).json({ error: 'Message is required' }); return; } if (message.length > 1600) { res.status(400).json({ error: 'Message cannot exceed 1600 characters' }); return; } const conversation = await smsConversationsService.startConversation({ phone, message: message.trim(), contactName, contactId, }); res.status(201).json(conversation); } catch (err: any) { if (err.statusCode === 409) { res.status(409).json({ error: err.message }); return; } if (err.statusCode === 400) { res.status(400).json({ error: err.message }); return; } next(err); } }); // GET /api/sms/conversations/stats — conversation stats router.get('/stats', async (_req, res, next) => { try { const stats = await smsConversationsService.getStats(); res.json(stats); } catch (err) { next(err); } }); // GET /api/sms/conversations/:id — single conversation with messages router.get('/:id', async (req, res, next) => { try { const conversation = await smsConversationsService.findById(req.params.id as string); if (!conversation) { res.status(404).json({ error: 'Conversation not found' }); return; } res.json(conversation); } catch (err) { next(err); } }); // POST /api/sms/conversations/:id/read — mark conversation as read router.post('/:id/read', async (req, res, next) => { try { await smsConversationsService.markRead(req.params.id as string); res.json({ success: true }); } catch (err) { next(err); } }); // PUT /api/sms/conversations/:id/notes — update notes router.put('/:id/notes', async (req, res, next) => { try { const { notes } = req.body as { notes: string }; const conversation = await smsConversationsService.updateNotes(req.params.id as string, notes || ''); res.json(conversation); } catch (err) { next(err); } }); // PUT /api/sms/conversations/:id/tags — update tags router.put('/:id/tags', async (req, res, next) => { try { const { tags } = req.body as { tags: string[] }; const conversation = await smsConversationsService.updateTags(req.params.id as string, tags || []); res.json(conversation); } catch (err) { next(err); } }); // POST /api/sms/conversations/:id/reply — send reply router.post('/:id/reply', async (req, res, next) => { try { const { message } = req.body as { message: string }; if (!message || typeof message !== 'string') { res.status(400).json({ error: 'Message is required' }); return; } const smsMessage = await smsConversationsService.reply(req.params.id as string, message); res.json(smsMessage); } catch (err) { next(err); } }); // --- Bulk Actions --- // POST /api/sms/conversations/bulk-read — mark multiple conversations as read router.post('/bulk-read', async (req, res, next) => { try { const { ids } = req.body as { ids: string[] }; if (!Array.isArray(ids) || ids.length === 0) { res.status(400).json({ error: 'ids array is required' }); return; } const result = await smsConversationsService.bulkMarkRead(ids); res.json(result); } catch (err) { next(err); } }); // POST /api/sms/conversations/bulk-close — close multiple conversations router.post('/bulk-close', async (req, res, next) => { try { const { ids } = req.body as { ids: string[] }; if (!Array.isArray(ids) || ids.length === 0) { res.status(400).json({ error: 'ids array is required' }); return; } const result = await smsConversationsService.bulkClose(ids); res.json(result); } catch (err) { next(err); } }); export const smsConversationsRouter = router;