feat: add sidebarMode and activeDmUserId to UI store

Extends UiState with sidebarMode ("channels" | "dms") and
activeDmUserId (number | null). Adds setSidebarMode (which auto-clears
activeDmUserId when switching back to channels) and setActiveDmUser
actions. All three new tests pass (TDD: RED → GREEN).
This commit is contained in:
jevb
2026-03-27 11:29:23 +01:00
parent efb3f1364a
commit 1eaf9ad72c
2 changed files with 54 additions and 0 deletions
@@ -15,6 +15,8 @@ export interface UiState {
readonly transientError: string | null;
readonly persistentError: string | null;
readonly collapsedCategories: ReadonlySet<string>;
readonly sidebarMode: "channels" | "dms";
readonly activeDmUserId: number | null;
}
const INITIAL_STATE: UiState = {
@@ -27,6 +29,8 @@ const INITIAL_STATE: UiState = {
transientError: null,
persistentError: null,
collapsedCategories: new Set(),
sidebarMode: "channels",
activeDmUserId: null,
};
export const uiStore = createStore<UiState>(INITIAL_STATE);
@@ -130,3 +134,21 @@ export function toggleCategory(category: string): void {
export function isCategoryCollapsed(category: string): boolean {
return uiStore.select((s) => s.collapsedCategories.has(category));
}
/** Switch the sidebar between channel mode and DM mode.
* Switching back to "channels" clears the active DM user. */
export function setSidebarMode(mode: "channels" | "dms"): void {
uiStore.setState((prev) => ({
...prev,
sidebarMode: mode,
activeDmUserId: mode === "channels" ? null : prev.activeDmUserId,
}));
}
/** Set the currently active DM conversation user ID. */
export function setActiveDmUser(userId: number | null): void {
uiStore.setState((prev) => ({
...prev,
activeDmUserId: userId,
}));
}
@@ -10,6 +10,8 @@ import {
setTheme,
toggleCategory,
isCategoryCollapsed,
setSidebarMode,
setActiveDmUser,
} from "../../src/stores/ui.store";
function resetStore(): void {
@@ -23,6 +25,8 @@ function resetStore(): void {
transientError: null,
persistentError: null,
collapsedCategories: new Set<string>(),
sidebarMode: "channels" as const,
activeDmUserId: null,
}));
}
@@ -190,4 +194,32 @@ describe("ui store", () => {
expect(listener).not.toHaveBeenCalled();
});
});
describe("sidebar mode", () => {
beforeEach(() => {
uiStore.setState((prev) => ({
...prev,
sidebarMode: "channels",
activeDmUserId: null,
}));
});
it("defaults to channels mode", () => {
expect(uiStore.getState().sidebarMode).toBe("channels");
});
it("switches to DM mode with user ID", () => {
setSidebarMode("dms");
setActiveDmUser(42);
const state = uiStore.getState();
expect(state.sidebarMode).toBe("dms");
expect(state.activeDmUserId).toBe(42);
});
it("clears DM user when switching back to channels", () => {
setActiveDmUser(42);
setSidebarMode("channels");
expect(uiStore.getState().activeDmUserId).toBeNull();
});
});
});