import { useState, useEffect, useCallback } from 'react';
import { Conversation } from '@vocantly/sdk';
function useTyping(conversation: Conversation) {
const [typingUsers, setTypingUsers] = useState<string[]>([]);
useEffect(() => {
const handleTyping = (event: { userId: string; state: 'start' | 'stop' }) => {
setTypingUsers(prev => {
if (event.state === 'start') {
return prev.includes(event.userId) ? prev : [...prev, event.userId];
} else {
return prev.filter(id => id !== event.userId);
}
});
};
conversation.on('typing', handleTyping);
return () => {
conversation.off('typing', handleTyping);
};
}, [conversation]);
return typingUsers;
}
function useTypingInput(conversation: Conversation) {
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
const isTypingRef = useRef(false);
const handleInput = useCallback(() => {
if (!isTypingRef.current) {
isTypingRef.current = true;
conversation.startTyping();
}
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}
timeoutRef.current = setTimeout(() => {
isTypingRef.current = false;
conversation.stopTyping();
}, 2000);
}, [conversation]);
const handleSend = useCallback(() => {
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}
isTypingRef.current = false;
conversation.stopTyping();
}, [conversation]);
return { handleInput, handleSend };
}
// Usage
function ChatInput({ conversation }) {
const [input, setInput] = useState('');
const typingUsers = useTyping(conversation);
const { handleInput, handleSend } = useTypingInput(conversation);
const onSubmit = (e) => {
e.preventDefault();
if (input.trim()) {
handleSend();
conversation.sendMessage(input);
setInput('');
}
};
return (
<div>
{typingUsers.length > 0 && (
<div className="typing-indicator">
{typingUsers.join(', ')} {typingUsers.length === 1 ? 'is' : 'are'} typing...
</div>
)}
<form onSubmit={onSubmit}>
<input
value={input}
onChange={(e) => {
setInput(e.target.value);
handleInput();
}}
placeholder="Type a message..."
/>
<button type="submit">Send</button>
</form>
</div>
);
}