"use client"; import { useState, useEffect, useRef } from 'react'; import { Job, Message } from '../types'; interface ChatScreenProps { job: Job; candidateName: string; linkId: string; isTestMode?: boolean; mandatoryAnswers?: string[]; onComplete: () => void; } export default function ChatScreen({ job, candidateName, linkId, isTestMode = false, mandatoryAnswers = [], onComplete }: ChatScreenProps) { const [messages, setMessages] = useState([]); const [inputMessage, setInputMessage] = useState(''); const [isLoading, setIsLoading] = useState(false); const [isInitializing, setIsInitializing] = useState(true); const [error, setError] = useState(''); const [isTyping, setIsTyping] = useState(false); const [typingMessage, setTypingMessage] = useState(''); const messagesEndRef = useRef(null); const scrollToBottom = () => { messagesEndRef.current?.scrollIntoView({ behavior: "smooth" }); }; // Build conversation history from mandatory answers for test mode const buildConversationHistory = () => { if (!isTestMode || !mandatoryAnswers.length) return []; const history: Message[] = []; const mandatoryQuestions = job.interview_questions || []; for (let i = 0; i < mandatoryQuestions.length; i++) { if (mandatoryAnswers[i]) { history.push({ id: `q-${i + 1}`, sender: 'ai', content: `Question ${i + 1}: ${mandatoryQuestions[i]}`, timestamp: new Date() }); history.push({ id: `a-${i + 1}`, sender: 'user', content: mandatoryAnswers[i], timestamp: new Date() }); } } return history; }; useEffect(() => { scrollToBottom(); }, [messages, typingMessage]); // Typing effect function const simulateTyping = (text: string, onComplete: (finalText: string) => void) => { setIsTyping(true); setTypingMessage(''); let currentIndex = 0; const typingSpeed = 20 + Math.random() * 30; // Random speed between 20-50ms per character const typeNextCharacter = () => { if (currentIndex < text.length) { setTypingMessage(text.slice(0, currentIndex + 1)); currentIndex++; setTimeout(typeNextCharacter, typingSpeed); } else { setIsTyping(false); onComplete(text); } }; // Small delay before starting to type setTimeout(typeNextCharacter, 500); }; useEffect(() => { initializeChat(); }, []); const initializeChat = async () => { try { setIsInitializing(true); // Send initial data to AI endpoint const response = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/rest/ai/start-interview${isTestMode ? '?test=true' : ''}`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ candidateName, job: job, linkId, test: isTestMode }) }); if (response.ok) { const data = await response.json(); // Use typing effect for AI's initial message const aiMessage = data.message || "Hello! I'm your evaluation agent. Let's begin the interview for the " + job.title + " position. Please tell me about yourself and your interest in this role."; simulateTyping(aiMessage, (finalText) => { setMessages([{ id: '1', content: finalText, sender: 'ai', timestamp: new Date() }]); }); } else { throw new Error('Failed to initialize chat'); } } catch (error) { console.error('Error initializing chat:', error); setError('Failed to start the interview. Please try again.'); // Add fallback message with typing effect const fallbackMessage = "Hello! I'm your evaluation agent. Let's begin the interview for the " + job.title + " position. Please tell me about yourself and your interest in this role."; simulateTyping(fallbackMessage, (finalText) => { setMessages([{ id: '1', content: finalText, sender: 'ai', timestamp: new Date() }]); }); } finally { setIsInitializing(false); } }; const sendMessage = async () => { if (!inputMessage.trim() || isLoading) return; const userMessage: Message = { id: Date.now().toString(), content: inputMessage.trim(), sender: 'user', timestamp: new Date() }; setMessages(prev => [...prev, userMessage]); setInputMessage(''); setIsLoading(true); try { // Build conversation history for test mode const conversationHistory = isTestMode ? [...buildConversationHistory(), ...messages.filter(msg => msg.content && msg.content !== 'undefined')] : messages; const response = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/rest/ai/chat${isTestMode ? '?test=true' : ''}`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ message: userMessage.content, candidateName, job: job, linkId, conversationHistory: conversationHistory.map(msg => ({ sender: msg.sender === 'user' ? 'candidate' : msg.sender, message: msg.content, timestamp: msg.timestamp })), test: isTestMode }) }); if (response.ok) { const data = await response.json(); // Use typing effect for AI response const aiResponseText = data.message || "Thank you for your response. Let me ask you another question..."; simulateTyping(aiResponseText, (finalText) => { const aiMessage: Message = { id: (Date.now() + 1).toString(), content: finalText, sender: 'ai', timestamp: new Date() }; setMessages(prev => [...prev, aiMessage]); // Check if interview is complete if (data.isComplete) { setTimeout(() => { onComplete(); }, 2000); } }); } else { throw new Error('Failed to send message'); } } catch (error) { console.error('Error sending message:', error); setError('Failed to send message. Please try again.'); } finally { setIsLoading(false); } }; const handleKeyPress = (e: React.KeyboardEvent) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); sendMessage(); } }; const formatTime = (date: Date) => { return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }); }; if (isInitializing) { return (

Initializing interview...

); } return (
{/* Header */}

Interview: {job.title}

Candidate: {candidateName} • {job.location || "Remote"}

AI Agent Online
{/* Error Banner */} {error && (
{error}
)} {/* Messages */}
{messages.map((message) => (
{message.sender === 'ai' && (
)}

{message.content}

{formatTime(message.timestamp)}

{message.sender === 'user' && (
)}
))} {isLoading && !isTyping && (
)} {isTyping && (

{typingMessage}

)}
{/* Input */}