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:
@@ -133,7 +133,10 @@ router.put('/branding', adminAuth, async (req, res) => {
|
||||
watermark_enabled,
|
||||
watermark_position,
|
||||
watermark_opacity,
|
||||
watermark_size
|
||||
watermark_size,
|
||||
favicon_url,
|
||||
logo_url,
|
||||
watermark_logo_url
|
||||
} = req.body;
|
||||
|
||||
const brandingSettings = {
|
||||
@@ -144,9 +147,72 @@ router.put('/branding', adminAuth, async (req, res) => {
|
||||
watermark_enabled,
|
||||
watermark_position,
|
||||
watermark_opacity,
|
||||
watermark_size
|
||||
watermark_size,
|
||||
favicon_url,
|
||||
logo_url,
|
||||
watermark_logo_url
|
||||
};
|
||||
|
||||
// Handle favicon deletion if empty string or null is provided
|
||||
if (favicon_url === '' || favicon_url === null || favicon_url === undefined) {
|
||||
// Get current favicon path to delete file
|
||||
const currentFaviconSetting = await db('app_settings')
|
||||
.where('setting_key', 'branding_favicon_url')
|
||||
.first();
|
||||
|
||||
if (currentFaviconSetting && currentFaviconSetting.setting_value) {
|
||||
let currentFaviconUrl;
|
||||
try {
|
||||
// Try to parse as JSON first
|
||||
currentFaviconUrl = JSON.parse(currentFaviconSetting.setting_value);
|
||||
} catch (e) {
|
||||
// If it's not valid JSON, use the raw value
|
||||
currentFaviconUrl = currentFaviconSetting.setting_value;
|
||||
}
|
||||
|
||||
if (currentFaviconUrl && typeof currentFaviconUrl === 'string' && currentFaviconUrl.startsWith('/uploads/favicons/')) {
|
||||
// Delete the file from filesystem
|
||||
const faviconPath = path.join(__dirname, '..', '..', 'storage', currentFaviconUrl.replace('/uploads/', ''));
|
||||
try {
|
||||
await fs.unlink(faviconPath);
|
||||
console.log('Deleted favicon file:', faviconPath);
|
||||
} catch (err) {
|
||||
console.error('Error deleting favicon file:', err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle logo deletion if empty string or null is provided
|
||||
if (logo_url === '' || logo_url === null || logo_url === undefined) {
|
||||
// Get current logo path to delete file
|
||||
const currentLogoSetting = await db('app_settings')
|
||||
.where('setting_key', 'branding_logo_url')
|
||||
.first();
|
||||
|
||||
if (currentLogoSetting && currentLogoSetting.setting_value) {
|
||||
let currentLogoUrl;
|
||||
try {
|
||||
// Try to parse as JSON first
|
||||
currentLogoUrl = JSON.parse(currentLogoSetting.setting_value);
|
||||
} catch (e) {
|
||||
// If it's not valid JSON, use the raw value
|
||||
currentLogoUrl = currentLogoSetting.setting_value;
|
||||
}
|
||||
|
||||
if (currentLogoUrl && typeof currentLogoUrl === 'string' && currentLogoUrl.startsWith('/uploads/logos/')) {
|
||||
// Delete the file from filesystem
|
||||
const logoPath = path.join(__dirname, '..', '..', 'storage', currentLogoUrl.replace('/uploads/', ''));
|
||||
try {
|
||||
await fs.unlink(logoPath);
|
||||
console.log('Deleted logo file:', logoPath);
|
||||
} catch (err) {
|
||||
console.error('Error deleting logo file:', err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update or insert each setting
|
||||
for (const [key, value] of Object.entries(brandingSettings)) {
|
||||
await db('app_settings')
|
||||
|
||||
Reference in New Issue
Block a user