| import { ReactComponent as AssistantIcon } from '@/assets/svg/assistant.svg'; | |
| import { MessageType } from '@/constants/chat'; | |
| import { useTranslate } from '@/hooks/commonHooks'; | |
| import { Message } from '@/interfaces/database/chat'; | |
| import { Avatar, Button, Flex, Input, Skeleton, Spin } from 'antd'; | |
| import classNames from 'classnames'; | |
| import { useSelectConversationLoading } from '../hooks'; | |
| import HightLightMarkdown from '@/components/highlight-markdown'; | |
| import React, { ChangeEventHandler, forwardRef } from 'react'; | |
| import { IClientConversation } from '../interface'; | |
| import styles from './index.less'; | |
| const MessageItem = ({ item }: { item: Message }) => { | |
| const isAssistant = item.role === MessageType.Assistant; | |
| return ( | |
| <div | |
| className={classNames(styles.messageItem, { | |
| [styles.messageItemLeft]: item.role === MessageType.Assistant, | |
| [styles.messageItemRight]: item.role === MessageType.User, | |
| })} | |
| > | |
| <section | |
| className={classNames(styles.messageItemSection, { | |
| [styles.messageItemSectionLeft]: item.role === MessageType.Assistant, | |
| [styles.messageItemSectionRight]: item.role === MessageType.User, | |
| })} | |
| > | |
| <div | |
| className={classNames(styles.messageItemContent, { | |
| [styles.messageItemContentReverse]: item.role === MessageType.User, | |
| })} | |
| > | |
| {item.role === MessageType.User ? ( | |
| <Avatar | |
| size={40} | |
| src={ | |
| 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png' | |
| } | |
| /> | |
| ) : ( | |
| <AssistantIcon></AssistantIcon> | |
| )} | |
| <Flex vertical gap={8} flex={1}> | |
| <b>{isAssistant ? '' : 'You'}</b> | |
| <div className={styles.messageText}> | |
| {item.content !== '' ? ( | |
| <HightLightMarkdown>{item.content}</HightLightMarkdown> | |
| ) : ( | |
| <Skeleton active className={styles.messageEmpty} /> | |
| )} | |
| </div> | |
| </Flex> | |
| </div> | |
| </section> | |
| </div> | |
| ); | |
| }; | |
| interface IProps { | |
| handlePressEnter(): void; | |
| handleInputChange: ChangeEventHandler<HTMLInputElement>; | |
| value: string; | |
| loading: boolean; | |
| sendLoading: boolean; | |
| conversation: IClientConversation; | |
| ref: React.LegacyRef<any>; | |
| } | |
| const ChatContainer = ( | |
| { | |
| handlePressEnter, | |
| handleInputChange, | |
| value, | |
| loading: sendLoading, | |
| conversation, | |
| }: IProps, | |
| ref: React.LegacyRef<any>, | |
| ) => { | |
| const loading = useSelectConversationLoading(); | |
| const { t } = useTranslate('chat'); | |
| return ( | |
| <> | |
| <Flex flex={1} className={styles.chatContainer} vertical> | |
| <Flex flex={1} vertical className={styles.messageContainer}> | |
| <div> | |
| <Spin spinning={loading}> | |
| {conversation?.message?.map((message) => { | |
| return ( | |
| <MessageItem key={message.id} item={message}></MessageItem> | |
| ); | |
| })} | |
| </Spin> | |
| </div> | |
| <div ref={ref} /> | |
| </Flex> | |
| <Input | |
| size="large" | |
| placeholder={t('sendPlaceholder')} | |
| value={value} | |
| // disabled={disabled} | |
| suffix={ | |
| <Button | |
| type="primary" | |
| onClick={handlePressEnter} | |
| loading={sendLoading} | |
| // disabled={disabled} | |
| > | |
| {t('send')} | |
| </Button> | |
| } | |
| onPressEnter={handlePressEnter} | |
| onChange={handleInputChange} | |
| /> | |
| </Flex> | |
| </> | |
| ); | |
| }; | |
| export default forwardRef(ChatContainer); | |