feat: Add 'atas' (minutes/records) management feature, and implement various improvements across UI, backend logic, and authentication.

This commit is contained in:
2025-12-02 16:37:48 -03:00
parent 05e7f1181d
commit 4bd9e21748
265 changed files with 29156 additions and 26460 deletions

View File

@@ -1,21 +1,20 @@
<script lang="ts">
import { page } from '$app/state';
import { goto } from '$app/navigation';
import logo from '$lib/assets/logo_governo_PE.png';
import type { Snippet } from 'svelte';
import { loginModalStore } from '$lib/stores/loginModal.svelte';
import { useQuery, useConvexClient } from 'convex-svelte';
import { api } from '@sgse-app/backend/convex/_generated/api';
import NotificationBell from '$lib/components/chat/NotificationBell.svelte';
import ChatWidget from '$lib/components/chat/ChatWidget.svelte';
import PresenceManager from '$lib/components/chat/PresenceManager.svelte';
import { Menu, User, Home, UserPlus, XCircle, LogIn, Tag, Plus, Check } from 'lucide-svelte';
import { authClient } from '$lib/auth';
import { useConvexClient, useQuery } from 'convex-svelte';
import { Check, Home, LogIn, Menu, Plus, Tag, User, UserPlus, XCircle } from 'lucide-svelte';
import type { Snippet } from 'svelte';
import { goto } from '$app/navigation';
import { resolve } from '$app/paths';
import { page } from '$app/state';
import logo from '$lib/assets/logo_governo_PE.png';
import { authClient } from '$lib/auth';
import ChatWidget from '$lib/components/chat/ChatWidget.svelte';
import NotificationBell from '$lib/components/chat/NotificationBell.svelte';
import PresenceManager from '$lib/components/chat/PresenceManager.svelte';
import { loginModalStore } from '$lib/stores/loginModal.svelte';
import { obterIPPublico } from '$lib/utils/deviceInfo';
let { children }: { children: Snippet } = $props();
const { children }: { children: Snippet } = $props();
const currentPath = $derived(page.url.pathname);
@@ -126,11 +125,11 @@
// Obter IP público e userAgent (rápido, não bloqueia)
const userAgent = typeof navigator !== 'undefined' ? navigator.userAgent : undefined;
// Obter IP público com timeout curto (não bloquear login)
const ipPublicoPromise = obterIPPublico().catch(() => undefined);
const ipPublicoTimeout = new Promise<undefined>((resolve) =>
setTimeout(() => resolve(undefined), 2000) // Timeout de 2 segundos
const ipPublicoTimeout = new Promise<undefined>(
(resolve) => setTimeout(() => resolve(undefined), 2000) // Timeout de 2 segundos
);
const ipPublico = await Promise.race([ipPublicoPromise, ipPublicoTimeout]);
@@ -140,9 +139,7 @@
const { obterLocalizacaoRapida } = await import('$lib/utils/deviceInfo');
// Usar versão rápida com timeout curto (3 segundos máximo)
const gpsPromise = obterLocalizacaoRapida();
const gpsTimeout = new Promise<{}>((resolve) =>
setTimeout(() => resolve({}), 3000)
);
const gpsTimeout = new Promise<{}>((resolve) => setTimeout(() => resolve({}), 3000));
return await Promise.race([gpsPromise, gpsTimeout]);
} catch (err) {
console.warn('Erro ao obter GPS (não bloqueia login):', err);
@@ -182,7 +179,7 @@
enderecoGPS: localizacaoGPS.endereco,
cidadeGPS: localizacaoGPS.cidade,
estadoGPS: localizacaoGPS.estado,
paisGPS: localizacaoGPS.pais,
paisGPS: localizacaoGPS.pais
});
} catch (err) {
console.error('Erro ao registrar tentativa de login falha:', err);
@@ -199,7 +196,7 @@
try {
// Aguardar um pouco para o usuário ser sincronizado no Convex
await new Promise((resolve) => setTimeout(resolve, 500));
// Tentar obter GPS se já estiver disponível (não esperar)
let localizacaoGPS: any = {};
try {
@@ -210,10 +207,10 @@
} catch {
// Ignorar se GPS não estiver pronto
}
// Buscar o usuário no Convex usando getCurrentUser
const usuario = await convexClient.query(api.auth.getCurrentUser, {});
if (usuario && usuario._id) {
await convexClient.mutation(api.logsLogin.registrarTentativaLogin, {
usuarioId: usuario._id,
@@ -227,7 +224,7 @@
enderecoGPS: localizacaoGPS.endereco,
cidadeGPS: localizacaoGPS.cidade,
estadoGPS: localizacaoGPS.estado,
paisGPS: localizacaoGPS.pais,
paisGPS: localizacaoGPS.pais
});
} else {
// Se não encontrou o usuário, registrar sem usuarioId (será atualizado depois)
@@ -242,7 +239,7 @@
enderecoGPS: localizacaoGPS.endereco,
cidadeGPS: localizacaoGPS.cidade,
estadoGPS: localizacaoGPS.estado,
paisGPS: localizacaoGPS.pais,
paisGPS: localizacaoGPS.pais
});
}
} catch (err) {
@@ -250,7 +247,7 @@
// Não bloquear o login se houver erro ao registrar
}
})();
closeLoginModal();
goto(resolve('/'));
} else {
@@ -278,7 +275,7 @@
<div class="flex-none lg:hidden">
<label
for="my-drawer-3"
class="group relative flex h-14 w-14 cursor-pointer items-center justify-center overflow-hidden rounded-2xl bg-primary shadow-xl transition-all duration-300 hover:scale-105 hover:shadow-2xl"
class="group bg-primary relative flex h-14 w-14 cursor-pointer items-center justify-center overflow-hidden rounded-2xl shadow-xl transition-all duration-300 hover:scale-105 hover:shadow-2xl"
aria-label="Abrir menu"
>
<!-- Efeito de brilho no hover -->
@@ -298,7 +295,7 @@
<!-- Logo MODERNO do Governo -->
<div class="avatar">
<div
class="group relative w-16 overflow-hidden rounded-2xl p-2 bg-base-100 border-2 border-primary/20 shadow-xl transition-all duration-300 hover:scale-105 lg:w-20"
class="group bg-base-100 border-primary/20 relative w-16 overflow-hidden rounded-2xl border-2 p-2 shadow-xl transition-all duration-300 hover:scale-105 lg:w-20"
>
<!-- Efeito de brilho no hover -->
<div
@@ -341,13 +338,13 @@
<button
type="button"
tabindex="0"
class="group relative flex h-14 w-14 items-center justify-center overflow-hidden rounded-2xl bg-primary shadow-xl transition-all duration-300 hover:scale-105 hover:shadow-2xl"
class="group bg-primary relative flex h-14 w-14 items-center justify-center overflow-hidden rounded-2xl shadow-xl transition-all duration-300 hover:scale-105 hover:shadow-2xl"
aria-label="Menu do usuário"
>
<!-- Efeito de brilho no hover -->
<div
class="absolute inset-0 bg-linear-to-br from-white/0 to-white/20 opacity-0 transition-opacity duration-300 group-hover:opacity-100"
> </div>
></div>
<!-- Avatar/Foto do usuário ou ícone padrão -->
{#if avatarUrlDoUsuario()}
@@ -371,10 +368,10 @@
></div>
<!-- Badge de status online -->
<div
class="bg-success absolute top-1 right-1 z-20 h-3 w-3 rounded-full border-2 border-white shadow-lg"
style="animation: pulse-dot 2s ease-in-out infinite;"
></div>
<div
class="bg-success absolute top-1 right-1 z-20 h-3 w-3 rounded-full border-2 border-white shadow-lg"
style="animation: pulse-dot 2s ease-in-out infinite;"
></div>
</button>
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
<ul