perf(renderer): memoize active task summary data

This commit is contained in:
777genius 2026-05-31 06:25:28 +03:00
parent 34c2215c31
commit 477d18d798

View file

@ -1,4 +1,4 @@
import { memo, type ReactNode, useState } from 'react'; import { memo, type ReactNode, useMemo, useState } from 'react';
import { useAppTranslation } from '@features/localization/renderer'; import { useAppTranslation } from '@features/localization/renderer';
import { CARD_BG, CARD_BORDER_STYLE, CARD_ICON_MUTED } from '@renderer/constants/cssVariables'; import { CARD_BG, CARD_BORDER_STYLE, CARD_ICON_MUTED } from '@renderer/constants/cssVariables';
@ -46,33 +46,45 @@ export const ActiveTasksBlock = memo(function ActiveTasksBlock({
const { t } = useAppTranslation('team'); const { t } = useAppTranslation('team');
const { isLight } = useTheme(); const { isLight } = useTheme();
const [collapsed, setCollapsed] = useState(defaultCollapsed); const [collapsed, setCollapsed] = useState(defaultCollapsed);
const colorMap = buildMemberColorMap(members);
const avatarMap = buildMemberAvatarMap(members);
const taskMap = new Map(tasks.map((t) => [t.id, t]));
const entries: ActivityEntry[] = []; const colorMap = useMemo(() => buildMemberColorMap(members), [members]);
const avatarMap = useMemo(() => buildMemberAvatarMap(members), [members]);
// Members working on tasks const entries = useMemo<ActivityEntry[]>(() => {
const workingMemberNames = new Set<string>(); const taskMap = new Map(tasks.map((task) => [task.id, task]));
for (const m of members) { const reviewTaskByReviewer = new Map<string, TeamTaskWithKanban>();
if (!m.currentTaskId) continue; for (const task of tasks) {
const task = taskMap.get(m.currentTaskId); if (!task.reviewer || getTeamTaskWorkflowColumn(task) !== 'review') continue;
// Defense-in-depth: hide stale currentTaskId until backend refresh clears it. if (!reviewTaskByReviewer.has(task.reviewer)) {
if (!isDisplayableCurrentTask(task)) continue; reviewTaskByReviewer.set(task.reviewer, task);
workingMemberNames.add(m.name); }
entries.push({ member: m, task, taskId: m.currentTaskId, kind: 'working' });
}
// Members reviewing tasks (only if not already shown as working)
for (const m of members) {
if (workingMemberNames.has(m.name)) continue;
const reviewTask = tasks.find(
(t) => t.reviewer === m.name && getTeamTaskWorkflowColumn(t) === 'review'
);
if (reviewTask) {
entries.push({ member: m, task: reviewTask, taskId: reviewTask.id, kind: 'reviewing' });
} }
}
const nextEntries: ActivityEntry[] = [];
const workingMemberNames = new Set<string>();
for (const member of members) {
if (!member.currentTaskId) continue;
const task = taskMap.get(member.currentTaskId);
// Defense-in-depth: hide stale currentTaskId until backend refresh clears it.
if (!isDisplayableCurrentTask(task)) continue;
workingMemberNames.add(member.name);
nextEntries.push({ member, task, taskId: member.currentTaskId, kind: 'working' });
}
for (const member of members) {
if (workingMemberNames.has(member.name)) continue;
const reviewTask = reviewTaskByReviewer.get(member.name);
if (reviewTask) {
nextEntries.push({
member,
task: reviewTask,
taskId: reviewTask.id,
kind: 'reviewing',
});
}
}
return nextEntries;
}, [members, tasks]);
if (entries.length === 0) return null; if (entries.length === 0) return null;