feat: show human playback markers on timeline

Resolves #105
This commit is contained in:
talksik
2026-04-01 11:02:48 -07:00
parent 4d1ad717ad
commit 7c77d02ab5
6 changed files with 156 additions and 91 deletions
+50
View File
@@ -0,0 +1,50 @@
import { useMemo } from "react";
import type { Human, Particle } from "@/api/types";
export interface HumanPresence {
humanId: string;
email: string;
emailPrefix: string;
}
/**
* Maps playback markers to segment indices, returning which users are present at each particle.
*/
export function usePresencePositions(
playbackMarkers: Record<string, Date> | undefined,
children: Particle[],
networkHumans: Human[] | undefined,
currentUserId: string | undefined,
): Map<number, HumanPresence[]> {
return useMemo(() => {
const result = new Map<number, HumanPresence[]>();
if (!playbackMarkers || !networkHumans || children.length === 0) return result;
for (const [userId, markerTimestamp] of Object.entries(playbackMarkers)) {
if (userId === currentUserId) continue;
const human = networkHumans.find((h) => h.id === userId);
if (!human) continue;
// Find the last particle whose created_at <= marker timestamp
let segmentIndex = -1;
for (let i = children.length - 1; i >= 0; i--) {
if (children[i].created_at.getTime() <= markerTimestamp.getTime()) {
segmentIndex = i;
break;
}
}
if (segmentIndex === -1) continue;
const existing = result.get(segmentIndex);
const presence: HumanPresence = { humanId: human.id, email: human.email, emailPrefix: human.email_prefix };
if (existing) {
existing.push(presence);
} else {
result.set(segmentIndex, [presence]);
}
}
return result;
}, [playbackMarkers, children, networkHumans, currentUserId]);
}