Skip to content

Commit

Permalink
Implement message reply info.
Browse files Browse the repository at this point in the history
  • Loading branch information
OnestarLee committed May 30, 2024
1 parent abe92cc commit d6b7734
Show file tree
Hide file tree
Showing 9 changed files with 289 additions and 212 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const MessageContainer = (props: Props) => {

MessageContainer.Incoming = function MessageContainerIncoming({
children,
replyInfo,
groupedWithNext,
groupedWithPrev,
message,
Expand All @@ -34,43 +35,48 @@ MessageContainer.Incoming = function MessageContainerIncoming({
const color = colors.ui.groupChannelMessage.incoming;

return (
<Box flexDirection={'row'} justifyContent={'flex-start'} alignItems={'flex-end'}>
<Box width={26} marginRight={12}>
{(message.isFileMessage() || message.isUserMessage()) && !groupedWithNext && (
<Pressable onPress={onPressAvatar}>
<Avatar size={26} uri={message.sender?.profileUrl} />
</Pressable>
)}
</Box>
<Box flexShrink={1}>
{parentMessage}
{!groupedWithPrev && !message.parentMessage && (
<Box marginLeft={12} marginBottom={4}>
{(message.isFileMessage() || message.isUserMessage()) && (
<Text caption1 color={color.enabled.textSenderName} numberOfLines={1}>
{strings?.senderName ?? message.sender.nickname}
</Text>
)}
</Box>
)}

<Box flexDirection={'row'} alignItems={'flex-end'}>
<Box style={styles.bubble}>{children}</Box>
{!groupedWithNext && (
<Box marginLeft={4}>
<Text caption4 color={color.enabled.textTime}>
{strings?.sentDate ?? getMessageTimeFormat(new Date(message.createdAt))}
</Text>
<Box flexDirection={'column'} justifyContent={'flex-start'} alignItems={'flex-start'}>
<Box flexDirection={'row'} justifyContent={'flex-start'} alignItems={'flex-end'}>
<Box width={26} marginRight={12}>
{(message.isFileMessage() || message.isUserMessage()) && !groupedWithNext && (
<Pressable onPress={onPressAvatar}>
<Avatar size={26} uri={message.sender?.profileUrl} />
</Pressable>
)}
</Box>
<Box flexShrink={1}>
{parentMessage}
{!groupedWithPrev && !message.parentMessage && (
<Box marginLeft={12} marginBottom={4}>
{(message.isFileMessage() || message.isUserMessage()) && (
<Text caption1 color={color.enabled.textSenderName} numberOfLines={1}>
{strings?.senderName ?? message.sender.nickname}
</Text>
)}
</Box>
)}
<Box flexDirection={'row'} alignItems={'flex-end'}>
<Box style={styles.bubble}>{children}</Box>
{!groupedWithNext && (
<Box marginLeft={4}>
<Text caption4 color={color.enabled.textTime}>
{strings?.sentDate ?? getMessageTimeFormat(new Date(message.createdAt))}
</Text>
</Box>
)}
</Box>
</Box>
</Box>
<Box marginLeft={40} marginTop={4} flexDirection={'row'} height={20}>
{replyInfo}
</Box>
</Box>
);
};

MessageContainer.Outgoing = function MessageContainerOutgoing({
children,
replyInfo,
message,
groupedWithNext,
strings,
Expand All @@ -96,6 +102,9 @@ MessageContainer.Outgoing = function MessageContainerOutgoing({
</Box>
<Box style={styles.bubble}>{children}</Box>
</Box>
<Box marginTop={4} flexDirection={'row-reverse'} height={20}>
{replyInfo}
</Box>
</Box>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export type GroupChannelMessageProps<T extends SendbirdMessage, AdditionalProps
children?: React.ReactNode;
sendingStatus?: React.ReactNode;
parentMessage?: React.ReactNode;
replyInfo?: React.ReactNode;

groupedWithPrev: boolean;
groupedWithNext: boolean;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ export type ChannelMessageListProps<T extends SendbirdGroupChannel | SendbirdOpe
onPress?: () => void;
onLongPress?: () => void;
onPressParentMessage?: ChannelMessageListProps<T>['onPressParentMessage'];
onReplyInThreadMessage?: ChannelMessageListProps<T>['onReplyInThreadMessage'];
onShowUserProfile?: UserProfileContextType['show'];
channel: T;
currentUserId?: ChannelMessageListProps<T>['currentUserId'];
Expand Down Expand Up @@ -143,6 +144,7 @@ const ChannelMessageList = <T extends SendbirdGroupChannel | SendbirdOpenChannel
onPress,
onLongPress,
onPressParentMessage,
onReplyInThreadMessage,
onShowUserProfile: show,
enableMessageGrouping,
channel,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import React from 'react';
import { User } from '@sendbird/chat';
import { Avatar, Box, createStyleSheet, Icon, PressBox, Text, useUIKitTheme } from '@sendbird/uikit-react-native-foundation';
import { SendbirdFileMessage, SendbirdGroupChannel, SendbirdMessage, SendbirdUserMessage } from '@sendbird/uikit-utils';

import { useLocalization } from '../../hooks/useContext';

const AVATAR_LIMIT = 5;

type Props = {
channel: SendbirdGroupChannel;
message: SendbirdMessage;
onPress?: (message: SendbirdUserMessage | SendbirdFileMessage) => void;
};

const createRepliedUserAvatars = (mostRepliedUsers: User[]) => {
if (!mostRepliedUsers || mostRepliedUsers.length === 0) return null;

const { palette } = useUIKitTheme();

return mostRepliedUsers.slice(0, AVATAR_LIMIT).map((user, index) => {
if (index < AVATAR_LIMIT - 1) {
return <Box style={styles.avatarContainer} key={index}>
<Avatar size={20} uri={user?.profileUrl} containerStyle={styles.avatar}></Avatar>
</Box>;
} else {
return <Box style={styles.avatarContainer} key={index}>
<Avatar size={20} uri={user?.profileUrl} containerStyle={styles.avatar}></Avatar>
<Box style={styles.avatarOverlay} backgroundColor={palette.overlay01}>
<Icon icon={'plus'} size={14} style={styles.plusIcon} color={'white'} />
</Box>
</Box>;
}
});
};

const GroupChannelMessageReplyInfo = ({ channel, message, onPress }: Props) => {
const { STRINGS } = useLocalization();
const { select, palette } = useUIKitTheme();

if (!channel || !message.threadInfo || !message.threadInfo.replyCount) return null;

const replyCountText = STRINGS.GROUP_CHANNEL_THREAD.REPLAY_POSTFIX(message.threadInfo.replyCount || 0);
const onPressReply = () => {
onPress?.(message as SendbirdUserMessage | SendbirdFileMessage);
};

const renderAvatars = createRepliedUserAvatars(message.threadInfo.mostRepliedUsers);

return <PressBox onPress={onPressReply} style={styles.messageContainer}>
{renderAvatars}
<Text caption3 color={select({ light: palette.primary300, dark: palette.primary200 })} style={styles.message}>
{replyCountText}
</Text>
</PressBox>;
};

const styles = createStyleSheet({
container: {
flexDirection: 'row',
},
messageContainer: {
flexDirection: 'row',
alignItems: 'flex-end',
},
message: {
marginHorizontal: 4,
},
avatarContainer: {
marginRight: 4,
width: 20,
height: 20,
},
avatar: {
width: '100%',
height: '100%',
},
avatarOverlay: {
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
borderRadius: 10,
},
plusIcon: {
position: 'absolute',
top: 3,
left: 3,
right: 0,
bottom: 0,
},
});

export default React.memo(GroupChannelMessageReplyInfo);
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import GroupChannelMessageDateSeparator from './GroupChannelMessageDateSeparator
import GroupChannelMessageFocusAnimation from './GroupChannelMessageFocusAnimation';
import GroupChannelMessageOutgoingStatus from './GroupChannelMessageOutgoingStatus';
import GroupChannelMessageParentMessage from './GroupChannelMessageParentMessage';
import GroupChannelMessageReplyInfo from './GroupChannelMessageReplyInfo';

const GroupChannelMessageRenderer: GroupChannelProps['Fragment']['renderMessage'] = ({
channel,
Expand All @@ -41,6 +42,7 @@ const GroupChannelMessageRenderer: GroupChannelProps['Fragment']['renderMessage'
onLongPress,
onPressParentMessage,
onShowUserProfile,
onReplyInThreadMessage,
enableMessageGrouping,
focused,
prevMessage,
Expand All @@ -58,7 +60,8 @@ const GroupChannelMessageRenderer: GroupChannelProps['Fragment']['renderMessage'
prevMessage,
nextMessage,
);

const variant = isMyMessage(message, currentUser?.userId) ? 'outgoing' : 'incoming';

const reactionChildren = useIIFE(() => {
const configs = sbOptions.uikitWithAppInfo.groupChannel.channel;
if (
Expand All @@ -70,7 +73,13 @@ const GroupChannelMessageRenderer: GroupChannelProps['Fragment']['renderMessage'
}
return null;
});


const renderReplyInfo = useIIFE(() => {
if (sbOptions.uikit.groupChannel.channel.replyType !== 'thread') return null;
if (!channel || !message.threadInfo || !message.threadInfo.replyCount) return null;
return <GroupChannelMessageReplyInfo channel={channel} message={message} onPress={onReplyInThreadMessage} />;
});

const resetPlayer = async () => {
playerUnsubscribes.current.forEach((unsubscribe) => {
try {
Expand All @@ -81,8 +90,6 @@ const GroupChannelMessageRenderer: GroupChannelProps['Fragment']['renderMessage'
await playerService.reset();
};

const variant = isMyMessage(message, currentUser?.userId) ? 'outgoing' : 'incoming';

const messageProps: Omit<GroupChannelMessageProps<SendbirdMessage>, 'message'> = {
channel,
variant,
Expand Down Expand Up @@ -147,6 +154,7 @@ const GroupChannelMessageRenderer: GroupChannelProps['Fragment']['renderMessage'
groupedWithPrev: groupWithPrev,
groupedWithNext: groupWithNext,
children: reactionChildren,
replyInfo: renderReplyInfo,
sendingStatus: isMyMessage(message, currentUser?.userId) ? (
<GroupChannelMessageOutgoingStatus channel={channel} message={message} />
) : null,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React, { useContext, useEffect } from 'react';

import { useChannelHandler } from '@sendbird/uikit-chat-hooks';
import { isDifferentChannel, useFreshCallback, useUniqHandlerId } from '@sendbird/uikit-utils';
import React, { useContext, useEffect, useLayoutEffect } from 'react';

import ChannelMessageList from '../../../components/ChannelMessageList';
import { useSendbirdChat } from '../../../hooks/useContext';
Expand All @@ -12,7 +11,7 @@ const GroupChannelThreadMessageList = (props: GroupChannelThreadProps['MessageLi
const { sdk } = useSendbirdChat();
const { setMessageToEdit } = useContext(GroupChannelThreadContexts.Fragment);
const { subscribe } = useContext(GroupChannelThreadContexts.PubSub);
const { flatListRef, lazyScrollToBottom } = useContext(GroupChannelThreadContexts.MessageList);
const { flatListRef, lazyScrollToBottom, lazyScrollToIndex } = useContext(GroupChannelThreadContexts.MessageList);

const id = useUniqHandlerId('GroupChannelThreadMessageList');

Expand All @@ -28,6 +27,16 @@ const GroupChannelThreadMessageList = (props: GroupChannelThreadProps['MessageLi
}
});

useLayoutEffect(() => {
if (props.startingPoint) {
const foundMessageIndex = props.messages.findIndex((it) => it.createdAt === props.startingPoint);
const isIncludedInList = foundMessageIndex > -1;
if (isIncludedInList) {
lazyScrollToIndex({ index: foundMessageIndex, animated: true, timeout: 100 });
}
}
}, [props.startingPoint]);

useChannelHandler(sdk, id, {
onReactionUpdated(channel, event) {
if (isDifferentChannel(channel, props.channel)) return;
Expand Down
Loading

0 comments on commit d6b7734

Please sign in to comment.