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: 16 additions & 3 deletions package/src/components/Message/MessageSimple/MessageStatus.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';

import { useChannelContext } from '../../../contexts/channelContext/ChannelContext';
import {
MessageContextValue,
useMessageContext,
Expand All @@ -23,6 +24,7 @@ const MessageStatusWithContext = <
>(
props: MessageStatusPropsWithContext<StreamChatGenerics>,
) => {
const { channel } = useChannelContext<StreamChatGenerics>();
const { message, threadList } = props;

const {
Expand All @@ -47,18 +49,29 @@ const MessageStatusWithContext = <
}

if (isMessageWithStylesReadByAndDateSeparator(message)) {
const members = channel?.state.members;
const otherMembers = Object.values(members).filter(
(member) => member.user_id !== message.user?.id,
);
const hasOtherMembersGreaterThanOne = otherMembers.length > 1;
const hasReadByGreaterThanOne = typeof message.readBy === 'number' && message.readBy > 1;
const shouldDisplayReadByCount = hasOtherMembersGreaterThanOne && hasReadByGreaterThanOne;
const countOfReadBy =
typeof message.readBy === 'number' && hasOtherMembersGreaterThanOne ? message.readBy - 1 : 0;
const showDoubleCheck = hasReadByGreaterThanOne || message.readBy === true;

return (
<View style={[styles.statusContainer, statusContainer]}>
{typeof message.readBy === 'number' ? (
{shouldDisplayReadByCount ? (
<Text
style={[styles.readByCount, { color: accent_blue }, readByCount]}
testID='read-by-container'
>
{message.readBy}
{countOfReadBy}
</Text>
) : null}
{message.type !== 'error' ? (
typeof message.readBy === 'number' || message.readBy === true ? (
showDoubleCheck ? (
<CheckAll pathFill={accent_blue} {...checkAllIcon} />
) : (
<Check pathFill={grey_dark} {...checkIcon} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@ import React from 'react';

import { cleanup, render, waitFor } from '@testing-library/react-native';

import { Channel } from '../../..';
import { ChannelsStateProvider } from '../../../../contexts/channelsStateContext/ChannelsStateContext';
import { getOrCreateChannelApi } from '../../../../mock-builders/api/getOrCreateChannel';
import { useMockedApis } from '../../../../mock-builders/api/useMockedApis';
import { generateChannelResponse } from '../../../../mock-builders/generator/channel';
import { generateMember } from '../../../../mock-builders/generator/member';
import { generateMessage } from '../../../../mock-builders/generator/message';
import { generateStaticUser, generateUser } from '../../../../mock-builders/generator/user';
import { getTestClientWithUser } from '../../../../mock-builders/mock';
Expand All @@ -10,26 +16,54 @@ import { Chat } from '../../../Chat/Chat';
import { MessageStatus } from '../MessageStatus';

let chatClient;
let id;
let i18nInstance;

let channel;
describe('MessageStatus', () => {
beforeAll(async () => {
const user1 = generateUser({ id: 'id1', name: 'name1' });
const user2 = generateUser({ id: 'id2', name: 'name2' });
const user3 = generateUser({ id: 'id3', name: 'name3' });
const messages = [generateMessage({ user: user1 })];
const members = [
generateMember({ user: user1 }),
generateMember({ user: user2 }),
generateMember({ user: user3 }),
];
beforeAll(() => {
id = 'testID';
chatClient = await getTestClientWithUser({ id });
i18nInstance = new Streami18n();
});
beforeEach(async () => {
jest.clearAllMocks();
const mockedChannel = generateChannelResponse({
members,
messages,
});

chatClient = await getTestClientWithUser(user1);
useMockedApis(chatClient, [getOrCreateChannelApi(mockedChannel)]);
channel = chatClient.channel('messaging', mockedChannel.id);
});
afterEach(cleanup);

renderMessageStatus = (options, channelProps) =>
render(
<ChannelsStateProvider>
<Chat client={chatClient}>
<Channel channel={channel} {...channelProps}>
<MessageStatus {...options} />
</Channel>
</Chat>
</ChannelsStateProvider>,
);

it('should render message status with delivered container', async () => {
const user = generateUser();
const message = generateMessage({ user });

const { getByTestId } = render(
<Chat client={chatClient} i18nInstance={i18nInstance}>
<MessageStatus lastReceivedId={message.id} message={{ ...message, status: 'received' }} />
</Chat>,
);
const { getByTestId } = renderMessageStatus({
lastReceivedId: message.id,
message: { ...message, status: 'received' },
});

await waitFor(() => {
expect(getByTestId('delivered-container')).toBeTruthy();
Expand All @@ -40,42 +74,43 @@ describe('MessageStatus', () => {
const user = generateUser();
const message = generateMessage({ readBy: 2, user });

const { getByTestId, getByText, rerender, toJSON } = render(
<Chat client={chatClient} i18nInstance={i18nInstance}>
<MessageStatus lastReceivedId={message.id} message={message} />
</Chat>,
);
const { getByTestId, getByText, rerender, toJSON } = renderMessageStatus({
lastReceivedId: message.id,
message,
});

await waitFor(() => {
expect(getByTestId('read-by-container')).toBeTruthy();
expect(getByText(message.readBy.toString())).toBeTruthy();
expect(getByText((message.readBy - 1).toString())).toBeTruthy();
});

const staticUser = generateStaticUser(0);
const staticMessage = generateMessage({ readBy: 2, staticUser });

rerender(
<Chat client={chatClient} i18nInstance={i18nInstance}>
<MessageStatus lastReceivedId={staticMessage.id} message={staticMessage} />
</Chat>,
<ChannelsStateProvider>
<Chat client={chatClient} i18nInstance={i18nInstance}>
<Channel channel={channel}>
<MessageStatus lastReceivedId={staticMessage.id} message={staticMessage} />
</Channel>
</Chat>
</ChannelsStateProvider>,
);

await waitFor(() => {
expect(toJSON()).toMatchSnapshot();
expect(getByTestId('read-by-container')).toBeTruthy();
expect(getByText(staticMessage.readBy.toString())).toBeTruthy();
expect(getByText((staticMessage.readBy - 1).toString())).toBeTruthy();
});
});

it('should render message status with sending container', async () => {
const user = generateUser();
const message = generateMessage({ user });

const { getByTestId } = render(
<Chat client={chatClient} i18nInstance={i18nInstance}>
<MessageStatus message={{ ...message, status: 'sending' }} />
</Chat>,
);
const { getByTestId } = renderMessageStatus({
message: { ...message, status: 'sending' },
});

await waitFor(() => {
expect(getByTestId('sending-container')).toBeTruthy();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,106 +2,124 @@

exports[`MessageStatus should render message status with read by container 1`] = `
<View
keyboardVerticalOffset={86.5}
onLayout={[Function]}
style={
[
{
"alignItems": "flex-end",
"flexDirection": "row",
"justifyContent": "center",
"paddingRight": 3,
},
{},
]
{
"paddingBottom": 0,
}
}
>
<Text
style={
[
{
"fontSize": 11,
"fontWeight": "700",
"paddingRight": 3,
},
{
"color": "#005FFF",
},
{},
]
}
testID="read-by-container"
>
2
</Text>
<RNSVGSvgView
align="xMidYMid"
bbHeight={16}
bbWidth={16}
focusable={false}
height={16}
meetOrSlice={0}
minX={0}
minY={0}
pathFill="#005FFF"
<View
style={
[
{
"backgroundColor": "transparent",
"borderWidth": 0,
},
{
"flex": 0,
"height": 16,
"width": 16,
},
]
{
"height": "100%",
}
}
vbHeight={24}
vbWidth={24}
width={16}
>
<RNSVGGroup
fill={
{
"payload": 4278190080,
"type": 0,
}
<View
style={
[
{
"alignItems": "flex-end",
"flexDirection": "row",
"justifyContent": "center",
"paddingRight": 3,
},
{},
]
}
>
<RNSVGPath
clipRule={0}
d="M2.293 11.293a1 1 0 011.414 0l4 4a1 1 0 11-1.414 1.414l-4-4a1 1 0 010-1.414zM9.293 12.293a1 1 0 011.414 0l3 3a1 1 0 01-1.414 1.414l-3-3a1 1 0 010-1.414z"
fill={
{
"payload": 4278214655,
"type": 0,
}
}
fillRule={0}
propList={
<Text
style={
[
"fill",
"fillRule",
{
"fontSize": 11,
"fontWeight": "700",
"paddingRight": 3,
},
{
"color": "#005FFF",
},
{},
]
}
/>
<RNSVGPath
clipRule={0}
d="M15.707 7.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414-1.414l8-8a1 1 0 011.414 0zM21.707 7.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414-1.414l8-8a1 1 0 011.414 0z"
fill={
{
"payload": 4278214655,
"type": 0,
}
}
fillRule={0}
propList={
testID="read-by-container"
>
1
</Text>
<RNSVGSvgView
align="xMidYMid"
bbHeight={16}
bbWidth={16}
focusable={false}
height={16}
meetOrSlice={0}
minX={0}
minY={0}
pathFill="#005FFF"
style={
[
"fill",
"fillRule",
{
"backgroundColor": "transparent",
"borderWidth": 0,
},
{
"flex": 0,
"height": 16,
"width": 16,
},
]
}
/>
</RNSVGGroup>
</RNSVGSvgView>
vbHeight={24}
vbWidth={24}
width={16}
>
<RNSVGGroup
fill={
{
"payload": 4278190080,
"type": 0,
}
}
>
<RNSVGPath
clipRule={0}
d="M2.293 11.293a1 1 0 011.414 0l4 4a1 1 0 11-1.414 1.414l-4-4a1 1 0 010-1.414zM9.293 12.293a1 1 0 011.414 0l3 3a1 1 0 01-1.414 1.414l-3-3a1 1 0 010-1.414z"
fill={
{
"payload": 4278214655,
"type": 0,
}
}
fillRule={0}
propList={
[
"fill",
"fillRule",
]
}
/>
<RNSVGPath
clipRule={0}
d="M15.707 7.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414-1.414l8-8a1 1 0 011.414 0zM21.707 7.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414-1.414l8-8a1 1 0 011.414 0z"
fill={
{
"payload": 4278214655,
"type": 0,
}
}
fillRule={0}
propList={
[
"fill",
"fillRule",
]
}
/>
</RNSVGGroup>
</RNSVGSvgView>
</View>
</View>
</View>
`;