import React, { useState, useEffect, useRef, useCallback } from 'react'; import { useSelector, useDispatch } from 'react-redux'; import SubRow from './Content/SubRow'; import Wrapper from './Content/Wrapper'; import MultiMessage from './MultiMessage'; import HoverButtons from './HoverButtons'; import SiblingSwitch from './SiblingSwitch'; import { setConversation, setLatestMessage } from '~/store/convoSlice'; import { setModel, setCustomModel, setCustomGpt, setDisabled } from '~/store/submitSlice'; import { setMessages } from '~/store/messageSlice'; import { fetchById } from '~/utils/fetchers'; import { getIconOfModel } from '~/utils'; import { useMessageHandler } from '~/utils/handleSubmit'; export default function Message({ message, messages, scrollToBottom, currentEditId, setCurrentEditId, siblingIdx, siblingCount, setSiblingIdx }) { const { isSubmitting, model, chatGptLabel, cursor, promptPrefix } = useSelector(state => state.submit); const [abortScroll, setAbort] = useState(false); const { sender, text, searchResult, isCreatedByUser, error, submitting } = message; const textEditor = useRef(null); const last = !message?.children?.length; const edit = message.messageId == currentEditId; const { ask } = useMessageHandler(); const dispatch = useDispatch(); // const currentConvo = convoMap[message.conversationId]; // const notUser = !isCreatedByUser; // sender.toLowerCase() !== 'user'; // const blinker = submitting && isSubmitting && last && !isCreatedByUser; const blinker = submitting && isSubmitting; const generateCursor = useCallback(() => { if (!blinker) { return ''; } if (!cursor) { return ''; } return █; }, [blinker, cursor]); useEffect(() => { if (blinker && !abortScroll) { scrollToBottom(); } }, [isSubmitting, blinker, text, scrollToBottom]); useEffect(() => { if (last) { // TODO: stop using conversation.parentMessageId and remove it. dispatch(setConversation({ parentMessageId: message?.messageId })); dispatch(setLatestMessage({ ...message })); } }, [last, message]); const enterEdit = cancel => setCurrentEditId(cancel ? -1 : message.messageId); const handleWheel = () => { if (blinker) { setAbort(true); } else { setAbort(false); } }; const props = { className: 'w-full border-b border-black/10 dark:border-gray-900/50 text-gray-800 bg-white dark:text-gray-100 group dark:bg-gray-800' }; const icon = getIconOfModel({ sender, isCreatedByUser, model, searchResult, chatGptLabel, promptPrefix, error }); if (!isCreatedByUser) props.className = 'w-full border-b border-black/10 bg-gray-50 dark:border-gray-900/50 text-gray-800 dark:text-gray-100 group bg-gray-100 dark:bg-[#444654]'; if (message.bg && searchResult) { props.className = message.bg.split('hover')[0]; props.titleClass = message.bg.split(props.className)[1] + ' cursor-pointer'; } const resubmitMessage = () => { const text = textEditor.current.innerText; ask({ text, parentMessageId: message?.parentMessageId, conversationId: message?.conversationId }); setSiblingIdx(siblingCount - 1); enterEdit(true); }; const clickSearchResult = async () => { if (!searchResult) return; dispatch(setMessages([])); const convoResponse = await fetchById('convos', message.conversationId); const convo = convoResponse.data; if (convo?.chatGptLabel) { dispatch(setModel('chatgptCustom')); dispatch(setCustomModel(convo.chatGptLabel.toLowerCase())); } else { dispatch(setModel(convo.model)); dispatch(setCustomModel(null)); } dispatch(setCustomGpt(convo)); dispatch(setConversation(convo)); const { data } = await fetchById('messages', message.conversationId); dispatch(setMessages(data)); dispatch(setDisabled(false)); }; return ( <>