feat: Add 'atas' (minutes/records) management feature, and implement various improvements across UI, backend logic, and authentication.
This commit is contained in:
@@ -1,157 +1,136 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
import { useConvexClient } from "convex-svelte";
|
||||
import { api } from "@sgse-app/backend/convex/_generated/api";
|
||||
import { useQuery } from "convex-svelte";
|
||||
import {
|
||||
registrarServiceWorker,
|
||||
solicitarPushSubscription,
|
||||
subscriptionToJSON,
|
||||
removerPushSubscription,
|
||||
} from "$lib/utils/notifications";
|
||||
import { api } from '@sgse-app/backend/convex/_generated/api';
|
||||
import { useConvexClient, useQuery } from 'convex-svelte';
|
||||
import { onMount } from 'svelte';
|
||||
import {
|
||||
registrarServiceWorker,
|
||||
removerPushSubscription,
|
||||
solicitarPushSubscription,
|
||||
subscriptionToJSON
|
||||
} from '$lib/utils/notifications';
|
||||
|
||||
const client = useConvexClient();
|
||||
const currentUser = useQuery(api.auth.getCurrentUser, {});
|
||||
const client = useConvexClient();
|
||||
const currentUser = useQuery(api.auth.getCurrentUser, {});
|
||||
|
||||
// Capturar erros de Promise não tratados relacionados a message channel
|
||||
// Este erro geralmente vem de extensões do Chrome ou comunicação com Service Worker
|
||||
if (typeof window !== "undefined") {
|
||||
window.addEventListener(
|
||||
"unhandledrejection",
|
||||
(event: PromiseRejectionEvent) => {
|
||||
const reason = event.reason;
|
||||
const errorMessage = reason?.message || reason?.toString() || "";
|
||||
// Capturar erros de Promise não tratados relacionados a message channel
|
||||
// Este erro geralmente vem de extensões do Chrome ou comunicação com Service Worker
|
||||
if (typeof window !== 'undefined') {
|
||||
window.addEventListener(
|
||||
'unhandledrejection',
|
||||
(event: PromiseRejectionEvent) => {
|
||||
const reason = event.reason;
|
||||
const errorMessage = reason?.message || reason?.toString() || '';
|
||||
|
||||
// Filtrar apenas erros relacionados a message channel fechado
|
||||
if (
|
||||
errorMessage.includes("message channel closed") ||
|
||||
errorMessage.includes("asynchronous response") ||
|
||||
(errorMessage.includes("message channel") &&
|
||||
errorMessage.includes("closed"))
|
||||
) {
|
||||
// Prevenir que o erro apareça no console
|
||||
event.preventDefault();
|
||||
// Silenciar o erro - é geralmente causado por extensões do Chrome
|
||||
return false;
|
||||
}
|
||||
},
|
||||
{ capture: true },
|
||||
);
|
||||
}
|
||||
// Filtrar apenas erros relacionados a message channel fechado
|
||||
if (
|
||||
errorMessage.includes('message channel closed') ||
|
||||
errorMessage.includes('asynchronous response') ||
|
||||
(errorMessage.includes('message channel') && errorMessage.includes('closed'))
|
||||
) {
|
||||
// Prevenir que o erro apareça no console
|
||||
event.preventDefault();
|
||||
// Silenciar o erro - é geralmente causado por extensões do Chrome
|
||||
return false;
|
||||
}
|
||||
},
|
||||
{ capture: true }
|
||||
);
|
||||
}
|
||||
|
||||
onMount(async () => {
|
||||
let checkAuth: ReturnType<typeof setInterval> | null = null;
|
||||
let mounted = true;
|
||||
onMount(async () => {
|
||||
let checkAuth: ReturnType<typeof setInterval> | null = null;
|
||||
let mounted = true;
|
||||
|
||||
// Aguardar usuário estar autenticado
|
||||
checkAuth = setInterval(async () => {
|
||||
if (currentUser?.data && mounted) {
|
||||
clearInterval(checkAuth!);
|
||||
checkAuth = null;
|
||||
try {
|
||||
await registrarPushSubscription();
|
||||
} catch (error) {
|
||||
// Silenciar erros de push subscription para evitar spam no console
|
||||
if (
|
||||
error instanceof Error &&
|
||||
!error.message.includes("message channel")
|
||||
) {
|
||||
console.error("Erro ao configurar push notifications:", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 500);
|
||||
// Aguardar usuário estar autenticado
|
||||
checkAuth = setInterval(async () => {
|
||||
if (currentUser?.data && mounted) {
|
||||
clearInterval(checkAuth!);
|
||||
checkAuth = null;
|
||||
try {
|
||||
await registrarPushSubscription();
|
||||
} catch (error) {
|
||||
// Silenciar erros de push subscription para evitar spam no console
|
||||
if (error instanceof Error && !error.message.includes('message channel')) {
|
||||
console.error('Erro ao configurar push notifications:', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 500);
|
||||
|
||||
// Limpar intervalo após 30 segundos (timeout)
|
||||
const timeout = setTimeout(() => {
|
||||
if (checkAuth) {
|
||||
clearInterval(checkAuth);
|
||||
checkAuth = null;
|
||||
}
|
||||
}, 30000);
|
||||
// Limpar intervalo após 30 segundos (timeout)
|
||||
const timeout = setTimeout(() => {
|
||||
if (checkAuth) {
|
||||
clearInterval(checkAuth);
|
||||
checkAuth = null;
|
||||
}
|
||||
}, 30000);
|
||||
|
||||
return () => {
|
||||
mounted = false;
|
||||
if (checkAuth) {
|
||||
clearInterval(checkAuth);
|
||||
}
|
||||
clearTimeout(timeout);
|
||||
};
|
||||
});
|
||||
return () => {
|
||||
mounted = false;
|
||||
if (checkAuth) {
|
||||
clearInterval(checkAuth);
|
||||
}
|
||||
clearTimeout(timeout);
|
||||
};
|
||||
});
|
||||
|
||||
async function registrarPushSubscription() {
|
||||
try {
|
||||
// Verificar se Service Worker está disponível antes de tentar
|
||||
if (!("serviceWorker" in navigator) || !("PushManager" in window)) {
|
||||
return;
|
||||
}
|
||||
async function registrarPushSubscription() {
|
||||
try {
|
||||
// Verificar se Service Worker está disponível antes de tentar
|
||||
if (!('serviceWorker' in navigator) || !('PushManager' in window)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Solicitar subscription com timeout para evitar travamentos
|
||||
const subscriptionPromise = solicitarPushSubscription();
|
||||
const timeoutPromise = new Promise<null>((resolve) =>
|
||||
setTimeout(() => resolve(null), 5000),
|
||||
);
|
||||
// Solicitar subscription com timeout para evitar travamentos
|
||||
const subscriptionPromise = solicitarPushSubscription();
|
||||
const timeoutPromise = new Promise<null>((resolve) => setTimeout(() => resolve(null), 5000));
|
||||
|
||||
const subscription = await Promise.race([
|
||||
subscriptionPromise,
|
||||
timeoutPromise,
|
||||
]);
|
||||
const subscription = await Promise.race([subscriptionPromise, timeoutPromise]);
|
||||
|
||||
if (!subscription) {
|
||||
// Não logar para evitar spam no console quando VAPID key não está configurada
|
||||
return;
|
||||
}
|
||||
if (!subscription) {
|
||||
// Não logar para evitar spam no console quando VAPID key não está configurada
|
||||
return;
|
||||
}
|
||||
|
||||
// Converter para formato serializável
|
||||
const subscriptionData = subscriptionToJSON(subscription);
|
||||
// Converter para formato serializável
|
||||
const subscriptionData = subscriptionToJSON(subscription);
|
||||
|
||||
// Registrar no backend com timeout
|
||||
const mutationPromise = client.mutation(
|
||||
api.pushNotifications.registrarPushSubscription,
|
||||
{
|
||||
endpoint: subscriptionData.endpoint,
|
||||
keys: subscriptionData.keys,
|
||||
userAgent: navigator.userAgent,
|
||||
},
|
||||
);
|
||||
// Registrar no backend com timeout
|
||||
const mutationPromise = client.mutation(api.pushNotifications.registrarPushSubscription, {
|
||||
endpoint: subscriptionData.endpoint,
|
||||
keys: subscriptionData.keys,
|
||||
userAgent: navigator.userAgent
|
||||
});
|
||||
|
||||
const timeoutMutationPromise = new Promise<{
|
||||
sucesso: false;
|
||||
erro: string;
|
||||
}>((resolve) =>
|
||||
setTimeout(() => resolve({ sucesso: false, erro: "Timeout" }), 5000),
|
||||
);
|
||||
const timeoutMutationPromise = new Promise<{
|
||||
sucesso: false;
|
||||
erro: string;
|
||||
}>((resolve) => setTimeout(() => resolve({ sucesso: false, erro: 'Timeout' }), 5000));
|
||||
|
||||
const resultado = await Promise.race([
|
||||
mutationPromise,
|
||||
timeoutMutationPromise,
|
||||
]);
|
||||
const resultado = await Promise.race([mutationPromise, timeoutMutationPromise]);
|
||||
|
||||
if (resultado.sucesso) {
|
||||
console.log("✅ Push subscription registrada com sucesso");
|
||||
} else if (resultado.erro && !resultado.erro.includes("Timeout")) {
|
||||
console.error(
|
||||
"❌ Erro ao registrar push subscription:",
|
||||
resultado.erro,
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
// Ignorar erros relacionados a message channel fechado
|
||||
if (error instanceof Error && error.message.includes("message channel")) {
|
||||
return;
|
||||
}
|
||||
console.error("❌ Erro ao configurar push notifications:", error);
|
||||
}
|
||||
}
|
||||
if (resultado.sucesso) {
|
||||
console.log('✅ Push subscription registrada com sucesso');
|
||||
} else if (resultado.erro && !resultado.erro.includes('Timeout')) {
|
||||
console.error('❌ Erro ao registrar push subscription:', resultado.erro);
|
||||
}
|
||||
} catch (error) {
|
||||
// Ignorar erros relacionados a message channel fechado
|
||||
if (error instanceof Error && error.message.includes('message channel')) {
|
||||
return;
|
||||
}
|
||||
console.error('❌ Erro ao configurar push notifications:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Remover subscription ao fazer logout
|
||||
$effect(() => {
|
||||
if (!currentUser?.data) {
|
||||
removerPushSubscription().then(() => {
|
||||
console.log("Push subscription removida");
|
||||
});
|
||||
}
|
||||
});
|
||||
// Remover subscription ao fazer logout
|
||||
$effect(() => {
|
||||
if (!currentUser?.data) {
|
||||
removerPushSubscription().then(() => {
|
||||
console.log('Push subscription removida');
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- Componente invisível - apenas lógica -->
|
||||
|
||||
Reference in New Issue
Block a user