feat(comments): implement mergeCommentsById function for comment deduplication and sorting
This commit is contained in:
@@ -243,6 +243,32 @@ const toLiveFeedFromComment = (comment: TaskCommentRead): LiveFeedItem => ({
|
|||||||
event_type: "task.comment",
|
event_type: "task.comment",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const mergeCommentsById = (...collections: TaskComment[][]): TaskComment[] => {
|
||||||
|
const byId = new Map<string, TaskComment>();
|
||||||
|
for (const collection of collections) {
|
||||||
|
for (const comment of collection) {
|
||||||
|
const existing = byId.get(comment.id);
|
||||||
|
if (!existing) {
|
||||||
|
byId.set(comment.id, comment);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const existingTime = apiDatetimeToMs(existing.created_at) ?? 0;
|
||||||
|
const incomingTime = apiDatetimeToMs(comment.created_at) ?? 0;
|
||||||
|
byId.set(
|
||||||
|
comment.id,
|
||||||
|
incomingTime >= existingTime
|
||||||
|
? { ...existing, ...comment }
|
||||||
|
: { ...comment, ...existing },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [...byId.values()].sort((a, b) => {
|
||||||
|
const aTime = apiDatetimeToMs(a.created_at) ?? 0;
|
||||||
|
const bTime = apiDatetimeToMs(b.created_at) ?? 0;
|
||||||
|
return bTime - aTime;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const toLiveFeedFromBoardChat = (memory: BoardChatMessage): LiveFeedItem => {
|
const toLiveFeedFromBoardChat = (memory: BoardChatMessage): LiveFeedItem => {
|
||||||
const content = (memory.content ?? "").trim();
|
const content = (memory.content ?? "").trim();
|
||||||
const actorName = resolveHumanActorName(memory.source, DEFAULT_HUMAN_LABEL);
|
const actorName = resolveHumanActorName(memory.source, DEFAULT_HUMAN_LABEL);
|
||||||
@@ -1694,35 +1720,9 @@ export default function BoardDetailPage() {
|
|||||||
) {
|
) {
|
||||||
return prev;
|
return prev;
|
||||||
}
|
}
|
||||||
const exists = prev.some(
|
return mergeCommentsById(prev, [
|
||||||
(item) => item.id === payload.comment?.id,
|
payload.comment as TaskComment,
|
||||||
);
|
]);
|
||||||
if (exists) {
|
|
||||||
return prev;
|
|
||||||
}
|
|
||||||
const createdMs = apiDatetimeToMs(
|
|
||||||
payload.comment?.created_at,
|
|
||||||
);
|
|
||||||
if (prev.length === 0 || createdMs === null) {
|
|
||||||
return [payload.comment as TaskComment, ...prev];
|
|
||||||
}
|
|
||||||
const first = prev[0];
|
|
||||||
const firstMs = apiDatetimeToMs(first?.created_at);
|
|
||||||
if (firstMs !== null && createdMs >= firstMs) {
|
|
||||||
return [payload.comment as TaskComment, ...prev];
|
|
||||||
}
|
|
||||||
const last = prev[prev.length - 1];
|
|
||||||
const lastMs = apiDatetimeToMs(last?.created_at);
|
|
||||||
if (lastMs !== null && createdMs <= lastMs) {
|
|
||||||
return [...prev, payload.comment as TaskComment];
|
|
||||||
}
|
|
||||||
const next = [...prev, payload.comment as TaskComment];
|
|
||||||
next.sort((a, b) => {
|
|
||||||
const aTime = apiDatetimeToMs(a.created_at) ?? 0;
|
|
||||||
const bTime = apiDatetimeToMs(b.created_at) ?? 0;
|
|
||||||
return bTime - aTime;
|
|
||||||
});
|
|
||||||
return next;
|
|
||||||
});
|
});
|
||||||
} else if (payload.task) {
|
} else if (payload.task) {
|
||||||
const incomingTask = payload.task;
|
const incomingTask = payload.task;
|
||||||
@@ -2337,13 +2337,7 @@ export default function BoardDetailPage() {
|
|||||||
taskId,
|
taskId,
|
||||||
);
|
);
|
||||||
if (result.status !== 200) throw new Error("Unable to load comments.");
|
if (result.status !== 200) throw new Error("Unable to load comments.");
|
||||||
const items = [...(result.data.items ?? [])];
|
setComments(mergeCommentsById(result.data.items ?? []));
|
||||||
items.sort((a, b) => {
|
|
||||||
const aTime = apiDatetimeToMs(a.created_at) ?? 0;
|
|
||||||
const bTime = apiDatetimeToMs(b.created_at) ?? 0;
|
|
||||||
return bTime - aTime;
|
|
||||||
});
|
|
||||||
setComments(items);
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setCommentsError(
|
setCommentsError(
|
||||||
err instanceof Error ? err.message : "Something went wrong.",
|
err instanceof Error ? err.message : "Something went wrong.",
|
||||||
@@ -2515,7 +2509,7 @@ export default function BoardDetailPage() {
|
|||||||
);
|
);
|
||||||
if (result.status !== 200) throw new Error("Unable to send message.");
|
if (result.status !== 200) throw new Error("Unable to send message.");
|
||||||
const created = result.data;
|
const created = result.data;
|
||||||
setComments((prev) => [created, ...prev]);
|
setComments((prev) => mergeCommentsById([created], prev));
|
||||||
return true;
|
return true;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
const message = formatActionError(err, "Unable to send message.");
|
const message = formatActionError(err, "Unable to send message.");
|
||||||
|
|||||||
Reference in New Issue
Block a user