Skip to content

Commit

Permalink
Merge branch 'develop' into chore/deps/bump-nanoid-from-4.0.2-to-5.0.1
Browse files Browse the repository at this point in the history
  • Loading branch information
arnautov-anton authored Oct 7, 2023
2 parents b5a2baa + def7c42 commit ec9a9ea
Show file tree
Hide file tree
Showing 8 changed files with 133 additions and 16 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
# [10.12.0](https://github.com/GetStream/stream-chat-react/compare/v10.11.0...v10.12.0) (2023-09-29)


### Features

* add messageDeliveryStatus prop to ChannelListPreview ([#2104](https://github.com/GetStream/stream-chat-react/issues/2104)) ([9aa4aea](https://github.com/GetStream/stream-chat-react/commit/9aa4aea6b900839a6de8f1ba49f5846167758614))
* allow to configure the search query debounce interval ([#2107](https://github.com/GetStream/stream-chat-react/issues/2107)) ([d563369](https://github.com/GetStream/stream-chat-react/commit/d5633693f1f087a5e6ad2ba29ccaa1257f9b7d7f))

# [10.11.0](https://github.com/GetStream/stream-chat-react/compare/v10.10.2...v10.11.0) (2023-09-26)


Expand Down
59 changes: 54 additions & 5 deletions docusaurus/docs/React/components/core-components/channel.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,14 @@ The Giphy version to render - check the keys of the [Image Object](https://devel
| ------ | -------------- |
| string | 'fixed_height' |

### HeaderComponent

Custom UI component to render at the top of the `MessageList`.

| Type | Default |
| --------- | ------- |
| component | none |

### imageAttachmentSizeHandler

A custom function to provide size configuration for image attachments
Expand All @@ -337,13 +345,54 @@ A custom function to provide size configuration for image attachments
| ---------------------------------------------------------------- |
| `(a: Attachment, e: HTMLElement) => ImageAttachmentConfigration` |

### HeaderComponent
### initializeOnMount

Allows to prevent triggering the `channel.watch()` (triggers channel query HTTP request) call when mounting the `Channel` component (the default behavior) with uninitialized (`channel.initialized`) `Channel` instance. That means that no channel data from the back-end will be received neither channel WS events will be delivered to the client. Preventing to initialize the channel on mount allows us to postpone the channel creation in the Stream's DB to a later point in time, for example, when a first message is sent:

```typescript jsx
import {useCallback} from "react";
import {
getChannel,
MessageInput as StreamMessageInput,
MessageInputProps, MessageToSend,
useChannelActionContext,
useChatContext
} from "stream-chat-react";
import {Message, SendMessageOptions} from "stream-chat";

import {useChannelInitContext} from "../../context/ChannelInitProvider";
import type { MyStreamChatGenerics } from "../../types";

export const MessageInput = (props: MessageInputProps) => {
const {client} = useChatContext();
const {sendMessage} = useChannelActionContext();
const { setInitializedChannelOnMount} = useChannelInitContext();

const submitHandler: MessageInputProps['overrideSubmitHandler'] = useCallback(async (
message: MessageToSend<MyStreamChatGenerics>,
channelCid: string,
customMessageData?: Partial<Message<MyStreamChatGenerics>>,
options?: SendMessageOptions,
) => {
const [channelType, channelId] = channelCid.split(":");
const channel = client.channel(channelType, channelId);
if (!channel.initialized) {
await getChannel({channel, client});
setInitializedChannelOnMount(true);
}

await sendMessage(message, customMessageData, options);
}, [client, sendMessage, setInitializedChannelOnMount]);

Custom UI component to render at the top of the `MessageList`.
return (
<StreamMessageInput {...props} overrideSubmitHandler={submitHandler} />
);
};
```

| Type | Default |
| --------- | ------- |
| component | none |
| Type | Default |
|---------|---------|
| boolean | true |

### Input

Expand Down
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.12.0",
"stream-chat": "^8.12.4",
"style-loader": "^2.0.0",
"ts-jest": "^26.5.1",
"typescript": "^4.7.4",
Expand Down
14 changes: 11 additions & 3 deletions src/components/Channel/Channel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,8 @@ export type ChannelProps<
EmptyPlaceholder?: React.ReactElement;
/** Custom UI component to be displayed when the `MessageList` is empty, defaults to and accepts same props as: [EmptyStateIndicator](https://github.com/GetStream/stream-chat-react/blob/master/src/components/EmptyStateIndicator/EmptyStateIndicator.tsx) */
EmptyStateIndicator?: ComponentContextValue<StreamChatGenerics>['EmptyStateIndicator'];
/** A global flag to toggle the URL enrichment and link previews in `MessageInput` components.
/**
* A global flag to toggle the URL enrichment and link previews in `MessageInput` components.
* By default, the feature is disabled. Can be overridden on Thread, MessageList level through additionalMessageInputProps
* or directly on MessageInput level through urlEnrichmentConfig.
*/
Expand All @@ -169,6 +170,12 @@ export type ChannelProps<
HeaderComponent?: ComponentContextValue<StreamChatGenerics>['HeaderComponent'];
/** A custom function to provide size configuration for image attachments */
imageAttachmentSizeHandler?: ImageAttachmentSizeHandler;
/**
* Allows to prevent triggering the channel.watch() call when mounting the component.
* That means that no channel data from the back-end will be received neither channel WS events will be delivered to the client.
* Preventing to initialize the channel on mount allows us to postpone the channel creation to a later point in time.
*/
initializeOnMount?: boolean;
/** Custom UI component handling how the message input is rendered, defaults to and accepts the same props as [MessageInputFlat](https://github.com/GetStream/stream-chat-react/blob/master/src/components/MessageInput/MessageInputFlat.tsx) */
Input?: ComponentContextValue<StreamChatGenerics>['Input'];
/** Custom component to render link previews in message input **/
Expand Down Expand Up @@ -312,6 +319,7 @@ const ChannelInner = <
dragAndDropWindow = false,
emojiData = defaultEmojiData,
enrichURLForPreviewConfig,
initializeOnMount = true,
LoadingErrorIndicator = DefaultLoadingErrorIndicator,
LoadingIndicator = DefaultLoadingIndicator,
maxNumberOfFiles,
Expand Down Expand Up @@ -478,7 +486,7 @@ const ChannelInner = <
};

(async () => {
if (!channel.initialized) {
if (!channel.initialized && initializeOnMount) {
try {
// 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
Expand Down Expand Up @@ -533,7 +541,7 @@ const ChannelInner = <
client.off('user.deleted', handleEvent);
notificationTimeouts.forEach(clearTimeout);
};
}, [channel.cid, doMarkReadRequest, channelConfig?.read_events]);
}, [channel.cid, doMarkReadRequest, channelConfig?.read_events, initializeOnMount]);

useEffect(() => {
if (!state.thread) return;
Expand Down
24 changes: 22 additions & 2 deletions src/components/Channel/__tests__/Channel.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -380,13 +380,33 @@ describe('Channel', () => {
jest.spyOn(channel, 'countUnread').mockImplementationOnce(() => 1);
const doMarkReadRequest = jest.fn();

renderComponent({
doMarkReadRequest,
await act(() => {
renderComponent({
doMarkReadRequest,
});
});

await waitFor(() => expect(doMarkReadRequest).toHaveBeenCalledTimes(1));
});

it('should not query the channel from the backend when initializeOnMount is disabled', async () => {
const watchSpy = jest.spyOn(channel, 'watch').mockImplementationOnce();
await act(() => {
renderComponent({
initializeOnMount: false,
});
});
await waitFor(() => expect(watchSpy).not.toHaveBeenCalled());
});

it('should query the channel from the backend when initializeOnMount is enabled (the default)', async () => {
const watchSpy = jest.spyOn(channel, 'watch').mockImplementationOnce();
await act(() => {
renderComponent();
});
await waitFor(() => expect(watchSpy).toHaveBeenCalledTimes(1));
});

describe('Children that consume the contexts set in Channel', () => {
it('should expose the emoji config', async () => {
let context;
Expand Down
29 changes: 29 additions & 0 deletions src/components/ChannelList/__tests__/ChannelList.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,35 @@ describe('ChannelList', () => {
expect(results).toHaveNoViolations();
});

it('should show unique channels', async () => {
useMockedApis(chatClientUthred, [queryChannelsApi([testChannel1, testChannel2])]);
const ChannelPreview = (props) => <div data-testid={props.channel.id} role='listitem' />;
render(
<Chat client={chatClientUthred}>
<ChannelList filters={{}} options={{ limit: 2 }} Preview={ChannelPreview} />
</Chat>,
);

await waitFor(() => {
expect(screen.getByTestId(testChannel1.channel.id)).toBeInTheDocument();
expect(screen.getByTestId(testChannel2.channel.id)).toBeInTheDocument();
expect(screen.getAllByRole('listitem')).toHaveLength(2);
});

useMockedApis(chatClientUthred, [queryChannelsApi([testChannel1, testChannel3])]);

await act(() => {
fireEvent.click(screen.getByTestId('load-more-button'));
});

await waitFor(() => {
expect(screen.getByTestId(testChannel1.channel.id)).toBeInTheDocument();
expect(screen.getByTestId(testChannel2.channel.id)).toBeInTheDocument();
expect(screen.getByTestId(testChannel3.channel.id)).toBeInTheDocument();
expect(screen.getAllByRole('listitem')).toHaveLength(3);
});
});

describe('Default and custom active channel', () => {
let setActiveChannel;
const watchersConfig = { limit: 20, offset: 0 };
Expand Down
5 changes: 4 additions & 1 deletion src/components/ChannelList/hooks/usePaginatedChannels.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useEffect, useMemo, useState } from 'react';
import uniqBy from 'lodash.uniqby';

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

Expand Down Expand Up @@ -52,7 +53,9 @@ export const usePaginatedChannels = <
const channelQueryResponse = await client.queryChannels(filters, sort || {}, newOptions);

const newChannels =
queryType === 'reload' ? channelQueryResponse : [...channels, ...channelQueryResponse];
queryType === 'reload'
? channelQueryResponse
: uniqBy([...channels, ...channelQueryResponse], 'cid');

setChannels(newChannels);
setHasNextPage(channelQueryResponse.length >= newOptions.limit);
Expand Down
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -13426,10 +13426,10 @@ stream-browserify@^2.0.1:
inherits "~2.0.1"
readable-stream "^2.0.2"

stream-chat@^8.12.0:
version "8.12.0"
resolved "https://registry.yarnpkg.com/stream-chat/-/stream-chat-8.12.0.tgz#5b661242f24577fe7b4fd56555bbc47d4f652c48"
integrity sha512-JpH3QICvQ17m4zliOTB1ADuhEdkJSvfDUFJfj4F5ykkM7qvhz9FP/3STnx3W6ltC/ed9xhSYbVmBnA5HuWlEUw==
stream-chat@^8.12.4:
version "8.12.4"
resolved "https://registry.yarnpkg.com/stream-chat/-/stream-chat-8.12.4.tgz#3c2044ceb74b4be8bd06191963723d7d47014ec1"
integrity sha512-YaNuQNqiJcF82+VKAGNSV8wv0+Th73kHIV4Owiu2Bvhwqt7398Ertr+bxW4WXkBtwKoAeOZOc0oacrUKWQAuKQ==
dependencies:
"@babel/runtime" "^7.16.3"
"@types/jsonwebtoken" "~9.0.0"
Expand Down

0 comments on commit ec9a9ea

Please sign in to comment.