pradit/components/ChatWidget.tsx
2025-11-20 17:04:57 +07:00

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>
);
};