dev/chat
Lei OT 2 years ago
parent 025289eae7
commit 4f525effce

@ -266,9 +266,9 @@ export const whatsappMsgTypeMapped = {
}, },
}, },
originText: msg.image?.caption || '', originText: msg.image?.caption || '',
onOpen: () => { // onOpen: () => {
console.log('Open image', msg.image.link); // console.log('Open image', msg.image.link);
}, // },
}), }),
renderForReply: (msg) => ({ renderForReply: (msg) => ({
id: msg.wamid, id: msg.wamid,

@ -1,60 +1,61 @@
import { useEffect, useState, useRef, memo, createRef, forwardRef } from 'react'; import { useEffect, useRef, useState, forwardRef, memo } from 'react';
import { Image, Button } from 'antd';
import { DownOutlined } from '@ant-design/icons';
import { MessageBox } from 'react-chat-elements'; import { MessageBox } from 'react-chat-elements';
import useConversationStore from '@/stores/ConversationStore'; import { Button } from 'antd';
import { DownOutlined } from '@ant-design/icons';
import { useShallow } from 'zustand/react/shallow'; import { useShallow } from 'zustand/react/shallow';
import useConversationStore from '@/stores/ConversationStore';
import { isEmpty, olog } from '@/utils/utils'; import { isEmpty, olog } from '@/utils/utils';
const MessagesList = ({ reference, contactsModalOpen, setContactsModalOpen, ...props }) => { const MessagesList = ({ messages, handlePreview, reference }) => {
const setReferenceMsg = useConversationStore(useShallow((state) => state.setReferenceMsg)); const setReferenceMsg = useConversationStore(useShallow((state) => state.setReferenceMsg));
olog('render message list');
const scrollToMessage = (id, index) => {
const _i = index || props.dataSource.findIndex((msg) => msg.id === id);
if (_i >= 0) {
messageRefs.current[_i].current.scrollIntoView({ behavior: 'smooth', block: 'center' });
}
};
// const messagesEndRef = useRef(null);
const messageRefs = useRef([]); const messageRefs = useRef([]);
messageRefs.current = props.dataSource.map((_, i) => messageRefs.current[i] ?? createRef()); const [page, setPage] = useState(1);
let timeout = null;
const toBottom = (e) => { const fetchNextPage = async () => {
if (!reference) return; olog('fetchNextPage')
reference.current.scrollTop = reference.current.scrollHeight - reference.current.offsetHeight; setPage(page + 1);
// Fetch next page of messages here
}; };
const prevProps = useRef(props); const handleScroll = (e) => {
useEffect(() => { const { scrollTop } = e.target;
if (prevProps.current.dataSource.length !== props.dataSource.length) { const delay = 1000; // 1 second
toBottom();
if (scrollTop === 0) {
if (timeout) clearTimeout(timeout);
timeout = setTimeout(fetchNextPage, delay);
} }
};
prevProps.current = props; const scrollToBottom = () => {
}, [prevProps, props]); if (reference.current) {
reference.current.scrollTop = reference.current.scrollHeight;
}
};
const [previewVisible, setPreviewVisible] = useState(false); const scrollToMessage = (id, index) => {
const [previewSrc, setPreviewSrc] = useState(); const _i = index || messages.findIndex((msg) => msg.id === id);
const onPreviewClose = () => { if (reference.current && messageRefs.current[_i]) {
setPreviewSrc(''); reference.current.scrollTop = messageRefs.current[_i].offsetTop;
setPreviewVisible(false); }
}; };
const handlePreview = (msg) => {
switch (msg.type) {
case 'photo':
setPreviewVisible(true);
setPreviewSrc(msg.data.uri);
return false;
case 'file': useEffect(scrollToBottom, [messages]);
window.open(msg.data.link || msg.data.uri, '_blank', 'noopener,noreferrer');
return false;
default: useEffect(() => {
return false; const messageList = reference.current;
if (messageList) {
messageList.addEventListener('scroll', handleScroll);
} }
}; return () => {
if (messageList) {
messageList.removeEventListener('scroll', handleScroll);
}
};
}, []);
const RenderText = memo(function renderText({ str }) { 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_Presentation})/gmu).filter((s) => s !== '');
@ -88,6 +89,7 @@ const MessagesList = ({ reference, contactsModalOpen, setContactsModalOpen, ...p
</span> </span>
); );
}); });
// eslint-disable-next-line react/display-name // eslint-disable-next-line react/display-name
const MessageBoxWithRef = forwardRef((props, ref) => ( const MessageBoxWithRef = forwardRef((props, ref) => (
<div ref={ref}> <div ref={ref}>
@ -96,27 +98,11 @@ const MessagesList = ({ reference, contactsModalOpen, setContactsModalOpen, ...p
)); ));
return ( return (
<div className='relative h-full overflow-y-auto overflow-x-hidden flex'> <div className='relative h-full overflow-y-auto overflow-x-hidden flex flex-1'>
<div className='relative overflow-y-auto block flex-1' ref={reference}> <div ref={reference} className='relative overflow-y-auto overflow-x-hidden block flex-1'>
{props.dataSource.map((message, index) => ( {messages.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']}>
<MessageBoxWithRef <MessageBoxWithRef
ref={messageRefs.current[index]} ref={(el) => (messageRefs.current[index] = el)}
key={message.id} key={message.id}
{...message} {...message}
position={message.sender === 'me' ? 'right' : 'left'} position={message.sender === 'me' ? 'right' : 'left'}
@ -149,11 +135,9 @@ const MessagesList = ({ reference, contactsModalOpen, setContactsModalOpen, ...p
} }
: {})} : {})}
/> />
// </Dropdown>
))} ))}
</div> </div>
<Button onClick={toBottom} ghost type={'dashed'} shape={'circle'} className=' absolute bottom-1 right-4' icon={<DownOutlined />} /> <Button onClick={scrollToBottom} ghost type={'dashed'} shape={'circle'} className=' absolute bottom-1 right-4' icon={<DownOutlined />} />
<Image src={null} preview={{ visible: previewVisible, src: previewSrc, onClose: onPreviewClose }} />
</div> </div>
); );
}; };

@ -1,15 +1,39 @@
import { useRef } from 'react'; import { useRef, useState } from 'react';
import useConversationStore from '@/stores/ConversationStore'; import useConversationStore from '@/stores/ConversationStore';
import { useShallow } from 'zustand/react/shallow'; import { useShallow } from 'zustand/react/shallow';
import { Image, } from 'antd';
import MessagesList from './MessagesList'; import MessagesList from './MessagesList';
const MessagesWrapper = () => { const MessagesWrapper = () => {
const activeMessages = useConversationStore(useShallow((state) => (state.currentConversation.sn && state.activeConversations[state.currentConversation.sn] ? state.activeConversations[state.currentConversation.sn]: []))); const activeMessages = useConversationStore(useShallow((state) => (state.currentConversation.sn && state.activeConversations[state.currentConversation.sn] ? state.activeConversations[state.currentConversation.sn]: [])));
const reference = useRef(null); const reference = useRef(null);
const [previewVisible, setPreviewVisible] = useState(false);
const [previewSrc, setPreviewSrc] = useState();
const onPreviewClose = () => {
setPreviewSrc('');
setPreviewVisible(false);
};
const handlePreview = (msg) => {
switch (msg.whatsapp_msg_type) {
case 'image':
setPreviewVisible(true);
setPreviewSrc(msg.data.uri);
return false;
case 'document':
window.open(msg.data.link || msg.data.uri, '_blank', 'noopener,noreferrer');
return false;
default:
return false;
}
};
return ( return (
<> <>
<MessagesList dataSource={activeMessages} reference={reference} /> <MessagesList messages={activeMessages} {...{ reference, handlePreview }} />
<Image width={0} height={0} src={null} preview={{ visible: previewVisible, src: previewSrc, onClose: onPreviewClose }} />
</> </>
); );
}; };

@ -67,7 +67,7 @@
.chatwindow-wrapper .rce-mbox-reply-message, .chatwindow-wrapper .rce-mbox-reply-message,
.chatwindow-wrapper .emoji .chatwindow-wrapper .emoji
{ {
font-family: "Noto Color Emoji", 'Apple Color Emoji', 'Twemoji Mozilla', 'Segoe UI Emoji', 'Segoe UI Symbol', 'EmojiOne Color', 'Android Emoji', sans-serif; font-family: "Noto Color Emoji", 'Apple Color Emoji', 'Twemoji Mozilla', 'Segoe UI Emoji', 'Segoe UI Symbol', 'EmojiOne Color', 'Android Emoji', Arial, sans-serif;
font-weight: 500; font-weight: 500;
} }
.chatwindow-wrapper .rce-mbox-text a{ .chatwindow-wrapper .rce-mbox-text a{

Loading…
Cancel
Save