Stabilize chat read-state effect against snapshot reloads
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.
This commit is contained in:
1 parent
1f78ae6f2e
commit
0eb1810246
3 files changed
+21
-9
No files matched your search
@@ -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<SnapshotActions>(() => ({ run, reload: load }), [run, load]);
|
||||
return { snapshot, actions };
|
||||
}
|
||||
@@ -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) : []),
|
||||
|
||||
@@ -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 (
|
||||
<div key={task.id} className="row" style={{ gap: 12 }}>
|
||||
@@ -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;
|
||||
|
||||
Reference in new issue
Block a user