pequenas mudanças no perfil e no suporte
This commit is contained in:
parent
6ccb0992c3
commit
5d1751b7f9
@ -488,3 +488,14 @@
|
|||||||
max-width: none;
|
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 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';
|
import './Header.css';
|
||||||
|
|
||||||
const Header = () => {
|
const Header = () => {
|
||||||
|
// --- Hooks (sempre chamados na mesma ordem) ---
|
||||||
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
|
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
|
||||||
const [isSuporteCardOpen, setIsSuporteCardOpen] = useState(false);
|
const [isSuporteCardOpen, setIsSuporteCardOpen] = useState(false);
|
||||||
const [isChatOpen, setIsChatOpen] = useState(false);
|
const [isChatOpen, setIsChatOpen] = useState(false);
|
||||||
@ -11,9 +14,11 @@ const Header = () => {
|
|||||||
const [showLogoutModal, setShowLogoutModal] = useState(false);
|
const [showLogoutModal, setShowLogoutModal] = useState(false);
|
||||||
const [avatarUrl, setAvatarUrl] = useState(null);
|
const [avatarUrl, setAvatarUrl] = useState(null);
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const location = useLocation();
|
||||||
const chatInputRef = useRef(null);
|
const chatInputRef = useRef(null);
|
||||||
const mensagensContainerRef = useRef(null);
|
const mensagensContainerRef = useRef(null);
|
||||||
|
|
||||||
|
// --- Efeitos ---
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const loadAvatar = () => {
|
const loadAvatar = () => {
|
||||||
const localAvatar = localStorage.getItem('user_avatar');
|
const localAvatar = localStorage.getItem('user_avatar');
|
||||||
@ -44,7 +49,18 @@ const Header = () => {
|
|||||||
}
|
}
|
||||||
}, [mensagens]);
|
}, [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 = () => {
|
const handleLogoutClick = () => {
|
||||||
setShowLogoutModal(true);
|
setShowLogoutModal(true);
|
||||||
setIsDropdownOpen(false);
|
setIsDropdownOpen(false);
|
||||||
@ -65,26 +81,21 @@ const Header = () => {
|
|||||||
sessionStorage.getItem("authToken");
|
sessionStorage.getItem("authToken");
|
||||||
|
|
||||||
if (token) {
|
if (token) {
|
||||||
const response = await fetch(
|
// tentativa de logout no backend (se houver)
|
||||||
"https://mock.apidog.com/m1/1053378-0-default/auth/v1/logout",
|
try {
|
||||||
{
|
await fetch(
|
||||||
method: "POST",
|
"https://mock.apidog.com/m1/1053378-0-default/auth/v1/logout",
|
||||||
headers: {
|
{
|
||||||
"Content-Type": "application/json",
|
method: "POST",
|
||||||
Authorization: `Bearer ${token}`,
|
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");
|
} catch (err) {
|
||||||
else {
|
// não interrompe o fluxo se a API falhar — prosseguimos para limpar local
|
||||||
try {
|
console.warn('Erro ao chamar endpoint de logout (ignorado):', err);
|
||||||
const errorData = await response.json();
|
|
||||||
console.error("Erro no logout:", errorData);
|
|
||||||
} catch {
|
|
||||||
console.error("Erro no logout - status:", response.status);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,12 +116,13 @@ const Header = () => {
|
|||||||
sessionStorage.removeItem(key);
|
sessionStorage.removeItem(key);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// tenta limpar caches relacionados se existirem
|
||||||
if (window.caches) {
|
if (window.caches) {
|
||||||
caches.keys().then(names => {
|
caches.keys().then(names => {
|
||||||
names.forEach(name => {
|
names.forEach(name => {
|
||||||
if (name.includes("auth") || name.includes("api")) caches.delete(name);
|
if (name.includes("auth") || name.includes("api")) caches.delete(name);
|
||||||
});
|
});
|
||||||
});
|
}).catch(()=>{ /* ignore */ });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -157,7 +169,6 @@ const Header = () => {
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (mensagem.trim() === '') return;
|
if (mensagem.trim() === '') return;
|
||||||
|
|
||||||
// Mensagem do usuário
|
|
||||||
const novaMensagemUsuario = {
|
const novaMensagemUsuario = {
|
||||||
id: Date.now(),
|
id: Date.now(),
|
||||||
texto: mensagem,
|
texto: mensagem,
|
||||||
@ -177,7 +188,6 @@ const Header = () => {
|
|||||||
|
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
|
|
||||||
// Resposta da IA
|
|
||||||
const respostaSuporte = {
|
const respostaSuporte = {
|
||||||
id: Date.now() + 1,
|
id: Date.now() + 1,
|
||||||
texto: data.resposta || data.reply || "Desculpe, não consegui processar sua pergunta no momento 😅",
|
texto: data.resposta || data.reply || "Desculpe, não consegui processar sua pergunta no momento 😅",
|
||||||
@ -198,6 +208,7 @@ const Header = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// --- Subcomponentes ---
|
||||||
const SuporteCard = () => (
|
const SuporteCard = () => (
|
||||||
<div className="suporte-card">
|
<div className="suporte-card">
|
||||||
<h2 className="suporte-titulo">Suporte</h2>
|
<h2 className="suporte-titulo">Suporte</h2>
|
||||||
@ -257,6 +268,82 @@ const Header = () => {
|
|||||||
</div>
|
</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 (
|
return (
|
||||||
<div className="header-container">
|
<div className="header-container">
|
||||||
<div className="right-corner-elements">
|
<div className="right-corner-elements">
|
||||||
@ -282,22 +369,9 @@ const Header = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Modal de Logout */}
|
{/* Modal de Logout via portal */}
|
||||||
{showLogoutModal && (
|
{showLogoutModal && (
|
||||||
<div className="logout-modal-overlay">
|
<LogoutModalPortal onCancel={handleLogoutCancel} onConfirm={handleLogoutConfirm} />
|
||||||
<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>
|
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{isSuporteCardOpen && (
|
{isSuporteCardOpen && (
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user