Update various configuration files, components, and assets; enhance notification system and API endpoints; improve documentation and styles across the application.
This commit is contained in:
223
server/api/notifications/[id].get.js
Normal file
223
server/api/notifications/[id].get.js
Normal file
@@ -0,0 +1,223 @@
|
||||
import prisma from "~/server/utils/prisma";
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
try {
|
||||
// Get notification ID from route parameters
|
||||
const notificationId = getRouterParam(event, "id");
|
||||
|
||||
if (!notificationId) {
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Notification ID is required",
|
||||
});
|
||||
}
|
||||
|
||||
// Get current user (assuming auth middleware provides this)
|
||||
const user = event.context.user;
|
||||
if (!user) {
|
||||
throw createError({
|
||||
statusCode: 401,
|
||||
statusMessage: "Authentication required",
|
||||
});
|
||||
}
|
||||
|
||||
// Fetch notification with all related data using Prisma
|
||||
const notification = await prisma.notifications.findFirst({
|
||||
where: {
|
||||
id: notificationId,
|
||||
created_by: user.id,
|
||||
},
|
||||
include: {
|
||||
notification_categories: {
|
||||
select: {
|
||||
name: true,
|
||||
value: true,
|
||||
},
|
||||
},
|
||||
notification_templates: {
|
||||
select: {
|
||||
name: true,
|
||||
subject: true,
|
||||
email_content: true,
|
||||
push_title: true,
|
||||
push_body: true,
|
||||
variables: true,
|
||||
},
|
||||
},
|
||||
notification_channels: {
|
||||
select: {
|
||||
channel_type: true,
|
||||
},
|
||||
},
|
||||
notification_user_segments: {
|
||||
include: {
|
||||
user_segments: {
|
||||
select: {
|
||||
value: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
notification_recipients: {
|
||||
select: {
|
||||
status: true,
|
||||
opened_at: true,
|
||||
clicked_at: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (!notification) {
|
||||
throw createError({
|
||||
statusCode: 404,
|
||||
statusMessage:
|
||||
"Notification not found or you do not have permission to access it",
|
||||
});
|
||||
}
|
||||
|
||||
// Calculate analytics
|
||||
const totalRecipients = notification.notification_recipients.length;
|
||||
const sentCount = notification.notification_recipients.filter(
|
||||
(r) => r.status === "sent"
|
||||
).length;
|
||||
const deliveredCount = notification.notification_recipients.filter(
|
||||
(r) => r.status === "delivered"
|
||||
).length;
|
||||
const failedCount = notification.notification_recipients.filter(
|
||||
(r) => r.status === "failed"
|
||||
).length;
|
||||
const openedCount = notification.notification_recipients.filter(
|
||||
(r) => r.opened_at !== null
|
||||
).length;
|
||||
const clickedCount = notification.notification_recipients.filter(
|
||||
(r) => r.clicked_at !== null
|
||||
).length;
|
||||
|
||||
// Calculate success rate
|
||||
const successRate =
|
||||
totalRecipients > 0
|
||||
? Math.round((deliveredCount / totalRecipients) * 100)
|
||||
: 0;
|
||||
|
||||
// Format the response
|
||||
const formattedNotification = {
|
||||
id: notification.id,
|
||||
title: notification.title,
|
||||
type: notification.type,
|
||||
priority: notification.priority,
|
||||
status: notification.status,
|
||||
category: {
|
||||
name: notification.notification_categories?.name || "Uncategorized",
|
||||
value: notification.notification_categories?.value,
|
||||
},
|
||||
channels: notification.notification_channels.map((c) => c.channel_type),
|
||||
deliveryType: notification.delivery_type,
|
||||
scheduledAt: notification.scheduled_at,
|
||||
timezone: notification.timezone,
|
||||
expiresAt: notification.expires_at,
|
||||
|
||||
// A/B Testing
|
||||
enableAbTesting: notification.enable_ab_testing,
|
||||
abTestSplit: notification.ab_test_split,
|
||||
abTestName: notification.ab_test_name,
|
||||
|
||||
// Tracking
|
||||
enableTracking: notification.enable_tracking,
|
||||
|
||||
// Audience
|
||||
audienceType: notification.audience_type,
|
||||
specificUsers: notification.specific_users,
|
||||
userSegments: notification.notification_user_segments.map(
|
||||
(s) => s.user_segments.value
|
||||
),
|
||||
userStatus: notification.user_status,
|
||||
registrationPeriod: notification.registration_period,
|
||||
excludeUnsubscribed: notification.exclude_unsubscribed,
|
||||
respectDoNotDisturb: notification.respect_do_not_disturb,
|
||||
|
||||
// Content
|
||||
contentType: notification.content_type,
|
||||
template: notification.notification_templates
|
||||
? {
|
||||
id: notification.template_id,
|
||||
name: notification.notification_templates.name,
|
||||
subject: notification.notification_templates.subject,
|
||||
emailContent: notification.notification_templates.email_content,
|
||||
pushTitle: notification.notification_templates.push_title,
|
||||
pushBody: notification.notification_templates.push_body,
|
||||
variables: notification.notification_templates.variables,
|
||||
}
|
||||
: null,
|
||||
|
||||
// Email Content
|
||||
emailSubject: notification.email_subject,
|
||||
emailContent: notification.email_content,
|
||||
callToActionText: notification.call_to_action_text,
|
||||
callToActionUrl: notification.call_to_action_url,
|
||||
|
||||
// Push Content
|
||||
pushTitle: notification.push_title,
|
||||
pushBody: notification.push_body,
|
||||
pushImageUrl: notification.push_image_url,
|
||||
|
||||
// Analytics
|
||||
analytics: {
|
||||
estimatedReach: notification.estimated_reach,
|
||||
actualSent: notification.actual_sent,
|
||||
totalRecipients,
|
||||
sentCount,
|
||||
deliveredCount,
|
||||
failedCount,
|
||||
openedCount,
|
||||
clickedCount,
|
||||
successRate,
|
||||
openRate:
|
||||
totalRecipients > 0
|
||||
? Math.round((openedCount / totalRecipients) * 100)
|
||||
: 0,
|
||||
clickRate:
|
||||
totalRecipients > 0
|
||||
? Math.round((clickedCount / totalRecipients) * 100)
|
||||
: 0,
|
||||
},
|
||||
|
||||
// Metadata
|
||||
createdBy: notification.created_by,
|
||||
createdAt: notification.created_at,
|
||||
updatedAt: notification.updated_at,
|
||||
sentAt: notification.sent_at,
|
||||
};
|
||||
|
||||
return {
|
||||
success: true,
|
||||
data: formattedNotification,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("Error fetching notification:", error);
|
||||
|
||||
if (error.code?.startsWith("P")) {
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Database operation failed",
|
||||
data: {
|
||||
error: error.message,
|
||||
code: error.code,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (error.statusCode) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
statusMessage: "Failed to fetch notification",
|
||||
data: {
|
||||
error: error.message,
|
||||
},
|
||||
});
|
||||
} finally {
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user