import prisma from "~/server/utils/prisma"; export default defineEventHandler(async (event) => { try { // Read request body const body = await readBody(event); // Get current user const user = event.context.user; if (!user || !user.userID) { throw createError({ statusCode: 401, statusMessage: 'Authentication required' }); } // Prepare data for saving const draftData = { title: body.title || 'Untitled Draft', type: body.type || 'single', priority: body.priority || 'medium', category: body.category, channels: Array.isArray(body.channels) ? body.channels : [], emailSubject: body.emailSubject || null, deliveryType: body.deliveryType || 'immediate', scheduledAt: body.scheduledAt || null, timezone: body.timezone || 'UTC', audienceType: body.audienceType || 'all', specificUsers: body.specificUsers || null, userSegments: Array.isArray(body.userSegments) ? body.userSegments : [], excludeUnsubscribed: body.excludeUnsubscribed !== false, // default true contentType: body.contentType || 'new', selectedTemplate: body.selectedTemplate || null, emailContent: body.emailContent || null, callToActionText: body.callToActionText || null, callToActionUrl: body.callToActionUrl || null, pushTitle: body.pushTitle || null, pushBody: body.pushBody || null, draftId: body.draftId // For updating existing drafts }; // Use Prisma transaction const result = await prisma.$transaction(async (tx) => { let notificationId = draftData.draftId; // Get category if provided let categoryId = null; if (draftData.category) { const category = await tx.notification_categories.findFirst({ where: { value: draftData.category } }); if (category) { categoryId = category.id; } } // Get template if provided let templateId = null; if (draftData.contentType === 'template' && draftData.selectedTemplate) { const template = await tx.notification_templates.findFirst({ where: { value: draftData.selectedTemplate, is_active: true } }); if (template) { templateId = template.id; } } if (notificationId) { // Check if the draft exists and belongs to the user const existingDraft = await tx.notifications.findFirst({ where: { id: notificationId, created_by: user.userID.toString(), status: 'draft' } }); if (!existingDraft) { throw createError({ statusCode: 404, statusMessage: 'Draft not found or you do not have permission to update it' }); } // Update existing draft const updatedDraft = await tx.notifications.update({ where: { id: notificationId }, data: { title: draftData.title, type: draftData.type, priority: draftData.priority, category_id: categoryId, delivery_type: draftData.deliveryType, scheduled_at: draftData.scheduledAt ? new Date(draftData.scheduledAt) : null, timezone: draftData.timezone, audience_type: draftData.audienceType, specific_users: draftData.specificUsers, exclude_unsubscribed: draftData.excludeUnsubscribed, content_type: draftData.contentType, template_id: templateId, email_subject: draftData.emailSubject, email_content: draftData.emailContent, call_to_action_text: draftData.callToActionText, call_to_action_url: draftData.callToActionUrl, push_title: draftData.pushTitle, push_body: draftData.pushBody, updated_at: new Date() } }); notificationId = updatedDraft.id; } else { // Create new draft const newDraft = await tx.notifications.create({ data: { title: draftData.title, type: draftData.type, priority: draftData.priority, category_id: categoryId, delivery_type: draftData.deliveryType, scheduled_at: draftData.scheduledAt ? new Date(draftData.scheduledAt) : null, timezone: draftData.timezone, audience_type: draftData.audienceType, specific_users: draftData.specificUsers, exclude_unsubscribed: draftData.excludeUnsubscribed, respect_do_not_disturb: true, enable_tracking: true, content_type: draftData.contentType, template_id: templateId, email_subject: draftData.emailSubject, email_content: draftData.emailContent, call_to_action_text: draftData.callToActionText, call_to_action_url: draftData.callToActionUrl, push_title: draftData.pushTitle, push_body: draftData.pushBody, created_by: user.userID.toString(), status: 'draft' } }); notificationId = newDraft.id; } // Update channels if (draftData.channels && draftData.channels.length > 0) { // Delete existing channels await tx.notification_channels.deleteMany({ where: { notification_id: notificationId } }); // Insert new channels await tx.notification_channels.createMany({ data: draftData.channels.map(channel => ({ notification_id: notificationId, channel_type: channel })) }); } // Update segments if (draftData.userSegments && draftData.userSegments.length > 0) { // Delete existing segments await tx.notification_user_segments.deleteMany({ where: { notification_id: notificationId } }); // Insert new segments for (const segment of draftData.userSegments) { const segmentData = await tx.user_segments.findFirst({ where: { value: segment, is_active: true } }); if (segmentData) { await tx.notification_user_segments.create({ data: { notification_id: notificationId, segment_id: segmentData.id } }); } } } return { id: notificationId }; }); return { success: true, data: { id: result.id, message: 'Draft saved successfully' } }; } catch (error) { console.error('Error saving draft:', error); // Handle Prisma errors if (error.code && error.code.startsWith('P')) { throw createError({ statusCode: 400, statusMessage: 'Database operation failed', data: { error: error.message, code: error.code } }); } // Handle known errors with status codes if (error.statusCode) { throw error; } // Generic server error throw createError({ statusCode: 500, statusMessage: 'Failed to save draft', data: { error: error.message } }); } finally { } });