Improve message interactions tracking

This commit is contained in:
Hakan Shehu
2025-01-13 16:23:36 +01:00
parent d63e2ee2d0
commit faa0554112
12 changed files with 56 additions and 30 deletions

View File

@@ -184,7 +184,8 @@ const createMessageInteractionsTable: Migration = {
.addColumn('message_id', 'text', (col) => col.notNull())
.addColumn('collaborator_id', 'text', (col) => col.notNull())
.addColumn('root_id', 'text', (col) => col.notNull())
.addColumn('seen_at', 'text')
.addColumn('first_seen_at', 'text')
.addColumn('last_seen_at', 'text')
.addColumn('first_opened_at', 'text')
.addColumn('last_opened_at', 'text')
.addColumn('version', 'integer', (col) => col.notNull())

View File

@@ -138,7 +138,8 @@ interface MessageInteractionTable {
message_id: ColumnType<string, string, never>;
collaborator_id: ColumnType<string, string, never>;
root_id: ColumnType<string, string, string>;
seen_at: ColumnType<string | null, string | null, string | null>;
first_seen_at: ColumnType<string | null, string | null, string | null>;
last_seen_at: ColumnType<string | null, string | null, string | null>;
first_opened_at: ColumnType<string | null, string | null, string | null>;
last_opened_at: ColumnType<string | null, string | null, string | null>;
version: ColumnType<bigint, bigint, bigint>;

View File

@@ -38,12 +38,23 @@ export class MessageMarkSeenMutationHandler
.where('collaborator_id', '=', input.userId)
.executeTakeFirst();
if (existingInteraction && existingInteraction.seen_at !== null) {
return {
success: true,
};
if (existingInteraction) {
const lastSeenAt = existingInteraction.last_seen_at;
if (
lastSeenAt &&
lastSeenAt > new Date(Date.now() - 5 * 1000).toISOString()
) {
return {
success: true,
};
}
}
const lastSeenAt = new Date().toISOString();
const firstSeenAt = existingInteraction
? existingInteraction.first_seen_at
: lastSeenAt;
const { createdInteraction, createdMutation } = await workspaceDatabase
.transaction()
.execute(async (trx) => {
@@ -53,17 +64,16 @@ export class MessageMarkSeenMutationHandler
.values({
message_id: input.messageId,
collaborator_id: input.userId,
seen_at: new Date().toISOString(),
first_seen_at: firstSeenAt,
last_seen_at: lastSeenAt,
version: 0n,
root_id: message.root_id,
})
.onConflict((b) =>
b
.columns(['message_id', 'collaborator_id'])
.doUpdateSet({
seen_at: new Date().toISOString(),
})
.where('seen_at', 'is', null)
b.columns(['message_id', 'collaborator_id']).doUpdateSet({
first_seen_at: firstSeenAt,
last_seen_at: lastSeenAt,
})
)
.executeTakeFirst();

View File

@@ -268,16 +268,18 @@ class MessageService {
message_id: messageInteraction.messageId,
collaborator_id: messageInteraction.collaboratorId,
root_id: messageInteraction.rootId,
seen_at: messageInteraction.seenAt,
last_opened_at: messageInteraction.lastOpenedAt,
first_seen_at: messageInteraction.firstSeenAt,
last_seen_at: messageInteraction.lastSeenAt,
first_opened_at: messageInteraction.firstOpenedAt,
last_opened_at: messageInteraction.lastOpenedAt,
version,
})
.onConflict((b) =>
b.columns(['message_id', 'collaborator_id']).doUpdateSet({
seen_at: messageInteraction.seenAt,
last_opened_at: messageInteraction.lastOpenedAt,
first_seen_at: messageInteraction.firstSeenAt,
last_seen_at: messageInteraction.lastSeenAt,
first_opened_at: messageInteraction.firstOpenedAt,
last_opened_at: messageInteraction.lastOpenedAt,
version,
})
)

View File

@@ -124,7 +124,7 @@ class RadarWorkspace {
)
.select(['message.id as message_id', 'message.entry_id as entry_id'])
.where('message.created_by', '!=', this.workspace.userId)
.where('message_interactions.seen_at', 'is', null)
.where('message_interactions.last_seen_at', 'is', null)
.where('entry_interactions.last_seen_at', 'is not', null)
.whereRef('message.created_at', '>=', 'entry_interactions.first_seen_at')
.execute();
@@ -149,7 +149,7 @@ class RadarWorkspace {
return;
}
if (interaction.seenAt) {
if (interaction.lastSeenAt) {
const unreadMessage = this.unreadMessages.get(interaction.messageId);
if (unreadMessage) {
this.unreadMessages.delete(interaction.messageId);
@@ -187,7 +187,7 @@ class RadarWorkspace {
.where('collaborator_id', '=', this.workspace.userId)
.executeTakeFirst();
if (messageInteraction && messageInteraction.seen_at) {
if (messageInteraction && messageInteraction.last_seen_at) {
return;
}

View File

@@ -345,7 +345,9 @@ export const mapMessageInteraction = (
messageId: row.message_id,
collaboratorId: row.collaborator_id,
rootId: row.root_id,
seenAt: row.seen_at,
firstSeenAt: row.first_seen_at,
lastSeenAt: row.last_seen_at,
firstOpenedAt: row.first_opened_at,
lastOpenedAt: row.last_opened_at,
version: row.version,
};

View File

@@ -31,7 +31,9 @@ export type MessageInteraction = {
messageId: string;
collaboratorId: string;
rootId: string;
seenAt: string | null;
firstSeenAt: string | null;
lastSeenAt: string | null;
firstOpenedAt: string | null;
lastOpenedAt: string | null;
version: bigint;
};

View File

@@ -506,7 +506,8 @@ const createMessageInteractionsTable: Migration = {
.addColumn('collaborator_id', 'varchar(30)', (col) => col.notNull())
.addColumn('root_id', 'varchar(30)', (col) => col.notNull())
.addColumn('workspace_id', 'varchar(30)', (col) => col.notNull())
.addColumn('seen_at', 'timestamptz')
.addColumn('first_seen_at', 'timestamptz')
.addColumn('last_seen_at', 'timestamptz')
.addColumn('first_opened_at', 'timestamptz')
.addColumn('last_opened_at', 'timestamptz')
.addColumn('version', 'bigint', (col) =>

View File

@@ -213,7 +213,8 @@ interface MessageInteractionTable {
collaborator_id: ColumnType<string, string, never>;
root_id: ColumnType<string, string, never>;
workspace_id: ColumnType<string, string, never>;
seen_at: ColumnType<Date | null, Date | null, Date | null>;
first_seen_at: ColumnType<Date | null, Date | null, Date | null>;
last_seen_at: ColumnType<Date | null, Date | null, Date | null>;
first_opened_at: ColumnType<Date | null, Date | null, Date | null>;
last_opened_at: ColumnType<Date | null, Date | null, Date | null>;
version: ColumnType<bigint, never, never>;

View File

@@ -345,25 +345,29 @@ class MessageService {
if (
existingInteraction &&
existingInteraction.seen_at !== null &&
existingInteraction.seen_at <= new Date(mutation.data.seenAt)
existingInteraction.last_seen_at !== null &&
existingInteraction.last_seen_at >= new Date(mutation.data.seenAt)
) {
return true;
}
const lastSeenAt = new Date(mutation.data.seenAt);
const firstSeenAt = existingInteraction?.first_seen_at ?? lastSeenAt;
const createdInteraction = await database
.insertInto('message_interactions')
.returningAll()
.values({
message_id: mutation.data.messageId,
collaborator_id: user.id,
seen_at: new Date(mutation.data.seenAt),
first_seen_at: firstSeenAt,
last_seen_at: lastSeenAt,
root_id: root.id,
workspace_id: root.workspace_id,
})
.onConflict((b) =>
b.columns(['message_id', 'collaborator_id']).doUpdateSet({
seen_at: new Date(mutation.data.seenAt),
last_seen_at: lastSeenAt,
first_seen_at: firstSeenAt,
})
)
.executeTakeFirst();

View File

@@ -60,7 +60,8 @@ export class MessageInteractionSynchronizer extends BaseSynchronizer<SyncMessage
(messageInteraction) => ({
messageId: messageInteraction.message_id,
collaboratorId: messageInteraction.collaborator_id,
seenAt: messageInteraction.seen_at?.toISOString() ?? null,
firstSeenAt: messageInteraction.first_seen_at?.toISOString() ?? null,
lastSeenAt: messageInteraction.last_seen_at?.toISOString() ?? null,
firstOpenedAt:
messageInteraction.first_opened_at?.toISOString() ?? null,
lastOpenedAt: messageInteraction.last_opened_at?.toISOString() ?? null,