- Implemented error handling for unhandled promise rejections related to message channels, improving stability during push notification operations. - Updated the PushNotificationManager component to manage push subscription registration with timeouts, preventing application hangs. - Enhanced the sidebar and chat components to display user avatars, improving user experience and visual consistency. - Refactored email processing logic to support scheduled email sending, integrating new backend functionalities for better email management. - Improved overall error handling and logging across components to reduce console spam and enhance debugging capabilities.
141 lines
4.5 KiB
Svelte
141 lines
4.5 KiB
Svelte
<script lang="ts">
|
|
import { onMount } from "svelte";
|
|
import { useConvexClient } from "convex-svelte";
|
|
import { api } from "@sgse-app/backend/convex/_generated/api";
|
|
import { authStore } from "$lib/stores/auth.svelte";
|
|
import {
|
|
registrarServiceWorker,
|
|
solicitarPushSubscription,
|
|
subscriptionToJSON,
|
|
removerPushSubscription,
|
|
} from "$lib/utils/notifications";
|
|
|
|
const client = useConvexClient();
|
|
|
|
// 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 }
|
|
);
|
|
}
|
|
|
|
onMount(async () => {
|
|
let checkAuth: ReturnType<typeof setInterval> | null = null;
|
|
let mounted = true;
|
|
|
|
// Aguardar usuário estar autenticado
|
|
checkAuth = setInterval(async () => {
|
|
if (authStore.usuario && 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);
|
|
|
|
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;
|
|
}
|
|
|
|
// 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]);
|
|
|
|
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);
|
|
|
|
// 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 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);
|
|
}
|
|
}
|
|
|
|
// Remover subscription ao fazer logout
|
|
$effect(() => {
|
|
if (!authStore.usuario) {
|
|
removerPushSubscription().then(() => {
|
|
console.log("Push subscription removida");
|
|
});
|
|
}
|
|
});
|
|
</script>
|
|
|
|
<!-- Componente invisível - apenas lógica -->
|
|
|