File size: 4,783 Bytes
d4017c8
 
 
 
 
 
 
 
 
 
c44fab6
0bb4dfa
d4017c8
 
0bb4dfa
d4017c8
 
 
0bb4dfa
 
 
 
4944128
a763505
d4017c8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4944128
d4017c8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4944128
d4017c8
c44fab6
 
 
a763505
 
 
 
 
 
 
 
 
 
 
 
 
 
c44fab6
 
4944128
 
 
 
 
 
 
 
 
 
 
0bb4dfa
4944128
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c44fab6
 
 
 
d4017c8
 
 
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
import React, { useState, useRef, useCallback, forwardRef, useImperativeHandle } from 'react';
import { Play } from 'lucide-react';

const DEMO_SUFFIX = ' [Or type your own question]';

function formatDemoDisplay(question) {
  if (!question) return '';
  const label = (question.title || question.text || '').trim();
  return `Demo Question: ${label}${DEMO_SUFFIX}`;
}

/**
 * Question field pre-filled with a cycling demo prompt; "Start Chat"
 * uses the demo question text or whatever the user typed.
 */
const ChatControls = forwardRef(function ChatControls({
  demoQuestions = [],
  onStart,
  onStop,
  disabled,
  isRunning,
  disabledReason,
  disabledTooltip,
  activeQuestion,
}, ref) {
  const demoIndexRef = useRef(0);
  const [demoIndex, setDemoIndex] = useState(0);
  const [mode, setMode] = useState('demo');
  const [userText, setUserText] = useState('');

  const currentDemo = demoQuestions.length > 0
    ? demoQuestions[demoIndex % demoQuestions.length]
    : null;
  const demoDisplay = formatDemoDisplay(currentDemo);
  const inputValue = mode === 'demo' ? demoDisplay : userText;

  const resolveQuestion = useCallback(() => {
    if (mode === 'custom') return userText.trim();
    return (currentDemo?.text || '').trim();
  }, [mode, userText, currentDemo]);

  useImperativeHandle(ref, () => ({
    getDraftQuestion: resolveQuestion,
  }), [resolveQuestion]);

  const advanceDemo = useCallback(() => {
    if (demoQuestions.length === 0) return;
    const next = (demoIndexRef.current + 1) % demoQuestions.length;
    demoIndexRef.current = next;
    setDemoIndex(next);
    setMode('demo');
    setUserText('');
  }, [demoQuestions.length]);

  const handleChange = (e) => {
    const v = e.target.value;
    if (mode === 'demo') {
      if (v === '' || v === demoDisplay) return;
      setMode('custom');
      setUserText(v);
      return;
    }
    if (v === '') {
      setMode('demo');
      setUserText('');
      return;
    }
    setUserText(v);
  };

  const handleKeyDown = (e) => {
    if (mode !== 'demo') return;
    if (e.key.length === 1 && !e.ctrlKey && !e.metaKey && !e.altKey) {
      setMode('custom');
      setUserText(e.key);
      e.preventDefault();
      return;
    }
    if (e.key === 'Backspace' || e.key === 'Delete') {
      setMode('custom');
      setUserText('');
      e.preventDefault();
    }
  };

  const handleStart = () => {
    const question = resolveQuestion();
    if (!question || disabled) return;
    onStart(question);
    advanceDemo();
  };

  const canStart = !disabled && !!resolveQuestion();
  const startButtonTitle = !canStart && disabledTooltip ? disabledTooltip : undefined;

  return (
    <div className="chat-controls">
      {isRunning ? (
        <>
          <button className="btn-stop" onClick={onStop}>
            Stop Chat
          </button>
          {activeQuestion && (
            <div
              className="ccai-active-question"
              title={activeQuestion}
            >
              <span className="ccai-active-question-label">Question:</span>
              <span className="ccai-active-question-text">{activeQuestion}</span>
            </div>
          )}
        </>
      ) : (
        <>
          <div className="chat-controls-row">
            <input
              type="text"
              className="chat-controls-question"
              value={inputValue}
              placeholder={
                disabled && disabledReason
                  ? disabledReason
                  : demoQuestions.length === 0
                    ? 'Loading demo questions…'
                    : ''
              }
              onChange={handleChange}
              onKeyDown={(e) => {
                handleKeyDown(e);
                if (e.key === 'Enter' && canStart) {
                  e.preventDefault();
                  handleStart();
                }
              }}
            />
            <span
              className={
                'chat-start-btn-wrap'
                + (startButtonTitle ? ' chat-start-btn-wrap-disabled' : '')
              }
              title={startButtonTitle}
            >
              <button
                type="button"
                className="btn-primary chat-controls-start"
                disabled={!canStart}
                onClick={handleStart}
                aria-disabled={!canStart}
              >
                <Play size={14} style={{ marginRight: 4, verticalAlign: 'middle' }} />
                Start Chat
              </button>
            </span>
          </div>
          {startButtonTitle && (
            <span className="chat-start-hint" role="status">
              {startButtonTitle}
            </span>
          )}
        </>
      )}
    </div>
  );
});

export default ChatControls;