278 lines
10 KiB
TypeScript

import React, { useState, useRef, useEffect } from "react";
import { MessageCircle, X, Send } from "lucide-react";
interface Message {
id: string;
text: string;
sender: "user" | "bot";
timestamp: Date;
}
interface ChatbotProps {
className?: string;
}
const Chatbot: React.FC<ChatbotProps> = ({ className = "" }) => {
const [isOpen, setIsOpen] = useState(false);
const [messages, setMessages] = useState<Message[]>([
{
id: "welcome",
text: "Olá! Sou o assistente virtual do MediConnect. Como posso ajudá-lo hoje?",
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 quickReplies = [
"Como agendar uma consulta?",
"Como cancelar agendamento?",
"Esqueci minha senha",
"Suporte técnico",
];
const getBotResponse = (userMessage: string): string => {
const message = userMessage.toLowerCase();
// Respostas baseadas em palavras-chave
if (message.includes("agendar") || message.includes("marcar")) {
return "Para agendar uma consulta:\n\n1. Acesse 'Agendar Consulta' no menu\n2. Selecione o médico desejado\n3. Escolha data e horário disponível\n4. Confirme o agendamento\n\nVocê receberá uma confirmação por e-mail!";
}
if (message.includes("cancelar") || message.includes("remarcar")) {
return "Para cancelar ou remarcar uma consulta:\n\n1. Vá em 'Minhas Consultas'\n2. Localize a consulta\n3. Clique em 'Cancelar' ou 'Remarcar'\n\nRecomendamos fazer isso com 24h de antecedência para evitar taxas.";
}
if (message.includes("senha") || message.includes("login")) {
return "Para recuperar sua senha:\n\n1. Clique em 'Esqueceu a senha?' na tela de login\n2. Insira seu e-mail cadastrado\n3. Você receberá um link para redefinir a senha\n\nSe não receber o e-mail, verifique sua caixa de spam.";
}
if (message.includes("pagamento") || message.includes("pagar")) {
return "Aceitamos as seguintes formas de pagamento:\n\n• Cartão de crédito (parcelamento em até 3x)\n• Cartão de débito\n• PIX\n• Boleto bancário\n\nTodos os pagamentos são processados com segurança.";
}
if (message.includes("teleconsulta") || message.includes("online")) {
return "Para realizar uma teleconsulta:\n\n1. Acesse 'Minhas Consultas' no horário agendado\n2. Clique em 'Iniciar Consulta Online'\n3. Permita acesso à câmera e microfone\n\nCertifique-se de ter uma boa conexão de internet!";
}
if (message.includes("histórico") || message.includes("prontuário")) {
return "Seu histórico médico pode ser acessado em:\n\n• 'Meu Perfil' > 'Histórico Médico'\n• 'Minhas Consultas' (consultas anteriores)\n\nVocê pode fazer download de relatórios e receitas quando necessário.";
}
if (
message.includes("suporte") ||
message.includes("ajuda") ||
message.includes("atendimento")
) {
return "Nossa equipe de suporte está disponível:\n\n📞 Telefone: 0800-123-4567\n📧 E-mail: suporte@mediconnect.com.br\n⏰ Horário: Segunda a Sexta, 8h às 18h\n\nVocê também pode acessar nossa Central de Ajuda completa no menu.";
}
if (message.includes("obrigad") || message.includes("valeu")) {
return "Por nada! Estou sempre aqui para ajudar. Se tiver mais dúvidas, é só chamar! 😊";
}
if (
message.includes("oi") ||
message.includes("olá") ||
message.includes("hello")
) {
return "Olá! Como posso ajudá-lo hoje? Você pode perguntar sobre agendamentos, consultas, pagamentos ou qualquer dúvida sobre o MediConnect.";
}
// Resposta padrão
return "Desculpe, não entendi sua pergunta. Você pode:\n\n• Perguntar sobre agendamentos\n• Consultar formas de pagamento\n• Saber sobre teleconsultas\n• Acessar histórico médico\n• Falar com suporte\n\nOu visite nossa Central de Ajuda para mais informações!";
};
const handleSend = () => {
if (!inputValue.trim()) return;
// Adiciona mensagem do usuário
const userMessage: Message = {
id: Date.now().toString(),
text: inputValue,
sender: "user",
timestamp: new Date(),
};
setMessages((prev) => [...prev, userMessage]);
setInputValue("");
// Simula digitação do bot
setIsTyping(true);
setTimeout(() => {
const botResponse: Message = {
id: (Date.now() + 1).toString(),
text: getBotResponse(inputValue),
sender: "bot",
timestamp: new Date(),
};
setMessages((prev) => [...prev, botResponse]);
setIsTyping(false);
}, 1000);
};
const handleQuickReply = (reply: string) => {
setInputValue(reply);
};
const handleKeyPress = (e: React.KeyboardEvent) => {
if (e.key === "Enter" && !e.shiftKey) {
e.preventDefault();
handleSend();
}
};
return (
<div className={`fixed bottom-6 left-6 z-50 ${className}`}>
{/* Floating Button */}
{!isOpen && (
<button
onClick={() => setIsOpen(true)}
className="bg-blue-600 hover:bg-blue-700 text-white rounded-full p-4 shadow-lg transition-all hover:scale-110 flex items-center gap-2"
aria-label="Abrir chat de ajuda"
>
<MessageCircle className="w-6 h-6" />
<span className="font-medium">Precisa de ajuda?</span>
</button>
)}
{/* Chat Window */}
{isOpen && (
<div className="bg-white rounded-lg shadow-2xl w-96 h-[600px] flex flex-col">
{/* Header */}
<div className="bg-gradient-to-r from-blue-600 to-blue-700 text-white p-4 rounded-t-lg flex items-center justify-between">
<div className="flex items-center gap-3">
<div className="bg-white/20 rounded-full p-2">
<MessageCircle className="w-5 h-5" />
</div>
<div>
<h3 className="font-semibold">Assistente MediConnect</h3>
<p className="text-xs text-blue-100">
Online Responde em segundos
</p>
</div>
</div>
<button
onClick={() => setIsOpen(false)}
className="hover:bg-white/20 rounded-full p-1 transition"
aria-label="Fechar chat"
>
<X className="w-5 h-5" />
</button>
</div>
{/* Messages */}
<div className="flex-1 overflow-y-auto p-4 space-y-4 bg-gray-50">
{messages.map((message) => (
<div
key={message.id}
className={`flex ${
message.sender === "user" ? "justify-end" : "justify-start"
}`}
>
<div
className={`max-w-[80%] rounded-lg p-3 ${
message.sender === "user"
? "bg-blue-600 text-white"
: "bg-white text-gray-800 shadow"
}`}
>
<p className="text-sm whitespace-pre-line">{message.text}</p>
<p
className={`text-xs mt-1 ${
message.sender === "user"
? "text-blue-100"
: "text-gray-400"
}`}
>
{message.timestamp.toLocaleTimeString("pt-BR", {
hour: "2-digit",
minute: "2-digit",
})}
</p>
</div>
</div>
))}
{isTyping && (
<div className="flex justify-start">
<div className="bg-white text-gray-800 shadow rounded-lg p-3">
<div className="flex gap-1">
<div
className="w-2 h-2 bg-gray-400 rounded-full animate-bounce"
style={{ animationDelay: "0ms" }}
></div>
<div
className="w-2 h-2 bg-gray-400 rounded-full animate-bounce"
style={{ animationDelay: "150ms" }}
></div>
<div
className="w-2 h-2 bg-gray-400 rounded-full animate-bounce"
style={{ animationDelay: "300ms" }}
></div>
</div>
</div>
</div>
)}
<div ref={messagesEndRef} />
</div>
{/* Quick Replies */}
{messages.length <= 1 && (
<div className="px-4 py-2 border-t bg-white">
<p className="text-xs text-gray-500 mb-2">
Perguntas frequentes:
</p>
<div className="flex flex-wrap gap-2">
{quickReplies.map((reply, index) => (
<button
key={index}
onClick={() => handleQuickReply(reply)}
className="text-xs bg-blue-50 hover:bg-blue-100 text-blue-700 px-3 py-1 rounded-full transition"
>
{reply}
</button>
))}
</div>
</div>
)}
{/* Input */}
<div className="p-4 border-t bg-white rounded-b-lg">
<div className="flex gap-2">
<input
type="text"
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
onKeyPress={handleKeyPress}
placeholder="Digite sua mensagem..."
className="flex-1 border border-gray-300 rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
/>
<button
onClick={handleSend}
disabled={!inputValue.trim()}
className="bg-blue-600 hover:bg-blue-700 disabled:bg-gray-300 disabled:cursor-not-allowed text-white rounded-lg p-2 transition"
aria-label="Enviar mensagem"
>
<Send className="w-5 h-5" />
</button>
</div>
</div>
</div>
)}
</div>
);
};
export default Chatbot;