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 { AppSnapshot } from "../../../shared/domain";
|
||||||
import type { DesktopResult } from "../../../shared/result";
|
import type { DesktopResult } from "../../../shared/result";
|
||||||
|
|
||||||
@@ -35,5 +35,6 @@ export function useSnapshot(): {
|
|||||||
});
|
});
|
||||||
}, [load]);
|
}, [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;
|
: fallbackSpaceId;
|
||||||
const activeSpace = spaces.find((space) => space.id === activeSpaceId) ?? null;
|
const activeSpace = spaces.find((space) => space.id === activeSpaceId) ?? null;
|
||||||
const latestActiveMessageId = useMemo(() => {
|
const latestActiveMessageId = useMemo(() => {
|
||||||
if (!activeSpace) return null;
|
if (!activeSpaceId) return null;
|
||||||
const inSpace = messagesAll.filter((message) => message.spaceId === activeSpace.id);
|
const inSpace = messagesAll.filter((message) => message.spaceId === activeSpaceId);
|
||||||
if (inSpace.length === 0) return null;
|
if (inSpace.length === 0) return null;
|
||||||
return inSpace[inSpace.length - 1].id;
|
return inSpace[inSpace.length - 1].id;
|
||||||
}, [messagesAll, activeSpace]);
|
}, [messagesAll, activeSpaceId]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!activeSpace || !latestActiveMessageId) return;
|
if (!activeSpaceId || !latestActiveMessageId) return;
|
||||||
void actions.run(() => window.agentCompany.markChatSpaceRead({
|
void actions.run(() => window.agentCompany.markChatSpaceRead({
|
||||||
orgId,
|
orgId,
|
||||||
employeeId: employee.id,
|
employeeId: employee.id,
|
||||||
spaceId: activeSpace.id,
|
spaceId: activeSpaceId,
|
||||||
}));
|
}));
|
||||||
}, [activeSpace, latestActiveMessageId, orgId, employee.id, actions]);
|
}, [activeSpaceId, latestActiveMessageId, orgId, employee.id, actions]);
|
||||||
|
|
||||||
const messagesInSpace = useMemo(
|
const messagesInSpace = useMemo(
|
||||||
() => (activeSpace ? messagesAll.filter((m) => m.spaceId === activeSpace.id) : []),
|
() => (activeSpace ? messagesAll.filter((m) => m.spaceId === activeSpace.id) : []),
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ function TodayCard({
|
|||||||
{rows.map((task) => {
|
{rows.map((task) => {
|
||||||
const owner = agents.find((agent) => agent.id === task.assigneeAgentId);
|
const owner = agents.find((agent) => agent.id === task.assigneeAgentId);
|
||||||
const ownerName = owner?.name ?? employee.displayName;
|
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);
|
const requiresApproval = approvals.some((approval) => approval.title === task.title);
|
||||||
return (
|
return (
|
||||||
<div key={task.id} className="row" style={{ gap: 12 }}>
|
<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[] {
|
function collectAgendaTasks(tasks: TaskRecord[], reference: Date): TaskRecord[] {
|
||||||
const startOfDay = new Date(reference.getFullYear(), reference.getMonth(), reference.getDate()).getTime();
|
const startOfDay = new Date(reference.getFullYear(), reference.getMonth(), reference.getDate()).getTime();
|
||||||
const endOfDay = startOfDay + 24 * 60 * 60 * 1000;
|
const endOfDay = startOfDay + 24 * 60 * 60 * 1000;
|
||||||
|
|||||||
Reference in new issue
Block a user