Skip to content

Commit

Permalink
Merge pull request #2098 from GetStream/develop
Browse files Browse the repository at this point in the history
v10.10.2
  • Loading branch information
MartinCupela authored Sep 19, 2023
2 parents 72b45ae + 959495c commit 365c6a0
Show file tree
Hide file tree
Showing 14 changed files with 262 additions and 68 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@
"rollup-plugin-url": "^3.0.1",
"rollup-plugin-visualizer": "^4.2.0",
"semantic-release": "^19.0.5",
"stream-chat": "^8.4.1",
"stream-chat": "^8.12.0",
"style-loader": "^2.0.0",
"ts-jest": "^26.5.1",
"typescript": "^4.7.4",
Expand Down
22 changes: 21 additions & 1 deletion src/components/Channel/Channel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import debounce from 'lodash.debounce';
import throttle from 'lodash.throttle';
import {
ChannelAPIResponse,
ChannelMemberResponse,
ChannelState,
Event,
logChatPromiseExecution,
Expand Down Expand Up @@ -68,6 +69,7 @@ import {
import { hasMoreMessagesProbably, hasNotMoreMessages } from '../MessageList/utils';
import defaultEmojiData from '../../stream-emoji.json';
import { makeAddNotifications } from './utils';
import { getChannel } from '../../utils/getChannel';

import type { Data as EmojiMartData } from 'emoji-mart';

Expand Down Expand Up @@ -478,7 +480,25 @@ const ChannelInner = <
(async () => {
if (!channel.initialized) {
try {
await channel.watch();
// if active channel has been set without id, we will create a temporary channel id from its member IDs
// to keep track of the /query request in progress. This is the same approach of generating temporary id
// that the JS client uses to keep track of channel in client.activeChannels
const members: string[] = [];
if (!channel.id && channel.data?.members) {
for (const member of channel.data.members) {
let userId: string | undefined;
if (typeof member === 'string') {
userId = member;
} else if (typeof member === 'object') {
const { user, user_id } = member as ChannelMemberResponse<StreamChatGenerics>;
userId = user_id || user?.id;
}
if (userId) {
members.push(userId);
}
}
}
await getChannel({ channel, client, members });
const config = channel.getConfig();
setChannelConfig(config);
} catch (e) {
Expand Down
8 changes: 6 additions & 2 deletions src/components/ChannelList/hooks/useChannelVisibleListener.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useEffect } from 'react';
import uniqBy from 'lodash.uniqby';

import { getChannel } from '../utils';
import { getChannel } from '../../../utils/getChannel';

import { useChatContext } from '../../../context/ChatContext';

Expand All @@ -25,7 +25,11 @@ export const useChannelVisibleListener = <
if (customHandler && typeof customHandler === 'function') {
customHandler(setChannels, event);
} else if (event.type && event.channel_type && event.channel_id) {
const channel = await getChannel(client, event.channel_type, event.channel_id);
const channel = await getChannel({
client,
id: event.channel_id,
type: event.channel_type,
});
setChannels((channels) => uniqBy([channel, ...channels], 'cid'));
}
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useEffect } from 'react';
import uniqBy from 'lodash.uniqby';

import { getChannel } from '../utils';
import { getChannel } from '../../../utils/getChannel';

import { useChatContext } from '../../../context/ChatContext';

Expand All @@ -26,7 +26,18 @@ export const useNotificationAddedToChannelListener = <
if (customHandler && typeof customHandler === 'function') {
customHandler(setChannels, event);
} else if (allowNewMessagesFromUnfilteredChannels && event.channel?.type) {
const channel = await getChannel(client, event.channel.type, event.channel.id);
const channel = await getChannel({
client,
id: event.channel.id,
members: event.channel.members?.reduce<string[]>((acc, { user, user_id }) => {
const userId = user_id || user?.id;
if (userId) {
acc.push(userId);
}
return acc;
}, []),
type: event.channel.type,
});
setChannels((channels) => uniqBy([channel, ...channels], 'cid'));
}
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useEffect } from 'react';
import uniqBy from 'lodash.uniqby';

import { getChannel } from '../utils';
import { getChannel } from '../../../utils/getChannel';

import { useChatContext } from '../../../context/ChatContext';

Expand All @@ -26,7 +26,11 @@ export const useNotificationMessageNewListener = <
if (customHandler && typeof customHandler === 'function') {
customHandler(setChannels, event);
} else if (allowNewMessagesFromUnfilteredChannels && event.channel?.type) {
const channel = await getChannel(client, event.channel.type, event.channel.id);
const channel = await getChannel({
client,
id: event.channel.id,
type: event.channel.type,
});
setChannels((channels) => uniqBy([channel, ...channels], 'cid'));
}
};
Expand Down
37 changes: 1 addition & 36 deletions src/components/ChannelList/utils.ts
Original file line number Diff line number Diff line change
@@ -1,43 +1,8 @@
import type { Channel, QueryChannelAPIResponse, StreamChat } from 'stream-chat';
import type { Channel } from 'stream-chat';
import uniqBy from 'lodash.uniqby';

import type { DefaultStreamChatGenerics } from '../../types/types';

/**
* prevent from duplicate invocation of channel.watch()
* when events 'notification.message_new' and 'notification.added_to_channel' arrive at the same time
*/
const WATCH_QUERY_IN_PROGRESS_FOR_CHANNEL: Record<
string,
Promise<QueryChannelAPIResponse> | undefined
> = {};

/**
* Calls channel.watch() if it was not already recently called. Waits for watch promise to resolve even if it was invoked previously.
* @param client
* @param type
* @param id
*/
export const getChannel = async <
StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics
>(
client: StreamChat<StreamChatGenerics>,
type: string,
id: string,
) => {
const channel = client.channel(type, id);
const queryPromise = WATCH_QUERY_IN_PROGRESS_FOR_CHANNEL[channel.cid];
if (queryPromise) {
await queryPromise;
} else {
WATCH_QUERY_IN_PROGRESS_FOR_CHANNEL[channel.cid] = channel.watch();
await WATCH_QUERY_IN_PROGRESS_FOR_CHANNEL[channel.cid];
WATCH_QUERY_IN_PROGRESS_FOR_CHANNEL[channel.cid] = undefined;
}

return channel;
};

export const MAX_QUERY_CHANNELS_LIMIT = 30;

type MoveChannelUpParams<
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,13 @@ describe('ChatAutoComplete', () => {
beforeEach(async () => {
const messages = [generateMessage({ user })];
const members = [generateMember({ user }), generateMember({ user: mentionUser })];
const mockedChannel = generateChannel({
const mockedChannelData = generateChannel({
members,
messages,
});
chatClient = await getTestClientWithUser(user);
useMockedApis(chatClient, [getOrCreateChannelApi(mockedChannel)]);
channel = chatClient.channel('messaging', mockedChannel.id);
useMockedApis(chatClient, [getOrCreateChannelApi(mockedChannelData)]);
channel = chatClient.channel('messaging', mockedChannelData.channel.id);
});

afterEach(cleanup);
Expand Down
22 changes: 11 additions & 11 deletions src/components/MessageInput/__tests__/LinkPreviewList.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ const threadMessage = generateMessage({
type: 'reply',
user: user1,
});
const mockedChannel = generateChannel({
const mockedChannelData = generateChannel({
members: [generateMember({ user: user1 }), generateMember({ user: mentionUser })],
messages: [mainListMessage],
thread: [threadMessage],
Expand Down Expand Up @@ -177,14 +177,14 @@ describe('Link preview', () => {

beforeEach(async () => {
chatClient = await getTestClientWithUser({ id: user1.id });
useMockedApis(chatClient, [getOrCreateChannelApi(mockedChannel)]);
channel = chatClient.channel('messaging', mockedChannel.id);
useMockedApis(chatClient, [getOrCreateChannelApi(mockedChannelData)]);
channel = chatClient.channel('messaging', mockedChannelData.channel.id);
});

afterEach(tearDown);

it('does not request URL enrichment if disabled in channel config', async () => {
const channel = chatClient.channel('messaging', mockedChannel.id);
const channel = chatClient.channel('messaging', mockedChannelData.channel.id);
const {
channel: { config },
} = generateChannel({ config: { url_enrichment: false } });
Expand Down Expand Up @@ -660,7 +660,7 @@ describe('Link preview', () => {
});

it('are sent as attachments to posted message with skip_enrich_url:true', async () => {
const channel = chatClient.channel('messaging', mockedChannel.id);
const channel = chatClient.channel('messaging', mockedChannelData.channel.id);
const sendMessageSpy = jest.spyOn(channel, 'sendMessage').mockImplementation();

jest
Expand Down Expand Up @@ -716,7 +716,7 @@ describe('Link preview', () => {
});

it('are not sent as attachments to posted message with skip_enrich_url:true if dismissed', async () => {
const channel = chatClient.channel('messaging', mockedChannel.id);
const channel = chatClient.channel('messaging', mockedChannelData.channel.id);
const sendMessageSpy = jest.spyOn(channel, 'sendMessage').mockImplementation();

jest
Expand Down Expand Up @@ -763,7 +763,7 @@ describe('Link preview', () => {
});

it('does not add failed link previews among attachments', async () => {
const channel = chatClient.channel('messaging', mockedChannel.id);
const channel = chatClient.channel('messaging', mockedChannelData.channel.id);
const sendMessageSpy = jest.spyOn(channel, 'sendMessage').mockImplementation();

jest
Expand Down Expand Up @@ -804,7 +804,7 @@ describe('Link preview', () => {
});

it('does not add dismissed link previews among attachments', async () => {
const channel = chatClient.channel('messaging', mockedChannel.id);
const channel = chatClient.channel('messaging', mockedChannelData.channel.id);
const sendMessageSpy = jest.spyOn(channel, 'sendMessage').mockImplementation();
jest
.spyOn(chatClient, 'enrichURL')
Expand Down Expand Up @@ -1001,7 +1001,7 @@ describe('Link preview', () => {
});

it('submit new message with skip_url_enrich:false if no link previews managed to get loaded', async () => {
const channel = chatClient.channel('messaging', mockedChannel.id);
const channel = chatClient.channel('messaging', mockedChannelData.channel.id);
const sendMessageSpy = jest.spyOn(channel, 'sendMessage').mockImplementation();
let resolveEnrichURLPromise;
jest
Expand Down Expand Up @@ -1030,7 +1030,7 @@ describe('Link preview', () => {
});

it('submit updated message with skip_url_enrich:false if no link previews managed to get loaded', async () => {
const channel = chatClient.channel('messaging', mockedChannel.id);
const channel = chatClient.channel('messaging', mockedChannelData.channel.id);
const scrapedAudioAttachment = generateScrapedAudioAttachment({
og_scrape_url: 'http://getstream.io/audio',
});
Expand Down Expand Up @@ -1348,7 +1348,7 @@ describe('Link preview', () => {
});

it('link preview state is cleared after message submission', async () => {
const channel = chatClient.channel('messaging', mockedChannel.id);
const channel = chatClient.channel('messaging', mockedChannelData.channel.id);
const sendMessageSpy = jest.spyOn(channel, 'sendMessage').mockImplementation();
let resolveEnrichURLPromise;
jest
Expand Down
10 changes: 5 additions & 5 deletions src/components/MessageInput/__tests__/MessageInput.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ const threadMessage = generateMessage({
type: 'reply',
user: user1,
});
const mockedChannel = generateChannel({
const mockedChannelData = generateChannel({
members: [generateMember({ user: user1 }), generateMember({ user: mentionUser })],
messages: [mainListMessage],
thread: [threadMessage],
Expand Down Expand Up @@ -162,8 +162,8 @@ function axeNoViolations(container) {
describe(`${componentName}`, () => {
beforeEach(async () => {
chatClient = await getTestClientWithUser({ id: user1.id });
useMockedApis(chatClient, [getOrCreateChannelApi(mockedChannel)]);
channel = chatClient.channel('messaging', mockedChannel.id);
useMockedApis(chatClient, [getOrCreateChannelApi(mockedChannelData)]);
channel = chatClient.channel('messaging', mockedChannelData.channel.id);
});
afterEach(tearDown);

Expand Down Expand Up @@ -1125,8 +1125,8 @@ function axeNoViolations(container) {
describe(`${componentName}`, () => {
beforeEach(async () => {
chatClient = await getTestClientWithUser({ id: user1.id });
useMockedApis(chatClient, [getOrCreateChannelApi(mockedChannel)]);
channel = chatClient.channel('messaging', mockedChannel.id);
useMockedApis(chatClient, [getOrCreateChannelApi(mockedChannelData)]);
channel = chatClient.channel('messaging', mockedChannelData.channel.id);
});

afterEach(tearDown);
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export * from './context';
export * from './i18n';
// todo: distribute utils into separate files
export * from './utils';
export { getChannel } from './utils/getChannel';
4 changes: 3 additions & 1 deletion src/mock-builders/generator/channel.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ export const generateChannel = (options = { channel: {} }) => {
const { channel: optionsChannel, config, ...optionsBesidesChannel } = options;
const id = optionsChannel?.id ?? nanoid();
const type = optionsChannel?.type ?? 'messaging';
const { id: _, type: __, ...restOptionsChannel } = optionsChannel ?? {};

return {
members: [],
messages: [],
Expand Down Expand Up @@ -56,7 +58,7 @@ export const generateChannel = (options = { channel: {} }) => {
id,
type,
updated_at: '2020-04-28T11:20:48.578147Z',
...optionsChannel,
...restOptionsChannel,
},
};
};
Loading

0 comments on commit 365c6a0

Please sign in to comment.