feat: Implement real-time message delivery for conversations via WebSocket integration and update admin seed email.
This commit is contained in:
@@ -1317,7 +1317,7 @@ async function main() {
|
|||||||
// =============================================
|
// =============================================
|
||||||
console.log('👤 Seeding Admin User...');
|
console.log('👤 Seeding Admin User...');
|
||||||
|
|
||||||
const adminEmail = process.env.ADMIN_EMAIL || 'admin@realestate.com';
|
const adminEmail = process.env.ADMIN_EMAIL || 'admin@re-quest.com';
|
||||||
const adminPassword = process.env.ADMIN_PASSWORD || 'Admin@123456';
|
const adminPassword = process.env.ADMIN_PASSWORD || 'Admin@123456';
|
||||||
|
|
||||||
// Hash password with Argon2 (more secure than bcrypt)
|
// Hash password with Argon2 (more secure than bcrypt)
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import {
|
|||||||
ApiParam,
|
ApiParam,
|
||||||
} from '@nestjs/swagger';
|
} from '@nestjs/swagger';
|
||||||
import { MessagesService } from './messages.service';
|
import { MessagesService } from './messages.service';
|
||||||
|
import { MessagesGateway } from './messages.gateway';
|
||||||
import { CreateMessageDto, StartConversationDto } from './dto';
|
import { CreateMessageDto, StartConversationDto } from './dto';
|
||||||
import { JwtAuthGuard } from '../auth/guards';
|
import { JwtAuthGuard } from '../auth/guards';
|
||||||
import { CurrentUser } from '../auth/decorators';
|
import { CurrentUser } from '../auth/decorators';
|
||||||
@@ -30,7 +31,10 @@ import { UserRole } from '@prisma/client';
|
|||||||
@UseGuards(JwtAuthGuard)
|
@UseGuards(JwtAuthGuard)
|
||||||
@ApiBearerAuth('JWT-auth')
|
@ApiBearerAuth('JWT-auth')
|
||||||
export class MessagesController {
|
export class MessagesController {
|
||||||
constructor(private readonly messagesService: MessagesService) {}
|
constructor(
|
||||||
|
private readonly messagesService: MessagesService,
|
||||||
|
private readonly messagesGateway: MessagesGateway,
|
||||||
|
) {}
|
||||||
|
|
||||||
// ==========================================
|
// ==========================================
|
||||||
// GET CONVERSATIONS LIST
|
// GET CONVERSATIONS LIST
|
||||||
@@ -177,7 +181,23 @@ export class MessagesController {
|
|||||||
@CurrentUser('id') userId: string,
|
@CurrentUser('id') userId: string,
|
||||||
@Body() dto: CreateMessageDto,
|
@Body() dto: CreateMessageDto,
|
||||||
) {
|
) {
|
||||||
return this.messagesService.createMessage(conversationId, userId, dto);
|
const message = await this.messagesService.createMessage(conversationId, userId, dto);
|
||||||
|
|
||||||
|
// Broadcast via WebSocket so the other party gets real-time delivery
|
||||||
|
try {
|
||||||
|
const participants = await this.messagesService.getConversationParticipants(conversationId);
|
||||||
|
if (participants) {
|
||||||
|
const otherUserId = userId === participants.userId
|
||||||
|
? participants.agentUserId
|
||||||
|
: participants.userId;
|
||||||
|
// Send to the other participant's socket(s)
|
||||||
|
this.messagesGateway.sendToUser(otherUserId, 'new_message', message);
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// Socket broadcast failure shouldn't fail the REST response
|
||||||
|
}
|
||||||
|
|
||||||
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==========================================
|
// ==========================================
|
||||||
|
|||||||
@@ -175,13 +175,8 @@ export class MessagesGateway implements OnGatewayConnection, OnGatewayDisconnect
|
|||||||
data.message,
|
data.message,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Broadcast to other clients in the conversation room (exclude sender)
|
// Send directly to the other participant's socket(s)
|
||||||
client
|
// This is the primary delivery mechanism — works even if they haven't joined the room
|
||||||
.to(`conversation:${data.conversationId}`)
|
|
||||||
.emit('new_message', message);
|
|
||||||
|
|
||||||
// Also send directly to the other participant's socket(s)
|
|
||||||
// so they receive the message even if they haven't joined this room
|
|
||||||
try {
|
try {
|
||||||
const participants = await this.messagesService.getConversationParticipants(data.conversationId);
|
const participants = await this.messagesService.getConversationParticipants(data.conversationId);
|
||||||
if (participants) {
|
if (participants) {
|
||||||
@@ -194,6 +189,12 @@ export class MessagesGateway implements OnGatewayConnection, OnGatewayDisconnect
|
|||||||
this.logger.warn(`Failed to get participants for direct delivery in ${data.conversationId}: ${participantError.message}`);
|
this.logger.warn(`Failed to get participants for direct delivery in ${data.conversationId}: ${participantError.message}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Also broadcast to the conversation room as a fallback
|
||||||
|
// (client.to excludes sender; recipients dedup by message ID)
|
||||||
|
client
|
||||||
|
.to(`conversation:${data.conversationId}`)
|
||||||
|
.emit('new_message', message);
|
||||||
|
|
||||||
return { success: true, message };
|
return { success: true, message };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return { error: error.message };
|
return { error: error.message };
|
||||||
|
|||||||
Reference in New Issue
Block a user