56 lines
1.8 KiB
TypeScript
56 lines
1.8 KiB
TypeScript
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]);
|
|
}
|
|
}
|
|
|
|
// Sort each segment's presence list by humanId for stable render order
|
|
for (const presenceList of result.values()) {
|
|
presenceList.sort((a, b) => a.humanId.localeCompare(b.humanId));
|
|
}
|
|
|
|
return result;
|
|
}, [playbackMarkers, children, networkHumans, currentUserId]);
|
|
}
|