refactor: enhance ProtectedRoute and dashboard components for improved access control and user experience

- Updated the ProtectedRoute component to optimize access checking logic, preventing unnecessary re-checks and improving authentication flow.
- Enhanced the dashboard page to automatically open the login modal for authentication errors and refined loading states for better user feedback.
- Improved UI elements across various components for consistency and visual appeal, including updated tab styles and enhanced alert messages.
- Removed redundant footer from the vacation management page to streamline the interface.
This commit is contained in:
2025-11-18 06:34:55 -03:00
parent 3420872a37
commit 422dc6f022
5 changed files with 398 additions and 541 deletions

View File

@@ -21,11 +21,26 @@
let isChecking = $state(true);
let hasAccess = $state(false);
let timeoutId: ReturnType<typeof setTimeout> | null = null;
let hasCheckedOnce = $state(false);
let lastUserState = $state<typeof currentUser | undefined>(undefined);
const currentUser = useQuery(api.auth.getCurrentUser, {});
// Usar $effect para reagir às mudanças na query
// Usar $effect para reagir apenas às mudanças na query currentUser
$effect(() => {
checkAccess();
// Não verificar novamente se já tem acesso concedido e usuário está autenticado
if (hasAccess && currentUser?.data) {
lastUserState = currentUser;
return;
}
// Evitar loop: só verificar se currentUser realmente mudou
// Comparar dados, não o objeto proxy
const currentData = currentUser?.data;
const lastData = lastUserState?.data;
if (currentData !== lastData || (currentUser === undefined) !== (lastUserState === undefined)) {
lastUserState = currentUser;
checkAccess();
}
});
function checkAccess() {
@@ -42,6 +57,9 @@
return;
}
// Marcar que já verificou pelo menos uma vez
hasCheckedOnce = true;
// Se a query retornou dados, verificar autenticação
if (currentUser?.data) {
// Verificar roles
@@ -67,20 +85,29 @@
return;
}
// Se não tem dados e requer autenticação, aguardar um pouco antes de redirecionar
// (pode estar carregando ainda)
// Se não tem dados e requer autenticação
if (requireAuth && !currentUser?.data) {
// Se a query já retornou (não está mais undefined), finalizar estado
if (currentUser !== undefined) {
const currentPath = window.location.pathname;
// Evitar redirecionamento em loop - verificar se já está na URL de erro
const urlParams = new URLSearchParams(window.location.search);
if (!urlParams.has('error')) {
// Só redirecionar se não estiver em loop
if (!hasCheckedOnce || currentUser === null) {
window.location.href = `${redirectTo}?error=auth_required&redirect=${encodeURIComponent(currentPath)}`;
return;
}
}
// Se já tem erro na URL, permitir renderização para mostrar o alerta
isChecking = false;
hasAccess = true;
return;
}
// Se ainda está carregando (undefined), aguardar
isChecking = true;
hasAccess = false;
// Aguardar 3 segundos antes de redirecionar (dar tempo para a query carregar)
timeoutId = setTimeout(() => {
// Verificar novamente antes de redirecionar
if (!currentUser?.data) {
const currentPath = window.location.pathname;
window.location.href = `${redirectTo}?error=auth_required&redirect=${encodeURIComponent(currentPath)}`;
}
}, 3000);
return;
}

View File

@@ -9,12 +9,13 @@
import { UserPlus, Mail } from "lucide-svelte";
import { useAuth } from "@mmailaender/convex-better-auth-svelte/svelte";
import ProtectedRoute from "$lib/components/ProtectedRoute.svelte";
import { loginModalStore } from "$lib/stores/loginModal.svelte";
let { data } = $props();
const auth = useAuth();
const isLoading = $derived(auth.isLoading && !data.currentUser);
const isAuthenticated = $derived(auth.isAuthenticated || !!data.currentUser);
const isLoading = $derived(auth.isLoading && !data?.currentUser);
const isAuthenticated = $derived(auth.isAuthenticated || !!data?.currentUser);
$inspect({ isLoading, isAuthenticated });
@@ -56,6 +57,11 @@
redirectRoute = route;
showAlert = true;
// Se for erro de autenticação, abrir modal de login automaticamente
if (error === "auth_required") {
loginModalStore.open(route || to.url.pathname);
}
// Limpar URL usando SvelteKit (após router estar inicializado)
try {
replaceState(to.url.pathname, {});
@@ -75,6 +81,17 @@
onMount(() => {
mounted = true;
// Verificar se há erro na URL ao carregar a página
const urlParams = new URLSearchParams(window.location.search);
if (urlParams.has("error")) {
const error = urlParams.get("error");
const route = urlParams.get("route") || urlParams.get("redirect") || "";
if (error === "auth_required") {
loginModalStore.open(route || window.location.pathname);
}
}
// Atualizar relógio e forçar refresh das queries a cada segundo
const interval = setInterval(() => {
currentTime = new Date();

File diff suppressed because it is too large Load Diff

View File

@@ -1993,12 +1993,6 @@
{/if}
{/await}
{/if}
<footer
class="border-base-300/60 bg-base-100 text-base-content/70 mt-8 border-t py-6 text-center text-sm"
>
SGSE - Sistema de Gerenciamento de Secretaria.
</footer>
<style>
/* Calendário de Férias */