110 lines
4.5 KiB
TypeScript
110 lines
4.5 KiB
TypeScript
import React, { useState, useRef, useEffect } from 'react';
|
|
import { MessageSquare, X, Send, Terminal } from 'lucide-react';
|
|
|
|
interface Message {
|
|
id: string;
|
|
text: string;
|
|
sender: 'user' | 'bot';
|
|
timestamp: Date;
|
|
}
|
|
|
|
export const ChatWidget: React.FC = () => {
|
|
const [isOpen, setIsOpen] = useState(false);
|
|
const [messages, setMessages] = useState<Message[]>([
|
|
{ id: '1', text: "System online. I am Pradit's automated assistant. How can I help you engineer your next AI system?", sender: 'bot', timestamp: new Date() }
|
|
]);
|
|
const [input, setInput] = useState("");
|
|
const bottomRef = useRef<HTMLDivElement>(null);
|
|
|
|
useEffect(() => {
|
|
if (isOpen) {
|
|
bottomRef.current?.scrollIntoView({ behavior: 'smooth' });
|
|
}
|
|
}, [messages, isOpen]);
|
|
|
|
const handleSend = async (e: React.FormEvent) => {
|
|
e.preventDefault();
|
|
if (!input.trim()) return;
|
|
|
|
const userMsg: Message = { id: Date.now().toString(), text: input, sender: 'user', timestamp: new Date() };
|
|
setMessages(prev => [...prev, userMsg]);
|
|
setInput("");
|
|
|
|
// Mock response
|
|
setTimeout(() => {
|
|
const botMsg: Message = {
|
|
id: (Date.now() + 1).toString(),
|
|
text: "ACK. Request received. Our engineers are currently optimizing a training run. Please visit 'Hire Us' to schedule a deep dive consultation.",
|
|
sender: 'bot',
|
|
timestamp: new Date()
|
|
};
|
|
setMessages(prev => [...prev, botMsg]);
|
|
}, 800);
|
|
};
|
|
|
|
return (
|
|
<div className="fixed bottom-6 right-6 z-50 font-sans">
|
|
{/* Chat Window */}
|
|
{isOpen && (
|
|
<div className="mb-4 w-[320px] md:w-[360px] bg-white rounded-sm shadow-2xl border border-gray-200 flex flex-col overflow-hidden animate-in slide-in-from-bottom-10 fade-in duration-200">
|
|
{/* Header */}
|
|
<div className="bg-[#1e1e1e] text-white p-4 flex items-center justify-between border-b border-gray-800">
|
|
<div className="flex items-center gap-3">
|
|
<div className="p-1 bg-green-500/20 rounded-sm">
|
|
<Terminal size={16} className="text-green-400" />
|
|
</div>
|
|
<span className="text-xs font-mono font-bold tracking-wider uppercase text-gray-200">Pradit/Assistant</span>
|
|
</div>
|
|
<button onClick={() => setIsOpen(false)} className="text-gray-400 hover:text-white transition-colors">
|
|
<X size={18} />
|
|
</button>
|
|
</div>
|
|
|
|
{/* Messages */}
|
|
<div className="h-[350px] overflow-y-auto p-4 bg-[#fdfdfd] space-y-4">
|
|
{messages.map((msg) => (
|
|
<div key={msg.id} className={`flex ${msg.sender === 'user' ? 'justify-end' : 'justify-start'}`}>
|
|
<div className={`max-w-[85%] p-3 rounded-sm text-sm font-serif leading-relaxed ${
|
|
msg.sender === 'user'
|
|
? 'bg-gray-100 text-ink border border-gray-200'
|
|
: 'bg-white text-subtle border border-gray-100 shadow-sm'
|
|
}`}>
|
|
{msg.text}
|
|
</div>
|
|
</div>
|
|
))}
|
|
<div ref={bottomRef} />
|
|
</div>
|
|
|
|
{/* Input */}
|
|
<form onSubmit={handleSend} className="p-3 bg-white border-t border-gray-200 flex gap-2">
|
|
<div className="flex-grow flex items-center bg-gray-50 border border-gray-200 px-3 py-2 rounded-sm focus-within:border-ink focus-within:ring-1 focus-within:ring-ink/5 transition-all">
|
|
<span className="text-gray-400 mr-2 text-xs font-mono">{">"}</span>
|
|
<input
|
|
type="text"
|
|
value={input}
|
|
onChange={(e) => setInput(e.target.value)}
|
|
placeholder="Type your query..."
|
|
className="flex-grow bg-transparent text-sm outline-none text-ink placeholder:text-gray-400 font-sans"
|
|
/>
|
|
</div>
|
|
<button type="submit" className="bg-ink text-white p-2 rounded-sm hover:bg-gray-800 transition-colors flex items-center justify-center">
|
|
<Send size={16} />
|
|
</button>
|
|
</form>
|
|
</div>
|
|
)}
|
|
|
|
{/* Toggle Button */}
|
|
{!isOpen && (
|
|
<button
|
|
onClick={() => setIsOpen(true)}
|
|
className="group flex items-center gap-2 bg-ink hover:bg-gray-800 text-white pl-4 pr-5 py-3 rounded-full shadow-lg transition-all hover:scale-105"
|
|
>
|
|
<MessageSquare size={20} className="text-gray-300 group-hover:text-white transition-colors" />
|
|
<span className="font-bold text-sm tracking-wide">Chat</span>
|
|
</button>
|
|
)}
|
|
</div>
|
|
);
|
|
}; |