- Validação cross-tenant no login e rotas protegidas
- File serving via /api/files/{bucket}/{path} (eliminação DNS)
- Mensagens de erro humanizadas inline (sem pop-ups)
- Middleware tenant detection via headers customizados
- Upload de logos retorna URLs via API
- README atualizado com changelog v1.4 completo
55 lines
1.7 KiB
TypeScript
55 lines
1.7 KiB
TypeScript
'use client';
|
|
|
|
import { useEffect, useState } from 'react';
|
|
import { getUser } from '@/lib/auth';
|
|
|
|
export function FaviconUpdater() {
|
|
const [mounted, setMounted] = useState(false);
|
|
|
|
useEffect(() => {
|
|
setMounted(true);
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
if (!mounted) return;
|
|
|
|
const updateFavicon = () => {
|
|
const user = getUser();
|
|
if (user?.logoUrl) {
|
|
// Usar requestAnimationFrame para garantir que o DOM esteja estável após hidratação
|
|
requestAnimationFrame(() => {
|
|
const link: HTMLLinkElement = document.querySelector("link[rel*='icon']") || document.createElement('link');
|
|
link.type = 'image/x-icon';
|
|
link.rel = 'shortcut icon';
|
|
link.href = user.logoUrl!;
|
|
if (!link.parentNode) {
|
|
document.getElementsByTagName('head')[0].appendChild(link);
|
|
}
|
|
});
|
|
}
|
|
};
|
|
|
|
// Atraso pequeno para garantir que a hidratação terminou
|
|
const timer = setTimeout(() => {
|
|
updateFavicon();
|
|
}, 0);
|
|
|
|
// Ouve mudanças no localStorage
|
|
const handleStorage = () => {
|
|
requestAnimationFrame(() => updateFavicon());
|
|
};
|
|
window.addEventListener('storage', handleStorage);
|
|
|
|
// Custom event para atualização interna na mesma aba
|
|
window.addEventListener('auth-update', handleStorage);
|
|
|
|
return () => {
|
|
clearTimeout(timer);
|
|
window.removeEventListener('storage', handleStorage);
|
|
window.removeEventListener('auth-update', handleStorage);
|
|
};
|
|
}, [mounted]);
|
|
|
|
return null;
|
|
}
|