feat: update ESLint and TypeScript configurations across frontend and backend; enhance component structure and improve data handling in various modules
This commit is contained in:
@@ -1,103 +1,102 @@
|
||||
"use node";
|
||||
'use node';
|
||||
|
||||
import { action } from "../_generated/server";
|
||||
import { v } from "convex/values";
|
||||
import { internal } from "../_generated/api";
|
||||
import { action } from '../_generated/server';
|
||||
import { v } from 'convex/values';
|
||||
import { internal } from '../_generated/api';
|
||||
|
||||
/**
|
||||
* Enviar push notification usando Web Push API
|
||||
*/
|
||||
export const enviarPush = action({
|
||||
args: {
|
||||
subscriptionId: v.id("pushSubscriptions"),
|
||||
titulo: v.string(),
|
||||
corpo: v.string(),
|
||||
data: v.optional(
|
||||
v.object({
|
||||
conversaId: v.optional(v.string()),
|
||||
mensagemId: v.optional(v.string()),
|
||||
tipo: v.optional(v.string()),
|
||||
})
|
||||
),
|
||||
},
|
||||
returns: v.object({ sucesso: v.boolean(), erro: v.optional(v.string()) }),
|
||||
handler: async (ctx, args) => {
|
||||
try {
|
||||
// Buscar subscription
|
||||
const subscription = await ctx.runQuery(internal.pushNotifications.getSubscriptionById, {
|
||||
subscriptionId: args.subscriptionId,
|
||||
});
|
||||
args: {
|
||||
subscriptionId: v.id('pushSubscriptions'),
|
||||
titulo: v.string(),
|
||||
corpo: v.string(),
|
||||
data: v.optional(
|
||||
v.object({
|
||||
conversaId: v.optional(v.string()),
|
||||
mensagemId: v.optional(v.string()),
|
||||
tipo: v.optional(v.string())
|
||||
})
|
||||
)
|
||||
},
|
||||
returns: v.object({ sucesso: v.boolean(), erro: v.optional(v.string()) }),
|
||||
handler: async (ctx, args) => {
|
||||
try {
|
||||
// Buscar subscription
|
||||
const subscription = await ctx.runQuery(internal.pushNotifications.getSubscriptionById, {
|
||||
subscriptionId: args.subscriptionId
|
||||
});
|
||||
|
||||
if (!subscription || !subscription.ativo) {
|
||||
return { sucesso: false, erro: "Subscription não encontrada ou inativa" };
|
||||
}
|
||||
if (!subscription || !subscription.ativo) {
|
||||
return { sucesso: false, erro: 'Subscription não encontrada ou inativa' };
|
||||
}
|
||||
|
||||
// Web Push requer VAPID keys (deve estar em variáveis de ambiente)
|
||||
// Por enquanto, vamos usar uma implementação básica
|
||||
// Em produção, você precisará configurar VAPID keys
|
||||
// Web Push requer VAPID keys (deve estar em variáveis de ambiente)
|
||||
// Por enquanto, vamos usar uma implementação básica
|
||||
// Em produção, você precisará configurar VAPID keys
|
||||
|
||||
const webpushModule = await import("web-push");
|
||||
// web-push pode exportar como default ou named exports
|
||||
// Usar a declaração de tipo do módulo web-push
|
||||
interface WebPushType {
|
||||
setVapidDetails: (subject: string, publicKey: string, privateKey: string) => void;
|
||||
sendNotification: (
|
||||
subscription: { endpoint: string; keys: { p256dh: string; auth: string } },
|
||||
payload: string | Buffer
|
||||
) => Promise<void>;
|
||||
}
|
||||
const webpush: WebPushType = (webpushModule.default || webpushModule) as WebPushType;
|
||||
const webpushModule = await import('web-push');
|
||||
// web-push pode exportar como default ou named exports
|
||||
// Usar a declaração de tipo do módulo web-push
|
||||
interface WebPushType {
|
||||
setVapidDetails: (subject: string, publicKey: string, privateKey: string) => void;
|
||||
sendNotification: (
|
||||
subscription: { endpoint: string; keys: { p256dh: string; auth: string } },
|
||||
payload: string | Buffer
|
||||
) => Promise<void>;
|
||||
}
|
||||
const webpush: WebPushType = (webpushModule.default || webpushModule) as WebPushType;
|
||||
|
||||
// VAPID keys devem vir de variáveis de ambiente
|
||||
const publicKey: string | undefined = process.env.VAPID_PUBLIC_KEY;
|
||||
const privateKey: string | undefined = process.env.VAPID_PRIVATE_KEY;
|
||||
// VAPID keys devem vir de variáveis de ambiente
|
||||
const publicKey: string | undefined = process.env.VAPID_PUBLIC_KEY;
|
||||
const privateKey: string | undefined = process.env.VAPID_PRIVATE_KEY;
|
||||
|
||||
if (!publicKey || !privateKey) {
|
||||
console.warn("⚠️ VAPID keys não configuradas. Push notifications não funcionarão.");
|
||||
// Em desenvolvimento, podemos retornar sucesso sem enviar
|
||||
return { sucesso: true };
|
||||
}
|
||||
if (!publicKey || !privateKey) {
|
||||
console.warn('⚠️ VAPID keys não configuradas. Push notifications não funcionarão.');
|
||||
// Em desenvolvimento, podemos retornar sucesso sem enviar
|
||||
return { sucesso: true };
|
||||
}
|
||||
|
||||
webpush.setVapidDetails("mailto:suporte@sgse.app", publicKey, privateKey);
|
||||
webpush.setVapidDetails('mailto:suporte@sgse.app', publicKey, privateKey);
|
||||
|
||||
// Preparar payload da notificação
|
||||
const payload = JSON.stringify({
|
||||
title: args.titulo,
|
||||
body: args.corpo,
|
||||
icon: "/favicon.png",
|
||||
badge: "/favicon.png",
|
||||
data: args.data || {},
|
||||
tag: args.data?.conversaId || "default",
|
||||
requireInteraction: args.data?.tipo === "mencao", // Menções requerem interação
|
||||
});
|
||||
// Preparar payload da notificação
|
||||
const payload = JSON.stringify({
|
||||
title: args.titulo,
|
||||
body: args.corpo,
|
||||
icon: '/favicon.png',
|
||||
badge: '/favicon.png',
|
||||
data: args.data || {},
|
||||
tag: args.data?.conversaId || 'default',
|
||||
requireInteraction: args.data?.tipo === 'mencao' // Menções requerem interação
|
||||
});
|
||||
|
||||
// Enviar push notification
|
||||
await webpush.sendNotification(
|
||||
{
|
||||
endpoint: subscription.endpoint,
|
||||
keys: {
|
||||
p256dh: subscription.keys.p256dh,
|
||||
auth: subscription.keys.auth,
|
||||
},
|
||||
},
|
||||
payload
|
||||
);
|
||||
// Enviar push notification
|
||||
await webpush.sendNotification(
|
||||
{
|
||||
endpoint: subscription.endpoint,
|
||||
keys: {
|
||||
p256dh: subscription.keys.p256dh,
|
||||
auth: subscription.keys.auth
|
||||
}
|
||||
},
|
||||
payload
|
||||
);
|
||||
|
||||
console.log(`✅ Push notification enviada para ${subscription.endpoint}`);
|
||||
return { sucesso: true };
|
||||
} catch (error: unknown) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||
console.error("❌ Erro ao enviar push notification:", errorMessage);
|
||||
console.log(`✅ Push notification enviada para ${subscription.endpoint}`);
|
||||
return { sucesso: true };
|
||||
} catch (error: unknown) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||
console.error('❌ Erro ao enviar push notification:', errorMessage);
|
||||
|
||||
// Se subscription inválida, marcar como inativa
|
||||
if (errorMessage.includes("410") || errorMessage.includes("expired")) {
|
||||
await ctx.runMutation(internal.pushNotifications.marcarSubscriptionInativa, {
|
||||
subscriptionId: args.subscriptionId,
|
||||
});
|
||||
}
|
||||
// Se subscription inválida, marcar como inativa
|
||||
if (errorMessage.includes('410') || errorMessage.includes('expired')) {
|
||||
await ctx.runMutation(internal.pushNotifications.marcarSubscriptionInativa, {
|
||||
subscriptionId: args.subscriptionId
|
||||
});
|
||||
}
|
||||
|
||||
return { sucesso: false, erro: errorMessage };
|
||||
}
|
||||
},
|
||||
return { sucesso: false, erro: errorMessage };
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user