95 lines
4.6 KiB
TypeScript
95 lines
4.6 KiB
TypeScript
"use client";
|
|
import { useState } from "react";
|
|
import { Button } from "@/components/ui/button";
|
|
import { Card } from "@/components/ui/card";
|
|
import { MessageCircle, X, Send } from "lucide-react";
|
|
import { motion, AnimatePresence } from "framer-motion";
|
|
|
|
export function Chatbot() {
|
|
const [isOpen, setIsOpen] = useState(false);
|
|
const [messages, setMessages] = useState([
|
|
{ role: "bot", text: "Hi! I'm the Apex Assistant. I'm powered by AI to help you while I'm out detailing cars. How can I help you today?" }
|
|
]);
|
|
const [input, setInput] = useState("");
|
|
|
|
const handleSend = () => {
|
|
if (!input.trim()) return;
|
|
const newMessages = [...messages, { role: "user", text: input }];
|
|
setMessages(newMessages);
|
|
setInput("");
|
|
|
|
// Simple automated responses
|
|
setTimeout(() => {
|
|
let response = "I'm not sure about that, but you can book a detail and I'll answer all your questions in person!";
|
|
const lowerInput = input.toLowerCase();
|
|
if (lowerInput.includes("price") || lowerInput.includes("cost")) response = "Our prices vary by car size: Full Interior starts at $80, Exterior Hand Wash at $40, and Full Detail at $110!";
|
|
if (lowerInput.includes("where") || lowerInput.includes("location")) response = "I'm based in Cedar Rapids and I'm mobile—I come right to your driveway!";
|
|
if (lowerInput.includes("equipment") || lowerInput.includes("tools")) response = "I use professional-grade pressure washers, steam cleaners, and industrial vacuums to get that better-than-pro finish.";
|
|
if (lowerInput.includes("who") || lowerInput.includes("old")) response = "I'm a 13-year-old entrepreneur saving up for my first car and college!";
|
|
if (lowerInput.includes("book") || lowerInput.includes("schedule")) response = "You can book directly on our site using the 'Book a Detail' button. We accept Stripe for secure payments!";
|
|
|
|
setMessages([...newMessages, { role: "bot", text: response }]);
|
|
}, 1000);
|
|
};
|
|
|
|
return (
|
|
<div className="fixed bottom-6 right-6 z-50">
|
|
<AnimatePresence>
|
|
{!isOpen ? (
|
|
<motion.div
|
|
initial={{ scale: 0, opacity: 0 }}
|
|
animate={{ scale: 1, opacity: 1 }}
|
|
exit={{ scale: 0, opacity: 0 }}
|
|
>
|
|
<Button onClick={() => setIsOpen(true)} className="rounded-full w-14 h-14 shadow-xl bg-blue-600 hover:bg-blue-700">
|
|
<MessageCircle className="w-6 h-6 text-white" />
|
|
</Button>
|
|
</motion.div>
|
|
) : (
|
|
<motion.div
|
|
initial={{ y: 100, opacity: 0 }}
|
|
animate={{ y: 0, opacity: 1 }}
|
|
exit={{ y: 100, opacity: 0 }}
|
|
>
|
|
<Card className="w-80 h-96 flex flex-col shadow-2xl border-neutral-200 dark:border-neutral-800 overflow-hidden">
|
|
<div className="p-4 bg-blue-600 text-white flex justify-between items-center">
|
|
<div className="flex items-center gap-2">
|
|
<div className="w-2 h-2 bg-green-400 rounded-full animate-pulse" />
|
|
<span className="font-bold">Apex AI Assistant</span>
|
|
</div>
|
|
<X className="w-4 h-4 cursor-pointer" onClick={() => setIsOpen(false)} />
|
|
</div>
|
|
<div className="flex-1 overflow-y-auto p-4 space-y-4 bg-white dark:bg-neutral-950">
|
|
{messages.map((m, i) => (
|
|
<motion.div
|
|
key={i}
|
|
initial={{ opacity: 0, x: m.role === "user" ? 20 : -20 }}
|
|
animate={{ opacity: 1, x: 0 }}
|
|
className={`flex ${m.role === "user" ? "justify-end" : "justify-start"}`}
|
|
>
|
|
<div className={`max-w-[80%] p-3 rounded-2xl text-sm ${m.role === "user" ? "bg-blue-600 text-white rounded-tr-none" : "bg-neutral-100 dark:bg-neutral-800 rounded-tl-none"}`}>
|
|
{m.text}
|
|
</div>
|
|
</motion.div>
|
|
))}
|
|
</div>
|
|
<div className="p-4 border-t bg-neutral-50 dark:bg-neutral-900 flex gap-2">
|
|
<input
|
|
className="flex-1 bg-transparent text-sm outline-none"
|
|
placeholder="Ask about pricing, equipment..."
|
|
value={input}
|
|
onChange={(e) => (setInput(e.target.value))}
|
|
onKeyDown={(e) => e.key === "Enter" && handleSend()}
|
|
/>
|
|
<Button size="icon" variant="ghost" className="h-8 w-8 text-blue-600" onClick={handleSend}>
|
|
<Send className="w-4 h-4" />
|
|
</Button>
|
|
</div>
|
|
</Card>
|
|
</motion.div>
|
|
)}
|
|
</AnimatePresence>
|
|
</div>
|
|
);
|
|
}
|