diff --git a/.nvmrc b/.nvmrc index b009dfb9d9..2bd5a0a98a 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -lts/* +22 diff --git a/package.json b/package.json index b07662962e..d22e90985e 100644 --- a/package.json +++ b/package.json @@ -113,7 +113,6 @@ "i18next": "^21.6.14", "linkifyjs": "^4.1.0", "lodash.debounce": "^4.0.8", - "lodash.defaultsdeep": "^4.6.1", "lodash.mergewith": "^4.6.2", "lodash.throttle": "^4.1.1", "lodash.uniqby": "^4.7.0", @@ -239,7 +238,7 @@ "react": "^19.0.0", "react-dom": "^19.0.0", "semantic-release": "^24.2.3", - "stream-chat": "^8.55.0", + "stream-chat": "^8.60.0", "ts-jest": "^29.2.5", "typescript": "^5.4.5", "typescript-eslint": "^8.17.0" @@ -260,7 +259,7 @@ "prepare": "husky install", "preversion": "yarn install", "test": "jest", - "types": "tsc --noEmit --skipLibCheck false", + "types": "tsc --noEmit --skipLibCheck true", "validate-translations": "node scripts/validate-translations.js", "validate-cjs": "concurrently 'node scripts/validate-cjs-node-bundle.cjs' 'node scripts/validate-cjs-browser-bundle.cjs'", "semantic-release": "semantic-release", diff --git a/src/components/Channel/Channel.tsx b/src/components/Channel/Channel.tsx index d89e63742e..3ba679f361 100644 --- a/src/components/Channel/Channel.tsx +++ b/src/components/Channel/Channel.tsx @@ -11,7 +11,6 @@ import React, { } from 'react'; import debounce from 'lodash.debounce'; -import defaultsDeep from 'lodash.defaultsdeep'; import throttle from 'lodash.throttle'; import { nanoid } from 'nanoid'; import clsx from 'clsx'; @@ -48,7 +47,6 @@ import { import { CHANNEL_CONTAINER_ID } from './constants'; import { DEFAULT_HIGHLIGHT_DURATION, - DEFAULT_INITIAL_CHANNEL_PAGE_SIZE, DEFAULT_JUMP_TO_PAGE_SIZE, DEFAULT_NEXT_CHANNEL_PAGE_SIZE, DEFAULT_THREAD_PAGE_SIZE, @@ -337,7 +335,7 @@ const ChannelInner = < acceptedFiles, activeUnreadHandler, channel, - channelQueryOptions: propChannelQueryOptions, + channelQueryOptions, children, doDeleteMessageRequest, doMarkReadRequest, @@ -357,16 +355,6 @@ const ChannelInner = < skipMessageDataMemoization, } = props; - const channelQueryOptions: ChannelQueryOptions & { - messages: { limit: number }; - } = useMemo( - () => - defaultsDeep(propChannelQueryOptions, { - messages: { limit: DEFAULT_INITIAL_CHANNEL_PAGE_SIZE }, - }), - [propChannelQueryOptions], - ); - const { client, customClasses, latestMessageDatesByChannels, mutes, searchController } = useChatContext('Channel'); const { t } = useTranslationContext('Channel'); diff --git a/src/components/Channel/__tests__/Channel.test.js b/src/components/Channel/__tests__/Channel.test.js index 691a71acaf..962261ef62 100644 --- a/src/components/Channel/__tests__/Channel.test.js +++ b/src/components/Channel/__tests__/Channel.test.js @@ -300,7 +300,11 @@ describe('Channel', () => { const { channel, chatClient } = await initClient(); const watchSpy = jest.spyOn(channel, 'watch'); - await renderComponent({ channel, chatClient }); + await renderComponent({ + channel, + channelQueryOptions: { messages: { limit: 25 } }, + chatClient, + }); await waitFor(() => { expect(watchSpy).toHaveBeenCalledTimes(1); @@ -349,9 +353,12 @@ describe('Channel', () => { ]); let hasMore; await act(() => { - renderComponent({ channel, chatClient }, ({ hasMore: contextHasMore }) => { - hasMore = contextHasMore; - }); + renderComponent( + { channel, channelQueryOptions: { messages: { limit: 25 } }, chatClient }, + ({ hasMore: contextHasMore }) => { + hasMore = contextHasMore; + }, + ); }); await waitFor(() => { @@ -365,9 +372,12 @@ describe('Channel', () => { queryChannelWithNewMessages(Array.from({ length: 25 }, generateMessage), channel), ]); let hasMore; - await renderComponent({ channel, chatClient }, ({ hasMore: contextHasMore }) => { - hasMore = contextHasMore; - }); + await renderComponent( + { channel, channelQueryOptions: { messages: { limit: 25 } }, chatClient }, + ({ hasMore: contextHasMore }) => { + hasMore = contextHasMore; + }, + ); await waitFor(() => { expect(hasMore).toBe(true); @@ -733,15 +743,21 @@ describe('Channel', () => { it("should initiate the hasMore flag with the current message set's pagination hasPrev value", async () => { const { channel, chatClient } = await initClient(); let hasMore; - await renderComponent({ channel, chatClient }, ({ hasMore: hasMoreCtx }) => { - hasMore = hasMoreCtx; - }); + await renderComponent( + { channel, channelQueryOptions: { messages: { limit: 25 } }, chatClient }, + ({ hasMore: hasMoreCtx }) => { + hasMore = hasMoreCtx; + }, + ); expect(hasMore).toBe(true); channel.state.messageSets[0].pagination.hasPrev = false; - await renderComponent({ channel, chatClient }, ({ hasMore: hasMoreCtx }) => { - hasMore = hasMoreCtx; - }); + await renderComponent( + { channel, channelQueryOptions: { messages: { limit: 25 } }, chatClient }, + ({ hasMore: hasMoreCtx }) => { + hasMore = hasMoreCtx; + }, + ); expect(hasMore).toBe(false); }); it('should be able to load more messages', async () => { @@ -752,7 +768,7 @@ describe('Channel', () => { const newMessages = [generateMessage()]; await renderComponent( - { channel, chatClient }, + { channel, channelQueryOptions: { messages: { limit: 25 } }, chatClient }, ({ loadMore, messages: contextMessages }) => { if (!contextMessages.find((message) => message.id === newMessages[0].id)) { // Our new message is not yet passed as part of channel context. Call loadMore and mock API response to include it. @@ -812,7 +828,7 @@ describe('Channel', () => { .fill(null) .map(() => generateMessage()); await renderComponent( - { channel, chatClient }, + { channel, channelQueryOptions: { messages: { limit: 25 } }, chatClient }, ({ hasMore, loadMore, messages: contextMessages }) => { if (!contextMessages.some((message) => message.id === newMessages[0].id)) { // Our new messages are not yet passed as part of channel context. Call loadMore and mock API response to include it. @@ -835,12 +851,15 @@ describe('Channel', () => { const queryPromise = new Promise(() => {}); let isLoadingMore = false; - await renderComponent({ channel, chatClient }, ({ loadingMore, loadMore }) => { - // return a promise that hasn't resolved yet, so loadMore will be stuck in the 'await' part of the function - jest.spyOn(channel, 'query').mockImplementationOnce(() => queryPromise); - loadMore(); - isLoadingMore = loadingMore; - }); + await renderComponent( + { channel, channelQueryOptions: { messages: { limit: 25 } }, chatClient }, + ({ loadingMore, loadMore }) => { + // return a promise that hasn't resolved yet, so loadMore will be stuck in the 'await' part of the function + jest.spyOn(channel, 'query').mockImplementationOnce(() => queryPromise); + loadMore(); + isLoadingMore = loadingMore; + }, + ); await waitFor(() => expect(isLoadingMore).toBe(true)); }); @@ -890,7 +909,7 @@ describe('Channel', () => { let queryNextPageSpy; let contextMessageCount; await renderComponent( - { channel, chatClient }, + { channel, channelQueryOptions: { messages: { limit: 25 } }, chatClient }, ({ loadMore, messages: contextMessages }) => { queryNextPageSpy = jest.spyOn(channel, 'query'); contextMessageCount = contextMessages.length; @@ -913,9 +932,9 @@ describe('Channel', () => { expect(chatClient.axiosInstance.post.mock.calls[1][1]).toMatchObject( expect.objectContaining({ data: {}, - messages: { id_lt: firstPageMessages[0].id, limit: 100 }, + messages: { id_lt: firstPageMessages[0].id, limit: 25 }, state: true, - watchers: { limit: 100 }, + watchers: { limit: 25 }, }), ); expect(contextMessageCount).toBe( diff --git a/src/components/ChannelHeader/__tests__/ChannelHeader.test.js b/src/components/ChannelHeader/__tests__/ChannelHeader.test.js index bda9b074bb..48bcb0c557 100644 --- a/src/components/ChannelHeader/__tests__/ChannelHeader.test.js +++ b/src/components/ChannelHeader/__tests__/ChannelHeader.test.js @@ -213,6 +213,7 @@ describe('ChannelHeader', () => { describe('group channel', () => { const props = { Avatar: ChannelAvatar, + watchers: { limit: 10 }, }; const getChannelState = (memberCount, channelData) => { diff --git a/src/components/ChannelList/ChannelList.tsx b/src/components/ChannelList/ChannelList.tsx index a69f42b7d2..fbb79a50cf 100644 --- a/src/components/ChannelList/ChannelList.tsx +++ b/src/components/ChannelList/ChannelList.tsx @@ -12,7 +12,7 @@ import { useChannelListShape, usePrepareShapeHandlers, } from './hooks/useChannelListShape'; -import { MAX_QUERY_CHANNELS_LIMIT, moveChannelUpwards } from './utils'; +import { moveChannelUpwards } from './utils'; import { Avatar as DefaultAvatar } from '../Avatar'; import { @@ -252,10 +252,7 @@ const UnMemoizedChannelList = < channels: Array>, setChannels: React.Dispatch>>>, ) => { - if ( - !channels.length || - channels.length > (options?.limit || MAX_QUERY_CHANNELS_LIMIT) - ) { + if (!channels.length) { return; } diff --git a/src/components/ChannelList/__tests__/ChannelList.test.js b/src/components/ChannelList/__tests__/ChannelList.test.js index 010e92ff99..c226ddb458 100644 --- a/src/components/ChannelList/__tests__/ChannelList.test.js +++ b/src/components/ChannelList/__tests__/ChannelList.test.js @@ -186,6 +186,7 @@ describe('ChannelList', () => { const props = { filters: {}, List: ChannelListComponent, + options: { limit: 25, message_limit: 25 }, Preview: ChannelPreviewComponent, }; @@ -291,6 +292,7 @@ describe('ChannelList', () => { channelRenderFilterFn: customFilterFunction, filters: {}, List: ChannelListComponent, + options: { limit: 25, message_limit: 25 }, Preview: ChannelPreviewComponent, }; @@ -612,7 +614,13 @@ describe('ChannelList', () => { customActiveChannel={testChannel2.channel.id} filters={{}} List={ChannelListComponent} - options={{ presence: true, state: true, watch: true }} + options={{ + limit: 25, + message_limit: 25, + presence: true, + state: true, + watch: true, + }} Preview={ChannelPreviewComponent} setActiveChannel={setActiveChannel} setActiveChannelOnMount @@ -909,6 +917,7 @@ describe('ChannelList', () => { const channelListProps = { filters: {}, List: ChannelListComponent, + options: { limit: 25, message_limit: 25 }, Preview: ChannelPreviewComponent, renderChannels, }; @@ -935,6 +944,7 @@ describe('ChannelList', () => { const props = { filters: {}, List: ChannelListComponent, + options: { limit: 25, message_limit: 25 }, Preview: ChannelPreviewComponent, }; const sendNewMessageOnChannel3 = async () => { @@ -1043,7 +1053,13 @@ describe('ChannelList', () => { , @@ -1082,7 +1098,13 @@ describe('ChannelList', () => { filters={{}} List={ChannelListComponent} onMessageNew={onMessageNew} - options={{ presence: true, state: true, watch: true }} + options={{ + limit: 25, + message_limit: 25, + presence: true, + state: true, + watch: true, + }} Preview={ChannelPreviewComponent} /> , @@ -1109,7 +1131,13 @@ describe('ChannelList', () => { const channelListProps = { filters: {}, List: ChannelListComponent, - options: { presence: true, state: true, watch: true }, + options: { + limit: 25, + message_limit: 25, + presence: true, + state: true, + watch: true, + }, Preview: ChannelPreviewComponent, }; @@ -1178,6 +1206,7 @@ describe('ChannelList', () => { const channelListProps = { filters: {}, List: ChannelListComponent, + options: { limit: 25, message_limit: 25 }, Preview: ChannelPreviewComponent, }; @@ -1241,6 +1270,7 @@ describe('ChannelList', () => { const channelListProps = { filters: {}, List: ChannelListComponent, + options: { limit: 25, message_limit: 25 }, Preview: ChannelPreviewComponent, }; @@ -1309,6 +1339,7 @@ describe('ChannelList', () => { const channelListProps = { filters: {}, List: ChannelListComponent, + options: { limit: 25, message_limit: 25 }, Preview: ChannelPreviewComponent, }; @@ -1398,6 +1429,7 @@ describe('ChannelList', () => { const channelListProps = { filters: {}, List: ChannelListComponent, + options: { limit: 25, message_limit: 25 }, Preview: ChannelPreviewComponent, }; @@ -1465,7 +1497,13 @@ describe('ChannelList', () => { const channelListProps = { filters: {}, List: ChannelListComponent, - options: { presence: true, state: true, watch: true }, + options: { + limit: 25, + message_limit: 25, + presence: true, + state: true, + watch: true, + }, Preview: ChannelPreviewComponent, }; @@ -1533,6 +1571,7 @@ describe('ChannelList', () => { const channelListProps = { filters: {}, List: ChannelListComponent, + options: { limit: 25, message_limit: 25 }, Preview: ChannelPreviewComponent, }; @@ -1573,6 +1612,7 @@ describe('ChannelList', () => { const channelListProps = { filters: {}, List: ChannelListComponent, + options: { limit: 25, message_limit: 25 }, Preview: ChannelPreviewComponent, }; diff --git a/src/components/ChannelList/hooks/usePaginatedChannels.ts b/src/components/ChannelList/hooks/usePaginatedChannels.ts index 7ee6656279..92130a3409 100644 --- a/src/components/ChannelList/hooks/usePaginatedChannels.ts +++ b/src/components/ChannelList/hooks/usePaginatedChannels.ts @@ -1,8 +1,6 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import uniqBy from 'lodash.uniqby'; -import { MAX_QUERY_CHANNELS_LIMIT } from '../utils'; - import type { Channel, ChannelFilters, @@ -15,7 +13,6 @@ import { useChatContext } from '../../../context/ChatContext'; import type { DefaultStreamChatGenerics } from '../../../types/types'; import type { ChannelsQueryState } from '../../Chat/hooks/useChannelsQueryState'; -import { DEFAULT_INITIAL_CHANNEL_PAGE_SIZE } from '../../../constants/limits'; const RECOVER_LOADED_CHANNELS_THROTTLE_INTERVAL_IN_MS = 5000; const MIN_RECOVER_LOADED_CHANNELS_THROTTLE_INTERVAL_IN_MS = 2000; @@ -88,8 +85,6 @@ export const usePaginatedChannels = < const offset = queryType === 'reload' ? 0 : channels.length; const newOptions = { - limit: options?.limit ?? MAX_QUERY_CHANNELS_LIMIT, - message_limit: options?.message_limit ?? DEFAULT_INITIAL_CHANNEL_PAGE_SIZE, offset, ...options, }; @@ -106,7 +101,7 @@ export const usePaginatedChannels = < : uniqBy([...channels, ...channelQueryResponse], 'cid'); setChannels(newChannels); - setHasNextPage(channelQueryResponse.length >= newOptions.limit); + setHasNextPage(channelQueryResponse.length >= (newOptions.limit ?? 1)); // Set active channel only on load of first page if (!offset && activeChannelHandler) { diff --git a/src/components/ChannelList/utils.ts b/src/components/ChannelList/utils.ts index 2a867d2dd2..22ed093bc9 100644 --- a/src/components/ChannelList/utils.ts +++ b/src/components/ChannelList/utils.ts @@ -9,8 +9,6 @@ import type { import type { DefaultStreamChatGenerics } from '../../types/types'; import type { ChannelListProps } from './ChannelList'; -export const MAX_QUERY_CHANNELS_LIMIT = 30; - type MoveChannelUpParams< SCG extends DefaultStreamChatGenerics = DefaultStreamChatGenerics, > = { diff --git a/src/components/ChannelPreview/__tests__/ChannelPreview.test.js b/src/components/ChannelPreview/__tests__/ChannelPreview.test.js index db9540daf4..dd285d197b 100644 --- a/src/components/ChannelPreview/__tests__/ChannelPreview.test.js +++ b/src/components/ChannelPreview/__tests__/ChannelPreview.test.js @@ -554,6 +554,7 @@ describe('ChannelPreview', () => { const channelPreviewProps = { Avatar: MockAvatar, + watchers: { limit: 10 }, }; it("should update the direct messaging channel's preview if other user's name has changed", async () => { diff --git a/src/components/Gallery/ModalGallery.tsx b/src/components/Gallery/ModalGallery.tsx index 924a9f443f..1f4777d47b 100644 --- a/src/components/Gallery/ModalGallery.tsx +++ b/src/components/Gallery/ModalGallery.tsx @@ -52,7 +52,6 @@ export const ModalGallery = < ); return ( - // @ts-expect-error ignore the TS error as react-image-gallery was on @types/react@18 while stream-chat-react being upgraded to React 19 (https://github.com/xiaolin/react-image-gallery/issues/809)