SkateSpots/src/hooks/useDmMute.ts

41 lines
1.4 KiB
TypeScript

import { useCallback, useEffect, useState } from 'react';
const KEY = 'skatespots:dm-muted-threads';
const EVENT = 'skatespots:dm-muted-threads-change';
function read(): string[] {
try {
const raw = localStorage.getItem(KEY);
const parsed = raw ? JSON.parse(raw) as unknown : [];
return Array.isArray(parsed) ? parsed.filter((id): id is string => typeof id === 'string') : [];
} catch {
return [];
}
}
/** Device-local per-thread mute for 1:1 DMs, group DMs and crew chat keys. */
export function useDmMute() {
const [keys, setKeys] = useState<string[]>(read);
useEffect(() => {
const onChange = (event: Event) => {
const detail = (event as CustomEvent<string[]>).detail;
if (Array.isArray(detail)) setKeys(detail);
};
window.addEventListener(EVENT, onChange);
return () => window.removeEventListener(EVENT, onChange);
}, []);
const write = useCallback((next: string[]) => {
setKeys(next);
try { localStorage.setItem(KEY, JSON.stringify(next)); } catch { /* ignore */ }
window.dispatchEvent(new CustomEvent(EVENT, { detail: next }));
}, []);
const isMuted = useCallback((key: string | undefined) => !!key && keys.includes(key), [keys]);
const toggle = useCallback((key: string) => {
write(keys.includes(key) ? keys.filter((k) => k !== key) : [...keys, key].slice(-200));
}, [keys, write]);
return { isMuted, toggle };
}