|
import { ReactComponent as ChatAppCube } from '@/assets/svg/chat-app-cube.svg';
|
|
import RenameModal from '@/components/rename-modal';
|
|
import { DeleteOutlined, EditOutlined, FormOutlined } from '@ant-design/icons';
|
|
import {
|
|
Avatar,
|
|
Button,
|
|
Card,
|
|
Divider,
|
|
Dropdown,
|
|
Flex,
|
|
MenuProps,
|
|
Space,
|
|
Spin,
|
|
Tag,
|
|
} from 'antd';
|
|
import { MenuItemProps } from 'antd/lib/menu/MenuItem';
|
|
import classNames from 'classnames';
|
|
import { useCallback } from 'react';
|
|
import ChatConfigurationModal from './chat-configuration-modal';
|
|
import ChatContainer from './chat-container';
|
|
import {
|
|
useClickConversationCard,
|
|
useClickDialogCard,
|
|
useEditDialog,
|
|
useFetchConversationList,
|
|
useFetchDialogOnMount,
|
|
useGetChatSearchParams,
|
|
useHandleItemHover,
|
|
useRemoveConversation,
|
|
useRemoveDialog,
|
|
useRenameConversation,
|
|
useSelectConversationList,
|
|
useSelectConversationListLoading,
|
|
useSelectDialogListLoading,
|
|
useSelectFirstDialogOnMount,
|
|
} from './hooks';
|
|
|
|
import styles from './index.less';
|
|
|
|
const Chat = () => {
|
|
const dialogList = useSelectFirstDialogOnMount();
|
|
const { onRemoveDialog } = useRemoveDialog();
|
|
const { onRemoveConversation } = useRemoveConversation();
|
|
const { handleClickDialog } = useClickDialogCard();
|
|
const { handleClickConversation } = useClickConversationCard();
|
|
const { dialogId, conversationId } = useGetChatSearchParams();
|
|
const { list: conversationList, addTemporaryConversation } =
|
|
useSelectConversationList();
|
|
const { activated, handleItemEnter, handleItemLeave } = useHandleItemHover();
|
|
const {
|
|
activated: conversationActivated,
|
|
handleItemEnter: handleConversationItemEnter,
|
|
handleItemLeave: handleConversationItemLeave,
|
|
} = useHandleItemHover();
|
|
const {
|
|
conversationRenameLoading,
|
|
initialConversationName,
|
|
onConversationRenameOk,
|
|
conversationRenameVisible,
|
|
hideConversationRenameModal,
|
|
showConversationRenameModal,
|
|
} = useRenameConversation();
|
|
const {
|
|
dialogSettingLoading,
|
|
initialDialog,
|
|
onDialogEditOk,
|
|
dialogEditVisible,
|
|
clearDialog,
|
|
hideDialogEditModal,
|
|
showDialogEditModal,
|
|
} = useEditDialog();
|
|
const dialogLoading = useSelectDialogListLoading();
|
|
const conversationLoading = useSelectConversationListLoading();
|
|
|
|
useFetchDialogOnMount(dialogId, true);
|
|
|
|
const handleAppCardEnter = (id: string) => () => {
|
|
handleItemEnter(id);
|
|
};
|
|
|
|
const handleConversationCardEnter = (id: string) => () => {
|
|
handleConversationItemEnter(id);
|
|
};
|
|
|
|
const handleShowChatConfigurationModal =
|
|
(dialogId?: string): any =>
|
|
(info: any) => {
|
|
info?.domEvent?.preventDefault();
|
|
info?.domEvent?.stopPropagation();
|
|
showDialogEditModal(dialogId);
|
|
};
|
|
|
|
const handleRemoveDialog =
|
|
(dialogId: string): MenuItemProps['onClick'] =>
|
|
({ domEvent }) => {
|
|
domEvent.preventDefault();
|
|
domEvent.stopPropagation();
|
|
onRemoveDialog([dialogId]);
|
|
};
|
|
|
|
const handleRemoveConversation =
|
|
(conversationId: string): MenuItemProps['onClick'] =>
|
|
({ domEvent }) => {
|
|
domEvent.preventDefault();
|
|
domEvent.stopPropagation();
|
|
onRemoveConversation([conversationId]);
|
|
};
|
|
|
|
const handleShowConversationRenameModal =
|
|
(conversationId: string): MenuItemProps['onClick'] =>
|
|
({ domEvent }) => {
|
|
domEvent.preventDefault();
|
|
domEvent.stopPropagation();
|
|
showConversationRenameModal(conversationId);
|
|
};
|
|
|
|
const handleDialogCardClick = (dialogId: string) => () => {
|
|
handleClickDialog(dialogId);
|
|
};
|
|
|
|
const handleConversationCardClick = (dialogId: string) => () => {
|
|
handleClickConversation(dialogId);
|
|
};
|
|
|
|
const handleCreateTemporaryConversation = useCallback(() => {
|
|
addTemporaryConversation();
|
|
}, [addTemporaryConversation]);
|
|
|
|
const items: MenuProps['items'] = [
|
|
{
|
|
key: '1',
|
|
onClick: handleCreateTemporaryConversation,
|
|
label: (
|
|
<Space>
|
|
<EditOutlined /> New chat
|
|
</Space>
|
|
),
|
|
},
|
|
];
|
|
|
|
const buildAppItems = (dialogId: string) => {
|
|
const appItems: MenuProps['items'] = [
|
|
{
|
|
key: '1',
|
|
onClick: handleShowChatConfigurationModal(dialogId),
|
|
label: (
|
|
<Space>
|
|
<EditOutlined />
|
|
Edit
|
|
</Space>
|
|
),
|
|
},
|
|
{ type: 'divider' },
|
|
{
|
|
key: '2',
|
|
onClick: handleRemoveDialog(dialogId),
|
|
label: (
|
|
<Space>
|
|
<DeleteOutlined />
|
|
Delete chat
|
|
</Space>
|
|
),
|
|
},
|
|
];
|
|
|
|
return appItems;
|
|
};
|
|
|
|
const buildConversationItems = (conversationId: string) => {
|
|
const appItems: MenuProps['items'] = [
|
|
{
|
|
key: '1',
|
|
onClick: handleShowConversationRenameModal(conversationId),
|
|
label: (
|
|
<Space>
|
|
<EditOutlined />
|
|
Edit
|
|
</Space>
|
|
),
|
|
},
|
|
{ type: 'divider' },
|
|
{
|
|
key: '2',
|
|
onClick: handleRemoveConversation(conversationId),
|
|
label: (
|
|
<Space>
|
|
<DeleteOutlined />
|
|
Delete chat
|
|
</Space>
|
|
),
|
|
},
|
|
];
|
|
|
|
return appItems;
|
|
};
|
|
|
|
useFetchConversationList();
|
|
|
|
return (
|
|
<Flex className={styles.chatWrapper}>
|
|
<Flex className={styles.chatAppWrapper}>
|
|
<Flex flex={1} vertical>
|
|
<Button type="primary" onClick={handleShowChatConfigurationModal()}>
|
|
Create an Assistant
|
|
</Button>
|
|
<Divider></Divider>
|
|
<Flex className={styles.chatAppContent} vertical gap={10}>
|
|
<Spin spinning={dialogLoading} wrapperClassName={styles.chatSpin}>
|
|
{dialogList.map((x) => (
|
|
<Card
|
|
key={x.id}
|
|
hoverable
|
|
className={classNames(styles.chatAppCard, {
|
|
[styles.chatAppCardSelected]: dialogId === x.id,
|
|
})}
|
|
onMouseEnter={handleAppCardEnter(x.id)}
|
|
onMouseLeave={handleItemLeave}
|
|
onClick={handleDialogCardClick(x.id)}
|
|
>
|
|
<Flex justify="space-between" align="center">
|
|
<Space size={15}>
|
|
<Avatar src={x.icon} shape={'square'} />
|
|
<section>
|
|
<b>{x.name}</b>
|
|
<div>{x.description}</div>
|
|
</section>
|
|
</Space>
|
|
{activated === x.id && (
|
|
<section>
|
|
<Dropdown menu={{ items: buildAppItems(x.id) }}>
|
|
<ChatAppCube
|
|
className={styles.cubeIcon}
|
|
></ChatAppCube>
|
|
</Dropdown>
|
|
</section>
|
|
)}
|
|
</Flex>
|
|
</Card>
|
|
))}
|
|
</Spin>
|
|
</Flex>
|
|
</Flex>
|
|
</Flex>
|
|
<Divider type={'vertical'} className={styles.divider}></Divider>
|
|
<Flex className={styles.chatTitleWrapper}>
|
|
<Flex flex={1} vertical>
|
|
<Flex
|
|
justify={'space-between'}
|
|
align="center"
|
|
className={styles.chatTitle}
|
|
>
|
|
<Space>
|
|
<b>Chat</b>
|
|
<Tag>{conversationList.length}</Tag>
|
|
</Space>
|
|
<Dropdown menu={{ items }}>
|
|
<FormOutlined />
|
|
</Dropdown>
|
|
</Flex>
|
|
<Divider></Divider>
|
|
<Flex vertical gap={10} className={styles.chatTitleContent}>
|
|
<Spin
|
|
spinning={conversationLoading}
|
|
wrapperClassName={styles.chatSpin}
|
|
>
|
|
{conversationList.map((x) => (
|
|
<Card
|
|
key={x.id}
|
|
hoverable
|
|
onClick={handleConversationCardClick(x.id)}
|
|
onMouseEnter={handleConversationCardEnter(x.id)}
|
|
onMouseLeave={handleConversationItemLeave}
|
|
className={classNames(styles.chatTitleCard, {
|
|
[styles.chatTitleCardSelected]: x.id === conversationId,
|
|
})}
|
|
>
|
|
<Flex justify="space-between" align="center">
|
|
<div>{x.name}</div>
|
|
{conversationActivated === x.id && x.id !== '' && (
|
|
<section>
|
|
<Dropdown
|
|
menu={{ items: buildConversationItems(x.id) }}
|
|
>
|
|
<ChatAppCube
|
|
className={styles.cubeIcon}
|
|
></ChatAppCube>
|
|
</Dropdown>
|
|
</section>
|
|
)}
|
|
</Flex>
|
|
</Card>
|
|
))}
|
|
</Spin>
|
|
</Flex>
|
|
</Flex>
|
|
</Flex>
|
|
<Divider type={'vertical'} className={styles.divider}></Divider>
|
|
<ChatContainer></ChatContainer>
|
|
<ChatConfigurationModal
|
|
visible={dialogEditVisible}
|
|
initialDialog={initialDialog}
|
|
showModal={showDialogEditModal}
|
|
hideModal={hideDialogEditModal}
|
|
loading={dialogSettingLoading}
|
|
onOk={onDialogEditOk}
|
|
clearDialog={clearDialog}
|
|
></ChatConfigurationModal>
|
|
<RenameModal
|
|
visible={conversationRenameVisible}
|
|
hideModal={hideConversationRenameModal}
|
|
onOk={onConversationRenameOk}
|
|
initialName={initialConversationName}
|
|
loading={conversationRenameLoading}
|
|
></RenameModal>
|
|
</Flex>
|
|
);
|
|
};
|
|
|
|
export default Chat;
|
|
|