refactor: unify read state handling in ActivityTimeline and TeamDetailView

- Consolidated the handling of read messages by introducing a `readState` prop in `ActivityTimeline`, which combines `readSet` and `getMessageKey`.
- Updated `TeamDetailView` to pass the new `readState` structure, improving clarity and reducing prop drilling.
- Enhanced unread message logic in `ActivityTimeline` to derive unread status from the new `readState` prop.
This commit is contained in:
iliya 2026-02-23 20:05:45 +02:00 committed by Илия
parent c3e4521cc8
commit 25b740c134
2 changed files with 17 additions and 10 deletions

View file

@ -723,8 +723,7 @@ export const TeamDetailView = ({ teamName }: TeamDetailViewProps): React.JSX.Ele
<ActivityTimeline <ActivityTimeline
messages={filteredMessages} messages={filteredMessages}
members={data.members} members={data.members}
readSet={readSet} readState={{ readSet, getMessageKey: toMessageKey }}
getMessageKey={toMessageKey}
onMemberClick={setSelectedMember} onMemberClick={setSelectedMember}
onCreateTaskFromMessage={(subject, description) => { onCreateTaskFromMessage={(subject, description) => {
openCreateTaskDialog(subject, description); openCreateTaskDialog(subject, description);

View file

@ -9,10 +9,11 @@ import type { InboxMessage, ResolvedTeamMember } from '@shared/types';
interface ActivityTimelineProps { interface ActivityTimelineProps {
messages: InboxMessage[]; messages: InboxMessage[];
members?: ResolvedTeamMember[]; members?: ResolvedTeamMember[];
/** Set of message keys that have been read; messages not in this set show an unread dot. */ /**
readSet?: Set<string>; * When provided, unread is derived from this set and getMessageKey.
/** Function to get a stable key for a message (used with readSet). */ * When omitted, unread is derived from message.read.
getMessageKey?: (message: InboxMessage) => string; */
readState?: { readSet: Set<string>; getMessageKey: (message: InboxMessage) => string };
onCreateTaskFromMessage?: (subject: string, description: string) => void; onCreateTaskFromMessage?: (subject: string, description: string) => void;
onReplyToMessage?: (message: InboxMessage) => void; onReplyToMessage?: (message: InboxMessage) => void;
onMemberClick?: (member: ResolvedTeamMember) => void; onMemberClick?: (member: ResolvedTeamMember) => void;
@ -92,8 +93,7 @@ const MessageRowWithObserver = ({
export const ActivityTimeline = ({ export const ActivityTimeline = ({
messages, messages,
members, members,
readSet, readState,
getMessageKey,
onCreateTaskFromMessage, onCreateTaskFromMessage,
onReplyToMessage, onReplyToMessage,
onMemberClick, onMemberClick,
@ -121,6 +121,13 @@ export const ActivityTimeline = ({
const resolvedLeadInfo = { role: leadInfo.role, color: teamLeadColor }; const resolvedLeadInfo = { role: leadInfo.role, color: teamLeadColor };
memberInfo.set('team-lead', resolvedLeadInfo); memberInfo.set('team-lead', resolvedLeadInfo);
memberInfo.set(leadMember.name, resolvedLeadInfo); memberInfo.set(leadMember.name, resolvedLeadInfo);
if (
leadMember.agentType &&
leadMember.agentType !== 'team-lead' &&
leadMember.agentType !== leadMember.name
) {
memberInfo.set(leadMember.agentType, resolvedLeadInfo);
}
} }
} }
} }
@ -147,8 +154,9 @@ export const ActivityTimeline = ({
const recipientColor = const recipientColor =
recipientInfo?.color ?? (message.to ? getMemberColorByName(message.to) : undefined); recipientInfo?.color ?? (message.to ? getMemberColorByName(message.to) : undefined);
const messageKey = `${message.messageId ?? index}-${message.timestamp}-${message.from}`; const messageKey = `${message.messageId ?? index}-${message.timestamp}-${message.from}`;
const isUnread = const isUnread = readState
readSet !== undefined && getMessageKey ? !readSet.has(getMessageKey(message)) : false; ? !readState.readSet.has(readState.getMessageKey(message))
: !message.read;
return ( return (
<MessageRowWithObserver <MessageRowWithObserver
key={messageKey} key={messageKey}