Files
boc/landvex/src/services/emailService.js
T
Bernt 6989a98d75 feat: Passwordless cross-device authentication
- Arkitektur: docs/auth/passwordless-architecture.md
- Backend: iom/quixzoom-auth-service/ (FastAPI + Redis)
- Webb: quixzoom-market-pages/se/login/ (QR-kod + polling)
- App: iom/quixzoom-app/src/features/auth/ (push + deep links)

Flöde: QR-kod → app-godkännande → webb-inloggad
2026-07-07 07:11:50 +00:00

116 lines
4.0 KiB
JavaScript

const nodemailer = require('nodemailer');
const logger = require('../utils/logger');
class EmailService {
constructor() {
this.transporter = nodemailer.createTransport({
host: process.env.SMTP_HOST,
port: process.env.SMTP_PORT,
secure: false,
auth: {
user: process.env.SMTP_USER,
pass: process.env.SMTP_PASSWORD
}
});
}
async sendReportEmail(to, order, report) {
const mailOptions = {
from: `"Landvex AI" <${process.env.SMTP_USER}>`,
to,
subject: `Din marknadsrapport är klar - ${order.productName}`,
html: `
<div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;">
<h2 style="color: #1a5276;">Din marknadsintelligensrapport är klar!</h2>
<p>Hej,</p>
<p>Din marknadsrapport för <strong>${order.productName}</strong> har genererats och är nu tillgänglig.</p>
<div style="background: #eaf2f8; padding: 20px; border-radius: 8px; margin: 20px 0;">
<h3 style="margin-top: 0; color: #1a5276;">Sammanfattning</h3>
<p>${report.executiveSummary || 'Rapporten innehåller en komplett marknadsanalys.'}</p>
</div>
<div style="text-align: center; margin: 30px 0;">
<a href="${process.env.APP_URL || 'http://localhost:3000'}/reports/${report.id}"
style="background: #1a5276; color: white; padding: 15px 30px; text-decoration: none; border-radius: 5px; display: inline-block;">
Visa rapport
</a>
</div>
<p style="color: #666; font-size: 0.9em;">
Rapport-ID: ${report.id}<br>
Genererad: ${new Date(report.generatedAt).toLocaleString('sv-SE')}
</p>
<hr style="border: none; border-top: 1px solid #ddd; margin: 30px 0;">
<p style="color: #666; font-size: 0.8em;">
Landvex AI - Data-driven marknadsintelligens<br>
<a href="${process.env.APP_URL || 'http://localhost:3000'}">www.landvex.ai</a>
</p>
</div>
`
};
try {
await this.transporter.sendMail(mailOptions);
logger.info(`Report email sent to ${to}`);
} catch (error) {
logger.error('Failed to send email:', error);
throw error;
}
}
async sendStatusUpdate(to, order) {
const mailOptions = {
from: `"Landvex AI" <${process.env.SMTP_USER}>`,
to,
subject: `Uppdatering om din beställning - ${order.productName}`,
html: `
<div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;">
<h2 style="color: #1a5276;">Statusuppdatering</h2>
<p>Hej,</p>
<p>Din beställning för <strong>${order.productName}</strong> har uppdaterats.</p>
<div style="background: #f5f5f5; padding: 20px; border-radius: 8px; margin: 20px 0;">
<p><strong>Status:</strong> ${this.translateStatus(order.status)}</p>
<p><strong>Framsteg:</strong> ${order.progress}%</p>
${order.progressMessage ? `<p><strong>Info:</strong> ${order.progressMessage}</p>` : ''}
</div>
<p>Du får ett nytt meddelande när rapporten är klar.</p>
<hr style="border: none; border-top: 1px solid #ddd; margin: 30px 0;">
<p style="color: #666; font-size: 0.8em;">
Landvex AI - Data-driven marknadsintelligens
</p>
</div>
`
};
try {
await this.transporter.sendMail(mailOptions);
logger.info(`Status update sent to ${to}`);
} catch (error) {
logger.error('Failed to send status email:', error);
}
}
translateStatus(status) {
const translations = {
pending: 'Väntar på start',
data_collection: 'Samlar in data',
analysis: 'Analyserar data',
report_generation: 'Genererar rapport',
completed: 'Klar',
failed: 'Misslyckades'
};
return translations[status] || status;
}
}
module.exports = new EmailService();