Enhance email templates with clickable links, branding, and improved styling
- Add clickable gallery links in all email templates - Include application logo in email header and footer (custom or PicPeak default) - Redesign emails with professional styling matching gallery login page - Gray background with white content box - PicPeak green header with centered logo - Clean typography and proper spacing - Responsive design for mobile devices - Styled call-to-action buttons - Footer with branding and copyright - Update email processor to fetch branding settings dynamically - Use proper API URLs for logo images in emails 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -50,7 +50,7 @@ async function getRecipientLanguage(email) {
|
||||
}
|
||||
|
||||
// Process email template with variables
|
||||
function processTemplate(template, variables, language = 'en') {
|
||||
async function processTemplate(template, variables, language = 'en') {
|
||||
// Get the appropriate language fields
|
||||
const subjectField = language === 'de' ? 'subject_de' : 'subject_en';
|
||||
const htmlField = language === 'de' ? 'body_html_de' : 'body_html_en';
|
||||
@@ -61,6 +61,38 @@ function processTemplate(template, variables, language = 'en') {
|
||||
let htmlBody = template[htmlField] || template.body_html || '';
|
||||
let textBody = template[textField] || template.body_text || '';
|
||||
|
||||
// Get branding settings for logo
|
||||
let logoUrl = '';
|
||||
let companyName = 'PicPeak';
|
||||
try {
|
||||
const brandingSettings = await db('app_settings')
|
||||
.whereIn('setting_key', ['branding_logo_url', 'branding_company_name'])
|
||||
.select('setting_key', 'setting_value');
|
||||
|
||||
brandingSettings.forEach(setting => {
|
||||
if (setting.setting_key === 'branding_logo_url' && setting.setting_value) {
|
||||
try {
|
||||
logoUrl = JSON.parse(setting.setting_value);
|
||||
} catch (e) {
|
||||
logoUrl = setting.setting_value;
|
||||
}
|
||||
} else if (setting.setting_key === 'branding_company_name' && setting.setting_value) {
|
||||
try {
|
||||
companyName = JSON.parse(setting.setting_value);
|
||||
} catch (e) {
|
||||
companyName = setting.setting_value;
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('Error fetching branding settings:', error);
|
||||
}
|
||||
|
||||
// If no custom logo, use default PicPeak logo
|
||||
const apiUrl = process.env.API_URL || 'http://localhost:3001';
|
||||
const frontendUrl = process.env.FRONTEND_URL || 'http://localhost:3005';
|
||||
const logoFullUrl = logoUrl ? `${apiUrl}${logoUrl}` : `${frontendUrl}/picpeak-logo-transparent.png`;
|
||||
|
||||
// Replace variables
|
||||
Object.entries(variables).forEach(([key, value]) => {
|
||||
const regex = new RegExp(`{{${key}}}`, 'g');
|
||||
@@ -69,7 +101,142 @@ function processTemplate(template, variables, language = 'en') {
|
||||
textBody = textBody.replace(regex, value || '');
|
||||
});
|
||||
|
||||
return { subject, htmlBody, textBody };
|
||||
// Wrap HTML body in styled template
|
||||
const styledHtmlBody = `
|
||||
<!DOCTYPE html>
|
||||
<html lang="${language}">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>${subject}</title>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||
background-color: #f5f5f5;
|
||||
color: #333;
|
||||
}
|
||||
.email-wrapper {
|
||||
background-color: #f5f5f5;
|
||||
padding: 40px 20px;
|
||||
}
|
||||
.email-container {
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
background-color: #ffffff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
overflow: hidden;
|
||||
}
|
||||
.email-header {
|
||||
background-color: #5C8762;
|
||||
padding: 30px;
|
||||
text-align: center;
|
||||
}
|
||||
.logo {
|
||||
max-width: 180px;
|
||||
height: auto;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.email-content {
|
||||
padding: 40px 30px;
|
||||
}
|
||||
.email-content h2 {
|
||||
color: #5C8762;
|
||||
margin-top: 0;
|
||||
margin-bottom: 20px;
|
||||
font-size: 24px;
|
||||
}
|
||||
.email-content p {
|
||||
line-height: 1.6;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.email-content ul {
|
||||
background-color: #f9f9f9;
|
||||
padding: 20px 20px 20px 40px;
|
||||
border-radius: 5px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
.email-content li {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.button {
|
||||
display: inline-block;
|
||||
padding: 12px 30px;
|
||||
background-color: #5C8762;
|
||||
color: white !important;
|
||||
text-decoration: none;
|
||||
border-radius: 5px;
|
||||
font-weight: 500;
|
||||
margin: 20px 0;
|
||||
}
|
||||
.button:hover {
|
||||
background-color: #4a6f4f;
|
||||
}
|
||||
.email-footer {
|
||||
background-color: #f9f9f9;
|
||||
padding: 30px;
|
||||
text-align: center;
|
||||
border-top: 1px solid #eee;
|
||||
}
|
||||
.email-footer img {
|
||||
max-width: 120px;
|
||||
height: auto;
|
||||
margin-bottom: 15px;
|
||||
opacity: 0.8;
|
||||
}
|
||||
.email-footer p {
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
margin: 5px 0;
|
||||
}
|
||||
a {
|
||||
color: #5C8762;
|
||||
text-decoration: underline;
|
||||
}
|
||||
a:hover {
|
||||
color: #4a6f4f;
|
||||
}
|
||||
strong {
|
||||
color: #333;
|
||||
}
|
||||
@media only screen and (max-width: 600px) {
|
||||
.email-wrapper {
|
||||
padding: 20px 10px;
|
||||
}
|
||||
.email-content {
|
||||
padding: 30px 20px;
|
||||
}
|
||||
.email-header {
|
||||
padding: 20px;
|
||||
}
|
||||
.logo {
|
||||
max-width: 150px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="email-wrapper">
|
||||
<div class="email-container">
|
||||
<div class="email-header">
|
||||
<img src="${logoFullUrl}" alt="${companyName}" class="logo">
|
||||
</div>
|
||||
<div class="email-content">
|
||||
${htmlBody}
|
||||
</div>
|
||||
<div class="email-footer">
|
||||
<img src="${logoFullUrl}" alt="${companyName}">
|
||||
<p>${companyName}</p>
|
||||
<p style="font-size: 12px; color: #999;">© ${new Date().getFullYear()} ${companyName}. All rights reserved.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>`;
|
||||
|
||||
return { subject, htmlBody: styledHtmlBody, textBody };
|
||||
}
|
||||
|
||||
// Send email using template
|
||||
@@ -101,7 +268,7 @@ async function sendTemplateEmail(to, templateKey, variables) {
|
||||
const language = await getRecipientLanguage(to);
|
||||
|
||||
// Process template with variables
|
||||
const { subject, htmlBody, textBody } = processTemplate(template, variables, language);
|
||||
const { subject, htmlBody, textBody } = await processTemplate(template, variables, language);
|
||||
|
||||
// Send email
|
||||
const info = await transporter.sendMail({
|
||||
|
||||
Reference in New Issue
Block a user