Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

QA for modularization phase 1 #353

Merged
merged 12 commits into from
Sep 6, 2024
7 changes: 3 additions & 4 deletions src/components/BotMessageFeedback.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { Feedback, FeedbackRating } from '@sendbird/chat/message';
import { BaseMessage, Feedback, FeedbackRating } from '@sendbird/chat/message';
import { useReducer } from 'react';

import FeedbackIconButton from '@uikit/ui/FeedbackIconButton';
import MessageFeedbackFailedModal from '@uikit/ui/MessageFeedbackFailedModal';
import MessageFeedbackModal from '@uikit/ui/MessageFeedbackModal';
import MobileFeedbackMenu from '@uikit/ui/MobileFeedbackMenu';
import { CoreMessageType } from '@uikit/utils';

import { elementIds } from '../const';
import { useConstantState } from '../context/ConstantContext';
Expand All @@ -17,7 +16,7 @@ type State = Partial<{
menuVisible: boolean;
}>;

function BotMessageFeedback({ message }: { message: CoreMessageType }) {
function BotMessageFeedback({ message }: { message: BaseMessage }) {
const { stringSet } = useConstantState();
const [state, setState] = useReducer((p: State, a: State) => ({ ...p, ...a }), {
errorText: '',
Expand Down Expand Up @@ -104,7 +103,7 @@ function BotMessageFeedback({ message }: { message: CoreMessageType }) {
isMobile
rootElementId={elementIds.widgetWindow}
selectedFeedback={message.myFeedback.rating}
message={message}
message={message as any}
onUpdate={async (selectedFeedback, comment) => {
if (message.myFeedback) {
try {
Expand Down
7 changes: 3 additions & 4 deletions src/components/BotMessageWithBodyInput.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { User } from '@sendbird/chat';
import { ReactNode } from 'react';
import styled from 'styled-components';

import BotProfileImage from './BotProfileImage';
import { useChatContext } from './chat/context/ChatProvider';
import { DefaultSentTime, FullBodyContainer, WideSentTime } from './MessageComponent';
import { useConstantState } from '../context/ConstantContext';
import { Label } from '../foundation/components/Label';
Expand All @@ -12,7 +12,6 @@ const Root = styled.span`
display: flex;
flex-direction: row;
align-items: flex-end;
margin-bottom: 6px;
gap: 8px;
position: relative;
`;
Expand All @@ -38,7 +37,6 @@ const EmptyImageContainer = styled.div`
`;

type Props = {
botUser?: User;
createdAt?: number;
messageData?: string;
bodyComponent: ReactNode;
Expand All @@ -55,9 +53,10 @@ const HEIGHTS = {
};

export default function BotMessageWithBodyInput(props: Props) {
const { botUser } = useChatContext();
const { botStudioEditProps, dateLocale } = useConstantState();

const { botUser, createdAt, bodyComponent, chainTop, chainBottom, messageFeedback, wideContainer = false } = props;
const { createdAt, bodyComponent, chainTop, chainBottom, messageFeedback, wideContainer = false } = props;

const profilePaddingBottom = (messageFeedback ? HEIGHTS.FEEDBACK : 0) + (wideContainer ? HEIGHTS.TIMESTAMP : 0);

Expand Down
2 changes: 0 additions & 2 deletions src/components/CurrentUserMessage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@ const Root = styled.div<{ enableEmojiFeedback: boolean }>`
display: flex;
justify-content: flex-end;
align-items: end;
margin-bottom: 6px;
gap: 4px;
margin-top: ${({ enableEmojiFeedback }) => (enableEmojiFeedback ? '16px' : '0')};
`;

type Props = {
Expand Down
28 changes: 14 additions & 14 deletions src/components/CustomMessage.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { User } from '@sendbird/chat';
import { BaseMessage } from '@sendbird/chat/message';

import { CoreMessageType, isVideoMessage } from '@uikit/utils';
import { isVideoMessage } from '@uikit/utils';

import AdminMessage from './AdminMessage';
import BotMessageFeedback from './BotMessageFeedback';
import BotMessageWithBodyInput from './BotMessageWithBodyInput';
import { useChatContext } from './chat/context/ChatProvider';
import CurrentUserMessage from './CurrentUserMessage';
import CustomMessageBody from './CustomMessageBody';
import CustomTypingIndicatorBubble from './CustomTypingIndicatorBubble';
Expand All @@ -21,26 +22,29 @@ import { messageExtension } from '../utils/messageExtension';
import { isSentBy } from '../utils/messages';

type Props = {
message: CoreMessageType;
message: BaseMessage;
activeSpinnerId: number;
botUser?: User;
chainTop?: boolean;
chainBottom?: boolean;
};

export default function CustomMessage(props: Props) {
const { message, activeSpinnerId, botUser } = props;
const { replacementTextList, enableEmojiFeedback, botStudioEditProps } = useConstantState();
const { botUser } = useChatContext();
const { message, activeSpinnerId } = props;
const { replacementTextList, enableEmojiFeedback, botStudioEditProps = {} } = useConstantState();
const { userId: currentUserId } = useWidgetSession();
const { profileUrl } = botStudioEditProps?.botInfo ?? {};
const { botInfo } = botStudioEditProps;

const botUserId = botUser?.userId;
const botProfileUrl = profileUrl ?? botUser?.profileUrl ?? '';
const botProfileUrl = botInfo?.profileUrl ?? botUser?.profileUrl ?? '';
const isWaitingForBotReply = activeSpinnerId === message.messageId && !!botUser;

const shouldRenderFeedback = () => {
return (
enableEmojiFeedback && message.myFeedbackStatus !== 'NOT_APPLICABLE' && !messageExtension.isStreaming(message)
enableEmojiFeedback &&
message.myFeedbackStatus !== 'NOT_APPLICABLE' &&
!messageExtension.isStreaming(message) &&
!messageExtension.isBotWelcomeMsg(message, botUserId ?? '')
);
};

Expand All @@ -65,7 +69,7 @@ export default function CustomMessage(props: Props) {
return (
<div>
<CurrentUserMessage message={message} />
{isWaitingForBotReply && <CustomTypingIndicatorBubble botProfileUrl={botProfileUrl} />}
{isWaitingForBotReply && <CustomTypingIndicatorBubble />}
</div>
);
}
Expand All @@ -77,7 +81,6 @@ export default function CustomMessage(props: Props) {
return (
<BotMessageWithBodyInput
{...props}
botUser={botUser}
bodyComponent={<FormMessage form={message.messageForm} message={message} />}
createdAt={message.createdAt}
/>
Expand All @@ -90,7 +93,6 @@ export default function CustomMessage(props: Props) {
<BotMessageWithBodyInput
wideContainer={isVideoMessage(message)}
{...props}
botUser={botUser}
bodyComponent={<FileMessage message={message} profileUrl={botProfileUrl} />}
createdAt={message.createdAt}
messageFeedback={renderFeedbackButtons()}
Expand All @@ -111,7 +113,6 @@ export default function CustomMessage(props: Props) {
<BotMessageWithBodyInput
wideContainer
{...props}
botUser={botUser}
bodyComponent={
<ShopItemsMessage message={message} streamingBody={<TypingBubble />} textBody={textMessageBody} />
}
Expand All @@ -125,7 +126,6 @@ export default function CustomMessage(props: Props) {
return (
<BotMessageWithBodyInput
{...props}
botUser={botUser}
bodyComponent={textMessageBody}
createdAt={message.createdAt}
messageFeedback={renderFeedbackButtons()}
Expand Down
12 changes: 10 additions & 2 deletions src/components/CustomTypingIndicatorBubble.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
import BotProfileImage from './BotProfileImage';
import { useChatContext } from './chat/context/ChatProvider';
import { useConstantState } from '../context/ConstantContext';
import { TypingBubble } from '../foundation/components/TypingBubble';

function CustomTypingIndicatorBubble({ botProfileUrl }: { botProfileUrl: string }) {
function CustomTypingIndicatorBubble() {
const { botStudioEditProps = {} } = useConstantState();
const { botUser } = useChatContext();

const botInfo = botStudioEditProps.botInfo;
const botProfileUrl = botInfo?.profileUrl ?? botUser?.profileUrl;

return (
<div style={{ display: 'flex', alignItems: 'flex-end', gap: 8 }}>
<div style={{ display: 'flex', alignItems: 'flex-end', gap: 8, marginTop: 16 }}>
<BotProfileImage size={28} profileUrl={botProfileUrl} />
<TypingBubble />
</div>
Expand Down
12 changes: 7 additions & 5 deletions src/components/SuggestedRepliesContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@ interface Props {
const SuggestedRepliesContainer = ({ replies = [], type = 'vertical', sendUserMessage }: Props) => {
if (replies.length <= 0) return null;
return (
<SuggestedReplies
replyOptions={replies}
onSendMessage={({ message }) => sendUserMessage?.({ message })}
type={type}
/>
<div style={{ marginTop: 8 }}>
<SuggestedReplies
replyOptions={replies}
onSendMessage={({ message }) => sendUserMessage?.({ message })}
type={type}
/>
</div>
);
};

Expand Down
1 change: 0 additions & 1 deletion src/components/UserMessageWithBodyInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import { formatCreatedAtToAMPM } from '../utils/messageTimestamp';
const Root = styled.div`
display: flex;
align-items: flex-end;
margin-bottom: 6px;
flex-wrap: wrap;
gap: 8px;
position: relative;
Expand Down
13 changes: 11 additions & 2 deletions src/components/chat/context/ChatProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { SendbirdChatWith, SendbirdError, SendbirdErrorCode } from '@sendbird/chat';
import { SendbirdChatWith, SendbirdError, SendbirdErrorCode, User } from '@sendbird/chat';
import { GroupChannel, GroupChannelModule } from '@sendbird/chat/groupChannel';
import { useGroupChannelMessages } from '@sendbird/uikit-tools';
import { createContext, PropsWithChildren, useContext, useEffect, useState } from 'react';
Expand All @@ -18,6 +18,7 @@ export interface WidgetStringSet {
export interface ChatContextType {
sdk: SendbirdChatWith<[GroupChannelModule]> | null;
channel: GroupChannel | null;
botUser?: User;
dataSource: ReturnType<typeof useGroupChannelMessages>;
scrollSource: ReturnType<typeof useMessageListScroll>;

Expand Down Expand Up @@ -74,14 +75,22 @@ export const ChatContainer = (props: PropsWithChildren<ChatContainerProps>) => {
if (errorMessage) return <Placeholder type={'error'} label={errorMessage} />;

return (
<ChatProvider channel={channel} dataSource={dataSource} scrollSource={scrollSource} handlers={handlers} {...props}>
<ChatProvider
channel={channel}
botUser={channel?.members.find((it) => it.userId === botId)}
dataSource={dataSource}
scrollSource={scrollSource}
handlers={handlers}
{...props}
>
{children}
</ChatProvider>
);
};

interface ChatProviderProps extends ChatContainerProps {
channel: GroupChannel | null;
botUser?: User;
dataSource: ReturnType<typeof useGroupChannelMessages>;
scrollSource: ReturnType<typeof useMessageListScroll>;
handlers: WidgetChatHandlers;
Expand Down
7 changes: 3 additions & 4 deletions src/components/chat/hooks/useBotStudioView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,10 @@ import { useChatContext } from '../context/ChatProvider';

export const useBotStudioView = () => {
const { botStudioEditProps = {}, botId, replacementTextList, stringSet } = useConstantState();
const { dataSource, channel, handlers } = useChatContext();
const { dataSource, handlers } = useChatContext();
const { suggestedRepliesDirection, welcomeMessages = [] } = botStudioEditProps;
const { messages } = dataSource;

const botUser = channel?.members.find((member) => member.userId === botId);
const originalWMs = getBotWelcomeMessages(messages, botId);

const firstUserMsg = messages[originalWMs.length + 1];
Expand Down Expand Up @@ -64,11 +63,10 @@ export const useBotStudioView = () => {
const isLastMessage = index === welcomeMessages.length - 1;

return (
<div key={index} style={{ padding: '0 16px' }}>
<div key={index} style={{ padding: '0 16px', marginBottom: 16 }}>
<BotMessageWithBodyInput
chainTop={index === 0}
chainBottom={index === welcomeMessages.length - 1}
botUser={botUser}
bodyComponent={<ParsedBotMessageBody text={text} tokens={tokens} />}
createdAt={firstOriginalWM?.createdAt}
/>
Expand Down Expand Up @@ -99,4 +97,5 @@ export const useBotStudioView = () => {

const dateSeparatorMargin = css`
margin: 8px 0;
padding: 0 16px;
`;
5 changes: 2 additions & 3 deletions src/components/chat/ui/ChatHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,12 @@ type Props = {
fullscreen: boolean;
};
export const ChatHeader = ({ fullscreen }: Props) => {
const { botId, botStudioEditProps, isMobileView, enableWidgetExpandButton, betaMark, customBetaMarkText } =
const { botStudioEditProps, isMobileView, enableWidgetExpandButton, betaMark, customBetaMarkText } =
useConstantState();
const { sdk, channel, dataSource } = useChatContext();
const { sdk, channel, botUser, dataSource } = useChatContext();
const { setIsOpen } = useWidgetState();

const { botInfo } = botStudioEditProps ?? {};
const botUser = channel?.members.find((member) => member.userId === botId);
const botNickname = botInfo?.nickname ?? botUser?.nickname;
const profileUrl = botInfo?.profileUrl ?? botUser?.profileUrl;
const buttonSize = isMobileView ? 24 : 16;
Expand Down
6 changes: 2 additions & 4 deletions src/components/chat/ui/ChatInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,20 @@ import { useRef } from 'react';
import useSendbirdStateContext from '@uikit/hooks/useSendbirdStateContext';
import MessageInputWrapperView from '@uikit/modules/GroupChannel/components/MessageInputWrapper/MessageInputWrapperView';

import { useConstantState } from '../../../context/ConstantContext';
import { themedColors } from '../../../foundation/colors/css';
import { useBlockWhileBotResponding } from '../../../hooks/useBlockWhileBotResponding';
import { isIOSMobile } from '../../../utils';
import { useChatContext } from '../context/ChatProvider';

export const ChatInput = () => {
const { botId } = useConstantState();
const { channel, dataSource, handlers } = useChatContext();
const { channel, botUser, dataSource, handlers } = useChatContext();

const ref = useRef<HTMLDivElement>(null);

const { config } = useSendbirdStateContext();
const isMessageInputDisabled = useBlockWhileBotResponding({
lastMessage: dataSource.messages[dataSource.messages.length - 1],
botUser: channel?.members.find((it) => it.userId === botId),
botUser,
});

return (
Expand Down
Loading