feat: implement per-user soft delete for conversations with automatic restoration on new messages
This commit is contained in:
@@ -507,6 +507,10 @@ model Conversation {
|
||||
userClearedAt DateTime?
|
||||
agentClearedAt DateTime?
|
||||
|
||||
// Soft delete (per-user) — conversation hidden for that user until a new message arrives
|
||||
userDeletedAt DateTime?
|
||||
agentDeletedAt DateTime?
|
||||
|
||||
// Timestamps
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@ -140,6 +140,21 @@ export class MessagesService {
|
||||
},
|
||||
include: conversationInclude,
|
||||
});
|
||||
} else {
|
||||
// Clear soft-delete flag for the caller so the conversation reappears
|
||||
const needsClear = callerRole === UserRole.AGENT
|
||||
? conversation.agentDeletedAt !== null
|
||||
: conversation.userDeletedAt !== null;
|
||||
|
||||
if (needsClear) {
|
||||
conversation = await this.prisma.conversation.update({
|
||||
where: { id: conversation.id },
|
||||
data: callerRole === UserRole.AGENT
|
||||
? { agentDeletedAt: null }
|
||||
: { userDeletedAt: null },
|
||||
include: conversationInclude,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Transform to include otherParty based on caller role
|
||||
@@ -275,6 +290,9 @@ export class MessagesService {
|
||||
...(isUser
|
||||
? { agentUnreadCount: { increment: 1 } }
|
||||
: { userUnreadCount: { increment: 1 } }),
|
||||
// Clear soft-delete flags so conversation reappears for both parties
|
||||
userDeletedAt: null,
|
||||
agentDeletedAt: null,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -315,7 +333,10 @@ export class MessagesService {
|
||||
}
|
||||
|
||||
conversations = await this.prisma.conversation.findMany({
|
||||
where: { agentProfileId: agentProfile.id },
|
||||
where: {
|
||||
agentProfileId: agentProfile.id,
|
||||
agentDeletedAt: null, // Exclude soft-deleted conversations
|
||||
},
|
||||
include: {
|
||||
user: {
|
||||
select: {
|
||||
@@ -362,7 +383,10 @@ export class MessagesService {
|
||||
} else {
|
||||
// Regular user
|
||||
conversations = await this.prisma.conversation.findMany({
|
||||
where: { userId },
|
||||
where: {
|
||||
userId,
|
||||
userDeletedAt: null, // Exclude soft-deleted conversations
|
||||
},
|
||||
include: {
|
||||
agentProfile: {
|
||||
select: {
|
||||
@@ -781,13 +805,17 @@ export class MessagesService {
|
||||
throw new ForbiddenException('You are not part of this conversation');
|
||||
}
|
||||
|
||||
// Delete all messages first, then the conversation
|
||||
await this.prisma.message.deleteMany({
|
||||
where: { conversationId },
|
||||
});
|
||||
// Soft delete: mark conversation as deleted for this user only
|
||||
// The other party still sees the conversation and all messages.
|
||||
// If a new message arrives later, the deletedAt flag is cleared so
|
||||
// the conversation reappears for the user who deleted it.
|
||||
const now = new Date();
|
||||
|
||||
await this.prisma.conversation.delete({
|
||||
await this.prisma.conversation.update({
|
||||
where: { id: conversationId },
|
||||
data: isUser
|
||||
? { userDeletedAt: now, userClearedAt: now, userUnreadCount: 0 }
|
||||
: { agentDeletedAt: now, agentClearedAt: now, agentUnreadCount: 0 },
|
||||
});
|
||||
|
||||
return null;
|
||||
|
||||
Reference in New Issue
Block a user