feat: implement user authentication checks in PresenceManager and perfil pages
- Added authentication verification in the PresenceManager component to manage user presence status based on authentication state. - Updated the perfil page to conditionally execute queries only if the user is authenticated, enhancing security and performance. - Introduced derived variables to track user authentication status, ensuring that presence management and data fetching are only performed for logged-in users.
This commit is contained in:
@@ -1,10 +1,15 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { useConvexClient } from "convex-svelte";
|
import { useConvexClient } from "convex-svelte";
|
||||||
|
import { useQuery } from "convex-svelte";
|
||||||
import { api } from "@sgse-app/backend/convex/_generated/api";
|
import { api } from "@sgse-app/backend/convex/_generated/api";
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
|
|
||||||
const client = useConvexClient();
|
const client = useConvexClient();
|
||||||
|
|
||||||
|
// Verificar se o usuário está autenticado antes de gerenciar presença
|
||||||
|
const currentUser = useQuery(api.auth.getCurrentUser, {});
|
||||||
|
const usuarioAutenticado = $derived(currentUser?.data !== null && currentUser?.data !== undefined);
|
||||||
|
|
||||||
// Token é passado automaticamente via interceptadores em +layout.svelte
|
// Token é passado automaticamente via interceptadores em +layout.svelte
|
||||||
|
|
||||||
let heartbeatInterval: ReturnType<typeof setInterval> | null = null;
|
let heartbeatInterval: ReturnType<typeof setInterval> | null = null;
|
||||||
@@ -13,6 +18,8 @@
|
|||||||
|
|
||||||
// Detectar atividade do usuário
|
// Detectar atividade do usuário
|
||||||
function handleActivity() {
|
function handleActivity() {
|
||||||
|
if (!usuarioAutenticado) return;
|
||||||
|
|
||||||
lastActivity = Date.now();
|
lastActivity = Date.now();
|
||||||
|
|
||||||
// Limpar timeout de inatividade anterior
|
// Limpar timeout de inatividade anterior
|
||||||
@@ -22,16 +29,29 @@
|
|||||||
|
|
||||||
// Configurar novo timeout (5 minutos)
|
// Configurar novo timeout (5 minutos)
|
||||||
inactivityTimeout = setTimeout(() => {
|
inactivityTimeout = setTimeout(() => {
|
||||||
client.mutation(api.chat.atualizarStatusPresenca, { status: "ausente" });
|
if (usuarioAutenticado) {
|
||||||
|
client.mutation(api.chat.atualizarStatusPresenca, { status: "ausente" });
|
||||||
|
}
|
||||||
}, 5 * 60 * 1000);
|
}, 5 * 60 * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
// Configurar como online ao montar
|
// Só configurar presença se usuário estiver autenticado
|
||||||
|
if (!usuarioAutenticado) return;
|
||||||
|
|
||||||
|
// Configurar como online ao montar (apenas se autenticado)
|
||||||
client.mutation(api.chat.atualizarStatusPresenca, { status: "online" });
|
client.mutation(api.chat.atualizarStatusPresenca, { status: "online" });
|
||||||
|
|
||||||
// Heartbeat a cada 30 segundos
|
// Heartbeat a cada 30 segundos (apenas se autenticado)
|
||||||
heartbeatInterval = setInterval(() => {
|
heartbeatInterval = setInterval(() => {
|
||||||
|
if (!usuarioAutenticado) {
|
||||||
|
if (heartbeatInterval) {
|
||||||
|
clearInterval(heartbeatInterval);
|
||||||
|
heartbeatInterval = null;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const timeSinceLastActivity = Date.now() - lastActivity;
|
const timeSinceLastActivity = Date.now() - lastActivity;
|
||||||
|
|
||||||
// Se houve atividade nos últimos 5 minutos, manter online
|
// Se houve atividade nos últimos 5 minutos, manter online
|
||||||
@@ -47,10 +67,14 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Configurar timeout inicial de inatividade
|
// Configurar timeout inicial de inatividade
|
||||||
handleActivity();
|
if (usuarioAutenticado) {
|
||||||
|
handleActivity();
|
||||||
|
}
|
||||||
|
|
||||||
// Detectar quando a aba fica inativa/ativa
|
// Detectar quando a aba fica inativa/ativa
|
||||||
function handleVisibilityChange() {
|
function handleVisibilityChange() {
|
||||||
|
if (!usuarioAutenticado) return;
|
||||||
|
|
||||||
if (document.hidden) {
|
if (document.hidden) {
|
||||||
// Aba ficou inativa
|
// Aba ficou inativa
|
||||||
client.mutation(api.chat.atualizarStatusPresenca, { status: "ausente" });
|
client.mutation(api.chat.atualizarStatusPresenca, { status: "ausente" });
|
||||||
@@ -65,8 +89,10 @@
|
|||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
return () => {
|
return () => {
|
||||||
// Marcar como offline ao desmontar
|
// Marcar como offline ao desmontar (apenas se autenticado)
|
||||||
client.mutation(api.chat.atualizarStatusPresenca, { status: "offline" });
|
if (usuarioAutenticado) {
|
||||||
|
client.mutation(api.chat.atualizarStatusPresenca, { status: "offline" });
|
||||||
|
}
|
||||||
|
|
||||||
if (heartbeatInterval) {
|
if (heartbeatInterval) {
|
||||||
clearInterval(heartbeatInterval);
|
clearInterval(heartbeatInterval);
|
||||||
@@ -86,4 +112,3 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- Componente invisível - apenas lógica -->
|
<!-- Componente invisível - apenas lógica -->
|
||||||
|
|
||||||
|
|||||||
@@ -125,11 +125,23 @@
|
|||||||
const funcionarioIdDisponivel = $derived(currentUser?.data?.funcionarioId ?? null);
|
const funcionarioIdDisponivel = $derived(currentUser?.data?.funcionarioId ?? null);
|
||||||
const gestorIdDisponivel = $derived(currentUser?.data?._id ?? null);
|
const gestorIdDisponivel = $derived(currentUser?.data?._id ?? null);
|
||||||
|
|
||||||
// ✅ CORRIGIDO: Queries no nível superior (sem argumentos) sempre criadas
|
// Verificar autenticação antes de executar queries
|
||||||
|
const usuarioAutenticado = $derived(currentUser?.data !== null && currentUser?.data !== undefined);
|
||||||
|
|
||||||
|
// ✅ CORRIGIDO: Queries condicionais - só executar se usuário estiver autenticado
|
||||||
// Queries que não requerem argumentos são criadas uma vez
|
// Queries que não requerem argumentos são criadas uma vez
|
||||||
const funcionarioQuery = useQuery(api.funcionarios.getCurrent, {});
|
const funcionarioQuery = useQuery(
|
||||||
const timesSubordinadosQuery = useQuery(api.times.listarSubordinadosDoGestorAtual, {});
|
api.funcionarios.getCurrent,
|
||||||
const chamadosQuery = useQuery(api.chamados.listarChamadosUsuario, {});
|
usuarioAutenticado ? {} : 'skip'
|
||||||
|
);
|
||||||
|
const timesSubordinadosQuery = useQuery(
|
||||||
|
api.times.listarSubordinadosDoGestorAtual,
|
||||||
|
usuarioAutenticado ? {} : 'skip'
|
||||||
|
);
|
||||||
|
const chamadosQuery = useQuery(
|
||||||
|
api.chamados.listarChamadosUsuario,
|
||||||
|
usuarioAutenticado ? {} : 'skip'
|
||||||
|
);
|
||||||
|
|
||||||
// ✅ CORRIGIDO: Queries com argumentos obrigatórios usando $derived.by para estabilidade
|
// ✅ CORRIGIDO: Queries com argumentos obrigatórios usando $derived.by para estabilidade
|
||||||
// Usamos uma chave estável baseada no ID para evitar recriação desnecessária
|
// Usamos uma chave estável baseada no ID para evitar recriação desnecessária
|
||||||
|
|||||||
Reference in New Issue
Block a user