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:
Haqeem Solehan
2025-10-16 16:05:39 +08:00
commit b124ff8092
336 changed files with 94392 additions and 0 deletions

View File

@@ -0,0 +1,122 @@
import { z } from "zod";
import prisma from "~/server/utils/prisma";
// Query parameter validation schema
const batchQuerySchema = z.object({
page: z
.string()
.transform((val) => parseInt(val) || 1)
.optional(),
limit: z
.string()
.transform((val) => parseInt(val) || 10)
.optional(),
status: z.string().optional(),
});
export default defineEventHandler(async (event) => {
try {
// Parse and validate query parameters
const queryParams = getQuery(event) || {};
const params = batchQuerySchema.parse(queryParams);
// Build where clause for filtering
const where = {
delivery_type: "batch", // Identify batch notifications
};
if (params.status) {
where.status = params.status;
}
// Get total count for pagination
const total = await prisma.notifications.count({ where });
// Calculate pagination metadata
const totalPages = Math.ceil(total / params.limit);
// Fetch batch notifications with related data
const batches = await prisma.notifications.findMany({
where,
select: {
id: true,
title: true,
status: true,
scheduled_at: true,
created_at: true,
priority: true,
notification_recipients: {
select: {
id: true,
status: true,
},
},
notification_queue: {
select: {
id: true,
status: true,
},
},
},
orderBy: {
created_at: "desc",
},
skip: (params.page - 1) * params.limit,
take: params.limit,
});
// Format batches for response
const formattedBatches = batches.map((batch) => {
// Calculate progress
const totalRecipients = batch.notification_recipients.length;
const processed = batch.notification_recipients.filter(
(r) => r.status === "sent" || r.status === "delivered"
).length;
// Map status to UI-friendly status
let status = batch.status;
if (status === "draft") status = "draft";
else if (status === "scheduled") status = "scheduled";
else if (status === "processing") status = "sending";
else if (status === "completed") status = "sent";
return {
id: batch.id,
name: batch.title,
description: `Batch notification with ${totalRecipients} recipients`,
status: status,
processed: processed,
total: totalRecipients,
time: batch.created_at,
};
});
return {
success: true,
data: {
batches: formattedBatches,
pagination: {
page: params.page,
totalPages,
total,
hasMore: params.page < totalPages,
},
},
};
} catch (error) {
console.error("Error fetching batches:", error);
if (error.statusCode) {
throw error;
}
throw createError({
statusCode: 500,
statusMessage: "Failed to fetch batch notifications",
data: {
error: error.message,
},
});
} finally {
}
});

View File

@@ -0,0 +1,98 @@
import { z } from "zod";
import prisma from "~/server/utils/prisma";
// Validation schema for batch creation
const createBatchSchema = z.object({
name: z.string().min(1, "Batch name is required"),
type: z.string().min(1, "Message type is required"),
description: z.string().optional(),
priority: z.string().default("medium"),
template: z.string().optional(),
segment: z.string().optional(),
scheduledAt: z.string().optional(),
});
export default defineEventHandler(async (event) => {
try {
// Parse and validate request body
const body = await readBody(event);
const batchData = createBatchSchema.parse(body);
// Create a new batch notification
const newBatch = await prisma.notifications.create({
data: {
title: batchData.name,
type: batchData.type,
priority: batchData.priority,
delivery_type: "batch",
status: batchData.scheduledAt ? "scheduled" : "draft",
scheduled_at: batchData.scheduledAt ? new Date(batchData.scheduledAt) : null,
audience_type: batchData.segment ? "segment" : "all",
content_type: "template",
template_id: batchData.template || null,
created_by: "system", // In a real application, this would be the user ID
created_at: new Date(),
updated_at: new Date(),
},
});
// If a segment is specified, create the segment association
if (batchData.segment) {
await prisma.notification_user_segments.create({
data: {
notification_id: newBatch.id,
segment_id: batchData.segment,
created_at: new Date(),
},
});
}
// Log the batch creation
await prisma.notification_logs.create({
data: {
notification_id: newBatch.id,
action: "Batch Created",
actor_id: "system", // In a real application, this would be the user ID
status: newBatch.status,
details: `Batch notification "${batchData.name}" created`,
created_at: new Date(),
},
});
return {
success: true,
data: {
id: newBatch.id,
name: newBatch.title,
status: newBatch.status,
message: "Batch created successfully",
},
};
} catch (error) {
console.error("Error creating batch:", error);
// Handle validation errors
if (error.name === "ZodError") {
throw createError({
statusCode: 400,
statusMessage: "Invalid batch data",
data: {
errors: error.errors,
},
});
}
if (error.statusCode) {
throw error;
}
throw createError({
statusCode: 500,
statusMessage: "Failed to create batch",
data: {
error: error.message,
},
});
} finally {
}
});

View File

@@ -0,0 +1,71 @@
import prisma from "~/server/utils/prisma";
export default defineEventHandler(async (event) => {
try {
// Since there's no explicit batch table in the schema, we'll simulate this by
// counting notifications with batch-related properties
// Get current date and set to start of day
const today = new Date();
today.setHours(0, 0, 0, 0);
// Define what constitutes a "batch" notification (likely based on delivery_type or audience_type)
const batchWhere = {
delivery_type: "batch",
};
// Get batch stats
const [pending, processing, completed, failed] = await Promise.all([
// Pending batches (draft or scheduled)
prisma.notifications.count({
where: {
...batchWhere,
status: {
in: ["draft", "scheduled"],
},
},
}),
// Processing batches
prisma.notifications.count({
where: {
...batchWhere,
status: "processing",
},
}),
// Completed batches
prisma.notifications.count({
where: {
...batchWhere,
status: "completed",
},
}),
// Failed batches
prisma.notifications.count({
where: {
...batchWhere,
status: "failed",
},
}),
]);
return {
success: true,
data: {
pending,
processing,
completed,
failed,
},
};
} catch (error) {
console.error("Error fetching batch stats:", error);
throw createError({
statusCode: 500,
statusMessage: "Failed to fetch batch statistics",
data: {
error: error.message,
},
});
} finally {
}
});