import { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useDispatch, useSelector } from 'react-redux'; import { useNavigate, useParams } from 'react-router-dom'; import conversationService from '../api/services/conversationService'; import MessageInput from '../components/MessageInput'; import { selectToken } from '../preferences/preferenceSlice'; import { AppDispatch } from '../store'; import { formatDate } from '../utils/dateTimeUtils'; import ConversationMessages from './ConversationMessages'; import { addQuery, fetchSharedAnswer, selectClientAPIKey, selectDate, selectQueries, selectStatus, selectTitle, setClientApiKey, setFetchedData, setIdentifier, updateQuery, } from './sharedConversationSlice'; import { selectCompletedAttachments } from '../upload/uploadSlice'; import { Head as DocumentHead } from '../components/Head'; export const SharedConversation = () => { const navigate = useNavigate(); const { identifier } = useParams(); //identifier is a uuid, not conversationId const token = useSelector(selectToken); const queries = useSelector(selectQueries); const title = useSelector(selectTitle); const date = useSelector(selectDate); const apiKey = useSelector(selectClientAPIKey); const status = useSelector(selectStatus); const completedAttachments = useSelector(selectCompletedAttachments); const { t } = useTranslation(); const dispatch = useDispatch(); const [lastQueryReturnedErr, setLastQueryReturnedErr] = useState(false); useEffect(() => { identifier && dispatch(setIdentifier(identifier)); }, []); useEffect(() => { if (queries.length) { queries[queries.length - 1].error && setLastQueryReturnedErr(true); queries[queries.length - 1].response && setLastQueryReturnedErr(false); //considering a query that initially returned error can later include a response property on retry } }, [queries[queries.length - 1]]); const fetchQueries = () => { identifier && conversationService .getSharedConversation(identifier || '', token) .then((res) => { if (res.status === 404 || res.status === 400) navigate('/pagenotfound'); return res.json(); }) .then((data) => { if (data.success) { dispatch( setFetchedData({ queries: data.queries, title: data.title, date: formatDate(data.timestamp), identifier, }), ); data.api_key && dispatch(setClientApiKey(data.api_key)); } }); }; const handleQuestionSubmission = (question?: string) => { if (question && status !== 'loading') { if (lastQueryReturnedErr) { // update last failed query with new prompt dispatch( updateQuery({ index: queries.length - 1, query: { prompt: question, }, }), ); handleQuestion({ question: queries[queries.length - 1].prompt, isRetry: true, }); } else { handleQuestion({ question }); } } }; const handleQuestion = ({ question, isRetry = false, }: { question: string; isRetry?: boolean; }) => { question = question.trim(); if (question === '') return; const filesAttached = completedAttachments .filter((a) => a.id) .map((a) => ({ id: a.id as string, fileName: a.fileName })); !isRetry && dispatch( addQuery({ prompt: question, attachments: filesAttached, }), ); //dispatch only new queries dispatch(fetchSharedAnswer({ question })); }; useEffect(() => { fetchQueries(); }, []); return ( <>

{title}

{t('sharedConv.subtitle')}{' '} DocsGPT

{date}

{apiKey ? ( { handleQuestionSubmission(text); }} loading={status === 'loading'} showSourceButton={false} showToolButton={false} /> ) : ( )}

{t('sharedConv.meta')}

); };