From 0eb1810246923fc40a6e93258f8effd2829489dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=B7=E7=94=B5=E8=8A=BD=E8=A1=A3?= Date: Thu, 21 May 2026 20:32:25 -0400 Subject: [PATCH] Stabilize chat read-state effect against snapshot reloads MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit useSnapshot now memoizes the actions object so dependants don't see a fresh reference on every render. ChatPage's mark-read effect keys off activeSpaceId/latestActiveMessageId primitives instead of the snapshot objects that re-allocate on reload, which prevents the markRead → reload → rerender loop that was deadlocking the Electron click path under Playwright. Also constrains HomePage agenda time to same-day activity so the 'Today' column doesn't surface a meaningless wall-clock for older tasks. --- .../src/renderer/src/app/useSnapshot.ts | 5 +++-- .../src/renderer/src/pages/ChatPage.tsx | 12 ++++++------ .../src/renderer/src/pages/HomePage.tsx | 13 ++++++++++++- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/AgentCompany-New/src/renderer/src/app/useSnapshot.ts b/AgentCompany-New/src/renderer/src/app/useSnapshot.ts index c824661c..9eee91a1 100644 --- a/AgentCompany-New/src/renderer/src/app/useSnapshot.ts +++ b/AgentCompany-New/src/renderer/src/app/useSnapshot.ts @@ -1,4 +1,4 @@ -import { useCallback, useEffect, useState } from "react"; +import { useCallback, useEffect, useMemo, useState } from "react"; import type { AppSnapshot } from "../../../shared/domain"; import type { DesktopResult } from "../../../shared/result"; @@ -35,5 +35,6 @@ export function useSnapshot(): { }); }, [load]); - return { snapshot, actions: { run, reload: load } }; + const actions = useMemo(() => ({ run, reload: load }), [run, load]); + return { snapshot, actions }; } diff --git a/AgentCompany-New/src/renderer/src/pages/ChatPage.tsx b/AgentCompany-New/src/renderer/src/pages/ChatPage.tsx index 54c95791..127c13a1 100644 --- a/AgentCompany-New/src/renderer/src/pages/ChatPage.tsx +++ b/AgentCompany-New/src/renderer/src/pages/ChatPage.tsx @@ -47,20 +47,20 @@ export function ChatPage({ snapshot, actions }: PageProps) { : fallbackSpaceId; const activeSpace = spaces.find((space) => space.id === activeSpaceId) ?? null; const latestActiveMessageId = useMemo(() => { - if (!activeSpace) return null; - const inSpace = messagesAll.filter((message) => message.spaceId === activeSpace.id); + if (!activeSpaceId) return null; + const inSpace = messagesAll.filter((message) => message.spaceId === activeSpaceId); if (inSpace.length === 0) return null; return inSpace[inSpace.length - 1].id; - }, [messagesAll, activeSpace]); + }, [messagesAll, activeSpaceId]); useEffect(() => { - if (!activeSpace || !latestActiveMessageId) return; + if (!activeSpaceId || !latestActiveMessageId) return; void actions.run(() => window.agentCompany.markChatSpaceRead({ orgId, employeeId: employee.id, - spaceId: activeSpace.id, + spaceId: activeSpaceId, })); - }, [activeSpace, latestActiveMessageId, orgId, employee.id, actions]); + }, [activeSpaceId, latestActiveMessageId, orgId, employee.id, actions]); const messagesInSpace = useMemo( () => (activeSpace ? messagesAll.filter((m) => m.spaceId === activeSpace.id) : []), diff --git a/AgentCompany-New/src/renderer/src/pages/HomePage.tsx b/AgentCompany-New/src/renderer/src/pages/HomePage.tsx index d748799c..dddf79e8 100644 --- a/AgentCompany-New/src/renderer/src/pages/HomePage.tsx +++ b/AgentCompany-New/src/renderer/src/pages/HomePage.tsx @@ -102,7 +102,7 @@ function TodayCard({ {rows.map((task) => { const owner = agents.find((agent) => agent.id === task.assigneeAgentId); const ownerName = owner?.name ?? employee.displayName; - const time = formatTime(task.updatedAt); + const time = agendaTime(task, date); const requiresApproval = approvals.some((approval) => approval.title === task.title); return (
@@ -279,6 +279,17 @@ function GoalCard({ ); } +function agendaTime(task: TaskRecord, reference: Date): string { + const updated = new Date(task.updatedAt); + if (Number.isNaN(updated.getTime())) return "—"; + const sameDay = + updated.getFullYear() === reference.getFullYear() && + updated.getMonth() === reference.getMonth() && + updated.getDate() === reference.getDate(); + if (!sameDay) return "—"; + return formatTime(task.updatedAt); +} + function collectAgendaTasks(tasks: TaskRecord[], reference: Date): TaskRecord[] { const startOfDay = new Date(reference.getFullYear(), reference.getMonth(), reference.getDate()).getTime(); const endOfDay = startOfDay + 24 * 60 * 60 * 1000;