250 lines
11 KiB
TypeScript
250 lines
11 KiB
TypeScript
import React, { useState, useRef, useEffect } from 'react';
|
|
import { MessageCircle, X, Send, User, Bot, Minimize2 } from 'lucide-react';
|
|
import { Button } from './ui/button';
|
|
import exampleImage from 'figma:asset/a28d79dd35b730f689b77dbb30452ca27bd25759.png';
|
|
|
|
interface Message {
|
|
id: string;
|
|
text: string;
|
|
sender: 'user' | 'bot';
|
|
timestamp: Date;
|
|
}
|
|
|
|
export function Chatbot() {
|
|
const [isOpen, setIsOpen] = useState(false);
|
|
const [messages, setMessages] = useState<Message[]>([
|
|
{
|
|
id: '1',
|
|
text: 'Hello! I\'m here to help you learn more about Kautilya Leadership Centre. How can I assist you today?',
|
|
sender: 'bot',
|
|
timestamp: new Date()
|
|
}
|
|
]);
|
|
const [inputValue, setInputValue] = useState('');
|
|
const [isTyping, setIsTyping] = useState(false);
|
|
const messagesEndRef = useRef<HTMLDivElement>(null);
|
|
|
|
const scrollToBottom = () => {
|
|
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
|
|
};
|
|
|
|
useEffect(() => {
|
|
scrollToBottom();
|
|
}, [messages]);
|
|
|
|
const predefinedResponses: { [key: string]: string } = {
|
|
'hello': 'Hello! Welcome to Kautilya Leadership Centre. I\'m here to help you with information about our programs, services, and how we can support your leadership development journey.',
|
|
'programs': 'We offer comprehensive leadership development programs including executive coaching, team development, strategic leadership training, and virtual learning experiences. Would you like to know more about any specific program?',
|
|
'services': 'Our services include Leadership Development, Executive Coaching, Team Building, Strategic Planning, Organizational Development, and Virtual Learning Platforms. Each is designed to enhance leadership capabilities.',
|
|
'contact': 'You can reach us through our contact form on the website, or feel free to schedule a consultation. We\'d be happy to discuss how we can support your leadership development goals.',
|
|
'virtual': 'Our virtual learning platform offers flexible, interactive leadership development experiences. You can access courses, participate in live sessions, and connect with other leaders from anywhere.',
|
|
'coaching': 'Our executive coaching program provides personalized one-on-one guidance to help leaders develop their skills, overcome challenges, and achieve their professional goals.',
|
|
'team': 'Our team development services focus on building high-performing teams through collaborative workshops, communication training, and strategic alignment exercises.',
|
|
'webinar': 'Join our upcoming leadership webinars! We regularly host sessions covering various leadership topics. Check our webinars section for schedules and registration.',
|
|
'default': 'That\'s a great question! For detailed information about our specific programs and services, I\'d recommend exploring our website or contacting our team directly. Is there anything specific about leadership development I can help you with?'
|
|
};
|
|
|
|
const getBotResponse = (userMessage: string): string => {
|
|
const lowerMessage = userMessage.toLowerCase();
|
|
|
|
for (const [key, response] of Object.entries(predefinedResponses)) {
|
|
if (key !== 'default' && lowerMessage.includes(key)) {
|
|
return response;
|
|
}
|
|
}
|
|
|
|
return predefinedResponses.default;
|
|
};
|
|
|
|
const handleSendMessage = async () => {
|
|
if (!inputValue.trim()) return;
|
|
|
|
const userMessage: Message = {
|
|
id: Date.now().toString(),
|
|
text: inputValue,
|
|
sender: 'user',
|
|
timestamp: new Date()
|
|
};
|
|
|
|
setMessages(prev => [...prev, userMessage]);
|
|
setInputValue('');
|
|
setIsTyping(true);
|
|
|
|
// Simulate typing delay
|
|
setTimeout(() => {
|
|
const botMessage: Message = {
|
|
id: (Date.now() + 1).toString(),
|
|
text: getBotResponse(inputValue),
|
|
sender: 'bot',
|
|
timestamp: new Date()
|
|
};
|
|
|
|
setMessages(prev => [...prev, botMessage]);
|
|
setIsTyping(false);
|
|
}, 1500);
|
|
};
|
|
|
|
const handleKeyPress = (e: React.KeyboardEvent) => {
|
|
if (e.key === 'Enter' && !e.shiftKey) {
|
|
e.preventDefault();
|
|
handleSendMessage();
|
|
}
|
|
};
|
|
|
|
const formatTime = (date: Date) => {
|
|
return date.toLocaleTimeString('en-US', {
|
|
hour: '2-digit',
|
|
minute: '2-digit',
|
|
hour12: true
|
|
});
|
|
};
|
|
|
|
return (
|
|
<>
|
|
{/* Chatbot Toggle Button */}
|
|
<div className="fixed bottom-6 right-6 z-50">
|
|
<button
|
|
onClick={() => setIsOpen(!isOpen)}
|
|
className="w-16 h-16 rounded-full shadow-xl transition-all duration-300 hover:scale-105 focus:outline-none focus:ring-4 focus:ring-blue-300 chatbot-button"
|
|
style={{
|
|
backgroundColor: '#04045B',
|
|
boxShadow: '0 8px 32px rgba(4, 4, 91, 0.3)'
|
|
}}
|
|
aria-label="Open chat"
|
|
>
|
|
{isOpen ? (
|
|
<X className="w-7 h-7 text-white mx-auto" />
|
|
) : (
|
|
<MessageCircle className="w-7 h-7 text-white mx-auto" />
|
|
)}
|
|
</button>
|
|
</div>
|
|
|
|
{/* Chatbot Window */}
|
|
{isOpen && (
|
|
<div
|
|
className="fixed bottom-24 right-6 w-80 bg-white rounded-2xl shadow-2xl border-0 z-50 flex flex-col overflow-hidden"
|
|
style={{
|
|
height: '500px',
|
|
boxShadow: '0 25px 50px -12px rgba(0, 0, 0, 0.25), 0 0 0 1px rgba(255, 255, 255, 0.1)'
|
|
}}
|
|
>
|
|
{/* Header with gradient background */}
|
|
<div
|
|
className="p-6 flex items-center justify-between relative"
|
|
style={{
|
|
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
|
|
borderRadius: '16px 16px 0 0'
|
|
}}
|
|
>
|
|
<div className="flex items-center space-x-3">
|
|
<div className="w-10 h-10 bg-white/20 backdrop-blur-sm rounded-full flex items-center justify-center">
|
|
<Bot className="w-6 h-6 text-white" />
|
|
</div>
|
|
<div>
|
|
<h3 className="text-white font-semibold text-lg">Welcome to KLC</h3>
|
|
<p className="text-white/80 text-sm">How can I help you today?</p>
|
|
</div>
|
|
</div>
|
|
<div className="flex items-center space-x-2">
|
|
<button
|
|
onClick={() => setIsOpen(false)}
|
|
className="text-white/70 hover:text-white transition-colors p-1"
|
|
>
|
|
<Minimize2 className="w-4 h-4" />
|
|
</button>
|
|
<button
|
|
onClick={() => setIsOpen(false)}
|
|
className="text-white/70 hover:text-white transition-colors p-1"
|
|
>
|
|
<X className="w-5 h-5" />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Messages Container */}
|
|
<div className="flex-1 p-5 overflow-y-auto space-y-4" style={{ backgroundColor: '#f8fafc' }}>
|
|
{messages.map((message) => (
|
|
<div
|
|
key={message.id}
|
|
className={`flex ${message.sender === 'user' ? 'justify-end' : 'justify-start'}`}
|
|
>
|
|
<div className={`flex items-start space-x-3 max-w-[85%] ${message.sender === 'user' ? 'flex-row-reverse space-x-reverse' : ''}`}>
|
|
<div className={`w-8 h-8 rounded-full flex items-center justify-center flex-shrink-0 ${
|
|
message.sender === 'user'
|
|
? 'bg-gradient-to-r from-blue-500 to-purple-600'
|
|
: 'bg-gradient-to-r from-purple-500 to-pink-500'
|
|
}`}>
|
|
{message.sender === 'user' ? (
|
|
<User className="w-4 h-4 text-white" />
|
|
) : (
|
|
<Bot className="w-4 h-4 text-white" />
|
|
)}
|
|
</div>
|
|
<div>
|
|
<div className={`p-4 rounded-2xl ${
|
|
message.sender === 'user'
|
|
? 'bg-gradient-to-r from-blue-500 to-purple-600 text-white'
|
|
: 'bg-white text-gray-800 shadow-sm border border-gray-100'
|
|
}`}>
|
|
<p className="text-sm leading-relaxed">{message.text}</p>
|
|
</div>
|
|
<p className="text-xs text-gray-400 mt-2 px-2">
|
|
{formatTime(message.timestamp)}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
))}
|
|
|
|
{/* Typing Indicator */}
|
|
{isTyping && (
|
|
<div className="flex justify-start">
|
|
<div className="flex items-start space-x-3">
|
|
<div className="w-8 h-8 rounded-full bg-gradient-to-r from-purple-500 to-pink-500 flex items-center justify-center">
|
|
<Bot className="w-4 h-4 text-white" />
|
|
</div>
|
|
<div className="bg-white p-4 rounded-2xl shadow-sm border border-gray-100">
|
|
<div className="flex space-x-1">
|
|
<div className="w-2 h-2 bg-purple-400 rounded-full animate-bounce"></div>
|
|
<div className="w-2 h-2 bg-purple-400 rounded-full animate-bounce" style={{ animationDelay: '0.1s' }}></div>
|
|
<div className="w-2 h-2 bg-purple-400 rounded-full animate-bounce" style={{ animationDelay: '0.2s' }}></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
<div ref={messagesEndRef} />
|
|
</div>
|
|
|
|
{/* Input Area */}
|
|
<div className="p-5 bg-white border-t border-gray-100">
|
|
<div className="flex space-x-3">
|
|
<input
|
|
type="text"
|
|
value={inputValue}
|
|
onChange={(e) => setInputValue(e.target.value)}
|
|
onKeyPress={handleKeyPress}
|
|
placeholder="Type your message..."
|
|
className="flex-1 px-4 py-3 border border-gray-200 rounded-xl focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-transparent text-sm bg-gray-50"
|
|
style={{ fontFamily: 'var(--font-family-brand)' }}
|
|
/>
|
|
<button
|
|
onClick={handleSendMessage}
|
|
disabled={!inputValue.trim()}
|
|
className="px-4 py-3 rounded-xl text-white transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed focus:outline-none focus:ring-2 focus:ring-purple-500"
|
|
style={{
|
|
background: inputValue.trim()
|
|
? 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)'
|
|
: '#e5e7eb'
|
|
}}
|
|
>
|
|
<Send className="w-5 h-5" />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</>
|
|
);
|
|
} |