41 lines
1.4 KiB
TypeScript
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 };
|
|
}
|