first commit
This commit is contained in:
250
src/components/Chatbot.tsx
Normal file
250
src/components/Chatbot.tsx
Normal file
@@ -0,0 +1,250 @@
|
||||
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>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user