Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 15 additions & 4 deletions src/components/structures/LoggedInView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ interface IState {
backgroundImage?: string;
}

const NEW_ROOM_LIST_MIN_WIDTH = 224;
/**
* This is what our MatrixChat shows when we are logged in. The precise view is
* determined by the page_type property.
Expand Down Expand Up @@ -261,10 +262,15 @@ class LoggedInView extends React.Component<IProps, IState> {
let panelCollapsed: boolean;
const useNewRoomList = SettingsStore.getValue("feature_new_room_list");
// TODO decrease this once Spaces launches as it'll no longer need to include the 56px Community Panel
const toggleSize = useNewRoomList ? 224 : 206 - 50;
const toggleSize = useNewRoomList ? NEW_ROOM_LIST_MIN_WIDTH : 206 - 50;

const collapseConfig: ICollapseConfig = {
toggleSize,
onCollapsed: (collapsed) => {
if (useNewRoomList) {
// The new room list does not support collapsing.
return;
}
panelCollapsed = collapsed;
if (collapsed) {
dis.dispatch({ action: "hide_left_panel" });
Expand All @@ -281,11 +287,13 @@ class LoggedInView extends React.Component<IProps, IState> {
this.props.resizeNotifier.startResizing();
},
onResizeStop: () => {
if (!panelCollapsed) window.localStorage.setItem("mx_lhs_size", "" + panelSize);
// Always save the lhs size for the new room list.
if (useNewRoomList || !panelCollapsed) window.localStorage.setItem("mx_lhs_size", "" + panelSize);
this.props.resizeNotifier.stopResizing();
},
isItemCollapsed: (domNode) => {
return domNode.classList.contains("mx_LeftPanel_minimized");
// New rooms list does not support collapsing.
return !useNewRoomList && domNode.classList.contains("mx_LeftPanel_minimized");
},
handler: this.resizeHandler.current ?? undefined,
};
Expand All @@ -299,8 +307,11 @@ class LoggedInView extends React.Component<IProps, IState> {
}

private loadResizerPreferences(): void {
const useNewRoomList = SettingsStore.getValue("feature_new_room_list");
let lhsSize = parseInt(window.localStorage.getItem("mx_lhs_size")!, 10);
if (isNaN(lhsSize)) {
// If the user has not set a size, or for the new room list if the size is less than the minimum width,
// set a default size.
if (isNaN(lhsSize) || (useNewRoomList && lhsSize < NEW_ROOM_LIST_MIN_WIDTH)) {
lhsSize = 350;
}
this.resizer?.forHandleWithId("lp-resizer")?.resize(lhsSize);
Expand Down
101 changes: 101 additions & 0 deletions test/unit-tests/components/structures/LoggedInView-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,27 @@ import { Action } from "../../../../src/dispatcher/actions";
import Modal from "../../../../src/Modal";
import { SETTINGS } from "../../../../src/settings/Settings";

// Create a mock resizer instance that can be shared across tests
const mockResizerInstance = {
attach: jest.fn(),
detach: jest.fn(),
forHandleWithId: jest.fn().mockReturnValue({ resize: jest.fn() }),
setClassNames: jest.fn(),
};

// Mock the Resizer module
jest.mock("../../../../src/resizer", () => {
const originalModule = jest.requireActual("../../../../src/resizer");
return {
...originalModule,
Resizer: jest.fn().mockImplementation((container, distributorBuilder, collapseConfig) => {
// Store the callbacks globally for test access
(global as any).__resizeCallbacks = collapseConfig;
return mockResizerInstance;
}),
};
});

describe("<LoggedInView />", () => {
const userId = "@alice:domain.org";
const mockClient = getMockClientWithEventEmitter({
Expand Down Expand Up @@ -475,4 +496,84 @@ describe("<LoggedInView />", () => {
expect(mockClient.deleteExtendedProfileProperty).toHaveBeenCalledWith("us.cloke.msc4175.tz");
});
});

describe("resizer preferences", () => {
let mockResize: jest.Mock;
let mockForHandleWithId: jest.Mock;
beforeEach(() => {
// Clear localStorage before each test
window.localStorage.clear();

mockResize = jest.fn();
mockForHandleWithId = jest.fn().mockReturnValue({ resize: mockResize });

// Update the shared mock instance for this test
mockResizerInstance.forHandleWithId = mockForHandleWithId;

// Clear any global callback state
delete (global as any).__resizeCallbacks;
});

it("should call resize with default size when localStorage contains NaN value", () => {
// Set invalid value in localStorage that will result in NaN
window.localStorage.setItem("mx_lhs_size", "not-a-number");

getComponent();

// Verify that when lhsSize is NaN, it defaults to 350 and calls resize
expect(mockForHandleWithId).toHaveBeenCalledWith("lp-resizer");
expect(mockResize).toHaveBeenCalledWith(350);
});

it("should use existing size when localStorage contains valid value", () => {
// Set valid value in localStorage
window.localStorage.setItem("mx_lhs_size", "400");

getComponent();

// Verify the resize method was called with the stored size (400)
expect(mockResize).toHaveBeenCalledWith(400);
});

it("should enforce minimum width for new room list when stored size is zero", async () => {
// Enable new room list feature
await SettingsStore.setValue("feature_new_room_list", null, SettingLevel.DEVICE, true);

// 0 represents the collapsed state for the old room list, which could have been set before the new room list was enabled
window.localStorage.setItem("mx_lhs_size", "0");

getComponent();

// Verify the resize method was called with the default size (350) when stored size is below minimum
expect(mockResize).toHaveBeenCalledWith(350);
});

it("should not set localStorage to 0 when resizing lp-resizer to minimum width for new room list", async () => {
// Enable new room list feature and mock SettingsStore
await SettingsStore.setValue("feature_new_room_list", null, SettingLevel.DEVICE, true);

const minimumWidth = 224; // NEW_ROOM_LIST_MIN_WIDTH

// Render the component
getComponent();

// Get the callbacks that were captured during resizer creation
const callbacks = (global as any).__resizeCallbacks;

// Create a mock DOM node for isItemCollapsed to check
const domNode = {
classList: {
contains: jest.fn().mockReturnValue(true), // Simulate the error where mx_LeftPanel_minimized is present
},
} as any;

callbacks.onResized(minimumWidth);
const isCollapsed = callbacks.isItemCollapsed(domNode);
callbacks.onCollapsed(isCollapsed); // Not collapsed for new room list
callbacks.onResizeStop();

// Verify localStorage was set to the minimum width (224), not 0
expect(window.localStorage.getItem("mx_lhs_size")).toBe("224");
});
});
});
Loading