purchase-confirmation.js
1 /** 2 * Purchase Confirmation Email 3 * 4 * Sends a confirmation email when a new purchase is ingested from the CF Worker. 5 * Uses Resend following the same pattern as src/outreach/email.js. 6 */ 7 8 import { Resend } from 'resend'; 9 import Logger from '../utils/logger.js'; 10 import '../utils/load-env.js'; 11 12 const logger = new Logger('PurchaseConfirmation'); 13 14 /** 15 * Send a purchase confirmation email 16 * @param {Object} params 17 * @param {string} params.email - Customer email 18 * @param {string} params.orderId - PayPal order ID 19 * @param {number} params.amount - Amount in smallest currency unit (cents) 20 * @param {string} params.currency - ISO 4217 currency code 21 * @param {string} params.url - Website URL being audited 22 */ 23 export async function sendConfirmationEmail({ email, orderId, amount, currency, url, product = 'full_audit' }) { 24 const apiKey = process.env.RESEND_API_KEY; 25 if (!apiKey) { 26 logger.warn('RESEND_API_KEY not configured, skipping confirmation email'); 27 return { success: false, reason: 'no_api_key' }; 28 } 29 30 const senderEmail = process.env.AUDITANDFIX_SENDER_EMAIL || 'reports@auditandfix.com'; 31 const resend = new Resend(apiKey); 32 33 // Format amount for display 34 const formattedAmount = `${currency} ${(amount / 100).toFixed(2)}`; 35 36 // Extract domain from URL 37 let domain; 38 try { 39 domain = new URL(url).hostname; 40 } catch { 41 domain = url; 42 } 43 44 const isQuickFixes = product === 'quick_fixes'; 45 const isAuditFix = product === 'audit_fix'; 46 47 const html = ` 48 <!DOCTYPE html> 49 <html> 50 <head> 51 <meta charset="utf-8"> 52 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 53 </head> 54 <body style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; line-height: 1.6; color: #2d3748; max-width: 600px; margin: 0 auto; padding: 20px; background-color: #f7fafc;"> 55 <div style="background: #1a365d; color: white; padding: 30px; border-radius: 8px 8px 0 0; text-align: center;"> 56 <h1 style="margin: 0; font-size: 24px;">Order Confirmed</h1> 57 <p style="margin: 10px 0 0; opacity: 0.9; font-size: 14px;">${isQuickFixes ? 'Your Quick Fixes Report is Being Prepared' : isAuditFix ? 'Your Audit + Implementation is Being Prepared' : 'Your CRO Audit Report is Being Prepared'}</p> 58 </div> 59 60 <div style="background: white; padding: 30px; border-radius: 0 0 8px 8px; border: 1px solid #e2e8f0; border-top: none;"> 61 <p>Thank you for your purchase!</p> 62 63 <div style="background: #f7fafc; padding: 20px; border-radius: 6px; margin: 20px 0;"> 64 <table style="width: 100%; border-collapse: collapse;"> 65 <tr> 66 <td style="padding: 8px 0; color: #718096;">Order ID</td> 67 <td style="padding: 8px 0; text-align: right; font-weight: 600;">${orderId}</td> 68 </tr> 69 <tr> 70 <td style="padding: 8px 0; color: #718096;">Website</td> 71 <td style="padding: 8px 0; text-align: right; font-weight: 600;">${domain}</td> 72 </tr> 73 <tr> 74 <td style="padding: 8px 0; color: #718096;">Amount Paid</td> 75 <td style="padding: 8px 0; text-align: right; font-weight: 600;">${formattedAmount}</td> 76 </tr> 77 </table> 78 </div> 79 80 <h3 style="color: #1a365d; margin-top: 25px;">What happens next?</h3> 81 ${isQuickFixes ? ` 82 <ol style="padding-left: 20px; color: #4a5568;"> 83 <li style="margin-bottom: 8px;">Our system captures a full-page screenshot of your website</li> 84 <li style="margin-bottom: 8px;">AI analyzes your 5 worst-scoring conversion factors</li> 85 <li style="margin-bottom: 8px;">A PDF with screenshot annotations and fix instructions is generated</li> 86 <li style="margin-bottom: 8px;">Your report will be delivered to this email <strong>today</strong></li> 87 </ol> 88 <p style="margin-top: 25px; padding: 15px; background: #ebf8ff; border-radius: 6px; color: #2b6cb0; font-size: 14px;"> 89 Please check your spam/junk folder if you don't see the report today. 90 </p>` : isAuditFix ? ` 91 <ol style="padding-left: 20px; color: #4a5568;"> 92 <li style="margin-bottom: 8px;">Our system captures a full-page screenshot of your website</li> 93 <li style="margin-bottom: 8px;">AI analyzes 10 conversion factors with zoomed-in problem screenshots</li> 94 <li style="margin-bottom: 8px;">A comprehensive PDF report is generated with prioritized recommendations</li> 95 <li style="margin-bottom: 8px;">Your report will be delivered to this email within <strong>24 hours</strong></li> 96 <li style="margin-bottom: 8px;">We implement your top 3 fixes with before/after screenshots within <strong>48 hours</strong></li> 97 </ol> 98 <p style="margin-top: 25px; padding: 15px; background: #ebf8ff; border-radius: 6px; color: #2b6cb0; font-size: 14px;"> 99 Please check your spam/junk folder if you don't see the report within 48 hours. 100 </p>` : ` 101 <ol style="padding-left: 20px; color: #4a5568;"> 102 <li style="margin-bottom: 8px;">Our system captures a full-page screenshot of your website</li> 103 <li style="margin-bottom: 8px;">AI analyzes 10 conversion factors with zoomed-in problem screenshots</li> 104 <li style="margin-bottom: 8px;">A comprehensive PDF report is generated with prioritized recommendations</li> 105 <li style="margin-bottom: 8px;">Your report will be delivered to this email within <strong>24 hours</strong></li> 106 </ol> 107 <p style="margin-top: 25px; padding: 15px; background: #ebf8ff; border-radius: 6px; color: #2b6cb0; font-size: 14px;"> 108 Please check your spam/junk folder if you don't see the report within 24 hours. 109 </p>`} 110 111 <p style="margin-top: 25px; color: #718096; font-size: 13px;"> 112 Questions? Reply to this email or contact us at <a href="mailto:${senderEmail}" style="color: #3182ce;">${senderEmail}</a> 113 </p> 114 </div> 115 116 <p style="text-align: center; color: #a0aec0; font-size: 12px; margin-top: 20px;"> 117 Audit&Fix CRO Reports 118 </p> 119 </body> 120 </html>`.trim(); 121 122 try { 123 const result = await resend.emails.send({ 124 from: `Audit&Fix <${senderEmail}>`, 125 to: email, 126 subject: isQuickFixes 127 ? `Order Confirmed — Your Quick Fixes Report for ${domain} is Being Prepared` 128 : isAuditFix 129 ? `Order Confirmed — Your Audit + Implementation for ${domain} is Being Prepared` 130 : `Order Confirmed — Your CRO Audit Report for ${domain} is Being Prepared`, 131 html, 132 }); 133 134 logger.success(`Confirmation email sent to ${email} (${result.id})`); 135 return { success: true, emailId: result.id }; 136 } catch (error) { 137 logger.error(`Failed to send confirmation to ${email}`, error); 138 throw error; 139 } 140 }