|
|
|
@ -1,5 +1,5 @@
|
|
|
|
|
import { useEffect, useState, useRef, useMemo, memo, createRef, forwardRef } from 'react';
|
|
|
|
|
import { Image, Spin, Dropdown, Button } from 'antd';
|
|
|
|
|
import { Image, Spin, Dropdown, Button, Affix } from 'antd';
|
|
|
|
|
import { DownOutlined } from '@ant-design/icons';
|
|
|
|
|
import { MessageBox } from 'react-chat-elements';
|
|
|
|
|
import useConversationStore from '@/stores/ConversationStore';
|
|
|
|
@ -7,7 +7,7 @@ import { useShallow } from 'zustand/react/shallow';
|
|
|
|
|
import { Emoji } from 'emoji-picker-react';
|
|
|
|
|
import { olog } from '@/utils/utils';
|
|
|
|
|
|
|
|
|
|
const Messages = () => {
|
|
|
|
|
const Messages = ({ ...props }) => {
|
|
|
|
|
// const currentConversation = useConversationStore(useShallow((state) => state.currentConversation));
|
|
|
|
|
const setReferenceMsg = useConversationStore(useShallow((state) => state.setReferenceMsg));
|
|
|
|
|
const msgListLoading = useConversationStore(useShallow((state) => state.msgListLoading));
|
|
|
|
@ -17,9 +17,9 @@ const Messages = () => {
|
|
|
|
|
const scrollToMessage = (id, index) => {
|
|
|
|
|
const _i = index || activeMessages.findIndex((msg) => msg.id === id);
|
|
|
|
|
if (_i >= 0) {
|
|
|
|
|
messageRefs.current[_i].current.scrollIntoView({ behavior: "smooth", block: "center" });
|
|
|
|
|
messageRefs.current[_i].current.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (activeMessages.length > 0) {
|
|
|
|
@ -30,6 +30,12 @@ const Messages = () => {
|
|
|
|
|
const messageRefs = useRef([]);
|
|
|
|
|
messageRefs.current = activeMessages.map((_, i) => messageRefs.current[i] ?? createRef());
|
|
|
|
|
|
|
|
|
|
const referance = useRef(null);
|
|
|
|
|
const toBottom = (e) => {
|
|
|
|
|
if (!referance) return;
|
|
|
|
|
referance.current.scrollTop = referance.current.scrollHeight;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const [previewVisible, setPreviewVisible] = useState(false);
|
|
|
|
|
const [previewSrc, setPreviewSrc] = useState();
|
|
|
|
|
const onPreviewClose = () => {
|
|
|
|
@ -44,7 +50,7 @@ const Messages = () => {
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
case 'file':
|
|
|
|
|
window.open(msg.data.uri, "_blank", "noopener,noreferrer")
|
|
|
|
|
window.open(msg.data.uri, '_blank', 'noopener,noreferrer');
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
@ -52,8 +58,8 @@ const Messages = () => {
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const RenderText = memo(function renderText({str}) {
|
|
|
|
|
const parts = str.split(/(https?:\/\/[^\s]+|\p{Emoji_Presentation})/gmu).filter(s => s !== '');
|
|
|
|
|
const RenderText = memo(function renderText({ str }) {
|
|
|
|
|
const parts = str.split(/(https?:\/\/[^\s]+|\p{Emoji_Presentation})/gmu).filter((s) => s !== '');
|
|
|
|
|
// const parts = str.split(/(https?:\/\/[^\s]+|\p{Emoji}\uFE0F?|\b\d+\b)/gu);
|
|
|
|
|
return (
|
|
|
|
|
<>
|
|
|
|
@ -62,8 +68,7 @@ const Messages = () => {
|
|
|
|
|
if (/\p{Emoji_Presentation}/u.test(part)) {
|
|
|
|
|
const code = [...part].map((e) => e.codePointAt(0).toString(16)).join(`-`);
|
|
|
|
|
return <Emoji key={`${part}${index}${code}`} unified={code} size={24} emojiStyle={'apple'} />;
|
|
|
|
|
} else
|
|
|
|
|
if (/https?:\/\/[\S]+/gi.test(part)) {
|
|
|
|
|
} else if (/https?:\/\/[\S]+/gi.test(part)) {
|
|
|
|
|
return (
|
|
|
|
|
<a href={part} target='_blank' key={`${part}${index}`} rel='noreferrer'>
|
|
|
|
|
{part}
|
|
|
|
@ -86,25 +91,26 @@ const Messages = () => {
|
|
|
|
|
));
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div>
|
|
|
|
|
<Spin spinning={msgListLoading} tip={'正在读取...'} wrapperClassName='pt-8 '>
|
|
|
|
|
{activeMessages.map((message, index) => (
|
|
|
|
|
// <Dropdown
|
|
|
|
|
// key={message.id}
|
|
|
|
|
// menu={{
|
|
|
|
|
// items: [{ label: '回复', key: 'reply', disabled: !['text'].includes(message.whatsapp_msg_type) }],
|
|
|
|
|
// onClick: ({ key, domEvent }) => {
|
|
|
|
|
// domEvent.stopPropagation();
|
|
|
|
|
// switch (key) {
|
|
|
|
|
// case 'reply':
|
|
|
|
|
// return setReferenceMsg(message);
|
|
|
|
|
<div className='relative h-full overflow-y-auto flex'>
|
|
|
|
|
<div className='relative overflow-y-auto block flex-1' ref={referance}>
|
|
|
|
|
<Spin spinning={msgListLoading} tip={'正在读取...'} wrapperClassName='pt-8 relative'>
|
|
|
|
|
{activeMessages.map((message, index) => (
|
|
|
|
|
// <Dropdown
|
|
|
|
|
// key={message.id}
|
|
|
|
|
// menu={{
|
|
|
|
|
// items: [{ label: '回复', key: 'reply', disabled: !['text'].includes(message.whatsapp_msg_type) }],
|
|
|
|
|
// onClick: ({ key, domEvent }) => {
|
|
|
|
|
// domEvent.stopPropagation();
|
|
|
|
|
// switch (key) {
|
|
|
|
|
// case 'reply':
|
|
|
|
|
// return setReferenceMsg(message);
|
|
|
|
|
|
|
|
|
|
// default:
|
|
|
|
|
// return;
|
|
|
|
|
// }
|
|
|
|
|
// },
|
|
|
|
|
// }}
|
|
|
|
|
// trigger={['contextMenu']}>
|
|
|
|
|
// default:
|
|
|
|
|
// return;
|
|
|
|
|
// }
|
|
|
|
|
// },
|
|
|
|
|
// }}
|
|
|
|
|
// trigger={['contextMenu']}>
|
|
|
|
|
<MessageBoxWithRef
|
|
|
|
|
ref={messageRefs.current[index]}
|
|
|
|
|
key={message.id}
|
|
|
|
@ -119,20 +125,20 @@ const Messages = () => {
|
|
|
|
|
? {
|
|
|
|
|
styles: { backgroundColor: '#ccd4ae' },
|
|
|
|
|
notchStyle: { fill: '#ccd4ae' },
|
|
|
|
|
replyButton: ['text'].includes(message.whatsapp_msg_type) && message.status !== 'failed' ? true : false,
|
|
|
|
|
replyButton: ['text', 'document', 'image'].includes(message.whatsapp_msg_type) && message.status !== 'failed' ? true : false,
|
|
|
|
|
className: 'whatsappme-container whitespace-pre-wrap',
|
|
|
|
|
}
|
|
|
|
|
: {
|
|
|
|
|
replyButton: ['text'].includes(message.whatsapp_msg_type) ? true : false,
|
|
|
|
|
replyButton: ['text', 'document', 'image'].includes(message.whatsapp_msg_type) ? true : false,
|
|
|
|
|
className: 'whitespace-pre-wrap',
|
|
|
|
|
})}
|
|
|
|
|
/>
|
|
|
|
|
// </Dropdown>
|
|
|
|
|
))}
|
|
|
|
|
|
|
|
|
|
</Spin>
|
|
|
|
|
|
|
|
|
|
<Image src={null} preview={{ visible: previewVisible, src: previewSrc, onClose: onPreviewClose }} />
|
|
|
|
|
// </Dropdown>
|
|
|
|
|
))}
|
|
|
|
|
</Spin>
|
|
|
|
|
<Image src={null} preview={{ visible: previewVisible, src: previewSrc, onClose: onPreviewClose }} />
|
|
|
|
|
</div>
|
|
|
|
|
<Button onClick={toBottom} shape={'circle'} className=' absolute bottom-1 right-4' icon={<DownOutlined />} />
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|