pequenas mudanças no perfil e no suporte
This commit is contained in:
parent
6ccb0992c3
commit
5d1751b7f9
@ -487,4 +487,15 @@
|
||||
width: calc(100vw - 20px);
|
||||
max-width: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* permite que cliques "passem" através do header (exceto para os elementos interativos) */
|
||||
.header-container {
|
||||
pointer-events: none; /* header não captura cliques */
|
||||
}
|
||||
|
||||
/* mas permite que os controles no canto (telefone e profile) continuem clicáveis */
|
||||
.phone-icon-container,
|
||||
.profile-section {
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
@ -1,8 +1,11 @@
|
||||
// src/components/Header/Header.jsx
|
||||
import React, { useState, useRef, useEffect } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { createPortal } from 'react-dom';
|
||||
import { useNavigate, useLocation } from 'react-router-dom';
|
||||
import './Header.css';
|
||||
|
||||
const Header = () => {
|
||||
// --- Hooks (sempre chamados na mesma ordem) ---
|
||||
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
|
||||
const [isSuporteCardOpen, setIsSuporteCardOpen] = useState(false);
|
||||
const [isChatOpen, setIsChatOpen] = useState(false);
|
||||
@ -11,9 +14,11 @@ const Header = () => {
|
||||
const [showLogoutModal, setShowLogoutModal] = useState(false);
|
||||
const [avatarUrl, setAvatarUrl] = useState(null);
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
const chatInputRef = useRef(null);
|
||||
const mensagensContainerRef = useRef(null);
|
||||
|
||||
// --- Efeitos ---
|
||||
useEffect(() => {
|
||||
const loadAvatar = () => {
|
||||
const localAvatar = localStorage.getItem('user_avatar');
|
||||
@ -44,7 +49,18 @@ const Header = () => {
|
||||
}
|
||||
}, [mensagens]);
|
||||
|
||||
// --- Logout ---
|
||||
// Fecha modal com ESC (útil para logout)
|
||||
useEffect(() => {
|
||||
const onKey = (e) => {
|
||||
if (e.key === 'Escape' && showLogoutModal) {
|
||||
setShowLogoutModal(false);
|
||||
}
|
||||
};
|
||||
window.addEventListener('keydown', onKey);
|
||||
return () => window.removeEventListener('keydown', onKey);
|
||||
}, [showLogoutModal]);
|
||||
|
||||
// --- Lógica e handlers ---
|
||||
const handleLogoutClick = () => {
|
||||
setShowLogoutModal(true);
|
||||
setIsDropdownOpen(false);
|
||||
@ -65,26 +81,21 @@ const Header = () => {
|
||||
sessionStorage.getItem("authToken");
|
||||
|
||||
if (token) {
|
||||
const response = await fetch(
|
||||
"https://mock.apidog.com/m1/1053378-0-default/auth/v1/logout",
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
if (response.status === 204) console.log("Logout realizado com sucesso");
|
||||
else if (response.status === 401) console.log("Token inválido ou expirado");
|
||||
else {
|
||||
try {
|
||||
const errorData = await response.json();
|
||||
console.error("Erro no logout:", errorData);
|
||||
} catch {
|
||||
console.error("Erro no logout - status:", response.status);
|
||||
}
|
||||
// tentativa de logout no backend (se houver)
|
||||
try {
|
||||
await fetch(
|
||||
"https://mock.apidog.com/m1/1053378-0-default/auth/v1/logout",
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
}
|
||||
);
|
||||
} catch (err) {
|
||||
// não interrompe o fluxo se a API falhar — prosseguimos para limpar local
|
||||
console.warn('Erro ao chamar endpoint de logout (ignorado):', err);
|
||||
}
|
||||
}
|
||||
|
||||
@ -105,12 +116,13 @@ const Header = () => {
|
||||
sessionStorage.removeItem(key);
|
||||
});
|
||||
|
||||
// tenta limpar caches relacionados se existirem
|
||||
if (window.caches) {
|
||||
caches.keys().then(names => {
|
||||
names.forEach(name => {
|
||||
if (name.includes("auth") || name.includes("api")) caches.delete(name);
|
||||
});
|
||||
});
|
||||
}).catch(()=>{ /* ignore */ });
|
||||
}
|
||||
};
|
||||
|
||||
@ -157,7 +169,6 @@ const Header = () => {
|
||||
e.preventDefault();
|
||||
if (mensagem.trim() === '') return;
|
||||
|
||||
// Mensagem do usuário
|
||||
const novaMensagemUsuario = {
|
||||
id: Date.now(),
|
||||
texto: mensagem,
|
||||
@ -177,7 +188,6 @@ const Header = () => {
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
// Resposta da IA
|
||||
const respostaSuporte = {
|
||||
id: Date.now() + 1,
|
||||
texto: data.resposta || data.reply || "Desculpe, não consegui processar sua pergunta no momento 😅",
|
||||
@ -198,6 +208,7 @@ const Header = () => {
|
||||
}
|
||||
};
|
||||
|
||||
// --- Subcomponentes ---
|
||||
const SuporteCard = () => (
|
||||
<div className="suporte-card">
|
||||
<h2 className="suporte-titulo">Suporte</h2>
|
||||
@ -257,6 +268,82 @@ const Header = () => {
|
||||
</div>
|
||||
);
|
||||
|
||||
// --- Modal de logout renderizado via Portal (garante top-most e clique) ---
|
||||
const LogoutModalPortal = ({ onCancel, onConfirm }) => {
|
||||
const modalContent = (
|
||||
<div
|
||||
className="logout-modal-overlay"
|
||||
// inline style reforçando z-index e pointer events caso algum CSS global esteja atrapalhando
|
||||
style={{
|
||||
position: 'fixed',
|
||||
top: 0, left: 0, right: 0, bottom: 0,
|
||||
backgroundColor: 'rgba(0,0,0,0.5)',
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
zIndex: 99999,
|
||||
padding: '1rem'
|
||||
}}
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
>
|
||||
<div
|
||||
className="logout-modal-content"
|
||||
style={{
|
||||
backgroundColor: 'white',
|
||||
padding: '1.6rem',
|
||||
borderRadius: '12px',
|
||||
boxShadow: '0 8px 24px rgba(0,0,0,0.2)',
|
||||
maxWidth: '480px',
|
||||
width: '100%',
|
||||
textAlign: 'center'
|
||||
}}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<h3 style={{ marginTop: 0 }}>Confirmar Logout</h3>
|
||||
<p>Tem certeza que deseja encerrar a sessão?</p>
|
||||
<div style={{ display: 'flex', gap: '1rem', justifyContent: 'center', marginTop: '1rem' }}>
|
||||
<button
|
||||
onClick={onCancel}
|
||||
style={{
|
||||
padding: '10px 18px',
|
||||
borderRadius: '8px',
|
||||
border: '1px solid #ccc',
|
||||
background: 'white',
|
||||
cursor: 'pointer'
|
||||
}}
|
||||
>
|
||||
Cancelar
|
||||
</button>
|
||||
<button
|
||||
onClick={onConfirm}
|
||||
style={{
|
||||
padding: '10px 18px',
|
||||
borderRadius: '8px',
|
||||
border: 'none',
|
||||
background: '#dc3545',
|
||||
color: 'white',
|
||||
cursor: 'pointer'
|
||||
}}
|
||||
>
|
||||
Sair
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
// garante que exista document antes de criar portal (SSRed apps podem não ter)
|
||||
if (typeof document === 'undefined') return null;
|
||||
return createPortal(modalContent, document.body);
|
||||
};
|
||||
|
||||
// --- Agora sim: condicional de render baseado na rota ---
|
||||
if (location.pathname === '/login') {
|
||||
return null;
|
||||
}
|
||||
|
||||
// --- JSX principal ---
|
||||
return (
|
||||
<div className="header-container">
|
||||
<div className="right-corner-elements">
|
||||
@ -282,22 +369,9 @@ const Header = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Modal de Logout */}
|
||||
{/* Modal de Logout via portal */}
|
||||
{showLogoutModal && (
|
||||
<div className="logout-modal-overlay">
|
||||
<div className="logout-modal-content">
|
||||
<h3>Confirmar Logout</h3>
|
||||
<p>Tem certeza que deseja encerrar a sessão?</p>
|
||||
<div className="logout-modal-buttons">
|
||||
<button onClick={handleLogoutCancel} className="logout-cancel-button">
|
||||
Cancelar
|
||||
</button>
|
||||
<button onClick={handleLogoutConfirm} className="logout-confirm-button">
|
||||
Sair
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<LogoutModalPortal onCancel={handleLogoutCancel} onConfirm={handleLogoutConfirm} />
|
||||
)}
|
||||
|
||||
{isSuporteCardOpen && (
|
||||
@ -319,4 +393,4 @@ const Header = () => {
|
||||
);
|
||||
};
|
||||
|
||||
export default Header;
|
||||
export default Header;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user