File size: 6,865 Bytes
e2eff86
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
import React, { useState, useEffect } from 'react';
import BrowserOnly from '@docusaurus/BrowserOnly';
import { useLocation } from '@docusaurus/router';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import { translate } from '@docusaurus/Translate';
import { useLanguage } from '@site/src/contexts/LanguageContext';
import './ChatbotWidget.css';

const ChatbotWidget = () => {
  const [isOpen, setIsOpen] = useState(false);
  const [messages, setMessages] = useState([]);
  const [inputValue, setInputValue] = useState('');
  const [isLoading, setIsLoading] = useState(false);
  const location = useLocation();
  const { siteConfig } = useDocusaurusContext();
  const { currentLanguage } = useLanguage(); // Get the current language from context

  // Function to toggle chatbot window
  const toggleChatbot = () => {
    setIsOpen(!isOpen);
  };

  // Function to close chatbot
  const closeChatbot = () => {
    setIsOpen(false);
  };

  // Function to handle sending a message
  const handleSendMessage = async (e) => {
    e.preventDefault();
    if (!inputValue.trim() || isLoading) return;

    const userMessage = inputValue.trim();
    setInputValue('');

    // Add user message to chat
    const newMessages = [...messages, { id: Date.now(), text: userMessage, sender: 'user' }];
    setMessages(newMessages);
    setIsLoading(true);

    try {
      // Get JWT token from localStorage
      const token = localStorage.getItem('token');

      if (!token) {
        // If no token, inform user they need to log in
        const errorMsg = translate({
          id: 'chatbot.loginRequired',
          message: 'You need to log in to use the chatbot. Please go to the login page.'
        });
        setMessages(prev => [
          ...prev,
          { id: Date.now() + 1, text: errorMsg, sender: 'system' }
        ]);
        setIsLoading(false);
        return;
      }

      // Call the backend API with the current language
      const response = await fetch('/api/chat/query', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${token}`
        },
        body: JSON.stringify({
          query: userMessage,
          language: currentLanguage // Use the selected language from context
        })
      });

      if (!response.ok) {
        if (response.status === 401) {
          // Token might be expired, redirect to login
          localStorage.removeItem('token');
          const errorMsg = translate({
            id: 'chatbot.authExpired',
            message: 'Your session has expired. Please log in again.'
          });
          setMessages(prev => [
            ...prev,
            { id: Date.now() + 1, text: errorMsg, sender: 'system' }
          ]);
        } else {
          throw new Error(`API error: ${response.status}`);
        }
      } else {
        const data = await response.json();
        setMessages(prev => [
          ...prev,
          { id: Date.now() + 1, text: data.response, sender: 'bot' }
        ]);
      }
    } catch (error) {
      console.error('Chatbot error:', error);
      const errorMsg = translate({
        id: 'chatbot.errorMessage',
        message: 'Sorry, I encountered an error. Please try again.'
      });
      setMessages(prev => [
        ...prev,
        { id: Date.now() + 1, text: errorMsg, sender: 'system' }
      ]);
    } finally {
      setIsLoading(false);
    }
  };

  // Close chatbot when navigating to auth pages
  useEffect(() => {
    if (location.pathname.includes('/login') || location.pathname.includes('/signup')) {
      setIsOpen(false);
    }
  }, [location]);

  return (
    <BrowserOnly>
      {() => {
        // Only render if not on auth pages
        const shouldRender = !location.pathname.includes('/login') && !location.pathname.includes('/signup');

        return shouldRender ? (
          <>
            {/* Floating Chatbot Icon */}
            <div
              className={`floating-chatbot-icon ${isOpen ? 'hidden' : ''}`}
              onClick={toggleChatbot}
              title={translate({ id: 'chatbot.openTitle', message: 'Open AI Assistant' })}
            >
              🤖
            </div>

            {/* Chatbot Window */}
            {isOpen && (
              <div className="chatbot-container">
                <div className="chatbot-header">
                  <h3>{translate({ id: 'chatbot.title', message: 'AI Assistant' })}</h3>
                  <button
                    className="chatbot-close"
                    onClick={closeChatbot}
                    aria-label={translate({ id: 'chatbot.closeAria', message: 'Close chat' })}
                  >
                    ×
                  </button>
                </div>
                <div className="chatbot-messages">
                  {messages.length === 0 ? (
                    <div className="chatbot-welcome">
                      {translate({
                        id: 'chatbot.welcome',
                        message: 'Hello! I\'m your AI assistant. Ask me anything about the Physical AI & Humanoid Robotics book.'
                      })}
                    </div>
                  ) : (
                    messages.map((message) => (
                      <div
                        key={message.id}
                        className={`chatbot-message ${message.sender}-message`}
                      >
                        <div className="message-content">{message.text}</div>
                      </div>
                    ))
                  )}
                  {isLoading && (
                    <div className="chatbot-message bot-message">
                      <div className="message-content typing-indicator">
                        <span></span>
                        <span></span>
                        <span></span>
                      </div>
                    </div>
                  )}
                </div>
                <form className="chatbot-input" onSubmit={handleSendMessage}>
                  <input
                    type="text"
                    value={inputValue}
                    onChange={(e) => setInputValue(e.target.value)}
                    placeholder={translate({
                      id: 'chatbot.inputPlaceholder',
                      message: 'Ask a question...'
                    })}
                    disabled={isLoading}
                  />
                  <button
                    type="submit"
                    disabled={!inputValue.trim() || isLoading}
                  >
                    {translate({ id: 'chatbot.sendButton', message: 'Send' })}
                  </button>
                </form>
              </div>
            )}
          </>
        ) : null;
      }}
    </BrowserOnly>
  );
};

export default ChatbotWidget;