278 lines
10 KiB
TypeScript
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;
|