()
| 34 | }; |
| 35 | |
| 36 | export function useThreadStorage(): UseThreadStorageResult { |
| 37 | const threadActivityRef = useRef<ThreadActivityMap>(loadThreadActivity()); |
| 38 | const pinnedThreadsRef = useRef<PinnedThreadsMap>(loadPinnedThreads()); |
| 39 | const [pinnedThreadsVersion, setPinnedThreadsVersion] = useState(0); |
| 40 | const customNamesRef = useRef<CustomNamesMap>({}); |
| 41 | |
| 42 | useEffect(() => { |
| 43 | if (typeof window === "undefined") { |
| 44 | return undefined; |
| 45 | } |
| 46 | customNamesRef.current = loadCustomNames(); |
| 47 | const handleStorage = (event: StorageEvent) => { |
| 48 | if (event.key === STORAGE_KEY_CUSTOM_NAMES) { |
| 49 | customNamesRef.current = loadCustomNames(); |
| 50 | } |
| 51 | }; |
| 52 | window.addEventListener("storage", handleStorage); |
| 53 | return () => window.removeEventListener("storage", handleStorage); |
| 54 | }, []); |
| 55 | |
| 56 | const getCustomName = useCallback((workspaceId: string, threadId: string) => { |
| 57 | const key = makeCustomNameKey(workspaceId, threadId); |
| 58 | return customNamesRef.current[key]; |
| 59 | }, []); |
| 60 | |
| 61 | const recordThreadActivity = useCallback( |
| 62 | (workspaceId: string, threadId: string, timestamp = Date.now()) => { |
| 63 | const nextForWorkspace = { |
| 64 | ...(threadActivityRef.current[workspaceId] ?? {}), |
| 65 | [threadId]: timestamp, |
| 66 | }; |
| 67 | const next = { |
| 68 | ...threadActivityRef.current, |
| 69 | [workspaceId]: nextForWorkspace, |
| 70 | }; |
| 71 | threadActivityRef.current = next; |
| 72 | saveThreadActivity(next); |
| 73 | }, |
| 74 | [], |
| 75 | ); |
| 76 | |
| 77 | useEffect(() => { |
| 78 | if (typeof window === "undefined") { |
| 79 | return undefined; |
| 80 | } |
| 81 | pinnedThreadsRef.current = loadPinnedThreads(); |
| 82 | const handleStorage = (event: StorageEvent) => { |
| 83 | if (event.key !== STORAGE_KEY_PINNED_THREADS) { |
| 84 | return; |
| 85 | } |
| 86 | pinnedThreadsRef.current = loadPinnedThreads(); |
| 87 | setPinnedThreadsVersion((version) => version + 1); |
| 88 | }; |
| 89 | window.addEventListener("storage", handleStorage); |
| 90 | return () => window.removeEventListener("storage", handleStorage); |
| 91 | }, []); |
| 92 | |
| 93 | const pinThread = useCallback((workspaceId: string, threadId: string): boolean => { |
no test coverage detected