From 38cc6e6f3a0ff56ab62f034771e73f2d849fc6ae Mon Sep 17 00:00:00 2001
From: Ajay Bura <32841439+ajbura@users.noreply.github.com>
Date: Mon, 3 Nov 2025 15:27:02 +0530
Subject: [PATCH] add room to active thread atom
---
.../pages/client/ClientInitStorageAtom.tsx | 12 ++-
src/app/state/hooks/roomToActiveThread.ts | 55 ++++++++++++++
src/app/state/roomToActiveThread.ts | 75 +++++++++++++++++++
3 files changed, 139 insertions(+), 3 deletions(-)
create mode 100644 src/app/state/hooks/roomToActiveThread.ts
create mode 100644 src/app/state/roomToActiveThread.ts
diff --git a/src/app/pages/client/ClientInitStorageAtom.tsx b/src/app/pages/client/ClientInitStorageAtom.tsx
index 1abee707..308a0212 100644
--- a/src/app/pages/client/ClientInitStorageAtom.tsx
+++ b/src/app/pages/client/ClientInitStorageAtom.tsx
@@ -8,6 +8,8 @@ import { makeNavToActivePathAtom } from '../../state/navToActivePath';
import { NavToActivePathProvider } from '../../state/hooks/navToActivePath';
import { makeOpenedSidebarFolderAtom } from '../../state/openedSidebarFolder';
import { OpenedSidebarFolderProvider } from '../../state/hooks/openedSidebarFolder';
+import { makeRoomToActiveThreadAtom } from '../../state/roomToActiveThread';
+import { RoomToActiveThreadProvider } from '../../state/hooks/roomToActiveThread';
type ClientInitStorageAtomProps = {
children: ReactNode;
@@ -22,15 +24,19 @@ export function ClientInitStorageAtom({ children }: ClientInitStorageAtomProps)
const navToActivePathAtom = useMemo(() => makeNavToActivePathAtom(userId), [userId]);
+ const roomToActiveThreadAtom = useMemo(() => makeRoomToActiveThreadAtom(userId), [userId]);
+
const openedSidebarFolderAtom = useMemo(() => makeOpenedSidebarFolderAtom(userId), [userId]);
return (
-
- {children}
-
+
+
+ {children}
+
+
diff --git a/src/app/state/hooks/roomToActiveThread.ts b/src/app/state/hooks/roomToActiveThread.ts
new file mode 100644
index 00000000..7abb5974
--- /dev/null
+++ b/src/app/state/hooks/roomToActiveThread.ts
@@ -0,0 +1,55 @@
+import { createContext, useCallback, useContext } from 'react';
+import { useAtomValue, useSetAtom } from 'jotai';
+import { RoomToActiveThreadAtom } from '../roomToActiveThread';
+
+const RoomToActiveThreadAtomContext = createContext(null);
+export const RoomToActiveThreadProvider = RoomToActiveThreadAtomContext.Provider;
+
+export const useRoomToActiveThreadAtom = (): RoomToActiveThreadAtom => {
+ const anAtom = useContext(RoomToActiveThreadAtomContext);
+
+ if (!anAtom) {
+ throw new Error('RoomToActiveThreadAtom is not provided!');
+ }
+
+ return anAtom;
+};
+
+export const useThreadSelector = (roomId: string): ((threadId: string) => void) => {
+ const roomToActiveThreadAtom = useRoomToActiveThreadAtom();
+ const setRoomToActiveThread = useSetAtom(roomToActiveThreadAtom);
+
+ const onThreadSelect = useCallback(
+ (threadId: string) => {
+ setRoomToActiveThread({
+ type: 'PUT',
+ roomId,
+ threadId,
+ });
+ },
+ [roomId, setRoomToActiveThread]
+ );
+
+ return onThreadSelect;
+};
+
+export const useActiveThread = (roomId: string): string | undefined => {
+ const roomToActiveThreadAtom = useRoomToActiveThreadAtom();
+ const roomToActiveThread = useAtomValue(roomToActiveThreadAtom);
+
+ return roomToActiveThread.get(roomId);
+};
+
+export const useThreadClose = (roomId: string): (() => void) => {
+ const roomToActiveThreadAtom = useRoomToActiveThreadAtom();
+ const setRoomToActiveThread = useSetAtom(roomToActiveThreadAtom);
+
+ const closeThread = useCallback(() => {
+ setRoomToActiveThread({
+ type: 'DELETE',
+ roomId,
+ });
+ }, [roomId, setRoomToActiveThread]);
+
+ return closeThread;
+};
diff --git a/src/app/state/roomToActiveThread.ts b/src/app/state/roomToActiveThread.ts
new file mode 100644
index 00000000..e156c63a
--- /dev/null
+++ b/src/app/state/roomToActiveThread.ts
@@ -0,0 +1,75 @@
+import { atom, WritableAtom } from 'jotai';
+import produce from 'immer';
+import {
+ atomWithLocalStorage,
+ getLocalStorageItem,
+ setLocalStorageItem,
+} from './utils/atomWithLocalStorage';
+
+const ROOM_TO_ACTIVE_THREAD = 'roomToActiveThread';
+
+const getStoreKey = (userId: string): string => `${ROOM_TO_ACTIVE_THREAD}${userId}`;
+
+type RoomToActiveThread = Map;
+
+type RoomToActiveThreadAction =
+ | {
+ type: 'PUT';
+ roomId: string;
+ threadId: string;
+ }
+ | {
+ type: 'DELETE';
+ roomId: string;
+ };
+
+export type RoomToActiveThreadAtom = WritableAtom<
+ RoomToActiveThread,
+ [RoomToActiveThreadAction],
+ undefined
+>;
+
+export const makeRoomToActiveThreadAtom = (userId: string): RoomToActiveThreadAtom => {
+ const storeKey = getStoreKey(userId);
+
+ const baseRoomToActiveThread = atomWithLocalStorage(
+ storeKey,
+ (key) => {
+ const obj: Record = getLocalStorageItem(key, {});
+ return new Map(Object.entries(obj));
+ },
+ (key, value) => {
+ const obj: Record = Object.fromEntries(value);
+ setLocalStorageItem(key, obj);
+ }
+ );
+
+ const navToActivePathAtom = atom(
+ (get) => get(baseRoomToActiveThread),
+ (get, set, action) => {
+ if (action.type === 'DELETE') {
+ set(
+ baseRoomToActiveThread,
+ produce(get(baseRoomToActiveThread), (draft) => {
+ draft.delete(action.roomId);
+ })
+ );
+ return;
+ }
+ if (action.type === 'PUT') {
+ set(
+ baseRoomToActiveThread,
+ produce(get(baseRoomToActiveThread), (draft) => {
+ draft.set(action.roomId, action.threadId);
+ })
+ );
+ }
+ }
+ );
+
+ return navToActivePathAtom;
+};
+
+export const clearRoomToActiveThreadStore = (userId: string) => {
+ localStorage.removeItem(getStoreKey(userId));
+};