Prototipo do chatsuporte
This commit is contained in:
parent
b2e2423978
commit
c9d1457775
@ -23,6 +23,6 @@
|
||||
<!-- <script src="%PUBLIC_URL%/vendors/perfect-scrollbar/perfect-scrollbar.min.js"></script>
|
||||
<script src="%PUBLIC_URL%/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="%PUBLIC_URL%/js/main.js"></script> -->
|
||||
<script src="https://website-widgets.pages.dev/dist/sienna.min.js" defer></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
45
src/App.css
45
src/App.css
@ -45,3 +45,48 @@ html[data-bs-theme="dark"] .App-header {
|
||||
html[data-bs-theme="dark"] .App-link {
|
||||
color: #bb86fc;
|
||||
}
|
||||
|
||||
.top-right-chat-button-wrapper {
|
||||
position: fixed; /* 'fixed' faz ele flutuar mesmo com scroll */
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
z-index: 1001; /* Garante que fique acima de outros elementos */
|
||||
}
|
||||
|
||||
/* App.css */
|
||||
|
||||
/* Container principal */
|
||||
.app-wrapper {
|
||||
display: flex; /* Organiza o conteúdo principal e o chat lado a lado */
|
||||
}
|
||||
|
||||
.main-content {
|
||||
position: relative; /* Essencial para ser o 'pai' */
|
||||
flex-grow: 1;
|
||||
transition: margin-right 0.4s ease-in-out;
|
||||
}
|
||||
.main-content.chat-open {
|
||||
margin-right: 350px;
|
||||
}
|
||||
|
||||
/* Posicionamento do botão que abre o chat */
|
||||
.chat-button-container {
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
/* App.css */
|
||||
|
||||
.floating-buttons-container {
|
||||
/* Posicionamento do GRUPO */
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
z-index: 1000;
|
||||
|
||||
/* Alinhamento dos botões */
|
||||
display: flex;
|
||||
gap: 10px; /* Espaçamento entre os botões */
|
||||
}
|
||||
51
src/App.js
51
src/App.js
@ -1,40 +1,43 @@
|
||||
import React, { useState } from "react";
|
||||
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
|
||||
import './App.css';
|
||||
|
||||
// Suas páginas
|
||||
import Login from "./pages/Login";
|
||||
import Register from "./pages/Register";
|
||||
import Forgot from "./pages/ForgotPassword";
|
||||
import PerfilSecretaria from "./perfis/perfil_secretaria/PerfilSecretaria";
|
||||
import LandingPage from './pages/LandingPage';
|
||||
import PerfilFinanceiro from "./perfis/perfil_financeiro/PerfilFinanceiro";
|
||||
import Perfiladm from "./perfis/Perfil_adm/Perfiladm";
|
||||
import PerfilMedico from "./perfis/Perfil_medico/PerfilMedico";
|
||||
import PerfilSecretaria from "./perfis/perfil_secretaria/PerfilSecretaria";
|
||||
|
||||
// Componentes globais de acessibilidade
|
||||
import VlibrasWidget from "./components/VlibrasWidget";
|
||||
|
||||
import BotaoAcessibilidade from "./components/botaoacessibilidade.jsx";
|
||||
import ChatToggleButton from './components/ChatButton/ChatButton';
|
||||
import ChatSidebar from './components/ChatSidebar/ChatSidebar';
|
||||
|
||||
function App() {
|
||||
const [isChatOpen, setIsChatOpen] = useState(false);
|
||||
|
||||
const toggleChat = () => {
|
||||
setIsChatOpen(!isChatOpen);
|
||||
};
|
||||
|
||||
return (
|
||||
<Router>
|
||||
<VlibrasWidget />
|
||||
<BotaoAcessibilidade />
|
||||
<div className="app-wrapper">
|
||||
<div className={`main-content ${isChatOpen ? 'chat-open' : ''}`}>
|
||||
<VlibrasWidget />
|
||||
|
||||
<Routes>
|
||||
<Route path="/" element={<LandingPage />} />
|
||||
<Route path="/login" element={<Login />} />
|
||||
<Route path="/register" element={<Register />} />
|
||||
<Route path="/forgotPassword" element={<Forgot />} />
|
||||
<Route path="/secretaria/*" element={<PerfilSecretaria />} />
|
||||
<Route path="/financeiro/*" element={<PerfilFinanceiro />} />
|
||||
<Route path="/medico/*" element={<PerfilMedico />} />
|
||||
<Route path="/admin/*" element={<Perfiladm />} />
|
||||
<Route path="*" element={<h2>Página não encontrada</h2>} />
|
||||
</Routes>
|
||||
<div className="floating-buttons-container">
|
||||
<BotaoAcessibilidade />
|
||||
<ChatToggleButton onClick={toggleChat} />
|
||||
</div>
|
||||
|
||||
<Routes>
|
||||
<Route path="/" element={<LandingPage />} />
|
||||
<Route path="/secretaria/*" element={<PerfilSecretaria />} />
|
||||
</Routes>
|
||||
</div>
|
||||
|
||||
<ChatSidebar isOpen={isChatOpen} onClose={toggleChat} />
|
||||
</div>
|
||||
</Router>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
|
||||
|
||||
27
src/components/ChatButton/ChatButton.css
Normal file
27
src/components/ChatButton/ChatButton.css
Normal file
@ -0,0 +1,27 @@
|
||||
|
||||
.chat-toggle-button {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border-radius: 50%;
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
border: none;
|
||||
box-shadow: 0 4px 8px rgba(0,0,0,0.2);
|
||||
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
|
||||
.chat-toggle-button:hover {
|
||||
background-color: #0056b3;
|
||||
}
|
||||
|
||||
.chat-toggle-button svg {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
fill: white;
|
||||
}
|
||||
15
src/components/ChatButton/ChatButton.jsx
Normal file
15
src/components/ChatButton/ChatButton.jsx
Normal file
@ -0,0 +1,15 @@
|
||||
import React from 'react';
|
||||
import './ChatButton.css';
|
||||
|
||||
const ChatButton = ({ onClick }) => {
|
||||
return (
|
||||
<button className="chat-toggle-button" onClick={onClick} aria-label="Abrir chat">
|
||||
{/* Ícone de Chat (SVG) */}
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<path d="M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2z"></path>
|
||||
</svg>
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
export default ChatButton;
|
||||
134
src/components/ChatSidebar/ChatSidebar.css
Normal file
134
src/components/ChatSidebar/ChatSidebar.css
Normal file
@ -0,0 +1,134 @@
|
||||
/* ================================================= */
|
||||
/* Novo Estilo para ChatSidebar.css */
|
||||
/* Inspirado no Design "MediConnect" */
|
||||
/* ================================================= */
|
||||
|
||||
.chat-sidebar {
|
||||
/* Layout e Posição */
|
||||
height: 100vh;
|
||||
width: 350px;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
|
||||
/* Estilo MediConnect */
|
||||
background-color: #FFFFFF; /* Fundo branco limpo, como os cards */
|
||||
color: #333; /* Texto escuro padrão */
|
||||
font-family: Arial, sans-serif; /* Use a mesma fonte do seu site, se souber */
|
||||
|
||||
/* Animação (sem alteração) */
|
||||
transform: translateX(100%);
|
||||
transition: transform 0.4s ease-in-out;
|
||||
|
||||
/* Sombra suave, como a dos cards */
|
||||
box-shadow: -2px 0 15px rgba(0, 0, 0, 0.1);
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.chat-sidebar.open {
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
/* Cabeçalho */
|
||||
.chat-header {
|
||||
padding: 15px 20px;
|
||||
background-color: #F8F9FA; /* Cinza bem claro, como o fundo do site */
|
||||
border-bottom: 1px solid #E9ECEF; /* Borda sutil */
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.chat-header h3 {
|
||||
margin: 0;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #212529; /* Cor do título dos cards */
|
||||
}
|
||||
|
||||
.chat-close-button {
|
||||
background: none;
|
||||
border: none;
|
||||
font-size: 24px;
|
||||
cursor: pointer;
|
||||
color: #6c757d; /* Cinza sutil para o ícone de fechar */
|
||||
transition: color 0.2s;
|
||||
}
|
||||
.chat-close-button:hover {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
/* Área das Mensagens */
|
||||
.chat-messages {
|
||||
flex-grow: 1;
|
||||
padding: 20px;
|
||||
overflow-y: auto;
|
||||
background-color: #F8F9FA; /* Fundo igual ao header para consistência */
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px; /* Espaçamento entre as mensagens */
|
||||
}
|
||||
|
||||
/* Adicionando estilo para os balões de mensagem */
|
||||
.message {
|
||||
padding: 10px 15px;
|
||||
border-radius: 18px;
|
||||
max-width: 80%;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.message.received {
|
||||
background-color: #E9ECEF; /* Cinza claro para mensagens recebidas */
|
||||
color: #212529;
|
||||
align-self: flex-start; /* Alinha à esquerda */
|
||||
border-bottom-left-radius: 4px; /* Detalhe de estilo */
|
||||
}
|
||||
|
||||
.message.sent {
|
||||
background-color: #6C63FF; /* Cor principal do seu site */
|
||||
color: white;
|
||||
align-self: flex-end; /* Alinha à direita */
|
||||
border-bottom-right-radius: 4px; /* Detalhe de estilo */
|
||||
}
|
||||
|
||||
|
||||
/* Área de Input */
|
||||
.chat-input-area {
|
||||
padding: 15px 20px;
|
||||
display: flex;
|
||||
gap: 10px; /* Espaço entre o input e o botão */
|
||||
border-top: 1px solid #E9ECEF;
|
||||
background-color: #FFFFFF; /* Fundo branco para destacar */
|
||||
}
|
||||
|
||||
.chat-input-area input {
|
||||
flex-grow: 1;
|
||||
border: 1px solid #DEE2E6; /* Borda padrão */
|
||||
border-radius: 8px; /* Bordas arredondadas como os elementos do site */
|
||||
padding: 12px 15px;
|
||||
font-size: 15px;
|
||||
color: #333;
|
||||
transition: border-color 0.2s;
|
||||
}
|
||||
.chat-input-area input:focus {
|
||||
outline: none;
|
||||
border-color: #6C63FF; /* Destaque com a cor principal */
|
||||
box-shadow: 0 0 0 2px rgba(108, 99, 255, 0.2);
|
||||
}
|
||||
|
||||
.chat-input-area button {
|
||||
background-color: #6C63FF; /* Cor principal do seu site */
|
||||
border: none;
|
||||
color: white;
|
||||
padding: 0 25px;
|
||||
border-radius: 8px; /* Mesma borda do input */
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
.chat-input-area button:hover {
|
||||
background-color: #574ee6; /* Um tom um pouco mais escuro ao passar o mouse */
|
||||
}
|
||||
79
src/components/ChatSidebar/ChatSidebar.jsx
Normal file
79
src/components/ChatSidebar/ChatSidebar.jsx
Normal file
@ -0,0 +1,79 @@
|
||||
import React, { useState, useEffect, useRef } from 'react';
|
||||
import './ChatSidebar.css';
|
||||
|
||||
const ChatSidebar = ({ isOpen, onClose }) => {
|
||||
|
||||
const [messages, setMessages] = useState([
|
||||
{ id: 1, text: 'Olá! Como podemos ajudar você hoje?', sender: 'support' }
|
||||
]);
|
||||
const [inputValue, setInputValue] = useState('');
|
||||
const messagesEndRef = useRef(null);
|
||||
const sidebarClassName = `chat-sidebar ${isOpen ? 'open' : ''}`;
|
||||
const scrollToBottom = () => {
|
||||
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
scrollToBottom();
|
||||
}, [messages]);
|
||||
|
||||
const handleSendMessage = () => {
|
||||
if (inputValue.trim() === '') return;
|
||||
const newMessage = {
|
||||
id: messages.length + 1,
|
||||
text: inputValue,
|
||||
sender: 'user'
|
||||
};
|
||||
setMessages(currentMessages => [...currentMessages, newMessage]);
|
||||
setInputValue('');
|
||||
setTimeout(() => {
|
||||
const supportReply = {
|
||||
id: messages.length + 2,
|
||||
text: 'Obrigado por sua mensagem. Um de nossos atendentes responderá em breve.',
|
||||
sender: 'support'
|
||||
};
|
||||
setMessages(currentMessages => [...currentMessages, supportReply]);
|
||||
}, 1000);
|
||||
};
|
||||
const handleKeyPress = (event) => {
|
||||
if (event.key === 'Enter') {
|
||||
handleSendMessage();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={sidebarClassName}>
|
||||
<div className="chat-header">
|
||||
<h3>Suporte Online</h3>
|
||||
<button onClick={onClose} className="chat-close-button">X</button>
|
||||
</div>
|
||||
|
||||
<div className="chat-messages">
|
||||
{/* Mapeia a lista de mensagens e cria um balão para cada uma */}
|
||||
{messages.map(message => (
|
||||
<div
|
||||
key={message.id}
|
||||
className={`message ${message.sender === 'user' ? 'sent' : 'received'}`}
|
||||
>
|
||||
{message.text}
|
||||
</div>
|
||||
))}
|
||||
{/* Elemento invisível no final para o scroll automático */}
|
||||
<div ref={messagesEndRef} />
|
||||
</div>
|
||||
|
||||
<div className="chat-input-area">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Digite sua mensagem..."
|
||||
value={inputValue}
|
||||
onChange={(e) => setInputValue(e.target.value)}
|
||||
onKeyPress={handleKeyPress}
|
||||
/>
|
||||
<button onClick={handleSendMessage}>Enviar</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ChatSidebar;
|
||||
@ -4,12 +4,7 @@
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.container-acessibilidade {
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
z-index: 10000;
|
||||
}
|
||||
|
||||
.botao-flutuante-acessibilidade {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user