47 lines
1.5 KiB
TypeScript
47 lines
1.5 KiB
TypeScript
import { useCallback, useEffect, useState } from 'react';
|
|
import {
|
|
cordnRoomReadEventName,
|
|
markCordnRoomActive,
|
|
markCordnRoomSeen,
|
|
readCordnRoomReads,
|
|
type CordnRoomReadMap,
|
|
} from '@/lib/cordnRoomRead';
|
|
|
|
/**
|
|
* Reactive view of {@link readCordnRoomReads}. Safe to mount on list pages:
|
|
* it only reads localStorage and listens for same-tab/cross-tab updates.
|
|
*/
|
|
export function useCordnRoomRead(pubkey: string | undefined) {
|
|
const [reads, setReads] = useState<CordnRoomReadMap>(() => readCordnRoomReads(pubkey));
|
|
|
|
useEffect(() => {
|
|
setReads(readCordnRoomReads(pubkey));
|
|
const onChange = (event: Event) => {
|
|
const detail = (event as CustomEvent<{ pubkey?: string; reads?: CordnRoomReadMap }>).detail;
|
|
if (!detail || detail.pubkey !== pubkey || !detail.reads) return;
|
|
setReads(detail.reads);
|
|
};
|
|
window.addEventListener(cordnRoomReadEventName(), onChange);
|
|
return () => window.removeEventListener(cordnRoomReadEventName(), onChange);
|
|
}, [pubkey]);
|
|
|
|
const isUnread = useCallback(
|
|
(gid: string | undefined) => {
|
|
if (!gid) return false;
|
|
const state = reads[gid];
|
|
return !!state && state.latestAt > state.seenAt;
|
|
},
|
|
[reads],
|
|
);
|
|
|
|
const markActive = useCallback(
|
|
(gid: string, latestAt: number) => markCordnRoomActive(pubkey, gid, latestAt),
|
|
[pubkey],
|
|
);
|
|
const markSeen = useCallback(
|
|
(gid: string, latestAt: number) => markCordnRoomSeen(pubkey, gid, latestAt),
|
|
[pubkey],
|
|
);
|
|
|
|
return { reads, isUnread, markActive, markSeen };
|
|
}
|