File size: 3,411 Bytes
ef1f403
95d1c6b
 
b23f51c
 
 
 
 
 
2e9dd8e
ef1f403
 
 
 
 
 
 
 
 
 
b23f51c
 
 
 
 
 
 
 
ef1f403
 
 
 
 
b23f51c
ef1f403
 
95d1c6b
cdcf600
ef1f403
2e9dd8e
 
 
 
 
 
 
 
 
cdcf600
 
2e9dd8e
 
 
 
 
 
cdcf600
 
 
 
 
 
 
 
 
 
b23f51c
ef1f403
 
b23f51c
ef1f403
 
 
 
 
 
 
 
95d1c6b
2c333c8
ef1f403
2e9dd8e
 
 
 
 
 
 
 
 
cdcf600
ef1f403
 
 
 
b23f51c
ef1f403
 
7b9ee3e
b23f51c
 
 
ef1f403
95d1c6b
 
 
 
 
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
import { useState, useRef, useEffect } from 'react';
import './ChatPanel.css';

/**
 * ChatPanel
 * 
 * Layer 3: Interaction (Utility Layer)
 * Handles live conversation and input.
 */
function ChatPanel({ messages, onSendMessage, onNewChat, userAvatar, isTyping, onInputStateChange }) {
  const [input, setInput] = useState('');
  const scrollRef = useRef(null);

  // Auto-scroll to bottom on new messages
  useEffect(() => {
    if (scrollRef.current) {
      scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
    }
  }, [messages, isTyping]);

  const handleInputChange = (e) => {
    const val = e.target.value;
    setInput(val);
    if (onInputStateChange) {
      onInputStateChange(val.length > 0);
    }
  };

  const handleSubmit = (e) => {
    e.preventDefault();
    if (!input.trim() || isTyping) return;
    onSendMessage(input);
    setInput('');
    if (onInputStateChange) onInputStateChange(false);
  };

  return (
    <div className="chat-interface">
      <div className="chat-messages" ref={scrollRef}>
        {messages.length === 0 && (
          <div className="welcome-state">
            <div className="welcome-icon">
              <span className="material-icons">lens_blur</span>
            </div>
            <h3>Neural Core Initialized.</h3>
            <p>Feed me a thought to begin building your neural pathways.</p>
          </div>
        )}
        {messages.map((msg, i) => (
          <div key={i} className={`chat-bubble-group ${msg.role}`}>
            <div className="chat-avatar">
              {msg.role === 'user' ? (
                <img src={userAvatar} alt="User" />
              ) : (
                <span className="material-icons">lens_blur</span>
              )}
            </div>
            <div className="bubble-body">
              <div className="bubble-meta">
                <strong>{msg.role === 'user' ? 'You' : 'Soma'}</strong>
              </div>
              <div className="bubble-text">{msg.content}</div>
              <div className="bubble-time">{msg.timestamp}</div>
            </div>
          </div>
        ))}
        {isTyping && messages.length > 0 && messages[messages.length - 1].role === 'user' && (
          <div className="chat-bubble-group soma typing">
             <div className="chat-avatar">
                <span className="material-icons">lens_blur</span>
             </div>
             <div className="bubble-body">
                <div className="typing-dots">
                   <span></span><span></span><span></span>
                </div>
             </div>
          </div>
        )}
      </div>

      <form className="chat-input-row" onSubmit={handleSubmit}>
        <button 
          className="new-chat-btn" 
          type="button" 
          onClick={onNewChat}
          title="New Chat"
          disabled={isTyping}
        >
          <span className="material-icons">add</span>
        </button>
        <div className="input-field-wrap">
          <input 
            type="text" 
            placeholder="Message Soma..." 
            value={input}
            onChange={handleInputChange}
            disabled={isTyping}
          />
        </div>
        <button className="send-btn" type="submit" disabled={!input.trim() || isTyping}>
          <span className="material-icons">north</span>
        </button>
      </form>
    </div>
  );
}

export default ChatPanel;