import { getTransporter, emailConfigured, FROM_EMAIL, APP_NAME } from "./client" import { BRAND, emailShell, detailTable, statusBadge, paragraph, escapeHtml, htmlToText, } from "./layout" // Re-exported so existing importers (`@/lib/email/send`) keep working. export { escapeHtml } interface SendEmailOptions { to: string subject: string html: string /** Optional plain-text part. Auto-derived from `html` when omitted. */ text?: string from?: string } export async function sendEmail({ to, subject, html, text, from }: SendEmailOptions) { if (!emailConfigured()) { console.warn(`[email] SMTP not configured — skipping "${subject}" to ${to}`) return { success: false, error: "email not configured" } } try { const info = await getTransporter().sendMail({ from: from ?? `${APP_NAME} <${FROM_EMAIL}>`, to, subject, html, // A plain-text alternative improves inbox placement and gives clients // that can't render HTML something clean to show. text: text ?? htmlToText(html), }) return { success: true, id: info.messageId } } catch (error) { console.error("Email send failed:", error) return { success: false, error } } } // ── Email templates ────────────────────────────────────────────── export function rentDueReminderHtml({ tenantName, propertyName, unitNumber, amount, dueDate, paymentLink, }: { tenantName: string propertyName: string unitNumber: string amount: string dueDate: string paymentLink?: string }) { return emailShell({ preheader: `Your rent of ${amount} is due on ${dueDate}.`, eyebrow: "Rent reminder", accent: BRAND.indigo, title: "Your rent is due soon", intro: `Hi ${escapeHtml(tenantName)}, this is a friendly reminder about your upcoming rent payment.`, body: detailTable([ { label: "Property", value: `${propertyName} — Unit ${unitNumber}` }, { label: "Amount due", value: amount, accent: true }, { label: "Due date", value: dueDate }, ]), button: paymentLink ? { href: paymentLink, label: "Pay rent now" } : undefined, footerNote: paymentLink ? "If the button doesn't work, contact your landlord for alternative payment options." : "Please arrange payment before the due date. Reach out to your landlord with any questions.", }) } export function rentOverdueHtml({ tenantName, propertyName, unitNumber, amount, dueDate, }: { tenantName: string propertyName: string unitNumber: string amount: string dueDate: string }) { return emailShell({ preheader: `Your rent payment of ${amount} is now overdue.`, eyebrow: "Action needed", accent: BRAND.red, title: "Your rent is overdue", intro: `Hi ${escapeHtml(tenantName)}, our records show the payment below hasn't been received yet.`, body: detailTable( [ { label: "Property", value: `${propertyName} — Unit ${unitNumber}` }, { label: "Amount due", value: amount, accent: true }, { label: "Was due", value: dueDate, accent: true }, ], BRAND.red ) + paragraph( "Please make payment as soon as possible to avoid any late fees. If you've already paid, you can disregard this notice." ), }) } export function leaseExpiryHtml({ tenantName, propertyName, unitNumber, leaseEnd, daysLeft, }: { tenantName: string propertyName: string unitNumber: string leaseEnd: string daysLeft: number }) { return emailShell({ preheader: `Your lease ends on ${leaseEnd} (${daysLeft} days away).`, eyebrow: "Lease update", accent: BRAND.amber, title: "Your lease is expiring soon", intro: `Hi ${escapeHtml(tenantName)}, your current lease is coming to an end.`, body: detailTable( [ { label: "Property", value: `${propertyName} — Unit ${unitNumber}` }, { label: "Lease ends", value: leaseEnd, accent: true }, { label: "Time remaining", value: `${daysLeft} days` }, ], BRAND.amber ) + paragraph("Please contact your landlord to discuss renewal options or next steps."), }) } export function maintenanceUpdateHtml({ tenantName, title, status, resolutionNotes, }: { tenantName: string title: string status: string resolutionNotes?: string }) { const prettyStatus = status.replace(/_/g, " ") const fontStack = "-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif" return emailShell({ preheader: `Your maintenance request is now "${prettyStatus}".`, eyebrow: "Maintenance", accent: BRAND.indigo, title: "Update on your maintenance request", intro: `Hi ${escapeHtml(tenantName)}, there's an update on your request.`, body: `
|
${escapeHtml(title)} ${statusBadge(prettyStatus, BRAND.indigo)} |