File size: 4,767 Bytes
3b6afc0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
import { useState, useEffect } from 'react';
import { useAuthContext } from '~/hooks/AuthContext';
import { useNavigate, useParams } from 'react-router-dom';
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil';

import Landing from '../components/ui/Landing';
import Messages from '../components/Messages';
import TextChat from '../components/Input';

import store from '~/store';
import {
  useGetMessagesByConvoId,
  useGetConversationByIdMutation,
  useGetStartupConfig,
} from '@librechat/data-provider';

export default function Chat() {
  const { isAuthenticated } = useAuthContext();
  const [shouldNavigate, setShouldNavigate] = useState(true);
  const searchQuery = useRecoilValue(store.searchQuery);
  const [conversation, setConversation] = useRecoilState(store.conversation);
  const setMessages = useSetRecoilState(store.messages);
  const messagesTree = useRecoilValue(store.messagesTree);
  const isSubmitting = useRecoilValue(store.isSubmitting);
  const { newConversation } = store.useConversation();
  const { conversationId } = useParams();
  const navigate = useNavigate();

  //disabled by default, we only enable it when messagesTree is null
  const messagesQuery = useGetMessagesByConvoId(conversationId, { enabled: false });
  const getConversationMutation = useGetConversationByIdMutation(conversationId);
  const { data: config } = useGetStartupConfig();

  useEffect(() => {
    let timeout = setTimeout(() => {
      if (!isAuthenticated) {
        navigate('/login', { replace: true });
      }
    }, 300);

    return () => {
      clearTimeout(timeout);
    };
  }, [isAuthenticated, navigate]);

  useEffect(() => {
    if (!isSubmitting && !shouldNavigate) {
      setShouldNavigate(true);
    }
  }, [shouldNavigate, isSubmitting]);

  // when conversation changed or conversationId (in url) changed
  useEffect(() => {
    // No current conversation and conversationId is 'new'
    if (conversation === null && conversationId === 'new') {
      newConversation();
      setShouldNavigate(true);
    }
    // No current conversation and conversationId exists
    else if (conversation === null && conversationId) {
      getConversationMutation.mutate(conversationId, {
        onSuccess: (data) => {
          console.log('Conversation fetched successfully');
          setConversation(data);
          setShouldNavigate(true);
        },
        onError: (error) => {
          console.error('Failed to fetch the conversation');
          console.error(error);
          navigate('/chat/new');
          newConversation();
          setShouldNavigate(true);
        },
      });
      setMessages(null);
    }
    // No current conversation and no conversationId
    else if (conversation === null) {
      navigate('/chat/new');
      setShouldNavigate(true);
    }
    // Current conversationId is 'search'
    else if (conversation?.conversationId === 'search') {
      navigate(`/search/${searchQuery}`);
      setShouldNavigate(true);
    }
    // Conversation change and isSubmitting
    else if (conversation?.conversationId !== conversationId && isSubmitting) {
      setShouldNavigate(false);
    }
    // conversationId (in url) should always follow conversation?.conversationId, unless conversation is null
    else if (conversation?.conversationId !== conversationId) {
      if (shouldNavigate) {
        navigate(`/chat/${conversation?.conversationId}`);
      } else {
        setShouldNavigate(true);
      }
    }
    document.title = conversation?.title || config?.appTitle || 'Chat';
  }, [conversation, conversationId, config]);

  useEffect(() => {
    if (messagesTree === null && conversation?.conversationId) {
      messagesQuery.refetch(conversation?.conversationId);
    }
  }, [conversation?.conversationId, messagesQuery, messagesTree]);

  useEffect(() => {
    if (messagesQuery.data) {
      setMessages(messagesQuery.data);
    } else if (messagesQuery.isError) {
      console.error('failed to fetch the messages');
      console.error(messagesQuery.error);
      setMessages(null);
    }
  }, [messagesQuery.data, messagesQuery.isError, setMessages]);

  if (!isAuthenticated) {
    return null;
  }

  // if not a conversation
  if (conversation?.conversationId === 'search') {
    return null;
  }
  // if conversationId not match
  if (conversation?.conversationId !== conversationId && !conversation) {
    return null;
  }
  // if conversationId is null
  if (!conversationId) {
    return null;
  }

  if (conversationId && !messagesTree) {
    return (
      <>
        <Messages />
        <TextChat />
      </>
    );
  }

  return (
    <>
      {conversationId === 'new' && !messagesTree?.length ? <Landing /> : <Messages />}
      <TextChat />
    </>
  );
}