Skip to content

Commit e6eff85

Browse files
authored
fix: Room not loading history (#34900)
1 parent 2f5e287 commit e6eff85

File tree

3 files changed

+119
-30
lines changed

3 files changed

+119
-30
lines changed

.changeset/good-clouds-brush.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@rocket.chat/meteor': patch
3+
---
4+
5+
Fixes an issue that prevented room history from loading under certain conditions.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import { renderHook } from '@testing-library/react';
2+
import React from 'react';
3+
4+
import { useGetMore } from './useGetMore';
5+
import { RoomHistoryManager } from '../../../../../app/ui-utils/client';
6+
7+
jest.mock('../../../../../app/ui-utils/client', () => ({
8+
RoomHistoryManager: {
9+
isLoading: jest.fn(),
10+
hasMore: jest.fn(),
11+
hasMoreNext: jest.fn(),
12+
getMore: jest.fn(),
13+
getMoreNext: jest.fn(),
14+
},
15+
}));
16+
17+
const mockGetMore = jest.fn();
18+
19+
describe('useGetMore', () => {
20+
it('should call getMore when scrolling near top and hasMore is true', () => {
21+
(RoomHistoryManager.isLoading as jest.Mock).mockReturnValue(false);
22+
(RoomHistoryManager.hasMore as jest.Mock).mockReturnValue(true);
23+
(RoomHistoryManager.hasMoreNext as jest.Mock).mockReturnValue(false);
24+
(RoomHistoryManager.getMore as jest.Mock).mockImplementation(mockGetMore);
25+
const atBottomRef = { current: false };
26+
27+
const mockElement = {
28+
addEventListener: jest.fn((event, handler) => {
29+
if (event === 'scroll') {
30+
handler({
31+
target: {
32+
scrollTop: 10,
33+
clientHeight: 300,
34+
},
35+
});
36+
}
37+
}),
38+
removeEventListener: jest.fn(),
39+
};
40+
41+
const useRefSpy = jest.spyOn(React, 'useRef').mockReturnValueOnce({ current: mockElement });
42+
43+
const { unmount } = renderHook(() => useGetMore('room-id', atBottomRef), { legacyRoot: true });
44+
45+
expect(useRefSpy).toHaveBeenCalledWith(null);
46+
expect(RoomHistoryManager.getMore).toHaveBeenCalledWith('room-id');
47+
48+
unmount();
49+
expect(mockElement.removeEventListener).toHaveBeenCalledWith('scroll', expect.any(Function));
50+
});
51+
52+
it('should call getMoreNext when scrolling near bottom and hasMoreNext is true', () => {
53+
(RoomHistoryManager.isLoading as jest.Mock).mockReturnValue(false);
54+
(RoomHistoryManager.hasMore as jest.Mock).mockReturnValue(false);
55+
(RoomHistoryManager.hasMoreNext as jest.Mock).mockReturnValue(true);
56+
(RoomHistoryManager.getMoreNext as jest.Mock).mockImplementation(mockGetMore);
57+
58+
const atBottomRef = { current: false };
59+
const mockElement = {
60+
addEventListener: jest.fn((event, handler) => {
61+
if (event === 'scroll') {
62+
handler({
63+
target: {
64+
scrollTop: 600,
65+
clientHeight: 300,
66+
scrollHeight: 800,
67+
},
68+
});
69+
}
70+
}),
71+
removeEventListener: jest.fn(),
72+
};
73+
const useRefSpy = jest.spyOn(React, 'useRef').mockReturnValueOnce({ current: mockElement });
74+
75+
renderHook(() => useGetMore('room-id', atBottomRef), { legacyRoot: true });
76+
77+
expect(useRefSpy).toHaveBeenCalledWith(null);
78+
expect(RoomHistoryManager.getMoreNext).toHaveBeenCalledWith('room-id', atBottomRef);
79+
});
80+
});
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,44 @@
11
import type { MutableRefObject } from 'react';
2-
import { useCallback } from 'react';
2+
import { useEffect, useRef } from 'react';
33

44
import { RoomHistoryManager } from '../../../../../app/ui-utils/client';
55
import { withThrottling } from '../../../../../lib/utils/highOrderFunctions';
66

77
export const useGetMore = (rid: string, atBottomRef: MutableRefObject<boolean>) => {
8-
return {
9-
innerRef: useCallback(
10-
(wrapper: HTMLElement | null) => {
11-
if (!wrapper) {
12-
return;
8+
const ref = useRef<HTMLElement>(null);
9+
10+
useEffect(() => {
11+
if (!ref.current) {
12+
return;
13+
}
14+
15+
const refValue = ref.current;
16+
17+
const handleScroll = withThrottling({ wait: 100 })((event) => {
18+
const lastScrollTopRef = event.target.scrollTop;
19+
const height = event.target.clientHeight;
20+
const isLoading = RoomHistoryManager.isLoading(rid);
21+
const hasMore = RoomHistoryManager.hasMore(rid);
22+
const hasMoreNext = RoomHistoryManager.hasMoreNext(rid);
23+
24+
if ((isLoading === false && hasMore === true) || hasMoreNext === true) {
25+
if (hasMore === true && lastScrollTopRef <= height / 3) {
26+
RoomHistoryManager.getMore(rid);
27+
} else if (hasMoreNext === true && Math.ceil(lastScrollTopRef) >= event.target.scrollHeight - height) {
28+
RoomHistoryManager.getMoreNext(rid, atBottomRef);
29+
atBottomRef.current = false;
1330
}
31+
}
32+
});
33+
34+
refValue.addEventListener('scroll', handleScroll);
1435

15-
let lastScrollTopRef = 0;
16-
17-
wrapper.addEventListener(
18-
'scroll',
19-
withThrottling({ wait: 100 })((event) => {
20-
lastScrollTopRef = event.target.scrollTop;
21-
const height = event.target.clientHeight;
22-
const isLoading = RoomHistoryManager.isLoading(rid);
23-
const hasMore = RoomHistoryManager.hasMore(rid);
24-
const hasMoreNext = RoomHistoryManager.hasMoreNext(rid);
25-
26-
if ((isLoading === false && hasMore === true) || hasMoreNext === true) {
27-
if (hasMore === true && lastScrollTopRef <= height / 3) {
28-
RoomHistoryManager.getMore(rid);
29-
} else if (hasMoreNext === true && Math.ceil(lastScrollTopRef) >= event.target.scrollHeight - height) {
30-
RoomHistoryManager.getMoreNext(rid, atBottomRef);
31-
atBottomRef.current = false;
32-
}
33-
}
34-
}),
35-
);
36-
},
37-
[atBottomRef, rid],
38-
),
36+
return () => {
37+
refValue.removeEventListener('scroll', handleScroll);
38+
};
39+
}, [rid, atBottomRef]);
40+
41+
return {
42+
innerRef: ref,
3943
};
4044
};

0 commit comments

Comments
 (0)