335 lines
13 KiB
TypeScript
335 lines
13 KiB
TypeScript
"use client";
|
|
import { useState, useEffect, useRef } from "react";
|
|
import Link from "next/link";
|
|
import Image from "next/image";
|
|
import { useRouter } from "next/navigation";
|
|
// import { Models } from "appwrite"; // Removido - não usamos mais Appwrite
|
|
import Navbar from "./Navbar";
|
|
// import RegistroIncompletoModal from "./RegistroIncompletoModal"; // Removido - agora é controlado pelo dashboard
|
|
import CarrinhoCompras from "./CarrinhoCompras";
|
|
import LojaVirtualMenu from "./LojaVirtualMenu";
|
|
import { useRegistroCompleto } from "@/hooks/useRegistroCompleto";
|
|
import {
|
|
ShoppingCartIcon,
|
|
XMarkIcon,
|
|
PlusIcon,
|
|
MinusIcon,
|
|
UserIcon,
|
|
ArrowRightOnRectangleIcon,
|
|
BuildingOffice2Icon,
|
|
BellIcon,
|
|
} from "@heroicons/react/24/outline";
|
|
|
|
interface HeaderProps {
|
|
user?: any | null; // Tipo genérico ao invés de Models.User
|
|
title?: string;
|
|
subtitle?: string;
|
|
showBackButton?: boolean;
|
|
}
|
|
|
|
const Header = ({
|
|
user,
|
|
title = "SaveInMed",
|
|
subtitle = "Plataforma B2B de Medicamentos",
|
|
showBackButton = false,
|
|
}: HeaderProps) => {
|
|
const router = useRouter();
|
|
const [isOpen, setIsOpen] = useState(false);
|
|
// const [showRegistroModal, setShowRegistroModal] = useState(false); // Removido - agora é controlado pelo dashboard
|
|
const dropdownRef = useRef<HTMLDivElement>(null);
|
|
const displayUserName =
|
|
user?.nome ||
|
|
user?.["nome-civil"] ||
|
|
user?.["nome-social"] ||
|
|
user?.name ||
|
|
"Usuário";
|
|
const displayCompanyName =
|
|
user?.empresa?.["nome-fantasia"] ||
|
|
user?.empresa?.["razao-social"] ||
|
|
user?.empresa?.nomeFantasia ||
|
|
user?.empresa?.razaoSocial ||
|
|
user?.empresaData?.["nome-fantasia"] ||
|
|
user?.empresaData?.["razao-social"] ||
|
|
user?.empresaData?.nomeFantasia ||
|
|
user?.empresaData?.razaoSocial ||
|
|
(Array.isArray(user?.empresas) ? user.empresas[0] : null) ||
|
|
(Array.isArray(user?.empresasDados) ? user.empresasDados[0] : null) ||
|
|
"Empresa não informada";
|
|
|
|
// Hook para verificar se o registro está completo
|
|
const { isCompleto, loading, dadosFaltantes } = useRegistroCompleto(user || null);
|
|
|
|
useEffect(() => {
|
|
const handleClickOutside = (event: MouseEvent) => {
|
|
if (
|
|
dropdownRef.current &&
|
|
!dropdownRef.current.contains(event.target as Node)
|
|
) {
|
|
setIsOpen(false);
|
|
}
|
|
};
|
|
document.addEventListener("mousedown", handleClickOutside);
|
|
return () => {
|
|
document.removeEventListener("mousedown", handleClickOutside);
|
|
};
|
|
}, []);
|
|
|
|
// // Verificar se deve mostrar o modal de registro incompleto - REMOVIDO
|
|
// // Agora essa funcionalidade é controlada pelo dashboard
|
|
// useEffect(() => {
|
|
// // Funcionalidade movida para o dashboard
|
|
// }, [loading, isCompleto, user]);
|
|
|
|
const handleLogout = async () => {
|
|
try {
|
|
|
|
// 1. Fazer logout no BFF
|
|
const token = localStorage.getItem('access_token');
|
|
if (token) {
|
|
const response = await fetch(`${process.env.NEXT_PUBLIC_BFF_API_URL}/auth/logout`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'accept': '*/*',
|
|
'Authorization': `Bearer ${token}`,
|
|
},
|
|
});
|
|
|
|
|
|
}
|
|
|
|
// 2. Limpar todos os dados locais
|
|
localStorage.removeItem("access_token");
|
|
localStorage.removeItem("user");
|
|
localStorage.removeItem("registro-incompleto-dismissed");
|
|
localStorage.removeItem("completar-registro-usuario-id");
|
|
|
|
|
|
// 3. Redirecionar para a página de login
|
|
router.push("/login");
|
|
|
|
} catch (error) {
|
|
console.error("❌ Erro no logout:", error);
|
|
// Mesmo com erro, limpar dados locais e redirecionar
|
|
localStorage.clear();
|
|
router.push("/login");
|
|
}
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<header className="bg-white shadow-sm border-b">
|
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
<div className="flex justify-between items-center h-16">
|
|
{/* Logo e navegação */}
|
|
<div className="flex items-center min-w-0 -ml-4 sm:-ml-6 lg:-ml-8">
|
|
{showBackButton && (
|
|
<button
|
|
onClick={() => router.push("/dashboard")}
|
|
className="text-gray-600 hover:text-gray-900 transition-colors cursor-pointer flex-shrink-0 mr-1"
|
|
>
|
|
<svg
|
|
className="w-6 h-6"
|
|
fill="none"
|
|
stroke="currentColor"
|
|
viewBox="0 0 24 24"
|
|
>
|
|
<path
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
strokeWidth={2}
|
|
d="M15 19l-7-7 7-7"
|
|
/>
|
|
</svg>
|
|
</button>
|
|
)}
|
|
<Link
|
|
href="/dashboard"
|
|
className="w-16 h-16 sm:w-20 sm:h-20 lg:w-24 lg:h-24 flex items-center justify-center flex-shrink-0"
|
|
>
|
|
<Image
|
|
src="/logo.png"
|
|
alt="SaveInMed Logo"
|
|
width={96}
|
|
height={96}
|
|
className="w-16 h-16 sm:w-20 sm:h-20 lg:w-24 lg:h-24 object-contain"
|
|
/>
|
|
</Link>
|
|
<div className="min-w-0 flex-shrink -ml-1">
|
|
<h1 className="text-lg sm:text-xl lg:text-2xl font-bold text-gray-900 truncate">
|
|
{title}
|
|
</h1>
|
|
<p className="text-xs text-gray-500 hidden sm:block truncate">
|
|
{subtitle}
|
|
</p>
|
|
</div>
|
|
<div className="ml-2 sm:ml-4 flex items-center">
|
|
<CarrinhoCompras />
|
|
</div>
|
|
</div>
|
|
|
|
{/* Informações do usuário */}
|
|
<div className="flex items-center space-x-2 sm:space-x-4 flex-shrink-0">
|
|
{/* Menu Loja Virtual */}
|
|
<LojaVirtualMenu />
|
|
|
|
<button
|
|
type="button"
|
|
className="relative rounded-full p-2 text-gray-500 hover:text-gray-700 hover:bg-gray-50 transition-colors"
|
|
aria-label="Notificações"
|
|
>
|
|
<BellIcon className="w-5 h-5 sm:w-6 sm:h-6" />
|
|
</button>
|
|
|
|
{/* Indicador de cadastro incompleto */}
|
|
{!loading && !isCompleto && (
|
|
<div className="flex items-center space-x-1 sm:space-x-2">
|
|
<div className="w-2 h-2 bg-red-500 rounded-full animate-pulse flex-shrink-0"></div>
|
|
<span className="text-xs text-red-600 font-medium hidden md:block whitespace-nowrap">
|
|
Cadastro incompleto
|
|
</span>
|
|
</div>
|
|
)}
|
|
|
|
<div
|
|
className="relative"
|
|
ref={dropdownRef}
|
|
onMouseEnter={() => setIsOpen(true)}
|
|
onMouseLeave={() => setIsOpen(false)}
|
|
>
|
|
<button
|
|
onClick={() => setIsOpen(!isOpen)}
|
|
className="flex items-center space-x-1 sm:space-x-3 hover:bg-gray-50 rounded-lg p-1 sm:p-2 transition-colors cursor-pointer"
|
|
>
|
|
<div className="w-6 h-6 sm:w-8 sm:h-8 bg-gradient-to-r from-blue-500 to-green-500 rounded-full flex items-center justify-center flex-shrink-0">
|
|
<span className="text-white text-xs sm:text-sm font-semibold">
|
|
{displayUserName?.charAt(0).toUpperCase()}
|
|
</span>
|
|
</div>
|
|
<div className="hidden sm:block min-w-0">
|
|
<p className="text-sm font-medium text-gray-900 truncate">
|
|
{displayUserName}
|
|
</p>
|
|
<p className="text-xs text-gray-500 truncate">
|
|
{displayCompanyName}
|
|
</p>
|
|
</div>
|
|
<svg
|
|
className="w-3 h-3 sm:w-4 sm:h-4 text-gray-400 flex-shrink-0"
|
|
fill="none"
|
|
stroke="currentColor"
|
|
viewBox="0 0 24 24"
|
|
>
|
|
<path
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
strokeWidth={2}
|
|
d="M19 9l-7 7-7-7"
|
|
/>
|
|
</svg>
|
|
</button>
|
|
{isOpen && (
|
|
<ul className="absolute right-0 mt-2 w-48 bg-white rounded-lg shadow-lg z-10 border">
|
|
<li>
|
|
<div className="px-4 py-3 border-b rounded-t-lg">
|
|
<div className="text-[10px] uppercase tracking-wide text-gray-400">
|
|
Empresa
|
|
</div>
|
|
<p className="text-sm font-semibold text-gray-900 truncate">
|
|
{displayCompanyName}
|
|
</p>
|
|
<div className="mt-2 text-[10px] uppercase tracking-wide text-gray-400">
|
|
Perfil do usuário
|
|
</div>
|
|
<p className="text-sm font-semibold text-gray-900 truncate">
|
|
{displayUserName}
|
|
</p>
|
|
</div>
|
|
</li>
|
|
<li>
|
|
<Link
|
|
href="/meu-perfil#usuario"
|
|
className="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 flex items-center"
|
|
>
|
|
<UserIcon className="w-4 h-4 mr-2 flex-shrink-0" />
|
|
Perfil do usuário
|
|
</Link>
|
|
</li>
|
|
<li>
|
|
<Link
|
|
href="/meu-perfil#empresa"
|
|
className="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 flex items-center"
|
|
>
|
|
<BuildingOffice2Icon className="w-4 h-4 mr-2 flex-shrink-0" />
|
|
Perfil da empresa
|
|
</Link>
|
|
</li>
|
|
<li>
|
|
<Link
|
|
href="/pedidos"
|
|
className="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 flex items-center"
|
|
>
|
|
<svg
|
|
className="w-4 h-4 mr-2 flex-shrink-0"
|
|
fill="none"
|
|
stroke="currentColor"
|
|
viewBox="0 0 24 24"
|
|
>
|
|
<path
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
strokeWidth={2}
|
|
d="M16 11V7a4 4 0 00-8 0v4M5 9h14l1 12H4L5 9z"
|
|
/>
|
|
</svg>
|
|
Meus Pedidos
|
|
</Link>
|
|
</li>
|
|
<li>
|
|
<Link
|
|
href="/mensagens"
|
|
className="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 flex items-center"
|
|
>
|
|
<svg
|
|
className="w-4 h-4 mr-2 flex-shrink-0"
|
|
fill="none"
|
|
stroke="currentColor"
|
|
viewBox="0 0 24 24"
|
|
>
|
|
<path
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
strokeWidth={2}
|
|
d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"
|
|
/>
|
|
</svg>
|
|
Mensagens
|
|
</Link>
|
|
</li>
|
|
<li>
|
|
<button
|
|
onClick={handleLogout}
|
|
className="w-full text-left px-4 py-2 text-sm text-red-600 hover:bg-red-50 rounded-b-lg flex items-center"
|
|
>
|
|
<ArrowRightOnRectangleIcon className="w-4 h-4 mr-2 flex-shrink-0" />
|
|
Sair
|
|
</button>
|
|
</li>
|
|
</ul>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Navbar Mobile - Aparece abaixo do header em telas pequenas */}
|
|
<div className="lg:hidden border-t border-gray-100 py-2">
|
|
<Navbar />
|
|
</div>
|
|
</div>
|
|
</header>
|
|
|
|
{/* Modal de Registro Incompleto Removido - Agora controlado pelo dashboard */}
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default Header;
|