Files
Nas-Notification/server/api/notifications/dashboard/overview.get.js

171 lines
4.4 KiB
JavaScript

import prisma from "~/server/utils/prisma";
export default defineEventHandler(async (event) => {
try {
const now = new Date();
const last24Hours = new Date(now.getTime() - 24 * 60 * 60 * 1000);
const last7Days = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);
const last30Days = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);
// Fetch comprehensive stats
const [
totalNotifications,
totalSent,
totalScheduled,
totalDraft,
sentLast24h,
sentLast7Days,
totalRecipients,
successfulDeliveries,
failedDeliveries,
queuedJobs,
channelStats,
categoryStats,
] = await Promise.all([
// Total notifications
prisma.notifications.count(),
// Total sent notifications
prisma.notifications.count({
where: { status: "sending" }
}),
// Total scheduled
prisma.notifications.count({
where: { status: "scheduled" }
}),
// Total drafts
prisma.notifications.count({
where: { status: "draft" }
}),
// Sent in last 24 hours
prisma.notifications.count({
where: {
status: "sending",
sent_at: { gte: last24Hours }
}
}),
// Sent in last 7 days
prisma.notifications.count({
where: {
status: "sending",
sent_at: { gte: last7Days }
}
}),
// Total recipients
prisma.notification_recipients.count(),
// Successful deliveries
prisma.notification_recipients.count({
where: { status: "sent" }
}),
// Failed deliveries
prisma.notification_recipients.count({
where: { status: "failed" }
}),
// Queued jobs
prisma.notification_queue.count({
where: { status: "queued" }
}),
// Channel distribution
prisma.notification_channels.groupBy({
by: ['channel_type'],
_count: {
channel_type: true
}
}),
// Category distribution
prisma.notifications.groupBy({
by: ['category_id'],
_count: {
category_id: true
},
take: 5,
orderBy: {
_count: {
category_id: 'desc'
}
}
}),
]);
// Calculate delivery rate
const totalDeliveryAttempts = successfulDeliveries + failedDeliveries;
const deliveryRate = totalDeliveryAttempts > 0
? ((successfulDeliveries / totalDeliveryAttempts) * 100).toFixed(1)
: 100;
// Calculate growth rate (last 7 days vs previous 7 days)
const previous7Days = new Date(last7Days.getTime() - 7 * 24 * 60 * 60 * 1000);
const sentPrevious7Days = await prisma.notifications.count({
where: {
status: "sending",
sent_at: {
gte: previous7Days,
lt: last7Days
}
}
});
const growthRate = sentPrevious7Days > 0
? (((sentLast7Days - sentPrevious7Days) / sentPrevious7Days) * 100).toFixed(1)
: 0;
// Get category names
const categoryIds = categoryStats.map(c => c.category_id).filter(Boolean);
const categories = await prisma.notification_categories.findMany({
where: { id: { in: categoryIds } },
select: { id: true, name: true }
});
const categoryMap = Object.fromEntries(categories.map(c => [c.id, c.name]));
return {
success: true,
data: {
overview: {
total: totalNotifications,
sent: totalSent,
scheduled: totalScheduled,
draft: totalDraft,
sentLast24h,
sentLast7Days,
growthRate: parseFloat(growthRate),
},
delivery: {
totalRecipients,
successful: successfulDeliveries,
failed: failedDeliveries,
deliveryRate: parseFloat(deliveryRate),
queued: queuedJobs,
},
channels: channelStats.map(ch => ({
channel: ch.channel_type,
count: ch._count.channel_type,
})),
topCategories: categoryStats.map(cat => ({
categoryId: cat.category_id,
categoryName: categoryMap[cat.category_id] || 'Unknown',
count: cat._count.category_id,
})),
},
};
} catch (error) {
console.error("Error fetching dashboard overview:", error);
throw createError({
statusCode: 500,
statusMessage: "Failed to fetch dashboard data",
data: { error: error.message },
});
} finally {
}
});